From d1fe216d0599c69c0e1733fca849b2cbf20bd611 Mon Sep 17 00:00:00 2001 From: bbinxie Date: Fri, 20 Sep 2019 22:26:40 +0800 Subject: [PATCH 001/278] Add new device data for dx010 (Celestica-DX010-C32,Celestica-DX010-D48C8) (#3492) * add config.bcm for hlx * modify config.bcm path for hlx * Delete hx4-cel-hbtn-48x1G+4x10G.config.bcm * add config.bcm and path * update led for cxp * Add new device data for dx010 --- .../Celestica-DX010-C32/buffers.json.j2 | 2 + .../buffers_defaults_t0.j2 | 54 ++ .../buffers_defaults_t1.j2 | 54 ++ .../Celestica-DX010-C32/pg_profile_lookup.ini | 17 + .../Celestica-DX010-C32/port_config.ini | 33 + .../Celestica-DX010-C32/qos.json.j2 | 1 + .../Celestica-DX010-C32/sai.profile.j2 | 13 + .../th-seastone-dx010-32x100G-t0.config.bcm | 376 ++++++++++ .../th-seastone-dx010-32x100G-t1.config.bcm | 696 ++++++++++++++++++ .../Celestica-DX010-D48C8/buffers.json.j2 | 2 + .../buffers_defaults_t0.j2 | 69 ++ .../pg_profile_lookup.ini | 17 + .../Celestica-DX010-D48C8/port_config.ini | 57 ++ .../Celestica-DX010-D48C8/qos.json.j2 | 1 + .../Celestica-DX010-D48C8/sai.profile | 1 + ...th-seastone-dx010-48x50G+8x100G.config.bcm | 648 ++++++++++++++++ 16 files changed, 2041 insertions(+) create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers.json.j2 create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t0.j2 create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t1.j2 create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/pg_profile_lookup.ini create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/port_config.ini create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/qos.json.j2 create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/sai.profile.j2 create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/th-seastone-dx010-32x100G-t0.config.bcm create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/th-seastone-dx010-32x100G-t1.config.bcm create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/buffers.json.j2 create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/buffers_defaults_t0.j2 create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/pg_profile_lookup.ini create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/port_config.ini create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/qos.json.j2 create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/sai.profile create mode 100644 device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/th-seastone-dx010-48x50G+8x100G.config.bcm diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers.json.j2 b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers.json.j2 new file mode 100644 index 000000000000..0b1cb2c541b6 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers.json.j2 @@ -0,0 +1,2 @@ +{%- set default_topo = 't1' %} +{%- include 'buffers_config.j2' %} diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t0.j2 b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t0.j2 new file mode 100644 index 000000000000..43b7d7e31a9c --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t0.j2 @@ -0,0 +1,54 @@ + +{%- set default_cable = '5m' %} + +{%- set ports2cable = { + 'torrouter_server' : '300m', + 'leafrouter_torrouter' : '300m', + 'spinerouter_leafrouter' : '300m' + } +-%} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {%- for port_idx in range(0,32) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %} + {%- endfor %} +{%- endmacro %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "10875072", + "type": "ingress", + "mode": "dynamic", + "xoff": "4194112" + }, + "egress_lossy_pool": { + "size": "9243812", + "type": "egress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "15982720", + "type": "egress", + "mode": "static" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "dynamic_th":"3" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "static_th":"3995680" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t1.j2 b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t1.j2 new file mode 100644 index 000000000000..6ec383c77081 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t1.j2 @@ -0,0 +1,54 @@ + +{%- set default_cable = '40m' %} + +{%- set ports2cable = { + 'torrouter_server' : '300m', + 'leafrouter_torrouter' : '300m', + 'spinerouter_leafrouter' : '300m' + } +-%} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {%- for port_idx in range(0,32) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %} + {%- endfor %} +{%- endmacro %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "10875072", + "type": "ingress", + "mode": "dynamic", + "xoff": "4194112" + }, + "egress_lossy_pool": { + "size": "9243812", + "type": "egress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "15982720", + "type": "egress", + "mode": "static" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "dynamic_th":"3" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "static_th":"3995680" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/pg_profile_lookup.ini b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/pg_profile_lookup.ini new file mode 100644 index 000000000000..aedda37a8878 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/pg_profile_lookup.ini @@ -0,0 +1,17 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold xon_offset + 10000 5m 1248 2288 35776 -3 2288 + 25000 5m 1248 2288 53248 -3 2288 + 40000 5m 1248 2288 66560 -3 2288 + 50000 5m 1248 2288 90272 -3 2288 + 100000 5m 1248 2288 165568 -3 2288 + 10000 40m 1248 2288 37024 -3 2288 + 25000 40m 1248 2288 53248 -3 2288 + 40000 40m 1248 2288 71552 -3 2288 + 50000 40m 1248 2288 96096 -3 2288 + 100000 40m 1248 2288 177632 -3 2288 + 10000 300m 1248 2288 46176 -3 2288 + 25000 300m 1248 2288 79040 -3 2288 + 40000 300m 1248 2288 108160 -3 2288 + 50000 300m 1248 2288 141856 -3 2288 + 100000 300m 1248 2288 268736 -3 2288 diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/port_config.ini b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/port_config.ini new file mode 100644 index 000000000000..24e7b3c99858 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/port_config.ini @@ -0,0 +1,33 @@ +# name lanes alias speed index +Ethernet0 65,66,67,68 etp1 100000 1 +Ethernet4 69,70,71,72 etp2 100000 2 +Ethernet8 73,74,75,76 etp3 100000 3 +Ethernet12 77,78,79,80 etp4 100000 4 +Ethernet16 33,34,35,36 etp5 100000 5 +Ethernet20 37,38,39,40 etp6 100000 6 +Ethernet24 41,42,43,44 etp7 100000 7 +Ethernet28 45,46,47,48 etp8 100000 8 +Ethernet32 49,50,51,52 etp9 100000 9 +Ethernet36 53,54,55,56 etp10 100000 10 +Ethernet40 57,58,59,60 etp11 100000 11 +Ethernet44 61,62,63,64 etp12 100000 12 +Ethernet48 81,82,83,84 etp13 100000 13 +Ethernet52 85,86,87,88 etp14 100000 14 +Ethernet56 89,90,91,92 etp15 100000 15 +Ethernet60 93,94,95,96 etp16 100000 16 +Ethernet64 97,98,99,100 etp17 100000 17 +Ethernet68 101,102,103,104 etp18 100000 18 +Ethernet72 105,106,107,108 etp19 100000 19 +Ethernet76 109,110,111,112 etp20 100000 20 +Ethernet80 1,2,3,4 etp21 100000 21 +Ethernet84 5,6,7,8 etp22 100000 22 +Ethernet88 9,10,11,12 etp23 100000 23 +Ethernet92 13,14,15,16 etp24 100000 24 +Ethernet96 17,18,19,20 etp25 100000 25 +Ethernet100 21,22,23,24 etp26 100000 26 +Ethernet104 25,26,27,28 etp27 100000 27 +Ethernet108 29,30,31,32 etp28 100000 28 +Ethernet112 113,114,115,116 etp29 100000 29 +Ethernet116 117,118,119,120 etp30 100000 30 +Ethernet120 121,122,123,124 etp31 100000 31 +Ethernet124 125,126,127,128 etp32 100000 32 diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/qos.json.j2 b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/qos.json.j2 new file mode 100644 index 000000000000..3e548325ea30 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/qos.json.j2 @@ -0,0 +1 @@ +{%- include 'qos_config.j2' %} diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/sai.profile.j2 b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/sai.profile.j2 new file mode 100644 index 000000000000..abc2daefd04e --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/sai.profile.j2 @@ -0,0 +1,13 @@ +{# Get sai.profile based on switch_role #} +{%- if DEVICE_METADATA is defined and DEVICE_METADATA['localhost'] is defined and DEVICE_METADATA['localhost']['type'] is defined -%} +{%- set switch_role = DEVICE_METADATA['localhost']['type'] -%} +{%- if switch_role.lower() == 'torrouter' %} +{% set sai_profile_contents = 'SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/th-seastone-dx010-32x100G-t0.config.bcm' -%} +{%- else %} +{% set sai_profile_contents = 'SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/th-seastone-dx010-32x100G-t1.config.bcm' -%} +{%- endif %} +{%- else %} +{% set sai_profile_contents = 'SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/th-seastone-dx010-32x100G-t1.config.bcm' -%} +{%- endif %} +{# Write the contents of sai_ profile_filename to sai.profile file #} +{{ sai_profile_contents }} diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/th-seastone-dx010-32x100G-t0.config.bcm b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/th-seastone-dx010-32x100G-t0.config.bcm new file mode 100644 index 000000000000..7c315460dc8e --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/th-seastone-dx010-32x100G-t0.config.bcm @@ -0,0 +1,376 @@ +# Define default OS / SAL +os=unix + +# all XPORTs to XE ports +#pbmp_xport_xe=0x1fffffffe +pbmp_xport_xe=0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +pbmp_oversubscribe=0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe + +# Mode control to select L2 Table DMA mode aka L2MODE_POLL (0) or +# L2MOD_FIFO mechanism aka L2MODE_FIFO (1) for L2 table change notification. +l2xmsg_mode=1 + +# Memory table size configs +l2_mem_entries=8192 +l3_mem_entries=8192 +l3_alpm_enable=2 +ipv6_lpm_128b_enable=1 +mmu_lossless=0 + +################################################################################### +# Celestica Customize for SeaStone +################################################################################### + +#ext mdio frequency to 495/0x80/2(1.933Mhz) or 415/0x80/2(1.62MHz) +# default is 40 +# Set external MDIO freq to 6.19MHz (495MHz) or 5.19MHz (415MHz) +#* target_freq is core_clock_freq * DIVIDEND / DIVISOR / 2 +# +rate_ext_mdio_divisor=0x80 + +# use internal rom boot +phy_ext_rom_boot=0 + +#fpem_mem_entries=32768 +oversubscribe_mode=1 +#pbmp_xport_xe=0x3fd000000ff4000003fc000001fe + + +dport_map_enable=1 + +dport_map_port_68=1 +dport_map_port_72=5 +dport_map_port_76=9 +dport_map_port_80=13 +dport_map_port_34=17 +dport_map_port_38=21 +dport_map_port_42=25 +dport_map_port_46=29 +dport_map_port_50=33 +dport_map_port_54=37 +dport_map_port_58=41 +dport_map_port_62=45 +dport_map_port_84=49 +dport_map_port_88=53 +dport_map_port_92=57 +dport_map_port_96=61 +dport_map_port_102=65 +dport_map_port_106=69 +dport_map_port_110=73 +dport_map_port_114=77 +dport_map_port_1=81 +dport_map_port_5=85 +dport_map_port_9=89 +dport_map_port_13=93 +dport_map_port_17=97 +dport_map_port_21=101 +dport_map_port_25=105 +dport_map_port_29=109 +dport_map_port_118=113 +dport_map_port_122=117 +dport_map_port_126=121 +dport_map_port_130=125 + + +# port mapping +portmap_68=65:100:4 +portmap_72=69:100:4 +portmap_76=73:100:4 +portmap_80=77:100:4 +portmap_34=33:100:4 +portmap_38=37:100:4 +portmap_42=41:100:4 +portmap_46=45:100:4 +portmap_50=49:100:4 +portmap_54=53:100:4 +portmap_58=57:100:4 +portmap_62=61:100:4 +portmap_84=81:100:4 +portmap_88=85:100:4 +portmap_92=89:100:4 +portmap_96=93:100:4 +portmap_102=97:100:4 +portmap_106=101:100:4 +portmap_110=105:100:4 +portmap_114=109:100:4 +portmap_1=1:100:4 +portmap_5=5:100:4 +portmap_9=9:100:4 +portmap_13=13:100:4 +portmap_17=17:100:4 +portmap_21=21:100:4 +portmap_25=25:100:4 +portmap_29=29:100:4 +portmap_118=113:100:4 +portmap_122=117:100:4 +portmap_126=121:100:4 +portmap_130=125:100:4 +#portmap_66=129:10 +#portmap_100=131:10 + +#WC16 +xgxs_tx_lane_map_68=0x3201 +xgxs_rx_lane_map_68=0x2310 + + +#WC17 +xgxs_tx_lane_map_72=0x3201 +xgxs_rx_lane_map_72=0x2301 + +#WC18 +xgxs_tx_lane_map_76=0x0132 +xgxs_rx_lane_map_76=0x0123 + +#WC19 +xgxs_tx_lane_map_80=0x2031 +xgxs_rx_lane_map_80=0x1320 + +#WC8 +xgxs_tx_lane_map_34=0x3021 +xgxs_rx_lane_map_34=0x0213 + +#WC9 +xgxs_tx_lane_map_38=0x3210 +xgxs_rx_lane_map_38=0x1023 + +#WC10 +xgxs_tx_lane_map_42=0x2310 +xgxs_rx_lane_map_42=0x3210 + +#WC11 +xgxs_tx_lane_map_46=0x1032 +xgxs_rx_lane_map_46=0x1302 + +#WC12 +xgxs_tx_lane_map_50=0x3201 +xgxs_rx_lane_map_50=0x0213 + + +#WC13 +xgxs_tx_lane_map_54=0x2301 +xgxs_rx_lane_map_54=0x2310 + +#WC14 +xgxs_tx_lane_map_58=0x3201 +xgxs_rx_lane_map_58=0x0213 + +#WC15 +xgxs_tx_lane_map_62=0x1302 +xgxs_rx_lane_map_62=0x2310 + +#WC20 +xgxs_tx_lane_map_84=0x0213 +xgxs_rx_lane_map_84=0x2301 + +#WC21 +xgxs_tx_lane_map_88=0x0132 +xgxs_rx_lane_map_88=0x3210 + +#WC22 +xgxs_tx_lane_map_92=0x0132 +xgxs_rx_lane_map_92=0x2031 + +#WC23 +xgxs_tx_lane_map_96=0x2031 +xgxs_rx_lane_map_96=0x3201 + +#WC24 +xgxs_tx_lane_map_102=0x0132 +xgxs_rx_lane_map_102=0x2301 + +#WC25 +xgxs_tx_lane_map_106=0x0132 +xgxs_rx_lane_map_106=0x3201 + +#WC26 +xgxs_tx_lane_map_110=0x0132 +xgxs_rx_lane_map_110=0x2031 + +#WC27 +xgxs_tx_lane_map_114=0x2031 +xgxs_rx_lane_map_114=0x2301 + + +#WC0 +xgxs_tx_lane_map_1=0x3210 +xgxs_rx_lane_map_1=0x3120 + +#WC1 +xgxs_tx_lane_map_5=0x0132 +xgxs_rx_lane_map_5=0x1023 + +#WC2 +xgxs_tx_lane_map_9=0x3201 +xgxs_rx_lane_map_9=0x3120 + +#WC3 +xgxs_tx_lane_map_13=0x2031 +xgxs_rx_lane_map_13=0x1032 + +#WC4 +xgxs_tx_lane_map_17=0x2310 +xgxs_rx_lane_map_17=0x3210 + +#WC5 +xgxs_tx_lane_map_21=0x2301 +xgxs_rx_lane_map_21=0x3120 + +#WC6 +xgxs_tx_lane_map_25=0x3201 +xgxs_rx_lane_map_25=0x0213 + +#WC7 +xgxs_tx_lane_map_29=0x1302 +xgxs_rx_lane_map_29=0x1023 + +#WC28 +xgxs_tx_lane_map_118=0x1320 +xgxs_rx_lane_map_118=0x1302 + +#WC29 +xgxs_tx_lane_map_122=0x1032 +xgxs_rx_lane_map_122=0x1023 + +#WC30 +xgxs_tx_lane_map_126=0x3120 +xgxs_rx_lane_map_126=0x3120 + +#WC31 +xgxs_tx_lane_map_130=0x1302 +xgxs_rx_lane_map_130=0x2310 + +#PN + +#WC16 +phy_xaui_tx_polarity_flip_68=0x0000 +phy_xaui_rx_polarity_flip_68=0x0000 + +#WC17 +phy_xaui_tx_polarity_flip_72=0x000D +phy_xaui_rx_polarity_flip_72=0x0002 + + +#WC18 +phy_xaui_tx_polarity_flip_76=0x000F +phy_xaui_rx_polarity_flip_76=0x0000 + +#WC19 +phy_xaui_tx_polarity_flip_80=0x000F +phy_xaui_rx_polarity_flip_80=0x000F + + +#WC8 +phy_xaui_tx_polarity_flip_34=0x000E +phy_xaui_rx_polarity_flip_34=0x0000 + +#WC9 +phy_xaui_tx_polarity_flip_38=0x0008 +phy_xaui_rx_polarity_flip_38=0x0000 + +#WC10 +phy_xaui_tx_polarity_flip_42=0x000D +phy_xaui_rx_polarity_flip_42=0x0000 + +#WC11 +phy_xaui_tx_polarity_flip_46=0x0000 +phy_xaui_rx_polarity_flip_46=0x0000 + + +#WC12 +phy_xaui_tx_polarity_flip_50=0x0002 +phy_xaui_rx_polarity_flip_50=0x0000 + +#WC13 +phy_xaui_tx_polarity_flip_54=0x0002 +phy_xaui_rx_polarity_flip_54=0x0000 + +#WC14 +phy_xaui_tx_polarity_flip_58=0x0000 +phy_xaui_rx_polarity_flip_58=0x0000 + +#WC15 +phy_xaui_tx_polarity_flip_62=0x000A +phy_xaui_rx_polarity_flip_62=0x000F + + +#WC20 + phy_xaui_tx_polarity_flip_84=0x0007 + phy_xaui_rx_polarity_flip_84=0x000E + +#WC21 +phy_xaui_tx_polarity_flip_88=0x000D +phy_xaui_rx_polarity_flip_88=0x000D + +#WC22 +phy_xaui_tx_polarity_flip_92=0x000F +phy_xaui_rx_polarity_flip_92=0x0008 + +#WC23 +phy_xaui_tx_polarity_flip_96=0x0005 +phy_xaui_rx_polarity_flip_96=0x0000 + +#WC24 +phy_xaui_tx_polarity_flip_102=0x0000 +phy_xaui_rx_polarity_flip_102=0x000F + +#WC25 +phy_xaui_tx_polarity_flip_106=0x000F +phy_xaui_rx_polarity_flip_106=0x0000 + +#WC26 +phy_xaui_tx_polarity_flip_110=0x000F +phy_xaui_rx_polarity_flip_110=0x000F + +#WC27 +phy_xaui_tx_polarity_flip_114=0x000F +phy_xaui_rx_polarity_flip_114=0x0007 + +#WC0 +phy_xaui_tx_polarity_flip_1=0x0003 +phy_xaui_rx_polarity_flip_1=0x000F + +#WC1 +phy_xaui_tx_polarity_flip_5=0x0007 +phy_xaui_rx_polarity_flip_5=0x0000 + +#WC2 +phy_xaui_tx_polarity_flip_9=0x0002 +phy_xaui_rx_polarity_flip_9=0x0008 + +#WC3 +phy_xaui_tx_polarity_flip_13=0x000F +phy_xaui_rx_polarity_flip_13=0x0000 + +#WC4 +phy_xaui_tx_polarity_flip_17=0x0007 +phy_xaui_rx_polarity_flip_17=0x0000 + +#WC5 +phy_xaui_tx_polarity_flip_21=0x0000 +phy_xaui_rx_polarity_flip_21=0x0000 + +#WC6 +phy_xaui_tx_polarity_flip_25=0x0002 +phy_xaui_rx_polarity_flip_25=0x0005 + +#WC7 +phy_xaui_tx_polarity_flip_29=0x0002 +phy_xaui_rx_polarity_flip_29=0x0000 + +#WC28 +phy_xaui_tx_polarity_flip_118=0x000F +phy_xaui_rx_polarity_flip_118=0x000F + +#WC29 +phy_xaui_tx_polarity_flip_122=0x0004 +phy_xaui_rx_polarity_flip_122=0x0000 + +#WC30 +phy_xaui_tx_polarity_flip_126=0x000F +phy_xaui_rx_polarity_flip_126=0x0000 + +#WC31 +phy_xaui_tx_polarity_flip_130=0x0006 +phy_xaui_rx_polarity_flip_130=0x0000 + +mmu_init_config="MSFT-TH-Tier0" diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/th-seastone-dx010-32x100G-t1.config.bcm b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/th-seastone-dx010-32x100G-t1.config.bcm new file mode 100644 index 000000000000..effdfb5d7570 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/th-seastone-dx010-32x100G-t1.config.bcm @@ -0,0 +1,696 @@ +# Define default OS / SAL +os=unix + +# all XPORTs to XE ports +#pbmp_xport_xe=0x1fffffffe +pbmp_xport_xe=0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +pbmp_oversubscribe=0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe + +# Mode control to select L2 Table DMA mode aka L2MODE_POLL (0) or +# L2MOD_FIFO mechanism aka L2MODE_FIFO (1) for L2 table change notification. +l2xmsg_mode=1 + +# Memory table size configs +l2_mem_entries=8192 +l3_mem_entries=8192 +l3_alpm_enable=2 +ipv6_lpm_128b_enable=1 +mmu_lossless=0 + +################################################################################### +# Celestica Customize for SeaStone +################################################################################### + +#ext mdio frequency to 495/0x80/2(1.933Mhz) or 415/0x80/2(1.62MHz) +# default is 40 +# Set external MDIO freq to 6.19MHz (495MHz) or 5.19MHz (415MHz) +#* target_freq is core_clock_freq * DIVIDEND / DIVISOR / 2 +# +rate_ext_mdio_divisor=0x80 + +# use internal rom boot +phy_ext_rom_boot=0 + +#fpem_mem_entries=32768 +oversubscribe_mode=1 +#pbmp_xport_xe=0x3fd000000ff4000003fc000001fe + + +dport_map_enable=1 + +dport_map_port_68=1 +dport_map_port_72=5 +dport_map_port_76=9 +dport_map_port_80=13 +dport_map_port_34=17 +dport_map_port_38=21 +dport_map_port_42=25 +dport_map_port_46=29 +dport_map_port_50=33 +dport_map_port_54=37 +dport_map_port_58=41 +dport_map_port_62=45 +dport_map_port_84=49 +dport_map_port_88=53 +dport_map_port_92=57 +dport_map_port_96=61 +dport_map_port_102=65 +dport_map_port_106=69 +dport_map_port_110=73 +dport_map_port_114=77 +dport_map_port_1=81 +dport_map_port_5=85 +dport_map_port_9=89 +dport_map_port_13=93 +dport_map_port_17=97 +dport_map_port_21=101 +dport_map_port_25=105 +dport_map_port_29=109 +dport_map_port_118=113 +dport_map_port_122=117 +dport_map_port_126=121 +dport_map_port_130=125 + + +# port mapping +portmap_68=65:100:4 +portmap_72=69:100:4 +portmap_76=73:100:4 +portmap_80=77:100:4 +portmap_34=33:100:4 +portmap_38=37:100:4 +portmap_42=41:100:4 +portmap_46=45:100:4 +portmap_50=49:100:4 +portmap_54=53:100:4 +portmap_58=57:100:4 +portmap_62=61:100:4 +portmap_84=81:100:4 +portmap_88=85:100:4 +portmap_92=89:100:4 +portmap_96=93:100:4 +portmap_102=97:100:4 +portmap_106=101:100:4 +portmap_110=105:100:4 +portmap_114=109:100:4 +portmap_1=1:100:4 +portmap_5=5:100:4 +portmap_9=9:100:4 +portmap_13=13:100:4 +portmap_17=17:100:4 +portmap_21=21:100:4 +portmap_25=25:100:4 +portmap_29=29:100:4 +portmap_118=113:100:4 +portmap_122=117:100:4 +portmap_126=121:100:4 +portmap_130=125:100:4 +#portmap_66=129:10 +#portmap_100=131:10 + +#WC16 +xgxs_tx_lane_map_68=0x3201 +xgxs_rx_lane_map_68=0x2310 + + +#WC17 +xgxs_tx_lane_map_72=0x3201 +xgxs_rx_lane_map_72=0x2301 + +#WC18 +xgxs_tx_lane_map_76=0x0132 +xgxs_rx_lane_map_76=0x0123 + +#WC19 +xgxs_tx_lane_map_80=0x2031 +xgxs_rx_lane_map_80=0x1320 + +#WC8 +xgxs_tx_lane_map_34=0x3021 +xgxs_rx_lane_map_34=0x0213 + +#WC9 +xgxs_tx_lane_map_38=0x3210 +xgxs_rx_lane_map_38=0x1023 + +#WC10 +xgxs_tx_lane_map_42=0x2310 +xgxs_rx_lane_map_42=0x3210 + +#WC11 +xgxs_tx_lane_map_46=0x1032 +xgxs_rx_lane_map_46=0x1302 + +#WC12 +xgxs_tx_lane_map_50=0x3201 +xgxs_rx_lane_map_50=0x0213 + + +#WC13 +xgxs_tx_lane_map_54=0x2301 +xgxs_rx_lane_map_54=0x2310 + +#WC14 +xgxs_tx_lane_map_58=0x3201 +xgxs_rx_lane_map_58=0x0213 + +#WC15 +xgxs_tx_lane_map_62=0x1302 +xgxs_rx_lane_map_62=0x2310 + +#WC20 +xgxs_tx_lane_map_84=0x0213 +xgxs_rx_lane_map_84=0x2301 + +#WC21 +xgxs_tx_lane_map_88=0x0132 +xgxs_rx_lane_map_88=0x3210 + +#WC22 +xgxs_tx_lane_map_92=0x0132 +xgxs_rx_lane_map_92=0x2031 + +#WC23 +xgxs_tx_lane_map_96=0x2031 +xgxs_rx_lane_map_96=0x3201 + +#WC24 +xgxs_tx_lane_map_102=0x0132 +xgxs_rx_lane_map_102=0x2301 + +#WC25 +xgxs_tx_lane_map_106=0x0132 +xgxs_rx_lane_map_106=0x3201 + +#WC26 +xgxs_tx_lane_map_110=0x0132 +xgxs_rx_lane_map_110=0x2031 + +#WC27 +xgxs_tx_lane_map_114=0x2031 +xgxs_rx_lane_map_114=0x2301 + + +#WC0 +xgxs_tx_lane_map_1=0x3210 +xgxs_rx_lane_map_1=0x3120 + +#WC1 +xgxs_tx_lane_map_5=0x0132 +xgxs_rx_lane_map_5=0x1023 + +#WC2 +xgxs_tx_lane_map_9=0x3201 +xgxs_rx_lane_map_9=0x3120 + +#WC3 +xgxs_tx_lane_map_13=0x2031 +xgxs_rx_lane_map_13=0x1032 + +#WC4 +xgxs_tx_lane_map_17=0x2310 +xgxs_rx_lane_map_17=0x3210 + +#WC5 +xgxs_tx_lane_map_21=0x2301 +xgxs_rx_lane_map_21=0x3120 + +#WC6 +xgxs_tx_lane_map_25=0x3201 +xgxs_rx_lane_map_25=0x0213 + +#WC7 +xgxs_tx_lane_map_29=0x1302 +xgxs_rx_lane_map_29=0x1023 + +#WC28 +xgxs_tx_lane_map_118=0x1320 +xgxs_rx_lane_map_118=0x1302 + +#WC29 +xgxs_tx_lane_map_122=0x1032 +xgxs_rx_lane_map_122=0x1023 + +#WC30 +xgxs_tx_lane_map_126=0x3120 +xgxs_rx_lane_map_126=0x3120 + +#WC31 +xgxs_tx_lane_map_130=0x1302 +xgxs_rx_lane_map_130=0x2310 + +#PN + +#WC16 +phy_xaui_tx_polarity_flip_68=0x0000 +phy_xaui_rx_polarity_flip_68=0x0000 + +#WC17 +phy_xaui_tx_polarity_flip_72=0x000D +phy_xaui_rx_polarity_flip_72=0x0002 + + +#WC18 +phy_xaui_tx_polarity_flip_76=0x000F +phy_xaui_rx_polarity_flip_76=0x0000 + +#WC19 +phy_xaui_tx_polarity_flip_80=0x000F +phy_xaui_rx_polarity_flip_80=0x000F + + +#WC8 +phy_xaui_tx_polarity_flip_34=0x000E +phy_xaui_rx_polarity_flip_34=0x0000 + +#WC9 +phy_xaui_tx_polarity_flip_38=0x0008 +phy_xaui_rx_polarity_flip_38=0x0000 + +#WC10 +phy_xaui_tx_polarity_flip_42=0x000D +phy_xaui_rx_polarity_flip_42=0x0000 + +#WC11 +phy_xaui_tx_polarity_flip_46=0x0000 +phy_xaui_rx_polarity_flip_46=0x0000 + + +#WC12 +phy_xaui_tx_polarity_flip_50=0x0002 +phy_xaui_rx_polarity_flip_50=0x0000 + +#WC13 +phy_xaui_tx_polarity_flip_54=0x0002 +phy_xaui_rx_polarity_flip_54=0x0000 + +#WC14 +phy_xaui_tx_polarity_flip_58=0x0000 +phy_xaui_rx_polarity_flip_58=0x0000 + +#WC15 +phy_xaui_tx_polarity_flip_62=0x000A +phy_xaui_rx_polarity_flip_62=0x000F + + +#WC20 + phy_xaui_tx_polarity_flip_84=0x0007 + phy_xaui_rx_polarity_flip_84=0x000E + +#WC21 +phy_xaui_tx_polarity_flip_88=0x000D +phy_xaui_rx_polarity_flip_88=0x000D + +#WC22 +phy_xaui_tx_polarity_flip_92=0x000F +phy_xaui_rx_polarity_flip_92=0x0008 + +#WC23 +phy_xaui_tx_polarity_flip_96=0x0005 +phy_xaui_rx_polarity_flip_96=0x0000 + +#WC24 +phy_xaui_tx_polarity_flip_102=0x0000 +phy_xaui_rx_polarity_flip_102=0x000F + +#WC25 +phy_xaui_tx_polarity_flip_106=0x000F +phy_xaui_rx_polarity_flip_106=0x0000 + +#WC26 +phy_xaui_tx_polarity_flip_110=0x000F +phy_xaui_rx_polarity_flip_110=0x000F + +#WC27 +phy_xaui_tx_polarity_flip_114=0x000F +phy_xaui_rx_polarity_flip_114=0x0007 + +#WC0 +phy_xaui_tx_polarity_flip_1=0x0003 +phy_xaui_rx_polarity_flip_1=0x000F + +#WC1 +phy_xaui_tx_polarity_flip_5=0x0007 +phy_xaui_rx_polarity_flip_5=0x0000 + +#WC2 +phy_xaui_tx_polarity_flip_9=0x0002 +phy_xaui_rx_polarity_flip_9=0x0008 + +#WC3 +phy_xaui_tx_polarity_flip_13=0x000F +phy_xaui_rx_polarity_flip_13=0x0000 + +#WC4 +phy_xaui_tx_polarity_flip_17=0x0007 +phy_xaui_rx_polarity_flip_17=0x0000 + +#WC5 +phy_xaui_tx_polarity_flip_21=0x0000 +phy_xaui_rx_polarity_flip_21=0x0000 + +#WC6 +phy_xaui_tx_polarity_flip_25=0x0002 +phy_xaui_rx_polarity_flip_25=0x0005 + +#WC7 +phy_xaui_tx_polarity_flip_29=0x0002 +phy_xaui_rx_polarity_flip_29=0x0000 + +#WC28 +phy_xaui_tx_polarity_flip_118=0x000F +phy_xaui_rx_polarity_flip_118=0x000F + +#WC29 +phy_xaui_tx_polarity_flip_122=0x0004 +phy_xaui_rx_polarity_flip_122=0x0000 + +#WC30 +phy_xaui_tx_polarity_flip_126=0x000F +phy_xaui_rx_polarity_flip_126=0x0000 + +#WC31 +phy_xaui_tx_polarity_flip_130=0x0006 +phy_xaui_rx_polarity_flip_130=0x0000 + +#ce0 +serdes_driver_current_lane0_68=0x0b +serdes_driver_current_lane1_68=0x0b +serdes_driver_current_lane2_68=0x0b +serdes_driver_current_lane3_68=0x0b +serdes_preemphasis_lane0_68=0x2d3f04 +serdes_preemphasis_lane1_68=0x2b4104 +serdes_preemphasis_lane2_68=0x2b4104 +serdes_preemphasis_lane3_68=0x2d3f04 + +#ce1 +serdes_driver_current_lane0_72=0x0b +serdes_driver_current_lane1_72=0x0a +serdes_driver_current_lane2_72=0x0a +serdes_driver_current_lane3_72=0x0b +serdes_preemphasis_lane0_72=0x2b4104 +serdes_preemphasis_lane1_72=0x294403 +serdes_preemphasis_lane2_72=0x294403 +serdes_preemphasis_lane3_72=0x2b4104 + +#ce2 +serdes_driver_current_lane0_76=0x0a +serdes_driver_current_lane1_76=0x0a +serdes_driver_current_lane2_76=0x0a +serdes_driver_current_lane3_76=0x0a +serdes_preemphasis_lane0_76=0x294403 +serdes_preemphasis_lane1_76=0x294403 +serdes_preemphasis_lane2_76=0x294403 +serdes_preemphasis_lane3_76=0x294403 + +#ce3 +serdes_driver_current_lane0_80=0x0a +serdes_driver_current_lane1_80=0x0a +serdes_driver_current_lane2_80=0x0a +serdes_driver_current_lane3_80=0x0a +serdes_preemphasis_lane0_80=0x254902 +serdes_preemphasis_lane1_80=0x254902 +serdes_preemphasis_lane2_80=0x294403 +serdes_preemphasis_lane3_80=0x294403 + +#ce4 +serdes_driver_current_lane0_34=0x0b +serdes_driver_current_lane1_34=0x0b +serdes_driver_current_lane2_34=0x0b +serdes_driver_current_lane3_34=0x0b +serdes_preemphasis_lane0_34=0x2b4104 +serdes_preemphasis_lane1_34=0x2d3f04 +serdes_preemphasis_lane2_34=0x2d3f04 +serdes_preemphasis_lane3_34=0x2b4104 + +#ce5 +serdes_driver_current_lane0_38=0x0a +serdes_driver_current_lane1_38=0x0b +serdes_driver_current_lane2_38=0x0b +serdes_driver_current_lane3_38=0x0b +serdes_preemphasis_lane0_38=0x294403 +serdes_preemphasis_lane1_38=0x2b4104 +serdes_preemphasis_lane2_38=0x2b4104 +serdes_preemphasis_lane3_38=0x2b4104 + +#ce6 +serdes_driver_current_lane0_42=0x0a +serdes_driver_current_lane1_42=0x0b +serdes_driver_current_lane2_42=0x0a +serdes_driver_current_lane3_42=0x0a +serdes_preemphasis_lane0_42=0x294403 +serdes_preemphasis_lane1_42=0x2b4104 +serdes_preemphasis_lane2_42=0x294403 +serdes_preemphasis_lane3_42=0x294403 + +#ce7 +serdes_driver_current_lane0_46=0x0a +serdes_driver_current_lane1_46=0x0a +serdes_driver_current_lane2_46=0x0a +serdes_driver_current_lane3_46=0x0a +serdes_preemphasis_lane0_46=0x254902 +serdes_preemphasis_lane1_46=0x294403 +serdes_preemphasis_lane2_46=0x254902 +serdes_preemphasis_lane3_46=0x294403 + +#ce8 +serdes_driver_current_lane0_50=0x0a +serdes_driver_current_lane1_50=0x0a +serdes_driver_current_lane2_50=0x0a +serdes_driver_current_lane3_50=0x0a +serdes_preemphasis_lane0_50=0x294403 +serdes_preemphasis_lane1_50=0x254902 +serdes_preemphasis_lane2_50=0x254902 +serdes_preemphasis_lane3_50=0x254902 + +#ce9 +serdes_driver_current_lane0_54=0x0a +serdes_driver_current_lane1_54=0x09 +serdes_driver_current_lane2_54=0x0a +serdes_driver_current_lane3_54=0x09 +serdes_preemphasis_lane0_54=0x254902 +serdes_preemphasis_lane1_54=0x244a02 +serdes_preemphasis_lane2_54=0x254902 +serdes_preemphasis_lane3_54=0x244a02 + +#ce10 +serdes_driver_current_lane0_58=0x0a +serdes_driver_current_lane1_58=0x09 +serdes_driver_current_lane2_58=0x09 +serdes_driver_current_lane3_58=0x0a +serdes_preemphasis_lane0_58=0x254902 +serdes_preemphasis_lane1_58=0x244a02 +serdes_preemphasis_lane2_58=0x244a02 +serdes_preemphasis_lane3_58=0x254902 + +#ce11 +serdes_driver_current_lane0_62=0x09 +serdes_driver_current_lane1_62=0x0a +serdes_driver_current_lane2_62=0x09 +serdes_driver_current_lane3_62=0x09 +serdes_preemphasis_lane0_62=0x244a02 +serdes_preemphasis_lane1_62=0x254902 +serdes_preemphasis_lane2_62=0x244a02 +serdes_preemphasis_lane3_62=0x244a02 + +#ce12 +serdes_driver_current_lane0_84=0x09 +serdes_driver_current_lane1_84=0x09 +serdes_driver_current_lane2_84=0x09 +serdes_driver_current_lane3_84=0x09 +serdes_preemphasis_lane0_84=0x204e02 +serdes_preemphasis_lane1_84=0x204e02 +serdes_preemphasis_lane2_84=0x204e02 +serdes_preemphasis_lane3_84=0x204e02 + +#ce13 +serdes_driver_current_lane0_88=0x09 +serdes_driver_current_lane1_88=0x08 +serdes_driver_current_lane2_88=0x08 +serdes_driver_current_lane3_88=0x09 +serdes_preemphasis_lane0_88=0x204e02 +serdes_preemphasis_lane1_88=0x1d5102 +serdes_preemphasis_lane2_88=0x1d5102 +serdes_preemphasis_lane3_88=0x204e02 + +#ce14 +serdes_driver_current_lane0_92=0x09 +serdes_driver_current_lane1_92=0x08 +serdes_driver_current_lane2_92=0x08 +serdes_driver_current_lane3_92=0x09 +serdes_preemphasis_lane0_92=0x204e02 +serdes_preemphasis_lane1_92=0x1d5102 +serdes_preemphasis_lane2_92=0x1d5102 +serdes_preemphasis_lane3_92=0x204e02 + +#ce15 +serdes_driver_current_lane0_96=0x08 +serdes_driver_current_lane1_96=0x08 +serdes_driver_current_lane2_96=0x09 +serdes_driver_current_lane3_96=0x09 +serdes_preemphasis_lane0_96=0x1d5102 +serdes_preemphasis_lane1_96=0x1d5102 +serdes_preemphasis_lane2_96=0x204e02 +serdes_preemphasis_lane3_96=0x204e02 + +#ce16 +serdes_driver_current_lane0_102=0x09 +serdes_driver_current_lane1_102=0x08 +serdes_driver_current_lane2_102=0x08 +serdes_driver_current_lane3_102=0x09 +serdes_preemphasis_lane0_102=0x204e02 +serdes_preemphasis_lane1_102=0x1d5102 +serdes_preemphasis_lane2_102=0x1d5102 +serdes_preemphasis_lane3_102=0x224c02 + +#ce17 +serdes_driver_current_lane0_106=0x09 +serdes_driver_current_lane1_106=0x08 +serdes_driver_current_lane2_106=0x08 +serdes_driver_current_lane3_106=0x09 +serdes_preemphasis_lane0_106=0x204e02 +serdes_preemphasis_lane1_106=0x1d5102 +serdes_preemphasis_lane2_106=0x1d5102 +serdes_preemphasis_lane3_106=0x204e02 + +#ce18 +serdes_driver_current_lane0_110=0x09 +serdes_driver_current_lane1_110=0x08 +serdes_driver_current_lane2_110=0x08 +serdes_driver_current_lane3_110=0x09 +serdes_preemphasis_lane0_110=0x204e02 +serdes_preemphasis_lane1_110=0x1d5102 +serdes_preemphasis_lane2_110=0x1d5102 +serdes_preemphasis_lane3_110=0x204e02 + +#ce19 +serdes_driver_current_lane0_114=0x09 +serdes_driver_current_lane1_114=0x08 +serdes_driver_current_lane2_114=0x09 +serdes_driver_current_lane3_114=0x09 +serdes_preemphasis_lane0_114=0x204e02 +serdes_preemphasis_lane1_114=0x1d5102 +serdes_preemphasis_lane2_114=0x224c02 +serdes_preemphasis_lane3_114=0x224c02 + +#ce20 +serdes_driver_current_lane0_1=0x09 +serdes_driver_current_lane1_1=0x0a +serdes_driver_current_lane2_1=0x09 +serdes_driver_current_lane3_1=0x0a +serdes_preemphasis_lane0_1=0x244a02 +serdes_preemphasis_lane1_1=0x254902 +serdes_preemphasis_lane2_1=0x244a02 +serdes_preemphasis_lane3_1=0x254902 + +#ce21 +serdes_driver_current_lane0_5=0x09 +serdes_driver_current_lane1_5=0x09 +serdes_driver_current_lane2_5=0x09 +serdes_driver_current_lane3_5=0x0a +serdes_preemphasis_lane0_5=0x244a02 +serdes_preemphasis_lane1_5=0x244a02 +serdes_preemphasis_lane2_5=0x244a02 +serdes_preemphasis_lane3_5=0x254902 + +#ce22 +serdes_driver_current_lane0_9=0x0a +serdes_driver_current_lane1_9=0x0a +serdes_driver_current_lane2_9=0x0a +serdes_driver_current_lane3_9=0x0a +serdes_preemphasis_lane0_9=0x254902 +serdes_preemphasis_lane1_9=0x254902 +serdes_preemphasis_lane2_9=0x254902 +serdes_preemphasis_lane3_9=0x294403 + +#ce23 +serdes_driver_current_lane0_13=0x09 +serdes_driver_current_lane1_13=0x0a +serdes_driver_current_lane2_13=0x0a +serdes_driver_current_lane3_13=0x0a +serdes_preemphasis_lane0_13=0x244a02 +serdes_preemphasis_lane1_13=0x254902 +serdes_preemphasis_lane2_13=0x294403 +serdes_preemphasis_lane3_13=0x294403 + +#ce24 +serdes_driver_current_lane0_17=0x0a +serdes_driver_current_lane1_17=0x0a +serdes_driver_current_lane2_17=0x0a +serdes_driver_current_lane3_17=0x0a +serdes_preemphasis_lane0_17=0x254902 +serdes_preemphasis_lane1_17=0x294403 +serdes_preemphasis_lane2_17=0x294403 +serdes_preemphasis_lane3_17=0x294403 + +#ce25 +serdes_driver_current_lane0_21=0x0a +serdes_driver_current_lane1_21=0x0a +serdes_driver_current_lane2_21=0x0a +serdes_driver_current_lane3_21=0x0a +serdes_preemphasis_lane0_21=0x294403 +serdes_preemphasis_lane1_21=0x294403 +serdes_preemphasis_lane2_21=0x294403 +serdes_preemphasis_lane3_21=0x254902 + +#ce26 +serdes_driver_current_lane0_25=0x0b +serdes_driver_current_lane1_25=0x0b +serdes_driver_current_lane2_25=0x0b +serdes_driver_current_lane3_25=0x0b +serdes_preemphasis_lane0_25=0x2b4104 +serdes_preemphasis_lane1_25=0x2b4104 +serdes_preemphasis_lane2_25=0x2b4104 +serdes_preemphasis_lane3_25=0x2d3f04 + +#ce27 +serdes_driver_current_lane0_29=0x0b +serdes_driver_current_lane1_29=0x0b +serdes_driver_current_lane2_29=0x0b +serdes_driver_current_lane3_29=0x0a +serdes_preemphasis_lane0_29=0x2d3f04 +serdes_preemphasis_lane1_29=0x2d3f04 +serdes_preemphasis_lane2_29=0x2b4104 +serdes_preemphasis_lane3_29=0x294403 + +#ce28 +serdes_driver_current_lane0_118=0x0a +serdes_driver_current_lane1_118=0x0a +serdes_driver_current_lane2_118=0x0a +serdes_driver_current_lane3_118=0x0a +serdes_preemphasis_lane0_118=0x254902 +serdes_preemphasis_lane1_118=0x294403 +serdes_preemphasis_lane2_118=0x294403 +serdes_preemphasis_lane3_118=0x254902 + +#ce29 +serdes_driver_current_lane0_122=0x0a +serdes_driver_current_lane1_122=0x0a +serdes_driver_current_lane2_122=0x0a +serdes_driver_current_lane3_122=0x0a +serdes_preemphasis_lane0_122=0x294403 +serdes_preemphasis_lane1_122=0x294403 +serdes_preemphasis_lane2_122=0x294403 +serdes_preemphasis_lane3_122=0x294403 + +#ce30 +serdes_driver_current_lane0_126=0x0a +serdes_driver_current_lane1_126=0x0a +serdes_driver_current_lane2_126=0x0b +serdes_driver_current_lane3_126=0x0b +serdes_preemphasis_lane0_126=0x294403 +serdes_preemphasis_lane1_126=0x294403 +serdes_preemphasis_lane2_126=0x2b4104 +serdes_preemphasis_lane3_126=0x2b4104 + +#ce31 +serdes_driver_current_lane0_130=0x0b +serdes_driver_current_lane1_130=0x0b +serdes_driver_current_lane2_130=0x0b +serdes_driver_current_lane3_130=0x0b +serdes_preemphasis_lane0_130=0x2d3f04 +serdes_preemphasis_lane1_130=0x2d3f04 +serdes_preemphasis_lane2_130=0x2b4104 +serdes_preemphasis_lane3_130=0x2b4104 + +mmu_init_config="MSFT-TH-Tier1" diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/buffers.json.j2 b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/buffers.json.j2 new file mode 100644 index 000000000000..1083a6210fc9 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/buffers.json.j2 @@ -0,0 +1,2 @@ +{%- set default_topo = 't0' %} +{%- include 'buffers_config.j2' %} diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/buffers_defaults_t0.j2 b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/buffers_defaults_t0.j2 new file mode 100644 index 000000000000..766de07b4945 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/buffers_defaults_t0.j2 @@ -0,0 +1,69 @@ + +{%- set default_cable = '5m' %} + +{%- set ports2cable = { + 'torrouter_server' : '300m', + 'leafrouter_torrouter' : '300m', + 'spinerouter_leafrouter' : '300m' + } +-%} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {%- for port_idx in range(0,9) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4 + 2)) %}{%- endif %} + {%- endfor %} + {%- for port_idx in range(14,17) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4 + 2)) %}{%- endif %} + {%- endfor %} + {%- for port_idx in range(22,31) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4 + 2)) %}{%- endif %} + {%- endfor %} + {%- for port_idx in range(10,13) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %} + {%- endfor %} + {%- for port_idx in range(18,21) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %} + {%- endfor %} +{%- endmacro %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "10875072", + "type": "ingress", + "mode": "dynamic", + "xoff": "4194112" + }, + "egress_lossy_pool": { + "size": "9243812", + "type": "egress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "15982720", + "type": "egress", + "mode": "static" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "dynamic_th":"3" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "static_th":"3995680" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/pg_profile_lookup.ini b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/pg_profile_lookup.ini new file mode 100644 index 000000000000..aedda37a8878 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/pg_profile_lookup.ini @@ -0,0 +1,17 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold xon_offset + 10000 5m 1248 2288 35776 -3 2288 + 25000 5m 1248 2288 53248 -3 2288 + 40000 5m 1248 2288 66560 -3 2288 + 50000 5m 1248 2288 90272 -3 2288 + 100000 5m 1248 2288 165568 -3 2288 + 10000 40m 1248 2288 37024 -3 2288 + 25000 40m 1248 2288 53248 -3 2288 + 40000 40m 1248 2288 71552 -3 2288 + 50000 40m 1248 2288 96096 -3 2288 + 100000 40m 1248 2288 177632 -3 2288 + 10000 300m 1248 2288 46176 -3 2288 + 25000 300m 1248 2288 79040 -3 2288 + 40000 300m 1248 2288 108160 -3 2288 + 50000 300m 1248 2288 141856 -3 2288 + 100000 300m 1248 2288 268736 -3 2288 diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/port_config.ini b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/port_config.ini new file mode 100644 index 000000000000..7595dfbb3fed --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/port_config.ini @@ -0,0 +1,57 @@ +# name lanes alias speed index +Ethernet0 65,66 etp1a 50000 1 +Ethernet2 67,68 etp1b 50000 1 +Ethernet4 69,70 etp2a 50000 2 +Ethernet6 71,72 etp2b 50000 2 +Ethernet8 73,74 etp3a 50000 3 +Ethernet10 75,76 etp3b 50000 3 +Ethernet12 77,78 etp4a 50000 4 +Ethernet14 79,80 etp4b 50000 4 +Ethernet16 33,34 etp5a 50000 5 +Ethernet18 35,36 etp5b 50000 5 +Ethernet20 37,38 etp6a 50000 6 +Ethernet22 39,40 etp6b 50000 6 +Ethernet24 41,42 etp7a 50000 7 +Ethernet26 43,44 etp7b 50000 7 +Ethernet28 45,46 etp8a 50000 8 +Ethernet30 47,48 etp8b 50000 8 +Ethernet32 49,50 etp9a 50000 9 +Ethernet34 51,52 etp9b 50000 9 +Ethernet36 53,54 etp10a 50000 10 +Ethernet38 55,56 etp10b 50000 10 +Ethernet40 57,58,59,60 etp11 100000 11 +Ethernet44 61,62,63,64 etp12 100000 12 +Ethernet48 81,82,83,84 etp13 100000 13 +Ethernet52 85,86,87,88 etp14 100000 14 +Ethernet56 89,90 etp15a 50000 15 +Ethernet58 91,92 etp15b 50000 15 +Ethernet60 93,94 etp16a 50000 16 +Ethernet62 95,96 etp16b 50000 16 +Ethernet64 97,98 etp17a 50000 17 +Ethernet66 99,100 etp17b 50000 17 +Ethernet68 101,102 etp18a 50000 18 +Ethernet70 103,104 etp18b 50000 18 +Ethernet72 105,106,107,108 etp19 100000 19 +Ethernet76 109,110,111,112 etp20 100000 20 +Ethernet80 1,2,3,4 etp21 100000 21 +Ethernet84 5,6,7,8 etp22 100000 22 +Ethernet88 9,10 etp23a 50000 23 +Ethernet90 11,12 etp23b 50000 23 +Ethernet92 13,14 etp24a 50000 24 +Ethernet94 15,16 etp24b 50000 24 +Ethernet96 17,18 etp25a 50000 25 +Ethernet98 19,20 etp25b 50000 25 +Ethernet100 21,22 etp26a 50000 26 +Ethernet102 23,24 etp26b 50000 26 +Ethernet104 25,26 etp27a 50000 27 +Ethernet106 27,28 etp27b 50000 27 +Ethernet108 29,30 etp28a 50000 28 +Ethernet110 31,32 etp28b 50000 28 +Ethernet112 113,114 etp29a 50000 29 +Ethernet114 115,116 etp29b 50000 29 +Ethernet116 117,118 etp30a 50000 30 +Ethernet118 119,120 etp30b 50000 30 +Ethernet120 121,122 etp31a 50000 31 +Ethernet122 123,124 etp31b 50000 31 +Ethernet124 125,126 etp32a 50000 32 +Ethernet126 127,128 etp32b 50000 32 diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/qos.json.j2 b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/qos.json.j2 new file mode 100644 index 000000000000..3e548325ea30 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/qos.json.j2 @@ -0,0 +1 @@ +{%- include 'qos_config.j2' %} diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/sai.profile b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/sai.profile new file mode 100644 index 000000000000..46d96b2fd905 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/th-seastone-dx010-48x50G+8x100G.config.bcm diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/th-seastone-dx010-48x50G+8x100G.config.bcm b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/th-seastone-dx010-48x50G+8x100G.config.bcm new file mode 100644 index 000000000000..6707aa71df09 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/th-seastone-dx010-48x50G+8x100G.config.bcm @@ -0,0 +1,648 @@ +os=unix +l2xmsg_mode=1 +parity_enable=0 +rate_ext_mdio_divisor=0x80 +phy_ext_rom_boot=0 +fpem_mem_entries=32768 +l2xmsg_mode=1 +oversubscribe_mode=1 +pbmp_xport_xe=0xcccc44cc33113333044cccccc66666622 + + +dport_map_enable=1 +dport_map_port_68=1 +dport_map_port_69=2 + +dport_map_port_72=5 +dport_map_port_73=6 + +dport_map_port_76=9 +dport_map_port_77=10 + +dport_map_port_80=13 +dport_map_port_81=14 + +dport_map_port_34=17 +dport_map_port_35=18 + +dport_map_port_38=21 +dport_map_port_39=22 + +dport_map_port_42=25 +dport_map_port_43=26 + +dport_map_port_46=29 +dport_map_port_47=30 + +dport_map_port_50=33 +dport_map_port_51=34 + +dport_map_port_54=37 +dport_map_port_55=38 + +dport_map_port_58=41 + +dport_map_port_62=45 + +dport_map_port_84=49 + +dport_map_port_88=53 + +dport_map_port_92=57 +dport_map_port_93=58 + +dport_map_port_96=61 +dport_map_port_97=62 + +dport_map_port_102=65 +dport_map_port_103=66 + +dport_map_port_106=69 +dport_map_port_107=70 + +dport_map_port_110=73 + +dport_map_port_114=77 + +dport_map_port_1=81 + +dport_map_port_5=85 + +dport_map_port_9=89 +dport_map_port_10=90 + +dport_map_port_13=93 +dport_map_port_14=94 + +dport_map_port_17=97 +dport_map_port_18=98 + +dport_map_port_21=101 +dport_map_port_22=102 + +dport_map_port_25=105 +dport_map_port_26=106 + +dport_map_port_29=109 +dport_map_port_30=110 + +dport_map_port_118=113 +dport_map_port_119=114 + +dport_map_port_122=117 +dport_map_port_123=118 + +dport_map_port_126=121 +dport_map_port_127=122 + +dport_map_port_130=125 +dport_map_port_131=126 + + +# port mapping +portmap_68=65:50:2 +portmap_69=67:50:2 + +portmap_72=69:50:2 +portmap_73=71:50:2 + +portmap_76=73:50:2 +portmap_77=75:50:2 + +portmap_80=77:50:2 +portmap_81=79:50:2 + +portmap_34=33:50:2 +portmap_35=35:50:2 + +portmap_38=37:50:2 +portmap_39=39:50:2 + +portmap_42=41:50:2 +portmap_43=43:50:2 + +portmap_46=45:50:2 +portmap_47=47:50:2 + +portmap_50=49:50:2 +portmap_51=51:50:2 + +portmap_54=53:50:2 +portmap_55=55:50:2 + +portmap_58=57:100:4 + +portmap_62=61:100:4 + +portmap_84=81:100:4 + +portmap_88=85:100:4 + +portmap_92=89:50:2 +portmap_93=91:50:2 + +portmap_96=93:50:2 +portmap_97=95:50:2 + +portmap_102=97:50:2 +portmap_103=99:50:2 + +portmap_106=101:50:2 +portmap_107=103:50:2 + +portmap_110=105:100:4 + +portmap_114=109:100:4 + +portmap_1=1:100:4 + +portmap_5=5:100:4 + +portmap_9=9:50:2 +portmap_10=11:50:2 + +portmap_13=13:50:2 +portmap_14=15:50:2 + +portmap_17=17:50:2 +portmap_18=19:50:2 + +portmap_21=21:50:2 +portmap_22=23:50:2 + +portmap_25=25:50:2 +portmap_26=27:50:2 + +portmap_29=29:50:2 +portmap_30=31:50:2 + +portmap_118=113:50:2 +portmap_119=115:50:2 + +portmap_122=117:50:2 +portmap_123=119:50:2 + +portmap_126=121:50:2 +portmap_127=123:50:2 + +portmap_130=125:50:2 +portmap_131=127:50:2 + + +#WC16 +xgxs_tx_lane_map_68=0x1023 +xgxs_rx_lane_map_68=0x0132 +xgxs_tx_lane_map_69=0x1023 +xgxs_rx_lane_map_69=0x0132 + + +#WC17 +xgxs_tx_lane_map_72=0x1023 +xgxs_rx_lane_map_72=0x1032 +xgxs_tx_lane_map_73=0x1023 +xgxs_rx_lane_map_73=0x1032 + +#WC18 +xgxs_tx_lane_map_76=0x2310 +xgxs_rx_lane_map_76=0x3210 +xgxs_tx_lane_map_77=0x2310 +xgxs_rx_lane_map_77=0x3210 + +#WC19 +xgxs_tx_lane_map_80=0x1302 +xgxs_rx_lane_map_80=0x0231 +xgxs_tx_lane_map_81=0x1302 +xgxs_rx_lane_map_81=0x0231 +#WC8 +xgxs_tx_lane_map_34=0x1203 +xgxs_rx_lane_map_34=0x3120 +xgxs_tx_lane_map_35=0x1203 +xgxs_rx_lane_map_35=0x3120 + +#WC9 +xgxs_tx_lane_map_38=0x0123 +xgxs_rx_lane_map_38=0x3201 +xgxs_tx_lane_map_39=0x0123 +xgxs_rx_lane_map_39=0x3201 + +#WC10 +xgxs_tx_lane_map_42=0x0132 +xgxs_rx_lane_map_42=0x0123 +xgxs_tx_lane_map_43=0x0132 +xgxs_rx_lane_map_43=0x0123 + +#WC11 +xgxs_tx_lane_map_46=0x2301 +xgxs_rx_lane_map_46=0x2031 +xgxs_tx_lane_map_47=0x2301 +xgxs_rx_lane_map_47=0x2031 + +#WC12 +xgxs_tx_lane_map_50=0x1032 +xgxs_rx_lane_map_50=0x3120 +xgxs_tx_lane_map_51=0x1032 +xgxs_rx_lane_map_51=0x3120 + + +#WC13 +xgxs_tx_lane_map_54=0x1032 +xgxs_rx_lane_map_54=0x0132 +xgxs_tx_lane_map_55=0x1032 +xgxs_rx_lane_map_55=0x0132 + +#WC14 + xgxs_tx_lane_map_58=0x1032 + xgxs_rx_lane_map_58=0x3120 + +#WC15 +xgxs_tx_lane_map_62=0x2031 +xgxs_rx_lane_map_62=0x0132 + +#WC20 + xgxs_tx_lane_map_84=0x3120 + xgxs_rx_lane_map_84=0x1032 + +#WC21 +xgxs_tx_lane_map_88=0x2310 +xgxs_rx_lane_map_88=0x0123 + +#WC22 +xgxs_tx_lane_map_92=0x2310 +xgxs_rx_lane_map_92=0x1302 +xgxs_tx_lane_map_93=0x2310 +xgxs_rx_lane_map_93=0x1302 + +#WC23 +xgxs_tx_lane_map_96=0x1302 +xgxs_rx_lane_map_96=0x1023 +xgxs_tx_lane_map_97=0x1302 +xgxs_rx_lane_map_97=0x1023 + +#WC24 +xgxs_tx_lane_map_102=0x2310 +xgxs_rx_lane_map_102=0x1032 +xgxs_tx_lane_map_103=0x2310 +xgxs_rx_lane_map_103=0x1032 + +#WC25 +xgxs_tx_lane_map_106=0x2310 +xgxs_rx_lane_map_106=0x1023 +xgxs_tx_lane_map_107=0x2310 +xgxs_rx_lane_map_107=0x1023 + +#WC26 +xgxs_tx_lane_map_110=0x2310 +xgxs_rx_lane_map_110=0x1302 + +#WC27 +xgxs_tx_lane_map_114=0x1302 +xgxs_rx_lane_map_114=0x1032 + +#WC0 +xgxs_tx_lane_map_1=0x0123 +xgxs_rx_lane_map_1=0x0213 + +#WC1 +xgxs_tx_lane_map_5=0x2310 +xgxs_rx_lane_map_5=0x3201 + +#WC2 +xgxs_tx_lane_map_9=0x1023 +xgxs_rx_lane_map_9=0x0213 +xgxs_tx_lane_map_10=0x1023 +xgxs_rx_lane_map_10=0x0213 + +#WC3 +xgxs_tx_lane_map_13=0x1302 +xgxs_rx_lane_map_13=0x3201 +xgxs_tx_lane_map_14=0x1302 +xgxs_rx_lane_map_14=0x3201 + +#WC4 +xgxs_tx_lane_map_17=0x0132 +xgxs_rx_lane_map_17=0x0123 +xgxs_tx_lane_map_18=0x0132 +xgxs_rx_lane_map_18=0x0123 + +#WC5 +xgxs_tx_lane_map_21=0x1032 +xgxs_rx_lane_map_21=0x0213 +xgxs_tx_lane_map_22=0x1032 +xgxs_rx_lane_map_22=0x0213 + +#WC6 +xgxs_tx_lane_map_25=0x1023 +xgxs_rx_lane_map_25=0x3120 +xgxs_tx_lane_map_26=0x1023 +xgxs_rx_lane_map_26=0x3120 + +#WC7 +xgxs_tx_lane_map_29=0x2031 +xgxs_rx_lane_map_29=0x3201 +xgxs_tx_lane_map_30=0x2031 +xgxs_rx_lane_map_30=0x3201 + +#WC28 +xgxs_tx_lane_map_118=0x0231 +xgxs_rx_lane_map_118=0x2031 +xgxs_tx_lane_map_119=0x0231 +xgxs_rx_lane_map_119=0x2031 + +#WC29 +xgxs_tx_lane_map_122=0x3201 +xgxs_rx_lane_map_122=0x2301 +xgxs_tx_lane_map_123=0x3201 +xgxs_rx_lane_map_123=0x2301 + +#WC30 +xgxs_tx_lane_map_126=0x0213 +xgxs_rx_lane_map_126=0x0213 +xgxs_tx_lane_map_127=0x0213 +xgxs_rx_lane_map_127=0x0213 + +#WC31 +xgxs_tx_lane_map_130=0x2031 +xgxs_rx_lane_map_130=0x1032 +xgxs_tx_lane_map_131=0x2031 +xgxs_rx_lane_map_131=0x1032 + +#PN + +#WC16 +phy_xaui_tx_polarity_flip_68=0x0000 +phy_xaui_rx_polarity_flip_68=0x0000 +phy_xaui_tx_polarity_flip_69=0x0000 +phy_xaui_rx_polarity_flip_69=0x0000 + +#WC17 +phy_xaui_tx_polarity_flip_72=0x0003 +phy_xaui_rx_polarity_flip_72=0x0000 +phy_xaui_tx_polarity_flip_73=0x0002 +phy_xaui_rx_polarity_flip_73=0x0001 + + + +#WC18 +phy_xaui_tx_polarity_flip_76=0x0003 +phy_xaui_rx_polarity_flip_76=0x0000 +phy_xaui_tx_polarity_flip_77=0x0003 +phy_xaui_rx_polarity_flip_77=0x0000 + + +#WC19 +phy_xaui_tx_polarity_flip_80=0x0003 +phy_xaui_rx_polarity_flip_80=0x0003 +phy_xaui_tx_polarity_flip_81=0x0003 +phy_xaui_rx_polarity_flip_81=0x0003 + + +#WC8 +phy_xaui_tx_polarity_flip_34=0x0003 +phy_xaui_rx_polarity_flip_34=0x0000 +phy_xaui_tx_polarity_flip_35=0x0001 +phy_xaui_rx_polarity_flip_35=0x0000 + + +#WC9 +phy_xaui_tx_polarity_flip_38=0x0001 +phy_xaui_rx_polarity_flip_38=0x0000 +phy_xaui_tx_polarity_flip_39=0x0000 +phy_xaui_rx_polarity_flip_39=0x0000 + + +#WC10 +phy_xaui_tx_polarity_flip_42=0x0003 +phy_xaui_rx_polarity_flip_42=0x0000 +phy_xaui_tx_polarity_flip_43=0x0002 +phy_xaui_rx_polarity_flip_43=0x0000 + + +#WC11 +phy_xaui_tx_polarity_flip_46=0x0000 +phy_xaui_rx_polarity_flip_46=0x0000 +phy_xaui_tx_polarity_flip_47=0x0000 +phy_xaui_rx_polarity_flip_47=0x0000 + + +#WC12 +phy_xaui_tx_polarity_flip_50=0x0000 +phy_xaui_rx_polarity_flip_50=0x0000 +phy_xaui_tx_polarity_flip_51=0x0001 +phy_xaui_rx_polarity_flip_51=0x0000 + +#WC13 +phy_xaui_tx_polarity_flip_54=0x0000 +phy_xaui_rx_polarity_flip_54=0x0000 +phy_xaui_tx_polarity_flip_55=0x0001 +phy_xaui_rx_polarity_flip_55=0x0000 + +#WC14 +phy_xaui_tx_polarity_flip_58=0x0000 +phy_xaui_rx_polarity_flip_58=0x0000 + +#WC15 +phy_xaui_tx_polarity_flip_62=0x0005 +phy_xaui_rx_polarity_flip_62=0x000F + +#WC20 + phy_xaui_tx_polarity_flip_84=0x000E + phy_xaui_rx_polarity_flip_84=0x0007 + +#WC21 +phy_xaui_tx_polarity_flip_88=0x000B +phy_xaui_rx_polarity_flip_88=0x000B + +#WC22 +phy_xaui_tx_polarity_flip_92=0x0003 +phy_xaui_rx_polarity_flip_92=0x0001 +phy_xaui_tx_polarity_flip_93=0x0003 +phy_xaui_rx_polarity_flip_93=0x0000 + + +#WC23 +phy_xaui_tx_polarity_flip_96=0x0002 +phy_xaui_rx_polarity_flip_96=0x0000 +phy_xaui_tx_polarity_flip_97=0x0002 +phy_xaui_rx_polarity_flip_97=0x0000 + +#WC24 +phy_xaui_tx_polarity_flip_102=0x0000 +phy_xaui_rx_polarity_flip_102=0x0003 +phy_xaui_tx_polarity_flip_103=0x0000 +phy_xaui_rx_polarity_flip_103=0x0003 + + +#WC25 +phy_xaui_tx_polarity_flip_106=0x0003 +phy_xaui_rx_polarity_flip_106=0x0000 +phy_xaui_tx_polarity_flip_107=0x0003 +phy_xaui_rx_polarity_flip_107=0x0000 + +#WC26 +phy_xaui_tx_polarity_flip_110=0x000F +phy_xaui_rx_polarity_flip_110=0x000F + +#WC27 +phy_xaui_tx_polarity_flip_114=0x000F +phy_xaui_rx_polarity_flip_114=0x000E + +#WC0 +phy_xaui_tx_polarity_flip_1=0x000C +phy_xaui_rx_polarity_flip_1=0x000F + +#WC1 +phy_xaui_tx_polarity_flip_5=0x000E +phy_xaui_rx_polarity_flip_5=0x0000 + +#WC2 +phy_xaui_tx_polarity_flip_9=0x0000 +phy_xaui_rx_polarity_flip_9=0x0001 +phy_xaui_tx_polarity_flip_10=0x0001 +phy_xaui_rx_polarity_flip_10=0x0000 + + +#WC3 +phy_xaui_tx_polarity_flip_13=0x0003 +phy_xaui_rx_polarity_flip_13=0x0000 +phy_xaui_tx_polarity_flip_14=0x0003 +phy_xaui_rx_polarity_flip_14=0x0000 + +#WC4 +phy_xaui_tx_polarity_flip_17=0x0002 +phy_xaui_rx_polarity_flip_17=0x0000 +phy_xaui_tx_polarity_flip_18=0x0003 +phy_xaui_rx_polarity_flip_18=0x0000 + + +#WC5 +phy_xaui_tx_polarity_flip_21=0x0000 +phy_xaui_rx_polarity_flip_21=0x0000 +phy_xaui_tx_polarity_flip_22=0x0000 +phy_xaui_rx_polarity_flip_22=0x0000 + + +#WC6 +phy_xaui_tx_polarity_flip_25=0x0000 +phy_xaui_rx_polarity_flip_25=0x0002 +phy_xaui_tx_polarity_flip_26=0x0001 +phy_xaui_rx_polarity_flip_26=0x0002 + + +#WC7 +phy_xaui_tx_polarity_flip_29=0x0000 +phy_xaui_rx_polarity_flip_29=0x0000 +phy_xaui_tx_polarity_flip_30=0x0001 +phy_xaui_rx_polarity_flip_30=0x0000 + + +#WC28 +phy_xaui_tx_polarity_flip_118=0x0003 +phy_xaui_rx_polarity_flip_118=0x0003 +phy_xaui_tx_polarity_flip_119=0x0003 +phy_xaui_rx_polarity_flip_119=0x0003 + + +#WC29 +phy_xaui_tx_polarity_flip_122=0x0002 +phy_xaui_rx_polarity_flip_122=0x0000 +phy_xaui_tx_polarity_flip_123=0x0000 +phy_xaui_rx_polarity_flip_123=0x0000 + + +#WC30 +phy_xaui_tx_polarity_flip_126=0x0003 +phy_xaui_rx_polarity_flip_126=0x0000 +phy_xaui_tx_polarity_flip_127=0x0003 +phy_xaui_rx_polarity_flip_127=0x0000 + + +#WC31 +phy_xaui_tx_polarity_flip_130=0x0002 +phy_xaui_rx_polarity_flip_130=0x0000 +phy_xaui_tx_polarity_flip_131=0x0001 +phy_xaui_rx_polarity_flip_131=0x0000 + +#xe +serdes_driver_current=0x0a +serdes_preemphasis=0x1a5402 + +#ce0 +serdes_driver_current_lane0_58=0x0a +serdes_driver_current_lane1_58=0x09 +serdes_driver_current_lane2_58=0x09 +serdes_driver_current_lane3_58=0x0a +serdes_preemphasis_lane0_58=0x254902 +serdes_preemphasis_lane1_58=0x244a02 +serdes_preemphasis_lane2_58=0x244a02 +serdes_preemphasis_lane3_58=0x254902 + +#ce1 +serdes_driver_current_lane0_62=0x09 +serdes_driver_current_lane1_62=0x0a +serdes_driver_current_lane2_62=0x09 +serdes_driver_current_lane3_62=0x09 +serdes_preemphasis_lane0_62=0x244a02 +serdes_preemphasis_lane1_62=0x254902 +serdes_preemphasis_lane2_62=0x244a02 +serdes_preemphasis_lane3_62=0x244a02 + +#ce2 +serdes_driver_current_lane0_84=0x09 +serdes_driver_current_lane1_84=0x09 +serdes_driver_current_lane2_84=0x09 +serdes_driver_current_lane3_84=0x09 +serdes_preemphasis_lane0_84=0x204e02 +serdes_preemphasis_lane1_84=0x204e02 +serdes_preemphasis_lane2_84=0x204e02 +serdes_preemphasis_lane3_84=0x204e02 + +#ce3 +serdes_driver_current_lane0_88=0x09 +serdes_driver_current_lane1_88=0x08 +serdes_driver_current_lane2_88=0x08 +serdes_driver_current_lane3_88=0x09 +serdes_preemphasis_lane0_88=0x204e02 +serdes_preemphasis_lane1_88=0x1d5102 +serdes_preemphasis_lane2_88=0x1d5102 +serdes_preemphasis_lane3_88=0x204e02 + +#ce4 +serdes_driver_current_lane0_110=0x09 +serdes_driver_current_lane1_110=0x08 +serdes_driver_current_lane2_110=0x08 +serdes_driver_current_lane3_110=0x09 +serdes_preemphasis_lane0_110=0x204e02 +serdes_preemphasis_lane1_110=0x1d5102 +serdes_preemphasis_lane2_110=0x1d5102 +serdes_preemphasis_lane3_110=0x204e02 + +#ce5 +serdes_driver_current_lane0_114=0x09 +serdes_driver_current_lane1_114=0x08 +serdes_driver_current_lane2_114=0x09 +serdes_driver_current_lane3_114=0x09 +serdes_preemphasis_lane0_114=0x204e02 +serdes_preemphasis_lane1_114=0x1d5102 +serdes_preemphasis_lane2_114=0x224c02 +serdes_preemphasis_lane3_114=0x224c02 + +#ce6 +serdes_driver_current_lane0_1=0x09 +serdes_driver_current_lane1_1=0x0a +serdes_driver_current_lane2_1=0x09 +serdes_driver_current_lane3_1=0x0a +serdes_preemphasis_lane0_1=0x244a02 +serdes_preemphasis_lane1_1=0x254902 +serdes_preemphasis_lane2_1=0x244a02 +serdes_preemphasis_lane3_1=0x254902 + +#ce7 +serdes_driver_current_lane0_5=0x09 +serdes_driver_current_lane1_5=0x09 +serdes_driver_current_lane2_5=0x09 +serdes_driver_current_lane3_5=0x0a +serdes_preemphasis_lane0_5=0x244a02 +serdes_preemphasis_lane1_5=0x244a02 +serdes_preemphasis_lane2_5=0x244a02 +serdes_preemphasis_lane3_5=0x254902 + From 766b15d11d9fdfd95fd1becd2033d65cd644941f Mon Sep 17 00:00:00 2001 From: ciju-juniper <53076238+ciju-juniper@users.noreply.github.com> Date: Fri, 20 Sep 2019 22:00:01 +0530 Subject: [PATCH 002/278] [Juniper][QFX5210] Workaround for orchagent crash (#3458) Orchagent is crashing on the latest SONiC images. Issue #458 is raised to track the problem. Dynamic port breakout commit 6f40933d3d7b9f21a97de275fbd14ea3598d9a0a introduced this regression. One of the recommendation that we received was to disable the loopback and mgmt ports in bcm config. It was helpful in fixing the issue but not the ideal solution. It works on qfx5210 as the loopback and management configurations are not applicable. While the orchagent crash is being debugged, we need this commit to fix the issue in qfx5210 platform. This patch can be reversed once the correct fix for the orchagent is identified. Signed-off-by: Ciju Rajan K --- .../th2-qfx5210-64x100G.config.bcm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/th2-qfx5210-64x100G.config.bcm b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/th2-qfx5210-64x100G.config.bcm index 5c03be736650..bc421a4e5152 100644 --- a/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/th2-qfx5210-64x100G.config.bcm +++ b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/th2-qfx5210-64x100G.config.bcm @@ -29,17 +29,17 @@ oversubscribe_mode=1 #add loopback port # port 33 is the first loopback port -portmap_33=260:10 +# portmap_33=260:10 # port 66 is the first management port -portmap_66=257:10 +# portmap_66=257:10 # port 67 is the second loopback port -portmap_67=261:10 +# portmap_67=261:10 # port 100 is the second management port -portmap_100=259:10 +# portmap_100=259:10 # port 101 is the third loopback port -portmap_101=262:10 +# portmap_101=262:10 # port 135 is the fourth loopback port -portmap_135=263:10 +# portmap_135=263:10 #Port0 #FC18 From dd4a50dd614bcb5123f7935176b0135314a3a52f Mon Sep 17 00:00:00 2001 From: Dong Zhang <41927498+dzhangalibaba@users.noreply.github.com> Date: Sat, 21 Sep 2019 00:34:32 +0800 Subject: [PATCH 003/278] [database-docker]: update multiBD config file (#3487) adding 'hostname' field and rename 'socket' --- dockers/docker-database/database_config.json | 9 +++++++-- dockers/docker-database/supervisord.conf.j2 | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/dockers/docker-database/database_config.json b/dockers/docker-database/database_config.json index 6725af38c5ea..d5d951bead5d 100644 --- a/dockers/docker-database/database_config.json +++ b/dockers/docker-database/database_config.json @@ -1,8 +1,9 @@ { "INSTANCES": { "redis":{ - "port": 6379, - "socket": "/var/run/redis/redis.sock" + "hostname" : "127.0.0.1", + "port" : 6379, + "unix_socket_path" : "/var/run/redis/redis.sock" } }, "DATABASES" : { @@ -37,6 +38,10 @@ "STATE_DB" : { "id" : 6, "instance" : "redis" + }, + "SNMP_OVERLAY_DB" : { + "id" : 7, + "instance" : "redis" } }, "VERSION" : "1.0" diff --git a/dockers/docker-database/supervisord.conf.j2 b/dockers/docker-database/supervisord.conf.j2 index 9e4a42d6b3a4..110619f762be 100644 --- a/dockers/docker-database/supervisord.conf.j2 +++ b/dockers/docker-database/supervisord.conf.j2 @@ -14,7 +14,7 @@ stderr_logfile=syslog {% if INSTANCES %} {% for redis_inst, redis_items in INSTANCES.iteritems() %} [program: {{ redis_inst }}] -command=/bin/bash -c "{ [[ -s /var/lib/{{ redis_inst }}/dump.rdb ]] || rm -f /var/lib/{{ redis_inst }}/dump.rdb; } && mkdir -p /var/lib/{{ redis_inst }} && exec /usr/bin/redis-server /etc/redis/redis.conf --port {{ redis_items['port'] }} --unixsocket {{ redis_items['socket'] }} --pidfile /var/run/redis/{{ redis_inst }}.pid --dir /var/lib/{{ redis_inst }}" +command=/bin/bash -c "{ [[ -s /var/lib/{{ redis_inst }}/dump.rdb ]] || rm -f /var/lib/{{ redis_inst }}/dump.rdb; } && mkdir -p /var/lib/{{ redis_inst }} && exec /usr/bin/redis-server /etc/redis/redis.conf --port {{ redis_items['port'] }} --unixsocket {{ redis_items['unix_socket_path'] }} --pidfile /var/run/redis/{{ redis_inst }}.pid --dir /var/lib/{{ redis_inst }}" priority=2 autostart=true autorestart=false From c60278de587ab0104fcd7e4d9aeb52fd04acaa6e Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Fri, 20 Sep 2019 15:33:40 -0700 Subject: [PATCH 004/278] [libteam]: Add Fast-Reboot mode for teamd (#3490) * [libteam]: add special Fast-Reboot teamd stop mode * Fix last packet sending * Update sonic-utilities module --- .../0008-libteam-Add-warm_reboot-mode.patch | 55 ++++++++++++------- src/sonic-utilities | 2 +- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch b/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch index 10770b8740b5..d92ac6987e62 100644 --- a/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch +++ b/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch @@ -1,18 +1,18 @@ -From a21a3dec9f9b9d825a0229e2963e07862395bbba Mon Sep 17 00:00:00 2001 +From 5d418847bf6fa86f049e18c1b57028c71e40a9c4 Mon Sep 17 00:00:00 2001 From: Pavel Shirshov -Date: Fri, 14 Jun 2019 14:20:05 -0700 -Subject: [PATCH] [libteam]: Reimplement Warm-Reboot procedure +Date: Thu, 19 Sep 2019 14:49:17 -0700 +Subject: [PATCH 1/1] [libteam]: Reimplement Warm-Reboot procedure --- libteam/ifinfo.c | 6 +- - teamd/teamd.c | 42 +++- + teamd/teamd.c | 57 ++++- teamd/teamd.h | 6 + teamd/teamd_events.c | 13 ++ teamd/teamd_runner_lacp.c | 474 +++++++++++++++++++++++++++++++++++--- - 5 files changed, 498 insertions(+), 43 deletions(-) + 5 files changed, 509 insertions(+), 47 deletions(-) diff --git a/libteam/ifinfo.c b/libteam/ifinfo.c -index 46d56a2..b86d34c 100644 +index a15788b..e48193e 100644 --- a/libteam/ifinfo.c +++ b/libteam/ifinfo.c @@ -109,15 +109,13 @@ static void update_hwaddr(struct team_ifinfo *ifinfo, struct rtnl_link *link) @@ -34,7 +34,7 @@ index 46d56a2..b86d34c 100644 } } diff --git a/teamd/teamd.c b/teamd/teamd.c -index 9dc85b5..96794e8 100644 +index 9dc85b5..679da49 100644 --- a/teamd/teamd.c +++ b/teamd/teamd.c @@ -117,7 +117,9 @@ static void print_help(const struct teamd_context *ctx) { @@ -90,51 +90,66 @@ index 9dc85b5..96794e8 100644 if (optind < argc) { fprintf(stderr, "Too many arguments\n"); return -1; -@@ -390,8 +410,14 @@ static int teamd_run_loop_run(struct teamd_context *ctx) +@@ -390,12 +410,21 @@ static int teamd_run_loop_run(struct teamd_context *ctx) if (err != -1) { switch(ctrl_byte) { case 'q': ++ case 'f': + case 'w': if (quit_in_progress) return -EBUSY; -+ if (ctrl_byte == 'w') { +- teamd_refresh_ports(ctx); +- err = teamd_flush_ports(ctx); +- if (err) +- return err; ++ if (ctrl_byte == 'w' || ctrl_byte == 'f') { + ctx->keep_ports = true; + ctx->no_quit_destroy = true; -+ teamd_ports_flush_data(ctx); ++ teamd_refresh_ports(ctx); ++ if (ctrl_byte == 'w') ++ teamd_ports_flush_data(ctx); ++ } else { ++ err = teamd_flush_ports(ctx); ++ if (err) ++ return err; + } - teamd_refresh_ports(ctx); - err = teamd_flush_ports(ctx); - if (err) -@@ -434,6 +460,12 @@ void teamd_run_loop_quit(struct teamd_context *ctx, int err) + quit_in_progress = true; + continue; + case 'r': +@@ -434,6 +463,12 @@ void teamd_run_loop_quit(struct teamd_context *ctx, int err) teamd_run_loop_sent_ctrl_byte(ctx, 'q'); } -+static void teamd_run_loop_quit_w_boot(struct teamd_context *ctx, int err) ++static void teamd_run_loop_quit_a_boot(struct teamd_context *ctx, char type, int err) +{ + ctx->run_loop.err = err; -+ teamd_run_loop_sent_ctrl_byte(ctx, 'w'); ++ teamd_run_loop_sent_ctrl_byte(ctx, type); +} + void teamd_run_loop_restart(struct teamd_context *ctx) { teamd_run_loop_sent_ctrl_byte(ctx, 'r'); -@@ -700,6 +732,10 @@ static int callback_daemon_signal(struct teamd_context *ctx, int events, +@@ -700,6 +735,14 @@ static int callback_daemon_signal(struct teamd_context *ctx, int events, teamd_log_warn("Got SIGINT, SIGQUIT or SIGTERM."); teamd_run_loop_quit(ctx, 0); break; + case SIGUSR1: + teamd_log_warn("Got SIGUSR1."); -+ teamd_run_loop_quit_w_boot(ctx, 0); ++ teamd_run_loop_quit_a_boot(ctx, 'w', 0); ++ break; ++ case SIGUSR2: ++ teamd_log_warn("Got SIGUSR2."); ++ teamd_run_loop_quit_a_boot(ctx, 'f', 0); + break; } return 0; } -@@ -1531,7 +1567,7 @@ static int teamd_start(struct teamd_context *ctx, enum teamd_exit_code *p_ret) +@@ -1531,7 +1574,7 @@ static int teamd_start(struct teamd_context *ctx, enum teamd_exit_code *p_ret) return -errno; } - if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, 0) < 0) { -+ if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGUSR1, 0) < 0) { ++ if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGUSR1, SIGUSR2, 0) < 0) { teamd_log_err("Could not register signal handlers."); daemon_retval_send(errno); err = -errno; diff --git a/src/sonic-utilities b/src/sonic-utilities index c1c53f5d4740..b19b125c5afa 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit c1c53f5d47401c4486b3fd4a32f6bf45c0926ae2 +Subproject commit b19b125c5afacea6c704d4003a12265cb94c8f8b From 622f3f5d1a37d14589497a55b8e64bdfecc85587 Mon Sep 17 00:00:00 2001 From: habeebmohammed Date: Sun, 22 Sep 2019 04:03:24 -0700 Subject: [PATCH 005/278] [broadcom]: add led_fw_path to permitted_list (#3498) * add led_fw_dir to permitted_list --- src/sonic-device-data/tests/permitted_list | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sonic-device-data/tests/permitted_list b/src/sonic-device-data/tests/permitted_list index 47eea9fa9dba..31c424857445 100644 --- a/src/sonic-device-data/tests/permitted_list +++ b/src/sonic-device-data/tests/permitted_list @@ -159,3 +159,4 @@ ccmdma_intr_enable phy_enable init_all_modules port_fec +led_fw_path From a97b15e0ec1e618527f82553d991945fcf4d7ac7 Mon Sep 17 00:00:00 2001 From: brandonchuang Date: Tue, 24 Sep 2019 05:27:18 +0800 Subject: [PATCH 006/278] [device/as5835-54t] Implement get_transceiver_change_event() in sfputil.py (#3485) Signed-off-by: brandon_chuang --- .../plugins/sfputil.py | 96 +++++++++++++++++-- 1 file changed, 89 insertions(+), 7 deletions(-) diff --git a/device/accton/x86_64-accton_as5835_54t-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as5835_54t-r0/plugins/sfputil.py index 58ed8007a477..4fcbdb022579 100644 --- a/device/accton/x86_64-accton_as5835_54t-r0/plugins/sfputil.py +++ b/device/accton/x86_64-accton_as5835_54t-r0/plugins/sfputil.py @@ -11,6 +11,8 @@ except ImportError as e: raise ImportError("%s - required module not found" % str(e)) +SFP_STATUS_INSERTED = '1' +SFP_STATUS_REMOVED = '0' class SfpUtil(SfpUtilBase): """Platform-specific SfpUtil class""" @@ -216,10 +218,90 @@ def reset(self, port_num): return True - def get_transceiver_change_event(self): - """ - TODO: This function need to be implemented - when decide to support monitoring SFP(Xcvrd) - on this platform. - """ - raise NotImplementedError + @property + def _get_presence_bitmap(self): + + bitmap = "" + try: + reg_file = open("/sys/bus/i2c/devices/3-0062/module_present_all") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + bitmap += reg_file.readline().rstrip() + " " + reg_file.close() + + rev = bitmap.split(" ") + rev.pop() # Remove the last useless character + + # Save port 49-54 into buffer + tmp = rev.pop() + + # Insert port 1-48 + for i in range (0, 6): + rev.append(hex(0)[2:]) + rev[i] = rev[i].zfill(2) + + # Expand port 49-54 + for i in range (0, 6): + val = (int(tmp,16) >> i) & 0x1 + rev.append(hex(val)[2:]) + + rev = "".join(rev[::-1]) + return int(rev,16) + + data = {'valid':0, 'present':0} + def get_transceiver_change_event(self, timeout=0): + + start_time = time.time() + port_dict = {} + port = 0 + blocking = False + + if timeout == 0: + blocking = True + elif timeout > 0: + timeout = timeout / float(1000) # Convert to secs + else: + print "get_transceiver_change_event:Invalid timeout value", timeout + return False, {} + + end_time = start_time + timeout + if start_time > end_time: + print 'get_transceiver_change_event:' \ + 'time wrap / invalid timeout value', timeout + + return False, {} # Time wrap or possibly incorrect timeout + + while timeout >= 0: + # Check for OIR events and return updated port_dict + + reg_value = self._get_presence_bitmap + changed_ports = self.data['present'] ^ reg_value + if changed_ports: + for port in range (self.port_start, self.port_end+1): + # Mask off the bit corresponding to our port + mask = (1 << (port - 1)) + 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 + self.data['valid'] = 1 + return True, port_dict + + if blocking: + time.sleep(1) + else: + timeout = end_time - time.time() + if timeout >= 1: + time.sleep(1) # We poll at 1 second granularity + else: + if timeout > 0: + time.sleep(timeout) + return True, {} + print "get_transceiver_change_event: Should not reach here." + return False, {} From 2f63e90b8bfbbe2e4711325557bc14f97d51b666 Mon Sep 17 00:00:00 2001 From: byu343 Date: Mon, 23 Sep 2019 18:07:20 -0700 Subject: [PATCH 007/278] [device/arista] Add hwSku Arista-7280CR3-C40 for 7280 (#3477) * Add hwSku Arista-7280CR3-C40 * Clean empty lines * Fix violation to config_checker * Fix no new line at end --- .../jr2-a7280cr3-32p4-40x100G.config.bcm | 755 ++++++++++++++++++ .../Arista-7280CR3-C40/port_config.ini | 41 + .../Arista-7280CR3-C40/sai.profile | 1 + src/sonic-device-data/tests/config_checker | 8 + src/sonic-device-data/tests/permitted_list | 42 + 5 files changed, 847 insertions(+) create mode 100644 device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/jr2-a7280cr3-32p4-40x100G.config.bcm create mode 100644 device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/port_config.ini create mode 100644 device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/sai.profile diff --git a/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/jr2-a7280cr3-32p4-40x100G.config.bcm b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/jr2-a7280cr3-32p4-40x100G.config.bcm new file mode 100644 index 000000000000..4787dc7db709 --- /dev/null +++ b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/jr2-a7280cr3-32p4-40x100G.config.bcm @@ -0,0 +1,755 @@ +soc_family.BCM8869X=BCM8869X + +custom_feature_ucode_path=u_code_db2pem.txt +system_headers_mode=1 +suppress_unknown_prop_warnings=1 +l4_protocols_load_balancing_enable=1 +fabric_logical_port_base=512 +trunk_group_max_members=128 +num_olp_tm_ports.BCM8869X=1 + +ucode_port_0.BCM8869X=CPU.0:core_0.0 +ucode_port_200.BCM8869X=CPU.8:core_1.200 +ucode_port_201.BCM8869X=CPU.16:core_0.201 +ucode_port_202.BCM8869X=CPU.24:core_1.202 +ucode_port_203.BCM8869X=CPU.32:core_0.203 + +port_init_speed_xe.BCM8869X=10000 +port_init_speed_xl.BCM8869X=40000 +port_init_speed_le.BCM8869X=50000 +port_init_speed_ce.BCM8869X=100000 +port_init_speed_cc.BCM8869X=200000 +port_init_speed_cd.BCM8869X=400000 +port_init_speed_il.BCM8869X=10312 + +port_init_cl72=0 + +serdes_tx_taps_1=pam4:-16:64:0:3:0:0 +serdes_tx_taps_2=pam4:-16:64:0:3:0:0 +serdes_tx_taps_3=pam4:-16:64:0:3:0:0 +serdes_tx_taps_4=pam4:-16:64:0:3:0:0 +serdes_tx_taps_5=pam4:-16:64:0:3:0:0 +serdes_tx_taps_6=pam4:-16:64:0:3:0:0 +serdes_tx_taps_7=pam4:-16:64:0:3:0:0 +serdes_tx_taps_8=pam4:-16:64:0:3:0:0 +serdes_tx_taps_9=pam4:-8:60:0:0:0:0 +serdes_tx_taps_10=pam4:-8:60:0:0:0:0 +serdes_tx_taps_11=pam4:-8:60:0:0:0:0 +serdes_tx_taps_12=pam4:-8:60:0:0:0:0 +serdes_tx_taps_13=pam4:-8:60:0:0:0:0 +serdes_tx_taps_14=pam4:-8:60:0:0:0:0 +serdes_tx_taps_15=pam4:-8:60:0:0:0:0 +serdes_tx_taps_16=pam4:-8:60:0:0:0:0 +serdes_tx_taps_17=pam4:-8:60:0:0:0:0 +serdes_tx_taps_18=pam4:-8:60:0:0:0:0 +serdes_tx_taps_19=pam4:-8:60:0:0:0:0 +serdes_tx_taps_20=pam4:-8:60:0:0:0:0 +serdes_tx_taps_21=pam4:-8:60:0:0:0:0 +serdes_tx_taps_22=pam4:-8:60:0:0:0:0 +serdes_tx_taps_23=pam4:-8:60:0:0:0:0 +serdes_tx_taps_24=pam4:-8:60:0:0:0:0 +serdes_tx_taps_25=pam4:-8:60:0:0:0:0 +serdes_tx_taps_26=pam4:-8:60:0:0:0:0 +serdes_tx_taps_27=pam4:-8:60:0:0:0:0 +serdes_tx_taps_28=pam4:-8:60:0:0:0:0 +serdes_tx_taps_29=pam4:-16:60:0:3:0:0 +serdes_tx_taps_30=pam4:-16:60:0:3:0:0 +serdes_tx_taps_31=pam4:-16:60:0:3:0:0 +serdes_tx_taps_32=pam4:-16:60:0:3:0:0 +serdes_tx_taps_33=nrz:0:71:-16:-5:0:0 +serdes_tx_taps_34=nrz:0:71:-16:-5:0:0 +serdes_tx_taps_35=nrz:0:78:-22:-4:0:0 +serdes_tx_taps_36=nrz:0:78:-22:-4:0:0 +serdes_tx_taps_37=nrz:0:72:-18:-5:0:0 +serdes_tx_taps_38=nrz:0:72:-18:-5:0:0 +serdes_tx_taps_39=nrz:0:68:-17:-6:0:0 +serdes_tx_taps_40=nrz:0:68:-17:-6:0:0 + +ucode_port_100.BCM8869X=RCY_MIRROR.0:core_0.100 +ucode_port_101.BCM8869X=RCY_MIRROR.1:core_0.101 +ucode_port_102.BCM8869X=RCY_MIRROR.2:core_0.102 +ucode_port_103.BCM8869X=RCY_MIRROR.3:core_0.103 +ucode_port_104.BCM8869X=RCY_MIRROR.4:core_0.104 +ucode_port_105.BCM8869X=RCY_MIRROR.5:core_0.105 +ucode_port_106.BCM8869X=RCY_MIRROR.6:core_0.106 +ucode_port_107.BCM8869X=RCY_MIRROR.7:core_0.107 +ucode_port_108.BCM8869X=RCY_MIRROR.8:core_0.108 +ucode_port_109.BCM8869X=RCY_MIRROR.9:core_0.109 +ucode_port_110.BCM8869X=RCY_MIRROR.10:core_0.110 +ucode_port_111.BCM8869X=RCY_MIRROR.11:core_0.111 +ucode_port_112.BCM8869X=RCY_MIRROR.12:core_0.112 +ucode_port_113.BCM8869X=RCY_MIRROR.13:core_0.113 +ucode_port_114.BCM8869X=RCY_MIRROR.14:core_0.114 +ucode_port_115.BCM8869X=RCY_MIRROR.15:core_0.115 +ucode_port_116.BCM8869X=RCY_MIRROR.16:core_0.116 +ucode_port_117.BCM8869X=RCY_MIRROR.17:core_0.117 +ucode_port_118.BCM8869X=RCY_MIRROR.18:core_0.118 +ucode_port_119.BCM8869X=RCY_MIRROR.19:core_0.119 +ucode_port_120.BCM8869X=RCY_MIRROR.0:core_1.120 +ucode_port_121.BCM8869X=RCY_MIRROR.1:core_1.121 +ucode_port_122.BCM8869X=RCY_MIRROR.2:core_1.122 +ucode_port_123.BCM8869X=RCY_MIRROR.3:core_1.123 +ucode_port_124.BCM8869X=RCY_MIRROR.4:core_1.124 +ucode_port_125.BCM8869X=RCY_MIRROR.5:core_1.125 +ucode_port_126.BCM8869X=RCY_MIRROR.6:core_1.126 +ucode_port_127.BCM8869X=RCY_MIRROR.7:core_1.127 +ucode_port_128.BCM8869X=RCY_MIRROR.8:core_1.128 +ucode_port_129.BCM8869X=RCY_MIRROR.9:core_1.129 +ucode_port_130.BCM8869X=RCY_MIRROR.10:core_1.130 +ucode_port_131.BCM8869X=RCY_MIRROR.11:core_1.131 +ucode_port_132.BCM8869X=RCY_MIRROR.12:core_1.132 +ucode_port_133.BCM8869X=RCY_MIRROR.13:core_1.133 +ucode_port_134.BCM8869X=RCY_MIRROR.14:core_1.134 +ucode_port_135.BCM8869X=RCY_MIRROR.15:core_1.135 +ucode_port_136.BCM8869X=RCY_MIRROR.16:core_1.136 +ucode_port_137.BCM8869X=RCY_MIRROR.17:core_1.137 +ucode_port_138.BCM8869X=RCY_MIRROR.18:core_1.138 +ucode_port_139.BCM8869X=RCY_MIRROR.19:core_1.139 + +port_priorities.BCM8869X=8 + +ucode_port_240.BCM8869X=OLP:core_0.240 + +sw_state_max_size.BCM8869X=750000000 + +stable_location.BCM8869X=4 +stable_location.BCM8869X_ADAPTER=3 + +stable_filename.BCM8869X_ADAPTER=warmboot_data_0 +stable_filename=/dev/shm/warmboot_data_0 +stable_filename.1=/dev/shm/warmboot_data_1 +stable_filename.2=/dev/shm/warmboot_data_2 + +stable_size.BCM8869X=800000000 + +tm_port_header_type_in_0.BCM8869X=INJECTED_2 +tm_port_header_type_out_0.BCM8869X=CPU + +tm_port_header_type_in_200.BCM8869X=INJECTED_2_PP +tm_port_header_type_out_200.BCM8869X=ETH +tm_port_header_type_in_201.BCM8869X=INJECTED_2_PP +tm_port_header_type_out_201.BCM8869X=ETH +tm_port_header_type_in_202.BCM8869X=INJECTED_2_PP +tm_port_header_type_out_202.BCM8869X=ETH +tm_port_header_type_in_203.BCM8869X=INJECTED_2_PP +tm_port_header_type_out_203.BCM8869X=ETH + +sat_enable.BCM8869X=1 +tm_port_header_type_out_218.BCM8869X=CPU +tm_port_header_type_in_218.BCM8869X=INJECTED_2 + +tm_port_header_type_in_232.BCM8869X=INJECTED_2 +tm_port_header_type_out_232.BCM8869X=CPU +tm_port_header_type_in_233.BCM8869X=INJECTED_2 +tm_port_header_type_out_233.BCM8869X=CPU + +tm_port_header_type_in_240.BCM8869X=INJECTED_2 +tm_port_header_type_out_240.BCM8869X=RAW + +dtm_flow_mapping_mode_region_64.BCM8869X=3 +dtm_flow_mapping_mode_region_65.BCM8869X=3 +dtm_flow_mapping_mode_region_66.BCM8869X=3 +dtm_flow_mapping_mode_region_67.BCM8869X=3 +dtm_flow_mapping_mode_region_68.BCM8869X=3 +dtm_flow_mapping_mode_region_69.BCM8869X=3 +dtm_flow_mapping_mode_region_70.BCM8869X=3 +dtm_flow_mapping_mode_region_71.BCM8869X=3 +dtm_flow_mapping_mode_region_72.BCM8869X=3 +dtm_flow_mapping_mode_region_73.BCM8869X=3 +dtm_flow_mapping_mode_region_74.BCM8869X=3 +dtm_flow_mapping_mode_region_75.BCM8869X=3 +dtm_flow_mapping_mode_region_76.BCM8869X=3 +dtm_flow_mapping_mode_region_77.BCM8869X=3 +dtm_flow_mapping_mode_region_78.BCM8869X=3 +dtm_flow_mapping_mode_region_79.BCM8869X=7 +dtm_flow_mapping_mode_region_80.BCM8869X=3 +dtm_flow_mapping_mode_region_81.BCM8869X=1 +dtm_flow_mapping_mode_region_82.BCM8869X=3 +dtm_flow_mapping_mode_region_83.BCM8869X=3 +dtm_flow_mapping_mode_region_84.BCM8869X=3 +dtm_flow_mapping_mode_region_85.BCM8869X=3 +dtm_flow_mapping_mode_region_86.BCM8869X=3 +dtm_flow_mapping_mode_region_87.BCM8869X=3 +dtm_flow_mapping_mode_region_88.BCM8869X=3 +dtm_flow_mapping_mode_region_89.BCM8869X=3 +dtm_flow_mapping_mode_region_90.BCM8869X=3 +dtm_flow_mapping_mode_region_91.BCM8869X=3 +dtm_flow_mapping_mode_region_92.BCM8869X=3 +dtm_flow_mapping_mode_region_93.BCM8869X=3 +dtm_flow_mapping_mode_region_94.BCM8869X=3 + +dtm_flow_nof_remote_cores_region_1.BCM8869X=2 +dtm_flow_nof_remote_cores_region_2.BCM8869X=2 +dtm_flow_nof_remote_cores_region_3.BCM8869X=2 +dtm_flow_nof_remote_cores_region_4.BCM8869X=2 +dtm_flow_nof_remote_cores_region_5.BCM8869X=2 +dtm_flow_nof_remote_cores_region_6.BCM8869X=2 +dtm_flow_nof_remote_cores_region_7.BCM8869X=2 +dtm_flow_nof_remote_cores_region_8.BCM8869X=2 +dtm_flow_nof_remote_cores_region_9.BCM8869X=2 +dtm_flow_nof_remote_cores_region_10.BCM8869X=2 +dtm_flow_nof_remote_cores_region_11.BCM8869X=2 +dtm_flow_nof_remote_cores_region_12.BCM8869X=2 +dtm_flow_nof_remote_cores_region_13.BCM8869X=2 +dtm_flow_nof_remote_cores_region_14.BCM8869X=2 +dtm_flow_nof_remote_cores_region_15.BCM8869X=2 +dtm_flow_nof_remote_cores_region_16.BCM8869X=2 +dtm_flow_nof_remote_cores_region_17.BCM8869X=2 +dtm_flow_nof_remote_cores_region_18.BCM8869X=2 +dtm_flow_nof_remote_cores_region_19.BCM8869X=2 +dtm_flow_nof_remote_cores_region_20.BCM8869X=2 +dtm_flow_nof_remote_cores_region_21.BCM8869X=2 +dtm_flow_nof_remote_cores_region_22.BCM8869X=2 +dtm_flow_nof_remote_cores_region_23.BCM8869X=2 +dtm_flow_nof_remote_cores_region_24.BCM8869X=2 +dtm_flow_nof_remote_cores_region_25.BCM8869X=2 +dtm_flow_nof_remote_cores_region_26.BCM8869X=2 +dtm_flow_nof_remote_cores_region_27.BCM8869X=2 +dtm_flow_nof_remote_cores_region_28.BCM8869X=2 +dtm_flow_nof_remote_cores_region_29.BCM8869X=2 +dtm_flow_nof_remote_cores_region_30.BCM8869X=2 +dtm_flow_nof_remote_cores_region_31.BCM8869X=2 +dtm_flow_nof_remote_cores_region_32.BCM8869X=2 +dtm_flow_nof_remote_cores_region_33.BCM8869X=2 +dtm_flow_nof_remote_cores_region_34.BCM8869X=2 +dtm_flow_nof_remote_cores_region_35.BCM8869X=2 +dtm_flow_nof_remote_cores_region_36.BCM8869X=2 +dtm_flow_nof_remote_cores_region_37.BCM8869X=2 +dtm_flow_nof_remote_cores_region_38.BCM8869X=2 +dtm_flow_nof_remote_cores_region_39.BCM8869X=2 +dtm_flow_nof_remote_cores_region_40.BCM8869X=2 +dtm_flow_nof_remote_cores_region_41.BCM8869X=2 +dtm_flow_nof_remote_cores_region_42.BCM8869X=2 +dtm_flow_nof_remote_cores_region_43.BCM8869X=2 +dtm_flow_nof_remote_cores_region_44.BCM8869X=2 +dtm_flow_nof_remote_cores_region_45.BCM8869X=2 +dtm_flow_nof_remote_cores_region_46.BCM8869X=2 +dtm_flow_nof_remote_cores_region_47.BCM8869X=2 +dtm_flow_nof_remote_cores_region_48.BCM8869X=2 +dtm_flow_nof_remote_cores_region_49.BCM8869X=2 +dtm_flow_nof_remote_cores_region_50.BCM8869X=2 +dtm_flow_nof_remote_cores_region_51.BCM8869X=2 +dtm_flow_nof_remote_cores_region_52.BCM8869X=2 +dtm_flow_nof_remote_cores_region_53.BCM8869X=2 +dtm_flow_nof_remote_cores_region_54.BCM8869X=2 +dtm_flow_nof_remote_cores_region_55.BCM8869X=2 +dtm_flow_nof_remote_cores_region_56.BCM8869X=2 +dtm_flow_nof_remote_cores_region_57.BCM8869X=2 +dtm_flow_nof_remote_cores_region_58.BCM8869X=2 +dtm_flow_nof_remote_cores_region_59.BCM8869X=2 +dtm_flow_nof_remote_cores_region_60.BCM8869X=2 + +mdb_profile.BCM8869X=l3-xl + +outlif_logical_to_physical_phase_map_1=S1 +outlif_logical_to_physical_phase_map_2=L1 +outlif_logical_to_physical_phase_map_3=XL +outlif_logical_to_physical_phase_map_4=L2 +outlif_logical_to_physical_phase_map_5=M1 +outlif_logical_to_physical_phase_map_6=M2 +outlif_logical_to_physical_phase_map_7=M3 +outlif_logical_to_physical_phase_map_8=S2 + +outlif_physical_phase_data_granularity_S1=60 +outlif_physical_phase_data_granularity_S2=60 +outlif_physical_phase_data_granularity_M1=60 +outlif_physical_phase_data_granularity_M2=60 +outlif_physical_phase_data_granularity_M3=60 +outlif_physical_phase_data_granularity_L1=60 +outlif_physical_phase_data_granularity_L2=60 +outlif_physical_phase_data_granularity_XL=60 + +port_init_speed_fabric.BCM8869X=53125 + +fabric_connect_mode.BCM8869X=SINGLE_FAP +protocol_traps_mode.BCM8869X=IN_LIF + +schan_intr_enable.BCM8869X=0 +tdma_intr_enable.BCM8869X=0 +tslam_intr_enable.BCM8869X=0 +miim_intr_enable.BCM8869X=0 +schan_timeout_usec.BCM8869X=300000 +tdma_timeout_usec.BCM8869X=1000000 +tslam_timeout_usec.BCM8869X=1000000 + +appl_enable_intr_init.BCM8869X=1 +polled_irq_mode.BCM8869X=1 +polled_irq_delay.BCM8869X=1000 + +bcm_stat_interval.BCM8869X=1000 + +mem_cache_enable_ecc.BCM8869X=1 +mem_cache_enable_parity.BCM8869X=1 + +serdes_nif_clk_freq_in.BCM8869X=2 +serdes_nif_clk_freq_out.BCM8869X=1 + +serdes_fabric_clk_freq_in.BCM8869X=2 +serdes_fabric_clk_freq_out.BCM8869X=1 + +dram_phy_tune_mode_on_init.BCM8869X=RUN_TUNE + +dport_map_direct.BCM8869X=1 + +pmf_sexem3_stage.BCM8869X=IPMF3 + +lane_to_serdes_map_fabric_lane0.0=rx0:tx0 +lane_to_serdes_map_fabric_lane1.0=rx1:tx1 +lane_to_serdes_map_fabric_lane2.0=rx2:tx2 +lane_to_serdes_map_fabric_lane3.0=rx3:tx3 +lane_to_serdes_map_fabric_lane4.0=rx4:tx4 +lane_to_serdes_map_fabric_lane5.0=rx5:tx5 +lane_to_serdes_map_fabric_lane6.0=rx6:tx6 +lane_to_serdes_map_fabric_lane7.0=rx7:tx7 +lane_to_serdes_map_fabric_lane8.0=rx8:tx8 +lane_to_serdes_map_fabric_lane9.0=rx9:tx9 +lane_to_serdes_map_fabric_lane10.0=rx10:tx10 +lane_to_serdes_map_fabric_lane11.0=rx11:tx11 +lane_to_serdes_map_fabric_lane12.0=rx12:tx12 +lane_to_serdes_map_fabric_lane13.0=rx13:tx13 +lane_to_serdes_map_fabric_lane14.0=rx14:tx14 +lane_to_serdes_map_fabric_lane15.0=rx15:tx15 +lane_to_serdes_map_fabric_lane16.0=rx16:tx16 +lane_to_serdes_map_fabric_lane17.0=rx17:tx17 +lane_to_serdes_map_fabric_lane18.0=rx18:tx18 +lane_to_serdes_map_fabric_lane19.0=rx19:tx19 +lane_to_serdes_map_fabric_lane20.0=rx20:tx20 +lane_to_serdes_map_fabric_lane21.0=rx21:tx21 +lane_to_serdes_map_fabric_lane22.0=rx22:tx22 +lane_to_serdes_map_fabric_lane23.0=rx23:tx23 +lane_to_serdes_map_fabric_lane24.0=rx24:tx24 +lane_to_serdes_map_fabric_lane25.0=rx25:tx25 +lane_to_serdes_map_fabric_lane26.0=rx26:tx26 +lane_to_serdes_map_fabric_lane27.0=rx27:tx27 +lane_to_serdes_map_fabric_lane28.0=rx28:tx28 +lane_to_serdes_map_fabric_lane29.0=rx29:tx29 +lane_to_serdes_map_fabric_lane30.0=rx30:tx30 +lane_to_serdes_map_fabric_lane31.0=rx31:tx31 +lane_to_serdes_map_fabric_lane32.0=rx32:tx32 +lane_to_serdes_map_fabric_lane33.0=rx33:tx33 +lane_to_serdes_map_fabric_lane34.0=rx34:tx34 +lane_to_serdes_map_fabric_lane35.0=rx35:tx35 +lane_to_serdes_map_fabric_lane36.0=rx36:tx36 +lane_to_serdes_map_fabric_lane37.0=rx37:tx37 +lane_to_serdes_map_fabric_lane38.0=rx38:tx38 +lane_to_serdes_map_fabric_lane39.0=rx39:tx39 +lane_to_serdes_map_fabric_lane40.0=rx40:tx40 +lane_to_serdes_map_fabric_lane41.0=rx41:tx41 +lane_to_serdes_map_fabric_lane42.0=rx42:tx42 +lane_to_serdes_map_fabric_lane43.0=rx43:tx43 +lane_to_serdes_map_fabric_lane44.0=rx44:tx44 +lane_to_serdes_map_fabric_lane45.0=rx45:tx45 +lane_to_serdes_map_fabric_lane46.0=rx46:tx46 +lane_to_serdes_map_fabric_lane47.0=rx47:tx47 +lane_to_serdes_map_fabric_lane48.0=rx48:tx48 +lane_to_serdes_map_fabric_lane49.0=rx49:tx49 +lane_to_serdes_map_fabric_lane50.0=rx50:tx50 +lane_to_serdes_map_fabric_lane51.0=rx51:tx51 +lane_to_serdes_map_fabric_lane52.0=rx52:tx52 +lane_to_serdes_map_fabric_lane53.0=rx53:tx53 +lane_to_serdes_map_fabric_lane54.0=rx54:tx54 +lane_to_serdes_map_fabric_lane55.0=rx55:tx55 +lane_to_serdes_map_fabric_lane56.0=rx56:tx56 +lane_to_serdes_map_fabric_lane57.0=rx57:tx57 +lane_to_serdes_map_fabric_lane58.0=rx58:tx58 +lane_to_serdes_map_fabric_lane59.0=rx59:tx59 +lane_to_serdes_map_fabric_lane60.0=rx60:tx60 +lane_to_serdes_map_fabric_lane61.0=rx61:tx61 +lane_to_serdes_map_fabric_lane62.0=rx62:tx62 +lane_to_serdes_map_fabric_lane63.0=rx63:tx63 +lane_to_serdes_map_fabric_lane64.0=rx64:tx64 +lane_to_serdes_map_fabric_lane65.0=rx65:tx65 +lane_to_serdes_map_fabric_lane66.0=rx66:tx66 +lane_to_serdes_map_fabric_lane67.0=rx67:tx67 +lane_to_serdes_map_fabric_lane68.0=rx68:tx68 +lane_to_serdes_map_fabric_lane69.0=rx69:tx69 +lane_to_serdes_map_fabric_lane70.0=rx70:tx70 +lane_to_serdes_map_fabric_lane71.0=rx71:tx71 +lane_to_serdes_map_fabric_lane72.0=rx72:tx72 +lane_to_serdes_map_fabric_lane73.0=rx73:tx73 +lane_to_serdes_map_fabric_lane74.0=rx74:tx74 +lane_to_serdes_map_fabric_lane75.0=rx75:tx75 +lane_to_serdes_map_fabric_lane76.0=rx76:tx76 +lane_to_serdes_map_fabric_lane77.0=rx77:tx77 +lane_to_serdes_map_fabric_lane78.0=rx78:tx78 +lane_to_serdes_map_fabric_lane79.0=rx79:tx79 +lane_to_serdes_map_fabric_lane80.0=rx80:tx80 +lane_to_serdes_map_fabric_lane81.0=rx81:tx81 +lane_to_serdes_map_fabric_lane82.0=rx82:tx82 +lane_to_serdes_map_fabric_lane83.0=rx83:tx83 +lane_to_serdes_map_fabric_lane84.0=rx84:tx84 +lane_to_serdes_map_fabric_lane85.0=rx85:tx85 +lane_to_serdes_map_fabric_lane86.0=rx86:tx86 +lane_to_serdes_map_fabric_lane87.0=rx87:tx87 +lane_to_serdes_map_fabric_lane88.0=rx88:tx88 +lane_to_serdes_map_fabric_lane89.0=rx89:tx89 +lane_to_serdes_map_fabric_lane90.0=rx90:tx90 +lane_to_serdes_map_fabric_lane91.0=rx91:tx91 +lane_to_serdes_map_fabric_lane92.0=rx92:tx92 +lane_to_serdes_map_fabric_lane93.0=rx93:tx93 +lane_to_serdes_map_fabric_lane94.0=rx94:tx94 +lane_to_serdes_map_fabric_lane95.0=rx95:tx95 +lane_to_serdes_map_fabric_lane96.0=rx96:tx96 +lane_to_serdes_map_fabric_lane97.0=rx97:tx97 +lane_to_serdes_map_fabric_lane98.0=rx98:tx98 +lane_to_serdes_map_fabric_lane99.0=rx99:tx99 +lane_to_serdes_map_fabric_lane100.0=rx100:tx100 +lane_to_serdes_map_fabric_lane101.0=rx101:tx101 +lane_to_serdes_map_fabric_lane102.0=rx102:tx102 +lane_to_serdes_map_fabric_lane103.0=rx103:tx103 +lane_to_serdes_map_fabric_lane104.0=rx104:tx104 +lane_to_serdes_map_fabric_lane105.0=rx105:tx105 +lane_to_serdes_map_fabric_lane106.0=rx106:tx106 +lane_to_serdes_map_fabric_lane107.0=rx107:tx107 +lane_to_serdes_map_fabric_lane108.0=rx108:tx108 +lane_to_serdes_map_fabric_lane109.0=rx109:tx109 +lane_to_serdes_map_fabric_lane110.0=rx110:tx110 +lane_to_serdes_map_fabric_lane111.0=rx111:tx111 + +lane_to_serdes_map_nif_lane0.0=rx5:tx7 +lane_to_serdes_map_nif_lane1.0=rx7:tx6 +lane_to_serdes_map_nif_lane2.0=rx4:tx5 +lane_to_serdes_map_nif_lane3.0=rx6:tx4 +lane_to_serdes_map_nif_lane4.0=rx0:tx0 +lane_to_serdes_map_nif_lane5.0=rx1:tx1 +lane_to_serdes_map_nif_lane6.0=rx2:tx3 +lane_to_serdes_map_nif_lane7.0=rx3:tx2 +lane_to_serdes_map_nif_lane8.0=rx13:tx15 +lane_to_serdes_map_nif_lane9.0=rx12:tx14 +lane_to_serdes_map_nif_lane10.0=rx15:tx13 +lane_to_serdes_map_nif_lane11.0=rx14:tx12 +lane_to_serdes_map_nif_lane12.0=rx10:tx10 +lane_to_serdes_map_nif_lane13.0=rx8:tx9 +lane_to_serdes_map_nif_lane14.0=rx9:tx11 +lane_to_serdes_map_nif_lane15.0=rx11:tx8 +lane_to_serdes_map_nif_lane16.0=rx23:tx23 +lane_to_serdes_map_nif_lane17.0=rx21:tx22 +lane_to_serdes_map_nif_lane18.0=rx22:tx21 +lane_to_serdes_map_nif_lane19.0=rx20:tx20 +lane_to_serdes_map_nif_lane20.0=rx16:tx18 +lane_to_serdes_map_nif_lane21.0=rx17:tx17 +lane_to_serdes_map_nif_lane22.0=rx18:tx16 +lane_to_serdes_map_nif_lane23.0=rx19:tx19 +lane_to_serdes_map_nif_lane24.0=rx31:tx31 +lane_to_serdes_map_nif_lane25.0=rx30:tx30 +lane_to_serdes_map_nif_lane26.0=rx29:tx29 +lane_to_serdes_map_nif_lane27.0=rx28:tx28 +lane_to_serdes_map_nif_lane28.0=rx24:tx26 +lane_to_serdes_map_nif_lane29.0=rx26:tx25 +lane_to_serdes_map_nif_lane30.0=rx25:tx24 +lane_to_serdes_map_nif_lane31.0=rx27:tx27 +lane_to_serdes_map_nif_lane32.0=rx39:tx35 +lane_to_serdes_map_nif_lane33.0=rx38:tx36 +lane_to_serdes_map_nif_lane34.0=rx32:tx32 +lane_to_serdes_map_nif_lane35.0=rx37:tx37 +lane_to_serdes_map_nif_lane36.0=rx33:tx34 +lane_to_serdes_map_nif_lane37.0=rx34:tx38 +lane_to_serdes_map_nif_lane38.0=rx35:tx33 +lane_to_serdes_map_nif_lane39.0=rx36:tx39 +lane_to_serdes_map_nif_lane40.0=rx44:tx47 +lane_to_serdes_map_nif_lane41.0=rx43:tx41 +lane_to_serdes_map_nif_lane42.0=rx47:tx46 +lane_to_serdes_map_nif_lane43.0=rx42:tx42 +lane_to_serdes_map_nif_lane44.0=rx45:tx45 +lane_to_serdes_map_nif_lane45.0=rx41:tx40 +lane_to_serdes_map_nif_lane46.0=rx46:tx44 +lane_to_serdes_map_nif_lane47.0=rx40:tx43 +lane_to_serdes_map_nif_lane48.0=rx55:tx55 +lane_to_serdes_map_nif_lane49.0=rx54:tx54 +lane_to_serdes_map_nif_lane50.0=rx53:tx53 +lane_to_serdes_map_nif_lane51.0=rx52:tx52 +lane_to_serdes_map_nif_lane52.0=rx48:tx48 +lane_to_serdes_map_nif_lane53.0=rx49:tx49 +lane_to_serdes_map_nif_lane54.0=rx50:tx50 +lane_to_serdes_map_nif_lane55.0=rx51:tx51 +lane_to_serdes_map_nif_lane56.0=rx60:tx60 +lane_to_serdes_map_nif_lane57.0=rx61:tx61 +lane_to_serdes_map_nif_lane58.0=rx62:tx63 +lane_to_serdes_map_nif_lane59.0=rx63:tx62 +lane_to_serdes_map_nif_lane60.0=rx58:tx59 +lane_to_serdes_map_nif_lane61.0=rx59:tx56 +lane_to_serdes_map_nif_lane62.0=rx57:tx58 +lane_to_serdes_map_nif_lane63.0=rx56:tx57 +lane_to_serdes_map_nif_lane64.0=rx68:tx69 +lane_to_serdes_map_nif_lane65.0=rx69:tx68 +lane_to_serdes_map_nif_lane66.0=rx70:tx71 +lane_to_serdes_map_nif_lane67.0=rx71:tx70 +lane_to_serdes_map_nif_lane68.0=rx67:tx64 +lane_to_serdes_map_nif_lane69.0=rx66:tx67 +lane_to_serdes_map_nif_lane70.0=rx65:tx65 +lane_to_serdes_map_nif_lane71.0=rx64:tx66 +lane_to_serdes_map_nif_lane72.0=rx78:tx76 +lane_to_serdes_map_nif_lane73.0=rx76:tx77 +lane_to_serdes_map_nif_lane74.0=rx79:tx78 +lane_to_serdes_map_nif_lane75.0=rx77:tx79 +lane_to_serdes_map_nif_lane76.0=rx75:tx72 +lane_to_serdes_map_nif_lane77.0=rx74:tx75 +lane_to_serdes_map_nif_lane78.0=rx73:tx73 +lane_to_serdes_map_nif_lane79.0=rx72:tx74 +lane_to_serdes_map_nif_lane80.0=rx81:tx83 +lane_to_serdes_map_nif_lane81.0=rx85:tx84 +lane_to_serdes_map_nif_lane82.0=rx80:tx80 +lane_to_serdes_map_nif_lane83.0=rx86:tx85 +lane_to_serdes_map_nif_lane84.0=rx82:tx82 +lane_to_serdes_map_nif_lane85.0=rx87:tx86 +lane_to_serdes_map_nif_lane86.0=rx83:tx81 +lane_to_serdes_map_nif_lane87.0=rx84:tx87 +lane_to_serdes_map_nif_lane88.0=rx91:tx95 +lane_to_serdes_map_nif_lane89.0=rx90:tx89 +lane_to_serdes_map_nif_lane90.0=rx95:tx94 +lane_to_serdes_map_nif_lane91.0=rx89:tx90 +lane_to_serdes_map_nif_lane92.0=rx93:tx93 +lane_to_serdes_map_nif_lane93.0=rx94:tx88 +lane_to_serdes_map_nif_lane94.0=rx92:tx92 +lane_to_serdes_map_nif_lane95.0=rx88:tx91 +phy_rx_polarity_flip_phy0=0 +phy_rx_polarity_flip_phy1=1 +phy_rx_polarity_flip_phy2=0 +phy_rx_polarity_flip_phy3=0 +phy_rx_polarity_flip_phy4=0 +phy_rx_polarity_flip_phy5=0 +phy_rx_polarity_flip_phy6=0 +phy_rx_polarity_flip_phy7=0 +phy_rx_polarity_flip_phy8=1 +phy_rx_polarity_flip_phy9=1 +phy_rx_polarity_flip_phy10=1 +phy_rx_polarity_flip_phy11=1 +phy_rx_polarity_flip_phy12=0 +phy_rx_polarity_flip_phy13=1 +phy_rx_polarity_flip_phy14=1 +phy_rx_polarity_flip_phy15=1 +phy_rx_polarity_flip_phy16=0 +phy_rx_polarity_flip_phy17=1 +phy_rx_polarity_flip_phy18=1 +phy_rx_polarity_flip_phy19=0 +phy_rx_polarity_flip_phy20=0 +phy_rx_polarity_flip_phy21=0 +phy_rx_polarity_flip_phy22=0 +phy_rx_polarity_flip_phy23=0 +phy_rx_polarity_flip_phy24=1 +phy_rx_polarity_flip_phy25=1 +phy_rx_polarity_flip_phy26=1 +phy_rx_polarity_flip_phy27=0 +phy_rx_polarity_flip_phy28=0 +phy_rx_polarity_flip_phy29=1 +phy_rx_polarity_flip_phy30=1 +phy_rx_polarity_flip_phy31=0 +phy_rx_polarity_flip_phy32=0 +phy_rx_polarity_flip_phy33=1 +phy_rx_polarity_flip_phy34=1 +phy_rx_polarity_flip_phy35=0 +phy_rx_polarity_flip_phy36=0 +phy_rx_polarity_flip_phy37=0 +phy_rx_polarity_flip_phy38=1 +phy_rx_polarity_flip_phy39=0 +phy_rx_polarity_flip_phy40=1 +phy_rx_polarity_flip_phy41=1 +phy_rx_polarity_flip_phy42=0 +phy_rx_polarity_flip_phy43=0 +phy_rx_polarity_flip_phy44=1 +phy_rx_polarity_flip_phy45=1 +phy_rx_polarity_flip_phy46=0 +phy_rx_polarity_flip_phy47=0 +phy_rx_polarity_flip_phy48=1 +phy_rx_polarity_flip_phy49=1 +phy_rx_polarity_flip_phy50=1 +phy_rx_polarity_flip_phy51=1 +phy_rx_polarity_flip_phy52=0 +phy_rx_polarity_flip_phy53=0 +phy_rx_polarity_flip_phy54=0 +phy_rx_polarity_flip_phy55=0 +phy_rx_polarity_flip_phy56=0 +phy_rx_polarity_flip_phy57=0 +phy_rx_polarity_flip_phy58=0 +phy_rx_polarity_flip_phy59=0 +phy_rx_polarity_flip_phy60=1 +phy_rx_polarity_flip_phy61=1 +phy_rx_polarity_flip_phy62=1 +phy_rx_polarity_flip_phy63=1 +phy_rx_polarity_flip_phy64=1 +phy_rx_polarity_flip_phy65=1 +phy_rx_polarity_flip_phy66=1 +phy_rx_polarity_flip_phy67=1 +phy_rx_polarity_flip_phy68=1 +phy_rx_polarity_flip_phy69=1 +phy_rx_polarity_flip_phy70=1 +phy_rx_polarity_flip_phy71=1 +phy_rx_polarity_flip_phy72=1 +phy_rx_polarity_flip_phy73=0 +phy_rx_polarity_flip_phy74=0 +phy_rx_polarity_flip_phy75=1 +phy_rx_polarity_flip_phy76=1 +phy_rx_polarity_flip_phy77=1 +phy_rx_polarity_flip_phy78=1 +phy_rx_polarity_flip_phy79=1 +phy_rx_polarity_flip_phy80=0 +phy_rx_polarity_flip_phy81=0 +phy_rx_polarity_flip_phy82=1 +phy_rx_polarity_flip_phy83=1 +phy_rx_polarity_flip_phy84=1 +phy_rx_polarity_flip_phy85=0 +phy_rx_polarity_flip_phy86=1 +phy_rx_polarity_flip_phy87=1 +phy_rx_polarity_flip_phy88=0 +phy_rx_polarity_flip_phy89=0 +phy_rx_polarity_flip_phy90=1 +phy_rx_polarity_flip_phy91=1 +phy_rx_polarity_flip_phy92=0 +phy_rx_polarity_flip_phy93=1 +phy_rx_polarity_flip_phy94=0 +phy_rx_polarity_flip_phy95=0 +phy_tx_polarity_flip_phy0=1 +phy_tx_polarity_flip_phy1=1 +phy_tx_polarity_flip_phy2=1 +phy_tx_polarity_flip_phy3=1 +phy_tx_polarity_flip_phy4=1 +phy_tx_polarity_flip_phy5=1 +phy_tx_polarity_flip_phy6=0 +phy_tx_polarity_flip_phy7=0 +phy_tx_polarity_flip_phy8=1 +phy_tx_polarity_flip_phy9=1 +phy_tx_polarity_flip_phy10=1 +phy_tx_polarity_flip_phy11=1 +phy_tx_polarity_flip_phy12=1 +phy_tx_polarity_flip_phy13=1 +phy_tx_polarity_flip_phy14=0 +phy_tx_polarity_flip_phy15=0 +phy_tx_polarity_flip_phy16=0 +phy_tx_polarity_flip_phy17=0 +phy_tx_polarity_flip_phy18=0 +phy_tx_polarity_flip_phy19=0 +phy_tx_polarity_flip_phy20=0 +phy_tx_polarity_flip_phy21=0 +phy_tx_polarity_flip_phy22=0 +phy_tx_polarity_flip_phy23=0 +phy_tx_polarity_flip_phy24=0 +phy_tx_polarity_flip_phy25=0 +phy_tx_polarity_flip_phy26=0 +phy_tx_polarity_flip_phy27=0 +phy_tx_polarity_flip_phy28=0 +phy_tx_polarity_flip_phy29=0 +phy_tx_polarity_flip_phy30=0 +phy_tx_polarity_flip_phy31=0 +phy_tx_polarity_flip_phy32=0 +phy_tx_polarity_flip_phy33=0 +phy_tx_polarity_flip_phy34=1 +phy_tx_polarity_flip_phy35=1 +phy_tx_polarity_flip_phy36=1 +phy_tx_polarity_flip_phy37=0 +phy_tx_polarity_flip_phy38=0 +phy_tx_polarity_flip_phy39=1 +phy_tx_polarity_flip_phy40=1 +phy_tx_polarity_flip_phy41=1 +phy_tx_polarity_flip_phy42=0 +phy_tx_polarity_flip_phy43=1 +phy_tx_polarity_flip_phy44=1 +phy_tx_polarity_flip_phy45=1 +phy_tx_polarity_flip_phy46=0 +phy_tx_polarity_flip_phy47=0 +phy_tx_polarity_flip_phy48=0 +phy_tx_polarity_flip_phy49=0 +phy_tx_polarity_flip_phy50=0 +phy_tx_polarity_flip_phy51=0 +phy_tx_polarity_flip_phy52=0 +phy_tx_polarity_flip_phy53=0 +phy_tx_polarity_flip_phy54=0 +phy_tx_polarity_flip_phy55=0 +phy_tx_polarity_flip_phy56=1 +phy_tx_polarity_flip_phy57=1 +phy_tx_polarity_flip_phy58=0 +phy_tx_polarity_flip_phy59=0 +phy_tx_polarity_flip_phy60=1 +phy_tx_polarity_flip_phy61=1 +phy_tx_polarity_flip_phy62=0 +phy_tx_polarity_flip_phy63=0 +phy_tx_polarity_flip_phy64=0 +phy_tx_polarity_flip_phy65=0 +phy_tx_polarity_flip_phy66=0 +phy_tx_polarity_flip_phy67=0 +phy_tx_polarity_flip_phy68=0 +phy_tx_polarity_flip_phy69=0 +phy_tx_polarity_flip_phy70=1 +phy_tx_polarity_flip_phy71=1 +phy_tx_polarity_flip_phy72=1 +phy_tx_polarity_flip_phy73=1 +phy_tx_polarity_flip_phy74=1 +phy_tx_polarity_flip_phy75=1 +phy_tx_polarity_flip_phy76=0 +phy_tx_polarity_flip_phy77=0 +phy_tx_polarity_flip_phy78=1 +phy_tx_polarity_flip_phy79=1 +phy_tx_polarity_flip_phy80=0 +phy_tx_polarity_flip_phy81=1 +phy_tx_polarity_flip_phy82=1 +phy_tx_polarity_flip_phy83=1 +phy_tx_polarity_flip_phy84=1 +phy_tx_polarity_flip_phy85=0 +phy_tx_polarity_flip_phy86=0 +phy_tx_polarity_flip_phy87=1 +phy_tx_polarity_flip_phy88=1 +phy_tx_polarity_flip_phy89=0 +phy_tx_polarity_flip_phy90=0 +phy_tx_polarity_flip_phy91=1 +phy_tx_polarity_flip_phy92=1 +phy_tx_polarity_flip_phy93=1 +phy_tx_polarity_flip_phy94=0 +phy_tx_polarity_flip_phy95=0 + +ucode_port_1=CGE2_0:core_0.1 +ucode_port_2=CGE2_1:core_0.2 +ucode_port_3=CGE2_2:core_0.3 +ucode_port_4=CGE2_3:core_0.4 +ucode_port_5=CGE2_4:core_0.5 +ucode_port_6=CGE2_5:core_0.6 +ucode_port_7=CGE2_6:core_0.7 +ucode_port_8=CGE2_7:core_0.8 +ucode_port_9=CGE2_8:core_0.9 +ucode_port_10=CGE2_9:core_0.10 +ucode_port_11=CGE2_10:core_0.11 +ucode_port_12=CGE2_11:core_0.12 +ucode_port_13=CGE2_12:core_0.13 +ucode_port_14=CGE2_13:core_0.14 +ucode_port_15=CGE2_14:core_0.15 +ucode_port_16=CGE2_15:core_0.16 +ucode_port_17=CGE2_36:core_1.17 +ucode_port_18=CGE2_37:core_1.18 +ucode_port_19=CGE2_38:core_1.19 +ucode_port_20=CGE2_39:core_1.20 +ucode_port_21=CGE2_32:core_1.21 +ucode_port_22=CGE2_33:core_1.22 +ucode_port_23=CGE2_34:core_1.23 +ucode_port_24=CGE2_35:core_1.24 +ucode_port_25=CGE2_28:core_1.25 +ucode_port_26=CGE2_29:core_1.26 +ucode_port_27=CGE2_30:core_1.27 +ucode_port_28=CGE2_31:core_1.28 +ucode_port_29=CGE2_24:core_1.29 +ucode_port_30=CGE2_25:core_1.30 +ucode_port_31=CGE2_26:core_1.31 +ucode_port_32=CGE2_27:core_1.32 + +port_fec_33=2 +port_fec_34=2 +port_fec_35=2 +port_fec_36=2 +port_fec_37=2 +port_fec_38=2 +port_fec_39=2 +port_fec_40=2 + +ucode_port_33=CGE8:core_0.33 +ucode_port_34=CGE9:core_0.34 +ucode_port_35=CGE10:core_0.35 +ucode_port_36=CGE11:core_0.36 +ucode_port_37=CGE22:core_1.37 +ucode_port_38=CGE23:core_1.38 +ucode_port_39=CGE20:core_1.39 +ucode_port_40=CGE21:core_1.40 + +rif_id_max=0x4000 + +dma_desc_aggregator_chain_length_max.BCM8869X=1000 +dma_desc_aggregator_buff_size_kb.BCM8869X=100 +dma_desc_aggregator_timeout_usec.BCM8869X=1000 +dma_desc_aggregator_enable_specific_MDB_LPM.BCM8869X=1 +dma_desc_aggregator_enable_specific_MDB_FEC.BCM8869X=1 diff --git a/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/port_config.ini b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/port_config.ini new file mode 100644 index 000000000000..2ba638aee50d --- /dev/null +++ b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/port_config.ini @@ -0,0 +1,41 @@ +# name lanes alias index speed +Ethernet0 0,1 Ethernet1/1 1 100000 +Ethernet4 2,3 Ethernet2/1 2 100000 +Ethernet8 4,5 Ethernet3/1 3 100000 +Ethernet12 6,7 Ethernet4/1 4 100000 +Ethernet16 8,9 Ethernet5/1 5 100000 +Ethernet20 10,11 Ethernet6/1 6 100000 +Ethernet24 12,13 Ethernet7/1 7 100000 +Ethernet28 14,15 Ethernet8/1 8 100000 +Ethernet32 16,17 Ethernet9/1 9 100000 +Ethernet36 18,19 Ethernet10/1 10 100000 +Ethernet40 20,21 Ethernet11/1 11 100000 +Ethernet44 22,23 Ethernet12/1 12 100000 +Ethernet48 24,25 Ethernet13/1 13 100000 +Ethernet52 26,27 Ethernet14/1 14 100000 +Ethernet56 28,29 Ethernet15/1 15 100000 +Ethernet60 30,31 Ethernet16/1 16 100000 +Ethernet64 72,73 Ethernet17/1 17 100000 +Ethernet68 74,75 Ethernet18/1 18 100000 +Ethernet72 76,77 Ethernet19/1 19 100000 +Ethernet76 78,79 Ethernet20/1 20 100000 +Ethernet80 64,65 Ethernet21/1 21 100000 +Ethernet84 66,67 Ethernet22/1 22 100000 +Ethernet88 68,69 Ethernet23/1 23 100000 +Ethernet92 70,71 Ethernet24/1 24 100000 +Ethernet96 56,57 Ethernet25/1 25 100000 +Ethernet100 58,59 Ethernet26/1 26 100000 +Ethernet104 60,61 Ethernet27/1 27 100000 +Ethernet108 62,63 Ethernet28/1 28 100000 +Ethernet112 48,49 Ethernet29/1 29 100000 +Ethernet116 50,51 Ethernet30/1 30 100000 +Ethernet120 52,53 Ethernet31/1 31 100000 +Ethernet124 54,55 Ethernet32/1 32 100000 +Ethernet128 32,33,34,35 Ethernet33/1 33 100000 +Ethernet132 36,37,38,39 Ethernet33/5 33 100000 +Ethernet136 40,41,42,43 Ethernet34/1 34 100000 +Ethernet140 44,45,46,47 Ethernet34/5 34 100000 +Ethernet144 88,89,90,91 Ethernet35/1 35 100000 +Ethernet148 92,93,94,95 Ethernet35/5 35 100000 +Ethernet152 80,81,82,83 Ethernet36/1 36 100000 +Ethernet156 84,85,86,87 Ethernet36/5 36 100000 diff --git a/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/sai.profile b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/sai.profile new file mode 100644 index 000000000000..130a3f8c4cbd --- /dev/null +++ b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/jr2-a7280cr3-32p4-40x100G.config.bcm diff --git a/src/sonic-device-data/tests/config_checker b/src/sonic-device-data/tests/config_checker index a0e3b0cbd45c..6d95c13efc7c 100755 --- a/src/sonic-device-data/tests/config_checker +++ b/src/sonic-device-data/tests/config_checker @@ -30,6 +30,8 @@ def check_file(file_name): continue p = line.split("=", 1)[0] + # Remove trailing chip name "bcm8869x" + p = re.sub(r"\.bcm8869x(_adapter)?$", "", p) # Remove trailing unit ".$" p = re.sub(r"\.[0-9]+$", '', p) # Remove trailing port name @@ -47,6 +49,12 @@ def check_file(file_name): p = re.sub(r"_lane\d+$", '', p) # Remove trailing "{.}$" p = re.sub(r"{[0-9]+\.[0-9]+}$", '', p) + # Remove trailing phy with number + p = re.sub(r"_phy\d+$", '', p) + # Remove trailing phase of data granularity + p = re.sub(r"_data_granularity_\w\w$", '_data_granularity', p) + # Remove trailing type of port_init_speed + p = re.sub(r"^port_init_speed_\w+$", 'port_init_speed', p) if not check_property(p): file_ok = False diff --git a/src/sonic-device-data/tests/permitted_list b/src/sonic-device-data/tests/permitted_list index 31c424857445..bba14e99db3e 100644 --- a/src/sonic-device-data/tests/permitted_list +++ b/src/sonic-device-data/tests/permitted_list @@ -159,4 +159,46 @@ ccmdma_intr_enable phy_enable init_all_modules port_fec +appl_enable_intr_init +custom_feature_ucode_path +dma_desc_aggregator_buff_size_kb +dma_desc_aggregator_chain_length_max +dma_desc_aggregator_enable_specific_mdb_fec +dma_desc_aggregator_enable_specific_mdb_lpm +dma_desc_aggregator_timeout_usec +dram_phy_tune_mode_on_init +dtm_flow_mapping_mode_region +dtm_flow_nof_remote_cores_region +fabric_connect_mode +fabric_logical_port_base +l4_protocols_load_balancing_enable +lane_to_serdes_map_fabric +lane_to_serdes_map_nif +mdb_profile +mem_cache_enable_ecc +mem_cache_enable_parity +num_olp_tm_ports +outlif_logical_to_physical_phase_map +outlif_physical_phase_data_granularity +pmf_sexem3_stage +polled_irq_delay +polled_irq_mode +port_priorities +protocol_traps_mode +rif_id_max +sat_enable +serdes_fabric_clk_freq_in +serdes_fabric_clk_freq_out +serdes_nif_clk_freq_in +serdes_nif_clk_freq_out +soc_family +stable_filename +stable_location +suppress_unknown_prop_warnings +sw_state_max_size +system_headers_mode +tm_port_header_type_in +tm_port_header_type_out +trunk_group_max_members +ucode_port led_fw_path From bccf18620a52168843734832231d2a97b7c6050c Mon Sep 17 00:00:00 2001 From: kannankvs Date: Wed, 25 Sep 2019 00:34:17 +0530 Subject: [PATCH 008/278] [snmpd] mvrf snmp ipv6 prototype mismatch issue resolved (#3504) --- .../0007-Linux-VRF-5.7.3-Support.patch | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/snmpd/patch-5.7.3+dfsg/0007-Linux-VRF-5.7.3-Support.patch b/src/snmpd/patch-5.7.3+dfsg/0007-Linux-VRF-5.7.3-Support.patch index e16014aeaf6b..48d13d7f62d6 100755 --- a/src/snmpd/patch-5.7.3+dfsg/0007-Linux-VRF-5.7.3-Support.patch +++ b/src/snmpd/patch-5.7.3+dfsg/0007-Linux-VRF-5.7.3-Support.patch @@ -49,9 +49,9 @@ Testing done included VRFs as well as non-VRF functionality with traps snmplib/transports/snmpUDPBaseDomain.c | 39 ++++++++++++++++++------ snmplib/transports/snmpUDPDomain.c | 15 ++++----- snmplib/transports/snmpUDPIPv4BaseDomain.c | 4 +-- - snmplib/transports/snmpUDPIPv6Domain.c | 13 ++++---- + snmplib/transports/snmpUDPIPv6Domain.c | 19 ++++----- snmplib/transports/snmpUnixDomain.c | 5 +-- - 23 files changed, 141 insertions(+), 70 deletions(-) + 23 files changed, 141 insertions(+), 76 deletions(-) diff --git a/agent/agent_trap.c b/agent/agent_trap.c index 080b8bf..c488ac9 100644 @@ -706,6 +706,19 @@ diff --git a/snmplib/transports/snmpUDPIPv6Domain.c b/snmplib/transports/snmpUDP index 18de876..6b44b22 100644 --- a/snmplib/transports/snmpUDPIPv6Domain.c +++ b/snmplib/transports/snmpUDPIPv6Domain.c +@@ -74,12 +74,6 @@ oid netsnmp_UDPIPv6Domain[] = { TRANSPORT_DOMAIN_UDP_IPV6 }; + static netsnmp_tdomain udp6Domain; + + /* +- * from snmpUDPDomain. not static, but not public, either. +- * (ie don't put it in a public header.) +- */ +-extern void _netsnmp_udp_sockopt_set(int fd, int server); +- +-/* + * Return a string representing the address in data, or else the "far end" + * address if data is NULL. + */ @@ -186,7 +186,7 @@ netsnmp_udp6_send(netsnmp_transport *t, void *buf, int size, */ From 75907f10aa7f4aa102f4c0665f3ae953e60ce067 Mon Sep 17 00:00:00 2001 From: Qi Luo Date: Tue, 24 Sep 2019 15:13:18 -0700 Subject: [PATCH 009/278] [snmp] Build snmpd with ipv6 support and enable it (#3500) --- dockers/docker-snmp-sv2/snmpd.conf.j2 | 4 ++-- ..._BUILD_ARCH_OS-in-order-to-build-ipv.patch | 24 +++++++++++++++++++ src/snmpd/patch-5.7.3+dfsg/series | 1 + 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/snmpd/patch-5.7.3+dfsg/0008-Enable-macro-DEB_BUILD_ARCH_OS-in-order-to-build-ipv.patch diff --git a/dockers/docker-snmp-sv2/snmpd.conf.j2 b/dockers/docker-snmp-sv2/snmpd.conf.j2 index 76a462026e18..78cf34d9f7fe 100644 --- a/dockers/docker-snmp-sv2/snmpd.conf.j2 +++ b/dockers/docker-snmp-sv2/snmpd.conf.j2 @@ -27,10 +27,9 @@ agentAddress {{ snmp_agent_address_3 }} {% endif %} {% else %} agentAddress udp:161 +agentAddress udp6:161 {% endif %} -# TODO: only support ipv4 lo addresses, add ipv6 support later - ############################################################################### # # ACCESS CONTROL @@ -47,6 +46,7 @@ rocommunity {{ community }} {% endfor %} {% else %} rocommunity {{ snmp_rocommunity }} +rocommunity6 {{ snmp_rocommunity }} {% endif %} ############################################################################### diff --git a/src/snmpd/patch-5.7.3+dfsg/0008-Enable-macro-DEB_BUILD_ARCH_OS-in-order-to-build-ipv.patch b/src/snmpd/patch-5.7.3+dfsg/0008-Enable-macro-DEB_BUILD_ARCH_OS-in-order-to-build-ipv.patch new file mode 100644 index 000000000000..f3e878077ff5 --- /dev/null +++ b/src/snmpd/patch-5.7.3+dfsg/0008-Enable-macro-DEB_BUILD_ARCH_OS-in-order-to-build-ipv.patch @@ -0,0 +1,24 @@ +From 6e038423d7a3269dbfd85b3d7ada6015479f1559 Mon Sep 17 00:00:00 2001 +From: Qi Luo +Date: Fri, 20 Sep 2019 00:42:19 +0000 +Subject: [PATCH] Enable macro DEB_BUILD_ARCH_OS in order to build ipv6 feature + +--- + debian/rules | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/debian/rules b/debian/rules +index 4c3b5b6..1fab6a4 100755 +--- a/debian/rules ++++ b/debian/rules +@@ -5,6 +5,7 @@ + # without -pie build fails during perl module build somehow... + export DEB_BUILD_MAINT_OPTIONS := hardening=+all,-pie + DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) ++DEB_BUILD_ARCH_OS ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS) + + LIB_VERSION = 30 + UPSTREAM_VERSION = $(shell dpkg-parsechangelog | egrep '^Version:' | cut -f 2 -d ':' | sed 's/ //' | sed 's/~dfsg.*$$//') +-- +2.18.0 + diff --git a/src/snmpd/patch-5.7.3+dfsg/series b/src/snmpd/patch-5.7.3+dfsg/series index a8741fb5bb9d..5cd0b06510f6 100644 --- a/src/snmpd/patch-5.7.3+dfsg/series +++ b/src/snmpd/patch-5.7.3+dfsg/series @@ -5,3 +5,4 @@ 0005-Port-OpenSSL-1.1.0-with-support-for-1.0.2.patch 0006-From-Jiri-Cervenka-snmpd-Fixed-agentx-crashing-and-or-freezing-on-timeout.patch 0007-Linux-VRF-5.7.3-Support.patch +0008-Enable-macro-DEB_BUILD_ARCH_OS-in-order-to-build-ipv.patch From 0e74e6d845058a3d9b5b66148b2a7289a48b21f0 Mon Sep 17 00:00:00 2001 From: "Sudharsan D.G" Date: Tue, 24 Sep 2019 15:16:21 -0700 Subject: [PATCH 010/278] Fixing orchagent crash in S6100,Z9100 (#3439) --- .../Force10-S6100/th-s6100-64x40G-t0.config.bcm | 6 ------ .../Force10-S6100/th-s6100-64x40G-t1.config.bcm | 6 ------ .../Force10-Z9100-C32/th-z9100-32x100G.config.bcm | 2 -- .../th-z9100-8x100G-48x50G.config.bcm | 12 ------------ 4 files changed, 26 deletions(-) diff --git a/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/th-s6100-64x40G-t0.config.bcm b/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/th-s6100-64x40G-t0.config.bcm index 2820853905ec..adbef9387eda 100644 --- a/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/th-s6100-64x40G-t0.config.bcm +++ b/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/th-s6100-64x40G-t0.config.bcm @@ -27,8 +27,6 @@ os=unix parity_correction=1 parity_enable=1 -port_phy_addr_66=0x176 -port_phy_addr_100=0x177 xgxs_tx_lane_map_104=0x3210 xgxs_rx_lane_map_104=0x0312 phy_xaui_tx_polarity_flip_104=0x0 @@ -340,8 +338,6 @@ phy_xaui_rx_polarity_flip_79=0x3 dport_map_port_78=63 dport_map_port_79=64 pbmp_xport_xe=0x3fffd0000ffff40003fffc0001fffe -portmap_66=129:10 -portmap_100=131:10 portmap_33=132:10 portmap_67=133:10 portmap_101=134:10 @@ -410,7 +406,5 @@ portmap_114=121:40:2 portmap_115=123:40:2 portmap_116=125:40:2 portmap_117=127:40:2 -dport_map_port_66=65 -dport_map_port_100=66 mmu_init_config="MSFT-TH-Tier0" diff --git a/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/th-s6100-64x40G-t1.config.bcm b/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/th-s6100-64x40G-t1.config.bcm index df22bcf23ed1..f9dc619849d0 100644 --- a/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/th-s6100-64x40G-t1.config.bcm +++ b/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/th-s6100-64x40G-t1.config.bcm @@ -27,8 +27,6 @@ os=unix parity_correction=1 parity_enable=1 -port_phy_addr_66=0x176 -port_phy_addr_100=0x177 xgxs_tx_lane_map_104=0x3210 xgxs_rx_lane_map_104=0x0312 phy_xaui_tx_polarity_flip_104=0x0 @@ -340,8 +338,6 @@ phy_xaui_rx_polarity_flip_79=0x3 dport_map_port_78=63 dport_map_port_79=64 pbmp_xport_xe=0x3fffd0000ffff40003fffc0001fffe -portmap_66=129:10 -portmap_100=131:10 portmap_33=132:10 portmap_67=133:10 portmap_101=134:10 @@ -410,7 +406,5 @@ portmap_114=121:40:2 portmap_115=123:40:2 portmap_116=125:40:2 portmap_117=127:40:2 -dport_map_port_66=65 -dport_map_port_100=66 mmu_init_config="MSFT-TH-Tier1" diff --git a/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C32/th-z9100-32x100G.config.bcm b/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C32/th-z9100-32x100G.config.bcm index 25aefca2dafa..39a3695b4cdc 100644 --- a/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C32/th-z9100-32x100G.config.bcm +++ b/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C32/th-z9100-32x100G.config.bcm @@ -57,8 +57,6 @@ portmap_2=5:100 portmap_1=1:100 portmap_4=13:100 portmap_3=9:100 -portmap_66=129:10 -portmap_100=131:10 portmap_33=132:10 portmap_67=133:10 portmap_101=134:10 diff --git a/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C8D48/th-z9100-8x100G-48x50G.config.bcm b/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C8D48/th-z9100-8x100G-48x50G.config.bcm index 5dddf7d2a2d4..3dd7cc89456d 100644 --- a/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C8D48/th-z9100-8x100G-48x50G.config.bcm +++ b/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C8D48/th-z9100-8x100G-48x50G.config.bcm @@ -25,7 +25,6 @@ parity_correction=1 parity_enable=1 #Port configuration -dport_map_port_100.0=130 dport_map_port_10.0=126 dport_map_port_1.0=117 dport_map_port_102.0=65 @@ -67,7 +66,6 @@ dport_map_port_58.0=9 dport_map_port_59.0=10 dport_map_port_62.0=13 dport_map_port_63.0=14 -dport_map_port_66.0=129 dport_map_port_68.0=17 dport_map_port_69.0=18 dport_map_port_72.0=21 @@ -84,7 +82,6 @@ dport_map_port_93.0=58 dport_map_port_96.0=61 dport_map_port_97.0=62 -phy_xaui_rx_polarity_flip_100.0=0xf phy_xaui_rx_polarity_flip_10.0=0x2 phy_xaui_rx_polarity_flip_1.0=0x9 phy_xaui_rx_polarity_flip_102.0=0x2 @@ -126,7 +123,6 @@ phy_xaui_rx_polarity_flip_58.0=0x2 phy_xaui_rx_polarity_flip_59.0=0x0 phy_xaui_rx_polarity_flip_62.0=0x3 phy_xaui_rx_polarity_flip_63.0=0x3 -phy_xaui_rx_polarity_flip_66.0=0xf phy_xaui_rx_polarity_flip_68.0=0x0 phy_xaui_rx_polarity_flip_69.0=0x3 phy_xaui_rx_polarity_flip_72.0=0x2 @@ -143,7 +139,6 @@ phy_xaui_rx_polarity_flip_93.0=0x1 phy_xaui_rx_polarity_flip_96.0=0x3 phy_xaui_rx_polarity_flip_97.0=0x2 -phy_xaui_tx_polarity_flip_100.0=0x6 phy_xaui_tx_polarity_flip_10.0=0x0 phy_xaui_tx_polarity_flip_1.0=0x3 phy_xaui_tx_polarity_flip_102.0=0x3 @@ -185,7 +180,6 @@ phy_xaui_tx_polarity_flip_58.0=0x2 phy_xaui_tx_polarity_flip_59.0=0x2 phy_xaui_tx_polarity_flip_62.0=0x3 phy_xaui_tx_polarity_flip_63.0=0x2 -phy_xaui_tx_polarity_flip_66.0=0x6 phy_xaui_tx_polarity_flip_68.0=0x2 phy_xaui_tx_polarity_flip_69.0=0x0 phy_xaui_tx_polarity_flip_72.0=0x0 @@ -202,7 +196,6 @@ phy_xaui_tx_polarity_flip_93.0=0x1 phy_xaui_tx_polarity_flip_96.0=0x0 phy_xaui_tx_polarity_flip_97.0=0x2 -portmap_100.0=131:10 portmap_10.0=11:50:2 portmap_1.0=1:100 portmap_102.0=97:50:2 @@ -244,7 +237,6 @@ portmap_58.0=57:50:2 portmap_59.0=59:50:2 portmap_62.0=61:50:2 portmap_63.0=63:50:2 -portmap_66.0=129:10 portmap_68.0=65:50:2 portmap_69.0=67:50:2 portmap_72.0=69:50:2 @@ -261,7 +253,6 @@ portmap_93.0=91:50:2 portmap_96.0=93:50:2 portmap_97.0=95:50:2 -xgxs_rx_lane_map_100.0=0x3210 xgxs_rx_lane_map_10.0=0x213 xgxs_rx_lane_map_1.0=0x213 xgxs_rx_lane_map_102.0=0x3201 @@ -303,7 +294,6 @@ xgxs_rx_lane_map_58.0=0x1203 xgxs_rx_lane_map_59.0=0x1203 xgxs_rx_lane_map_62.0=0x1302 xgxs_rx_lane_map_63.0=0x1302 -xgxs_rx_lane_map_66.0=0x3210 xgxs_rx_lane_map_68.0=0x3201 xgxs_rx_lane_map_69.0=0x3201 xgxs_rx_lane_map_72.0=0x1302 @@ -319,7 +309,6 @@ xgxs_rx_lane_map_92.0=0x3210 xgxs_rx_lane_map_93.0=0x3210 xgxs_rx_lane_map_96.0=0x3210 xgxs_rx_lane_map_97.0=0x3210 -xgxs_tx_lane_map_100.0=0x132 xgxs_tx_lane_map_10.0=0x123 xgxs_tx_lane_map_1.0=0x123 xgxs_tx_lane_map_102.0=0x123 @@ -361,7 +350,6 @@ xgxs_tx_lane_map_58.0=0x123 xgxs_tx_lane_map_59.0=0x123 xgxs_tx_lane_map_62.0=0x3201 xgxs_tx_lane_map_63.0=0x3201 -xgxs_tx_lane_map_66.0=0x132 xgxs_tx_lane_map_68.0=0x3210 xgxs_tx_lane_map_69.0=0x3210 xgxs_tx_lane_map_72.0=0x2301 From 905d429022f20bf2c118d564f8c1c11c7491e340 Mon Sep 17 00:00:00 2001 From: John Cheung Date: Tue, 24 Sep 2019 16:59:25 -0700 Subject: [PATCH 011/278] [barefoot]: updated SDK to 9.0.0 released debian package (#3471) --- platform/barefoot/bfn-platform.mk | 4 ++-- platform/barefoot/bfn-sai.mk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/barefoot/bfn-platform.mk b/platform/barefoot/bfn-platform.mk index 22fc9e6d7c46..15fbd80daafd 100644 --- a/platform/barefoot/bfn-platform.mk +++ b/platform/barefoot/bfn-platform.mk @@ -1,5 +1,5 @@ -BFN_PLATFORM = bfnplatform_9.0.0.cc6ccbe_pr_deb9.deb -$(BFN_PLATFORM)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/rel_9_0/bfnplatform_9.0.0.cc6ccbe_pr_deb9.deb" +BFN_PLATFORM = bfnplatform_9.0.0.e658347_deb9.deb +$(BFN_PLATFORM)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/rel_9_0/bfnplatform_9.0.0.e658347_deb9.deb" SONIC_ONLINE_DEBS += $(BFN_PLATFORM) $(BFN_SAI_DEV)_DEPENDS += $(BFN_PLATFORM) diff --git a/platform/barefoot/bfn-sai.mk b/platform/barefoot/bfn-sai.mk index 584c89157527..2e6b8f711fda 100644 --- a/platform/barefoot/bfn-sai.mk +++ b/platform/barefoot/bfn-sai.mk @@ -1,5 +1,5 @@ -BFN_SAI = bfnsdk_9.0.0.cc6ccbe_pr_deb9.deb -$(BFN_SAI)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/rel_9_0/bfnsdk_9.0.0.cc6ccbe_pr_deb9.deb" +BFN_SAI = bfnsdk_9.0.0.e658347_deb9.deb +$(BFN_SAI)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/rel_9_0/bfnsdk_9.0.0.e658347_deb9.deb" SONIC_ONLINE_DEBS += $(BFN_SAI) $(BFN_SAI_DEV)_DEPENDS += $(BFN_SAI) From b6a09999ded10cb5a66af3a93cfcc8c74d55d97b Mon Sep 17 00:00:00 2001 From: Long Ou Date: Wed, 25 Sep 2019 08:36:02 +0800 Subject: [PATCH 012/278] [hostcfgd] hostcfgd will exit when set hostname in DEVICE_METADATA (#3394) Signed-off-by: ouxiaolong --- files/image_config/hostcfgd/hostcfgd | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/files/image_config/hostcfgd/hostcfgd b/files/image_config/hostcfgd/hostcfgd index 4b37c64b9a68..b32e3d8cd668 100755 --- a/files/image_config/hostcfgd/hostcfgd +++ b/files/image_config/hostcfgd/hostcfgd @@ -24,10 +24,8 @@ TACPLUS_SERVER_TIMEOUT_DEFAULT = "5" TACPLUS_SERVER_AUTH_TYPE_DEFAULT = "pap" -def is_valid_hostname(name): - if hostname[-1] == ".": - hostname = hostname[:-1] # strip exactly one dot from the right, if present - if len(hostname) > 253: +def is_valid_hostname(hostname): + if hostname[-1] == "." or len(hostname) > 253: return False allowed = re.compile("(?!-)[A-Z\d-]{1,63}(? Date: Wed, 25 Sep 2019 19:29:44 +0300 Subject: [PATCH 013/278] [submodule update] update sonic-snmpagent pointer (#3495) [sonic-snmpagent] - Fix issue #104: lldpLocManAddrTable supports multiple IP addresses (#106) - Add mgmt port speed test (#107) - [rfc2737] fix typo in xcvr removal flow (#109) - Add signal handler to change debug level. (#96) - [LLDP MIB] fix lldp loc mgmt ip logic (#113) --- src/sonic-snmpagent | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-snmpagent b/src/sonic-snmpagent index 70a6c7dad4fc..875831ecda26 160000 --- a/src/sonic-snmpagent +++ b/src/sonic-snmpagent @@ -1 +1 @@ -Subproject commit 70a6c7dad4fcfa750fb4d4efbf267842d19ca8ef +Subproject commit 875831ecda2601a88612c0185242d11e97eb6e82 From c34a4783e0c3fb5d2a1335d91d15564754cabafc Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Wed, 25 Sep 2019 21:00:24 +0300 Subject: [PATCH 014/278] [build] install new platform api on host (#3282) slave.mk: add SONIC_PLATFORM_API_PY2 as dependency of host sonic_debian_extension.j2: install sonic_daemon_base and Mellanox-specific sonic_platform on host mlnx-platform-api.mk: export mlnx_platform_api_py2_wheel_path for sonic_debian_extension.j2 sonic-daemon-base.mk: export daemon_base_py2_wheel_path for sonic_debian_extension.j2 daemon_base.py: hind unnecessary dependency of swss_common on host --- files/build_templates/sonic_debian_extension.j2 | 12 ++++++++++++ platform/mellanox/mlnx-platform-api.mk | 1 + rules/sonic-daemon-base.mk | 1 + slave.mk | 3 ++- .../sonic_daemon_base/daemon_base.py | 2 +- 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index bcdecaa71766..d08aa7b6f1cc 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -116,6 +116,12 @@ sudo cp {{platform_common_py2_wheel_path}} $FILESYSTEM_ROOT/$PLATFORM_COMMON_PY2 sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install $PLATFORM_COMMON_PY2_WHEEL_NAME sudo rm -rf $FILESYSTEM_ROOT/$PLATFORM_COMMON_PY2_WHEEL_NAME +# Install sonic-daemon-base Python 2 package +DAEMON_BASE_PY2_WHEEL_NAME=$(basename {{daemon_base_py2_wheel_path}}) +sudo cp {{daemon_base_py2_wheel_path}} $FILESYSTEM_ROOT/$DAEMON_BASE_PY2_WHEEL_NAME +sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install $DAEMON_BASE_PY2_WHEEL_NAME +sudo rm -rf $FILESYSTEM_ROOT/$DAEMON_BASE_PY2_WHEEL_NAME + # Install built Python Click package (and its dependencies via 'apt-get -y install -f') # Do this before installing sonic-utilities so that it doesn't attempt to install # an older version as part of its dependencies @@ -377,6 +383,12 @@ sudo cp $files_path/$ISSU_VERSION_FILE $FILESYSTEM_ROOT/etc/mlnx/issu-version sudo cp $files_path/$MLNX_FFB_SCRIPT $FILESYSTEM_ROOT/usr/bin/mlnx-ffb.sh j2 platform/mellanox/mlnx-fw-upgrade.j2 | sudo tee $FILESYSTEM_ROOT/usr/bin/mlnx-fw-upgrade.sh sudo chmod 755 $FILESYSTEM_ROOT/usr/bin/mlnx-fw-upgrade.sh + +# Install mlnx-sonic-platform-common Python 2 package +MLNX_PLATFORM_COMMON_PY2_WHEEL_NAME=$(basename {{mlnx_platform_api_py2_wheel_path}}) +sudo cp {{mlnx_platform_api_py2_wheel_path}} $FILESYSTEM_ROOT/$MLNX_PLATFORM_COMMON_PY2_WHEEL_NAME +sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install $MLNX_PLATFORM_COMMON_PY2_WHEEL_NAME +sudo rm -rf $FILESYSTEM_ROOT/$MLNX_PLATFORM_COMMON_PY2_WHEEL_NAME {% endif %} {%- if SONIC_ROUTING_STACK == "frr" %} diff --git a/platform/mellanox/mlnx-platform-api.mk b/platform/mellanox/mlnx-platform-api.mk index 98a57d0090ed..4b70e59debc1 100644 --- a/platform/mellanox/mlnx-platform-api.mk +++ b/platform/mellanox/mlnx-platform-api.mk @@ -5,3 +5,4 @@ $(SONIC_PLATFORM_API_PY2)_SRC_PATH = $(PLATFORM_PATH)/mlnx-platform-api $(SONIC_PLATFORM_API_PY2)_PYTHON_VERSION = 2 SONIC_PYTHON_WHEELS += $(SONIC_PLATFORM_API_PY2) +export mlnx_platform_api_py2_wheel_path="$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_PLATFORM_API_PY2))" diff --git a/rules/sonic-daemon-base.mk b/rules/sonic-daemon-base.mk index dad0900e75ca..5385c18f1f12 100644 --- a/rules/sonic-daemon-base.mk +++ b/rules/sonic-daemon-base.mk @@ -5,3 +5,4 @@ $(SONIC_DAEMON_BASE_PY2)_SRC_PATH = $(SRC_PATH)/sonic-daemon-base $(SONIC_DAEMON_BASE_PY2)_PYTHON_VERSION = 2 SONIC_PYTHON_WHEELS += $(SONIC_DAEMON_BASE_PY2) +export daemon_base_py2_wheel_path="$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_DAEMON_BASE_PY2))" diff --git a/slave.mk b/slave.mk index dc13e43f62b2..1f5f3de7b3b0 100644 --- a/slave.mk +++ b/slave.mk @@ -622,7 +622,8 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ $(addprefix $(PYTHON_DEBS_PATH)/,$(SONIC_UTILS)) \ $(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_CONFIG_ENGINE)) \ $(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_PLATFORM_COMMON_PY2)) \ - $(addprefix $(PYTHON_WHEELS_PATH)/,$(REDIS_DUMP_LOAD_PY2)) + $(addprefix $(PYTHON_WHEELS_PATH)/,$(REDIS_DUMP_LOAD_PY2)) \ + $(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_PLATFORM_API_PY2)) $(HEADER) # Pass initramfs and linux kernel explicitly. They are used for all platforms export debs_path="$(STRETCH_DEBS_PATH)" diff --git a/src/sonic-daemon-base/sonic_daemon_base/daemon_base.py b/src/sonic-daemon-base/sonic_daemon_base/daemon_base.py index e238c13c22be..afdb189de672 100644 --- a/src/sonic-daemon-base/sonic_daemon_base/daemon_base.py +++ b/src/sonic-daemon-base/sonic_daemon_base/daemon_base.py @@ -7,7 +7,6 @@ import os import sys import syslog - from swsscommon import swsscommon except ImportError, e: raise ImportError (str(e) + " - required module not found") @@ -38,6 +37,7 @@ # def db_connect(db): + from swsscommon import swsscommon return swsscommon.DBConnector(db, REDIS_HOSTNAME, REDIS_PORT, From 362a6855ec1659b67f9f7806024440a61186dee0 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Wed, 25 Sep 2019 21:41:07 +0300 Subject: [PATCH 015/278] [Mellanox] enhance the initialization flow of sfp part of new platform api (#3319) * [sonic_platform.sfp_event]enhance the initialization flow of sfp_event * [sonic_platform.sfp_event] replace "retry = retry + 1" with "retry += 1" * [sonic_platform] fix typo in sfp_event * [sfp_event] remove unused variables * [sonic_platform/sfp_event.py]remove unnecessary statements --- .../sonic_platform/sfp_event.py | 109 +++++++++++++----- 1 file changed, 78 insertions(+), 31 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp_event.py b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp_event.py index 1e57603d38ad..439df785b24e 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp_event.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp_event.py @@ -24,6 +24,14 @@ SDK_SFP_STATE_OUT: STATUS_PLUGOUT, } +# system level event/error +EVENT_ON_ALL_SFP = '-1' +SYSTEM_NOT_READY = 'system_not_ready' +SYSTEM_READY = 'system_become_ready' +SYSTEM_FAIL = 'system_fail' + +SDK_DAEMON_READY_FILE = '/tmp/sdk_ready' + PMPE_PACKET_SIZE = 2000 logger = Logger(SYSLOG_IDENTIFIER) @@ -31,47 +39,86 @@ class sfp_event: ''' Listen to plugin/plugout cable events ''' - SX_OPEN_RETRIES = 20 + SX_OPEN_RETRIES = 30 + SX_OPEN_TIMEOUT = 5 + SELECT_TIMEOUT = 1 def __init__(self): self.swid = 0 self.handle = None - def initialize(self): - # open SDK API handle. - # retry at most SX_OPEN_RETRIES times to wait until SDK is started during system startup - retry = 1 - while True: - rc, self.handle = sx_api_open(None) - if rc == SX_STATUS_SUCCESS: - break - - logger.log_info("failed to open SDK API handle... retrying {}".format(retry)) - - time.sleep(2 ** retry) - retry += 1 - - if retry > self.SX_OPEN_RETRIES: - raise RuntimeError("failed to open SDK API handle after {} retries".format(retry)) - # Allocate SDK fd and user channel structures self.rx_fd_p = new_sx_fd_t_p() self.user_channel_p = new_sx_user_channel_t_p() - rc = sx_api_host_ifc_open(self.handle, self.rx_fd_p) - if rc != SX_STATUS_SUCCESS: - raise RuntimeError("sx_api_host_ifc_open exited with error, rc {}".format(rc)) - - self.user_channel_p.type = SX_USER_CHANNEL_TYPE_FD - self.user_channel_p.channel.fd = self.rx_fd_p + def initialize(self): + swid_cnt_p = None - rc = sx_api_host_ifc_trap_id_register_set(self.handle, - SX_ACCESS_CMD_REGISTER, - self.swid, - SX_TRAP_ID_PMPE, - self.user_channel_p) - if rc != SX_STATUS_SUCCESS: - raise RuntimeError("sx_api_host_ifc_trap_id_register_set exited with error, rc {}".format(rc)) + try: + # Wait for SDK daemon to be started with detect the sdk_ready file + retry = 0 + while not os.path.exists(SDK_DAEMON_READY_FILE): + if retry >= self.SX_OPEN_RETRIES: + raise RuntimeError("SDK daemon failed to start after {} retries and {} seconds waiting, exiting..." + .format(retry, self.SX_OPEN_TIMEOUT * self.SX_OPEN_RETRIES)) + else: + logger.log_info("SDK daemon not started yet, retry {} times".format(retry)) + retry += 1 + time.sleep(self.SX_OPEN_TIMEOUT) + + # After SDK daemon started, sx_api_open and sx_api_host_ifc_open is ready for call + rc, self.handle = sx_api_open(None) + if rc != SX_STATUS_SUCCESS: + raise RuntimeError("failed to call sx_api_open with rc {}, exiting...".format(rc)) + + rc = sx_api_host_ifc_open(self.handle, self.rx_fd_p) + if rc != SX_STATUS_SUCCESS: + raise RuntimeError("failed to call sx_api_host_ifc_open with rc {}, exiting...".format(rc)) + + self.user_channel_p.type = SX_USER_CHANNEL_TYPE_FD + self.user_channel_p.channel.fd = self.rx_fd_p + + # Wait for switch to be created and initialized inside SDK + retry = 0 + swid_cnt_p = new_uint32_t_p() + uint32_t_p_assign(swid_cnt_p, 0) + swid_cnt = 0 + while True: + if retry >= self.SX_OPEN_RETRIES: + raise RuntimeError("switch not created after {} retries and {} seconds waiting, exiting..." + .format(retry, self.SX_OPEN_RETRIES * self.SX_OPEN_TIMEOUT)) + else: + rc = sx_api_port_swid_list_get(self.handle, None, swid_cnt_p) + if rc == SX_STATUS_SUCCESS: + swid_cnt = uint32_t_p_value(swid_cnt_p) + if swid_cnt > 0: + delete_uint32_t_p(swid_cnt_p) + swid_cnt_p = None + break + else: + logger.log_info("switch not created yet, swid_cnt {}, retry {} times and wait for {} seconds" + .format(swid_cnt, retry, self.SX_OPEN_TIMEOUT * retry)) + else: + raise RuntimeError("sx_api_port_swid_list_get fail with rc {}, retry {} times and wait for {} seconds". + format(rc, retry, self.SX_OPEN_TIMEOUT * retry)) + + retry += 1 + time.sleep(self.SX_OPEN_TIMEOUT) + + # After switch was created inside SDK, sx_api_host_ifc_trap_id_register_set is ready to call + rc = sx_api_host_ifc_trap_id_register_set(self.handle, + SX_ACCESS_CMD_REGISTER, + self.swid, + SX_TRAP_ID_PMPE, + self.user_channel_p) + + if rc != SX_STATUS_SUCCESS: + raise RuntimeError("sx_api_host_ifc_trap_id_register_set failed with rc {}, exiting...".format(rc)) + except Exception as e: + logger.log_error("sfp_event initialization failed due to {}, exiting...".format(repr(e))) + if swid_cnt_p is not None: + delete_uint32_t_p(swid_cnt_p) + self.deinitialize() def deinitialize(self): if self.handle is None: From d059bda21c56b57934d7cbe002a5575b73560886 Mon Sep 17 00:00:00 2001 From: Kebo Liu Date: Thu, 26 Sep 2019 03:07:28 +0800 Subject: [PATCH 016/278] Update sonic-platform-daemons submodule to pick up recent fix: (#3509) [xcvrd] state machine enhancement [xcvrd] Fix transceiver tuning issue --- src/sonic-platform-daemons | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-platform-daemons b/src/sonic-platform-daemons index 88d6d5a13c12..a34ba131f618 160000 --- a/src/sonic-platform-daemons +++ b/src/sonic-platform-daemons @@ -1 +1 @@ -Subproject commit 88d6d5a13c12cc26458762ce3f54fd90dda7fe9f +Subproject commit a34ba131f618a8df6beec1f548aa08f9cedc48db From 7b0a5ba6ae14dc7596dec87c8f60dc827c29ee46 Mon Sep 17 00:00:00 2001 From: Wenda Ni Date: Wed, 25 Sep 2019 15:57:07 -0700 Subject: [PATCH 017/278] Remove the divide by 4 operation to the under the hood SAI (#1532) * Remove the divide by 4 operation to the under the hood SAI This is to avoid the need and thus the confusion for application program to know the mmu internal architecture This change must have support from SAI change to reach the correct config Signed-off-by: Wenda * Relegate the divide by 4 operation to the under the hood SAI for egress lossless pool Extend to 7060 and 6100 Signed-off-by: Wenda * Add more TH/TH2 hwskus Signed-off-by: Wenda Ni * Update config test Signed-off-by: Wenda Ni * Add TH2 ingress lossy profile Signed-off-by: Wenda Ni * Move the divide by 4 operation to SAI internal Signed-off-by: Wenda Ni * [bcm SAI] Upgrade Broadcom SAI to version 3.5.3.1-15 - Broadcom SAI 3.5 GA release 20190924. Signed-off-by: Ying Xie --- .../Arista-7060CX-32S-C32/buffers_defaults_t0.j2 | 2 +- .../Arista-7060CX-32S-C32/buffers_defaults_t1.j2 | 2 +- .../Arista-7060CX-32S-D48C8/buffers_defaults_t0.j2 | 2 +- .../Arista-7060CX-32S-Q24C8/buffers_defaults_t0.j2 | 2 +- .../Arista-7060CX-32S-Q32/buffers_defaults_t0.j2 | 2 +- .../Arista-7060CX-32S-Q32/buffers_defaults_t1.j2 | 2 +- .../Arista-7170-64C/buffers_defaults_t0.j2 | 4 ++-- .../Arista-7170-Q59S20/buffers_defaults_t0.j2 | 4 ++-- .../Arista-7260CX3-D108C8/buffers_defaults_t0.j2 | 4 ++-- .../Arista-7260CX3-Q64/buffers_defaults_t0.j2 | 4 ++-- .../Celestica-DX010-C32/buffers_defaults_t0.j2 | 2 +- .../Celestica-DX010-C32/buffers_defaults_t1.j2 | 2 +- .../Celestica-DX010-D48C8/buffers_defaults_t0.j2 | 2 +- .../Force10-S6100/buffers_defaults_t0.j2 | 2 +- .../Force10-S6100/buffers_defaults_t1.j2 | 2 +- .../Force10-Z9100-C32/buffers_defaults_t1.j2 | 2 +- .../Force10-Z9100-C8D48/buffers_defaults_t0.j2 | 2 +- platform/broadcom/sai.mk | 8 ++++---- .../tests/sample_output/buffers-dell6100.json | 2 +- 19 files changed, 26 insertions(+), 26 deletions(-) diff --git a/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/buffers_defaults_t0.j2 b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/buffers_defaults_t0.j2 index cb74cb75281b..0869e63968ac 100644 --- a/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/buffers_defaults_t0.j2 +++ b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/buffers_defaults_t0.j2 @@ -36,7 +36,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/buffers_defaults_t1.j2 b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/buffers_defaults_t1.j2 index 0699433bffb4..80e96bdceca7 100644 --- a/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/buffers_defaults_t1.j2 +++ b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/buffers_defaults_t1.j2 @@ -36,7 +36,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-D48C8/buffers_defaults_t0.j2 b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-D48C8/buffers_defaults_t0.j2 index 5d6e0cd61a7e..5add8968e621 100644 --- a/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-D48C8/buffers_defaults_t0.j2 +++ b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-D48C8/buffers_defaults_t0.j2 @@ -50,7 +50,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-Q24C8/buffers_defaults_t0.j2 b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-Q24C8/buffers_defaults_t0.j2 index 7463e20afabe..c0fa1ff0864e 100644 --- a/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-Q24C8/buffers_defaults_t0.j2 +++ b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-Q24C8/buffers_defaults_t0.j2 @@ -50,7 +50,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-Q32/buffers_defaults_t0.j2 b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-Q32/buffers_defaults_t0.j2 index cb74cb75281b..0869e63968ac 100644 --- a/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-Q32/buffers_defaults_t0.j2 +++ b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-Q32/buffers_defaults_t0.j2 @@ -36,7 +36,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-Q32/buffers_defaults_t1.j2 b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-Q32/buffers_defaults_t1.j2 index 0699433bffb4..80e96bdceca7 100644 --- a/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-Q32/buffers_defaults_t1.j2 +++ b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-Q32/buffers_defaults_t1.j2 @@ -36,7 +36,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t0.j2 b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t0.j2 index 62a6bac1c25f..3442612f70b2 100644 --- a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t0.j2 +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t0.j2 @@ -30,12 +30,12 @@ "ingress_lossy_profile": { "pool":"[BUFFER_POOL|ingress_lossless_pool]", "size":"0", - "static_th":"11075584" + "static_th":"44302336" }, "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"0", - "static_th":"10587408" + "static_th":"42349632" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t0.j2 b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t0.j2 index 8ca15c1b0391..fabdac2df879 100644 --- a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t0.j2 +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t0.j2 @@ -42,12 +42,12 @@ "ingress_lossy_profile": { "pool":"[BUFFER_POOL|ingress_lossless_pool]", "size":"0", - "static_th":"11075584" + "static_th":"44302336" }, "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"0", - "static_th":"10587408" + "static_th":"42349632" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/buffers_defaults_t0.j2 b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/buffers_defaults_t0.j2 index a5951e156b26..74579a022dcb 100644 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/buffers_defaults_t0.j2 +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/buffers_defaults_t0.j2 @@ -38,12 +38,12 @@ "ingress_lossy_profile": { "pool":"[BUFFER_POOL|ingress_lossless_pool]", "size":"0", - "static_th":"11075584" + "static_th":"44302336" }, "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"0", - "static_th":"10587408" + "static_th":"42349632" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-Q64/buffers_defaults_t0.j2 b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-Q64/buffers_defaults_t0.j2 index 62a6bac1c25f..3442612f70b2 100644 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-Q64/buffers_defaults_t0.j2 +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-Q64/buffers_defaults_t0.j2 @@ -30,12 +30,12 @@ "ingress_lossy_profile": { "pool":"[BUFFER_POOL|ingress_lossless_pool]", "size":"0", - "static_th":"11075584" + "static_th":"44302336" }, "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"0", - "static_th":"10587408" + "static_th":"42349632" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t0.j2 b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t0.j2 index 43b7d7e31a9c..4dd6bd96ad96 100644 --- a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t0.j2 +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t0.j2 @@ -43,7 +43,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t1.j2 b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t1.j2 index 6ec383c77081..3c93fb8fe2e3 100644 --- a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t1.j2 +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-C32/buffers_defaults_t1.j2 @@ -43,7 +43,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/buffers_defaults_t0.j2 b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/buffers_defaults_t0.j2 index 766de07b4945..4e4489f84a87 100644 --- a/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/buffers_defaults_t0.j2 +++ b/device/celestica/x86_64-cel_seastone-r0/Celestica-DX010-D48C8/buffers_defaults_t0.j2 @@ -58,7 +58,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/buffers_defaults_t0.j2 b/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/buffers_defaults_t0.j2 index f949a31eab7b..8f55022973fb 100644 --- a/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/buffers_defaults_t0.j2 +++ b/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/buffers_defaults_t0.j2 @@ -36,7 +36,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/buffers_defaults_t1.j2 b/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/buffers_defaults_t1.j2 index e56bbb65845f..47a9c81f0796 100644 --- a/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/buffers_defaults_t1.j2 +++ b/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100/buffers_defaults_t1.j2 @@ -36,7 +36,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C32/buffers_defaults_t1.j2 b/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C32/buffers_defaults_t1.j2 index e127362c091a..fa78303b2468 100644 --- a/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C32/buffers_defaults_t1.j2 +++ b/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C32/buffers_defaults_t1.j2 @@ -36,7 +36,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C8D48/buffers_defaults_t0.j2 b/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C8D48/buffers_defaults_t0.j2 index f200b85b2027..fa5b0fc5a52b 100644 --- a/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C8D48/buffers_defaults_t0.j2 +++ b/device/dell/x86_64-dell_z9100_c2538-r0/Force10-Z9100-C8D48/buffers_defaults_t0.j2 @@ -50,7 +50,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", diff --git a/platform/broadcom/sai.mk b/platform/broadcom/sai.mk index 28fdf57577c9..d29e0907796d 100644 --- a/platform/broadcom/sai.mk +++ b/platform/broadcom/sai.mk @@ -1,9 +1,9 @@ -BRCM_SAI = libsaibcm_3.5.2.3_amd64.deb -$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm_3.5.2.3_amd64.deb?sv=2015-04-05&sr=b&sig=anY6TeLouYsw7L6hfpH%2BTHOkvF8M3WR%2B6P2C7Dh8sHg%3D&se=2033-02-20T17%3A19%3A46Z&sp=r" +BRCM_SAI = libsaibcm_3.5.3.1-15_amd64.deb +$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm_3.5.3.1-15_amd64.deb?sv=2015-04-05&sr=b&sig=zXY%2FK%2FeGlxteIFlEkPdE%2FNDRet5T%2Fc1LgL0qyX9%2FmfQ%3D&se=2033-06-03T17%3A45%3A51Z&sp=r" -BRCM_SAI_DEV = libsaibcm-dev_3.5.2.3_amd64.deb +BRCM_SAI_DEV = libsaibcm-dev_3.5.3.1-15_amd64.deb $(eval $(call add_derived_package,$(BRCM_SAI),$(BRCM_SAI_DEV))) -$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm-dev_3.5.2.3_amd64.deb?sv=2015-04-05&sr=b&sig=o%2BVIKwVnlNv8LAvVzcS2kIXc0%2BIKaTzmA8LIkIfsh6c%3D&se=2033-02-20T17%3A20%3A03Z&sp=r" +$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm-dev_3.5.3.1-15_amd64.deb?sv=2015-04-05&sr=b&sig=%2BYOVgRo6dLxv3sLb8JE1wLoD%2FneYDABadwFv5xH3XRE%3D&se=2033-06-03T17%3A46%3A14Z&sp=r" SONIC_ONLINE_DEBS += $(BRCM_SAI) $(BRCM_SAI_DEV)_DEPENDS += $(BRCM_SAI) diff --git a/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json b/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json index 0b6c8cbe19a3..ce157b442614 100644 --- a/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json +++ b/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json @@ -96,7 +96,7 @@ "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"1518", - "static_th":"3995680" + "static_th":"15982720" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", From a577a80b059ed40486e9585b0fd19c76f6796357 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Wed, 25 Sep 2019 16:08:44 -0700 Subject: [PATCH 018/278] Flush port in both worm-reboot and fast-reboot mode on exit. Otherwise teamd will stuck (#3512) --- src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch b/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch index d92ac6987e62..52a181d4da6f 100644 --- a/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch +++ b/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch @@ -108,7 +108,7 @@ index 9dc85b5..679da49 100644 + teamd_refresh_ports(ctx); + if (ctrl_byte == 'w') + teamd_ports_flush_data(ctx); -+ } else { ++ /* Flush ports to destroy port object */ + err = teamd_flush_ports(ctx); + if (err) + return err; From a8f10c7b646bb9c0ec7d223c7076358625b112a6 Mon Sep 17 00:00:00 2001 From: Joe LeVeque Date: Thu, 26 Sep 2019 10:57:16 -0700 Subject: [PATCH 019/278] [sonic-slave] Update linux-compiler-gcc package version to fix build (#3514) --- sonic-slave/Dockerfile.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonic-slave/Dockerfile.j2 b/sonic-slave/Dockerfile.j2 index 42d4aa98f648..7ed7c4eb7096 100644 --- a/sonic-slave/Dockerfile.j2 +++ b/sonic-slave/Dockerfile.j2 @@ -150,7 +150,7 @@ RUN apt-get update && apt-get install -y \ zip \ {%- if CONFIGURED_ARCH == "amd64" %} # For broadcom sdk build - linux-compiler-gcc-4.8-x86 \ + linux-compiler-gcc-4.9-x86 \ {%- endif %} linux-kbuild-3.16 \ # teamd build From e9785d507d128666b937ecf14831dbec3a6d9b28 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Fri, 27 Sep 2019 01:25:35 +0300 Subject: [PATCH 020/278] [sonic-utilities] advance head to cbf19f6 (#3519) --- src/sonic-utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-utilities b/src/sonic-utilities index b19b125c5afa..cbf19f643a1a 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit b19b125c5afacea6c704d4003a12265cb94c8f8b +Subproject commit cbf19f643a1aa708eee6306814c0d52fd7535ec4 From 504cf62bfc476e22895747766f57f89db9fb51af Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Thu, 26 Sep 2019 16:39:48 -0700 Subject: [PATCH 021/278] [libteam]: Use last fixes from libteam master repo (#3513) --- src/libteam/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libteam/Makefile b/src/libteam/Makefile index cf8e382bb78c..b1ef12375416 100644 --- a/src/libteam/Makefile +++ b/src/libteam/Makefile @@ -15,7 +15,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : rm -rf ./libteam git clone https://github.com/jpirko/libteam.git pushd ./libteam - git checkout -b teamd -f 5c5e498bff9 + git checkout -b teamd -f 8c7614abf5993d92e332a800f244bdebd7c9a2c8 # Apply patch series stg init From 8c4678718e9ff1bcc31d31501e70065c9d986e21 Mon Sep 17 00:00:00 2001 From: Qi Luo Date: Thu, 26 Sep 2019 18:23:12 -0700 Subject: [PATCH 022/278] [snmp] snmpd ipv6 supports multiple community strings (#3523) --- dockers/docker-snmp-sv2/snmpd.conf.j2 | 1 + 1 file changed, 1 insertion(+) diff --git a/dockers/docker-snmp-sv2/snmpd.conf.j2 b/dockers/docker-snmp-sv2/snmpd.conf.j2 index 78cf34d9f7fe..9784cc42e7f7 100644 --- a/dockers/docker-snmp-sv2/snmpd.conf.j2 +++ b/dockers/docker-snmp-sv2/snmpd.conf.j2 @@ -43,6 +43,7 @@ view systemonly included .1.3.6.1.2.1.25.1 {% if snmp_rocommunities %} {% for community in snmp_rocommunities %} rocommunity {{ community }} +rocommunity6 {{ community }} {% endfor %} {% else %} rocommunity {{ snmp_rocommunity }} From 7308d2eb97edc1e191ffcc9842c01bae747da7b4 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Fri, 27 Sep 2019 11:15:46 +0300 Subject: [PATCH 023/278] [Mellanox] Stop pmon ahead of syncd (#3505) Issue Overview shutdown flow For any shutdown flow, which means all dockers are stopped in order, pmon docker stops after syncd docker has stopped, causing pmon docker fail to release sx_core resources and leaving sx_core in a bad state. The related logs are like the following: INFO syncd.sh[23597]: modprobe: FATAL: Module sx_core is in use. INFO syncd.sh[23597]: Unloading sx_core[FAILED] INFO syncd.sh[23597]: rmmod: ERROR: Module sx_core is in use config reload & service swss.restart In the flows like "config reload" and "service swss restart", the failure cause further consequences: sx_core initialization error with error message like "sx_core: create EMAD sdq 0 failed. err: -16" syncd fails to execute the create switch api with error message "syncd_main: Runtime error: :- processEvent: failed to execute api: create, key: SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000, status: SAI_STATUS_FAILURE" swss fails to call SAI API "SAI_SWITCH_ATTR_INIT_SWITCH", which causes orchagent to restart. This will introduce an extra 1 or 2 minutes for the system to be available, failing related test cases. reboot, warm-reboot & fast-reboot In the reboot flows including "reboot", "fast-reboot" and "warm-reboot" this failure doesn't have further negative effects since the system has already rebooted. In addition, "warm-reboot" requires the system to be shutdown as soon as possible to meet the GR time restriction of both BGP and LACP. "fast-reboot" also requires to meet the GR time restriction of BGP which is longer than LACP. In this sense, any unnecessary steps should be avoided. It's better to keep those flows untouched. summary To summarize, we have to come up with a way to ensure: shutdown pmon docker ahead of syncd for "config reload" or "service swss restart" flow; don't shutdown pmon docker ahead of syncd for "fast-reboot" or "warm-reboot" flow in order to save time. for "reboot" flow, either order is acceptable. Solution To solve the issue, pmon shoud be stopped ahead of syncd stopped for all flows except for the warm-reboot. - How I did it To stop pmon ahead of syncd stopped. This is done in /usr/local/bin/syncd.sh::stop() and for all shutdown sequence. Now pmon stops ahead of syncd so there must be a way in which pmon can start after syncd started. Another point that should be taken consideration is that pmon starting should be deferred so that services which have the logic of graceful restart in fast-reboot and warm-reboot have sufficient CPU cycles to meet their deadline. This is done by add "syncd.service" as "After" to pmon.service and startin /usr/local/bin/syncd.sh::wait() To start pmon automatically after syncd started. --- files/build_templates/pmon.service.j2 | 3 +++ files/scripts/syncd.sh | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/files/build_templates/pmon.service.j2 b/files/build_templates/pmon.service.j2 index 33f3173b4887..9c4226256818 100644 --- a/files/build_templates/pmon.service.j2 +++ b/files/build_templates/pmon.service.j2 @@ -2,6 +2,9 @@ Description=Platform monitor container Requires=updategraph.service After=updategraph.service +{% if sonic_asic_platform == 'mellanox' %} +After=syncd.service +{% endif %} Before=ntp-config.service [Service] diff --git a/files/scripts/syncd.sh b/files/scripts/syncd.sh index 0c3be805e7d6..2b7c76263d8a 100755 --- a/files/scripts/syncd.sh +++ b/files/scripts/syncd.sh @@ -104,11 +104,9 @@ start() { if [[ x"$WARM_BOOT" != x"true" ]]; then if [[ x"$(/bin/systemctl is-active pmon)" == x"active" ]]; then /bin/systemctl stop pmon - /usr/bin/hw-management.sh chipdown - /bin/systemctl restart pmon - else - /usr/bin/hw-management.sh chipdown + debug "pmon is active while syncd starting, stop it first" fi + /usr/bin/hw-management.sh chipdown fi if [[ x"$BOOT_TYPE" == x"fast" ]]; then @@ -134,6 +132,11 @@ start() { } wait() { + if [[ x"$sonic_asic_platform" == x"mellanox" ]]; then + debug "Starting pmon service..." + /bin/systemctl start pmon + debug "Started pmon service" + fi /usr/bin/${SERVICE}.sh wait } @@ -150,6 +153,12 @@ stop() { TYPE=cold fi + if [[ x$sonic_asic_platform == x"mellanox" ]] && [[ x$TYPE == x"cold" ]]; then + debug "Stopping pmon service ahead of syncd..." + /bin/systemctl stop pmon + debug "Stopped pmon service" + fi + if [[ x$sonic_asic_platform != x"mellanox" ]] || [[ x$TYPE != x"cold" ]]; then debug "${TYPE} shutdown syncd process ..." /usr/bin/docker exec -i syncd /usr/bin/syncd_request_shutdown --${TYPE} From 00ab25d4e346fb2f409d2d93d5d784e69eb3acd9 Mon Sep 17 00:00:00 2001 From: Aravind Mani <53524901+aravindmani-1@users.noreply.github.com> Date: Fri, 27 Sep 2019 13:50:07 +0530 Subject: [PATCH 024/278] [devices]: DellEMC-Z9264f: 10G_Port_addition (#3475) Added 10G ports for all the HWSKU(100G/40G/50G) --- .../DellEMC-Z9264f-C64/port_config.ini | 4 +++- .../DellEMC-Z9264f-C8D112/port_config.ini | 2 ++ .../th2-z9264f-8x100G-112x50G.config.bcm | 8 ++++++-- .../DellEMC-Z9264f-Q64/port_config.ini | 2 ++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-C64/port_config.ini b/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-C64/port_config.ini index 1dc88972d530..2bd5931d7866 100644 --- a/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-C64/port_config.ini +++ b/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-C64/port_config.ini @@ -62,4 +62,6 @@ Ethernet236 173,174,175,176 hundredGigE1/60 60 100000 Ethernet240 185,186,187,188 hundredGigE1/61 61 100000 Ethernet244 189,190,191,192 hundredGigE1/62 62 100000 Ethernet248 201,202,203,204 hundredGigE1/63 63 100000 -Ethernet252 205,206,207,208 hundredGigE1/64 64 100000 +Ethernet252 205,206,207,208 hundredGigE1/64 64 100000 +Ethernet256 257 tenGigE1/65 65 10000 +Ethernet257 259 tenGigE1/66 66 10000 diff --git a/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-C8D112/port_config.ini b/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-C8D112/port_config.ini index 5a2051c9d8dd..27c3906a9a49 100644 --- a/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-C8D112/port_config.ini +++ b/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-C8D112/port_config.ini @@ -119,3 +119,5 @@ Ethernet248 201,202 fiftyGigE1/63/1 63 50000 Ethernet250 203,204 fiftyGigE1/63/2 63 50000 Ethernet252 205,206 fiftyGigE1/64/1 64 50000 Ethernet254 207,208 fiftyGigE1/64/2 64 50000 +Ethernet256 257 tenGigE1/65 65 10000 +Ethernet257 259 tenGigE1/66 66 10000 diff --git a/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-C8D112/th2-z9264f-8x100G-112x50G.config.bcm b/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-C8D112/th2-z9264f-8x100G-112x50G.config.bcm index 2329ecc6baee..f4b3addfb516 100644 --- a/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-C8D112/th2-z9264f-8x100G-112x50G.config.bcm +++ b/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-C8D112/th2-z9264f-8x100G-112x50G.config.bcm @@ -73,6 +73,10 @@ dport_map_port_92=49 dport_map_port_93=50 dport_map_port_90=51 dport_map_port_91=52 +dport_map_port_104=53 +dport_map_port_105=54 +dport_map_port_102=55 +dport_map_port_103=56 dport_map_port_29=57 dport_map_port_30=58 dport_map_port_27=59 @@ -1107,8 +1111,8 @@ phy_chain_rx_lane_map_physical{253.0}=0x2013 physical_ports=64 logical_ports=136 uplink_ports=2 -dport_map_port_66=65 -dport_map_port_100=66 +dport_map_port_66=121 +dport_map_port_100=122 module_64ports=1 mmu_init_config="MSFT-TH-Tier0" diff --git a/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-Q64/port_config.ini b/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-Q64/port_config.ini index 646d91492beb..13c0d6600020 100644 --- a/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-Q64/port_config.ini +++ b/device/dell/x86_64-dellemc_z9264f_c3538-r0/DellEMC-Z9264f-Q64/port_config.ini @@ -63,3 +63,5 @@ Ethernet240 185,186,187,188 fortyGigE1/61 61 40000 Ethernet244 189,190,191,192 fortyGigE1/62 62 40000 Ethernet248 201,202,203,204 fortyGigE1/63 63 40000 Ethernet252 205,206,207,208 fortyGigE1/64 64 40000 +Ethernet256 257 tenGigE1/65 65 10000 +Ethernet257 259 tenGigE1/66 66 10000 From d3d04dcc58a7744e18adfa41bc8a22387540c35c Mon Sep 17 00:00:00 2001 From: Andriy Kokhan <43479230+akokhan@users.noreply.github.com> Date: Fri, 27 Sep 2019 11:23:07 +0300 Subject: [PATCH 025/278] [bfn] Add missing port 65 for Mavericks board (#3461) Signed-off-by: Andriy Kokhan --- .../x86_64-accton_wedge100bf_65x-r0/mavericks/port_config.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/device/barefoot/x86_64-accton_wedge100bf_65x-r0/mavericks/port_config.ini b/device/barefoot/x86_64-accton_wedge100bf_65x-r0/mavericks/port_config.ini index 7a3b600fe8de..def494da0081 100644 --- a/device/barefoot/x86_64-accton_wedge100bf_65x-r0/mavericks/port_config.ini +++ b/device/barefoot/x86_64-accton_wedge100bf_65x-r0/mavericks/port_config.ini @@ -62,4 +62,5 @@ Ethernet236 236,237,238,239 Ethernet236 60 100000 0 rs Ethernet240 240,241,242,243 Ethernet240 61 100000 0 rs Ethernet244 244,245,246,247 Ethernet244 62 100000 0 rs Ethernet248 248,249,250,251 Ethernet248 63 100000 0 rs -Ethernet252 252,253,254,255 Etherner252 64 100000 0 rs +Ethernet252 252,253,254,255 Ethernet252 64 100000 0 rs +Ethernet256 256,257,258,259 Ethernet256 65 100000 0 none From 500c20f3cd24b5777ad5afe85dc4cbd56d422f2a Mon Sep 17 00:00:00 2001 From: hans-tseng Date: Fri, 27 Sep 2019 16:26:09 +0800 Subject: [PATCH 026/278] [devics]: update the installer.conf and config.bcm for delta devices (#3482) 1. add the console port in install.conf 2. update the ag9032v2a configuration file 3. add the default_sku in ag9032v2a Signed-off-by: hans-tseng --- .../x86_64-delta_ag5648-r0/installer.conf | 1 + .../x86_64-delta_ag9032v1-r0/installer.conf | 1 + .../Delta-ag9032v2a/port_config.ini | 68 +++++++++---------- .../td3-ag9032v2a-32x100G+1x10G.config.bcm | 1 - .../x86_64-delta_ag9032v2a-r0/default_sku | 1 + .../x86_64-delta_ag9032v2a-r0/installer.conf | 1 + .../x86_64-delta_ag9064-r0/installer.conf | 1 + 7 files changed, 39 insertions(+), 35 deletions(-) create mode 100644 device/delta/x86_64-delta_ag9032v2a-r0/default_sku diff --git a/device/delta/x86_64-delta_ag5648-r0/installer.conf b/device/delta/x86_64-delta_ag5648-r0/installer.conf index fa2af8b7a007..85ed43ab48ed 100644 --- a/device/delta/x86_64-delta_ag5648-r0/installer.conf +++ b/device/delta/x86_64-delta_ag5648-r0/installer.conf @@ -1,2 +1,3 @@ CONSOLE_PORT=0x3f8 CONSOLE_SPEED=115200 +CONSOLE_DEV=0 diff --git a/device/delta/x86_64-delta_ag9032v1-r0/installer.conf b/device/delta/x86_64-delta_ag9032v1-r0/installer.conf index fa2af8b7a007..85ed43ab48ed 100644 --- a/device/delta/x86_64-delta_ag9032v1-r0/installer.conf +++ b/device/delta/x86_64-delta_ag9032v1-r0/installer.conf @@ -1,2 +1,3 @@ CONSOLE_PORT=0x3f8 CONSOLE_SPEED=115200 +CONSOLE_DEV=0 diff --git a/device/delta/x86_64-delta_ag9032v2a-r0/Delta-ag9032v2a/port_config.ini b/device/delta/x86_64-delta_ag9032v2a-r0/Delta-ag9032v2a/port_config.ini index ea064a708a3a..d7b858054ff9 100644 --- a/device/delta/x86_64-delta_ag9032v2a-r0/Delta-ag9032v2a/port_config.ini +++ b/device/delta/x86_64-delta_ag9032v2a-r0/Delta-ag9032v2a/port_config.ini @@ -1,34 +1,34 @@ -# name lanes alias -Ethernet0 41,42,43,44 hundredGigE1/1 -Ethernet4 45,46,47,48 hundredGigE1/2 -Ethernet8 49,50,51,52 hundredGigE1/3 -Ethernet12 37,38,39,40 hundredGigE1/4 -Ethernet16 33,34,35,36 hundredGigE1/5 -Ethernet20 53,54,55,56 hundredGigE1/6 -Ethernet24 57,58,59,60 hundredGigE1/7 -Ethernet28 61,62,63,64 hundredGigE1/8 -Ethernet32 65,66,67,68 hundredGigE1/9 -Ethernet36 69,70,71,72 hundredGigE1/10 -Ethernet40 73,74,75,76 hundredGigE1/11 -Ethernet44 77,78,79,80 hundredGigE1/12 -Ethernet48 81,82,83,84 hundredGigE1/13 -Ethernet52 85,86,87,88 hundredGigE1/14 -Ethernet56 89,90,91,92 hundredGigE1/15 -Ethernet60 93,94,95,96 hundredGigE1/16 -Ethernet64 97,98,99,100 hundredGigE1/17 -Ethernet68 101,102,103,104 hundredGigE1/18 -Ethernet72 105,106,107,108 hundredGigE1/19 -Ethernet76 109,110,111,112 hundredGigE1/20 -Ethernet80 121,122,123,124 hundredGigE1/21 -Ethernet84 113,114,115,116 hundredGigE1/22 -Ethernet88 1,2,3,4 hundredGigE1/23 -Ethernet92 117,118,119,120 hundredGigE1/24 -Ethernet96 5,6,7,8 hundredGigE1/25 -Ethernet100 125,126,127,128 hundredGigE1/26 -Ethernet104 29,30,31,32 hundredGigE1/27 -Ethernet108 9,10,11,12 hundredGigE1/28 -Ethernet112 13,14,15,16 hundredGigE1/29 -Ethernet116 25,26,27,28 hundredGigE1/30 -Ethernet120 17,18,19,20 hundredGigE1/31 -Ethernet124 21,22,23,24 hundredGigE1/32 -Ethernet128 129 hundredGigE1/33 +# name lanes alias index speed +Ethernet0 1,2,3,4 hundredGigE1/1 1 100000 +Ethernet4 5,6,7,8 hundredGigE1/2 2 100000 +Ethernet8 9,10,11,12 hundredGigE1/3 3 100000 +Ethernet12 13,14,15,16 hundredGigE1/4 4 100000 +Ethernet16 17,18,19,20 hundredGigE1/5 5 100000 +Ethernet20 21,22,23,24 hundredGigE1/6 6 100000 +Ethernet24 25,26,27,28 hundredGigE1/7 7 100000 +Ethernet28 29,30,31,32 hundredGigE1/8 8 100000 +Ethernet32 33,34,35,36 hundredGigE1/9 9 100000 +Ethernet36 37,38,39,40 hundredGigE1/10 10 100000 +Ethernet40 41,42,43,44 hundredGigE1/11 11 100000 +Ethernet44 45,46,47,48 hundredGigE1/12 12 100000 +Ethernet48 49,50,51,52 hundredGigE1/13 13 100000 +Ethernet52 53,54,55,56 hundredGigE1/14 14 100000 +Ethernet56 57,58,59,60 hundredGigE1/15 15 100000 +Ethernet60 61,62,63,64 hundredGigE1/16 16 100000 +Ethernet64 65,66,67,68 hundredGigE1/17 17 100000 +Ethernet68 69,70,71,72 hundredGigE1/18 18 100000 +Ethernet72 73,74,75,76 hundredGigE1/19 19 100000 +Ethernet76 77,78,79,80 hundredGigE1/20 20 100000 +Ethernet80 81,82,83,84 hundredGigE1/21 21 100000 +Ethernet84 85,86,87,88 hundredGigE1/22 22 100000 +Ethernet88 89,90,91,92 hundredGigE1/23 23 100000 +Ethernet92 93,94,95,96 hundredGigE1/24 24 100000 +Ethernet96 97,98,99,100 hundredGigE1/25 25 100000 +Ethernet100 101,102,103,104 hundredGigE1/26 26 100000 +Ethernet104 105,106,107,108 hundredGigE1/27 27 100000 +Ethernet108 109,110,111,112 hundredGigE1/28 28 100000 +Ethernet112 113,114,115,116 hundredGigE1/29 29 100000 +Ethernet116 117,118,119,120 hundredGigE1/30 30 100000 +Ethernet120 121,122,123,124 hundredGigE1/31 31 100000 +Ethernet124 125,126,127,128 hundredGigE1/32 32 100000 +Ethernet128 129 tenGigE1/33 33 10000 diff --git a/device/delta/x86_64-delta_ag9032v2a-r0/Delta-ag9032v2a/td3-ag9032v2a-32x100G+1x10G.config.bcm b/device/delta/x86_64-delta_ag9032v2a-r0/Delta-ag9032v2a/td3-ag9032v2a-32x100G+1x10G.config.bcm index f15efb4e2a10..4c6ceb075bf4 100755 --- a/device/delta/x86_64-delta_ag9032v2a-r0/Delta-ag9032v2a/td3-ag9032v2a-32x100G+1x10G.config.bcm +++ b/device/delta/x86_64-delta_ag9032v2a-r0/Delta-ag9032v2a/td3-ag9032v2a-32x100G+1x10G.config.bcm @@ -350,7 +350,6 @@ phy_chain_tx_polarity_flip_physical{97.0}=0x1 phy_chain_tx_polarity_flip_physical{98.0}=0x1 phy_chain_tx_polarity_flip_physical{99.0}=0x0 portmap_66.0=129:10:m -portmap_130.0=128:10:m portmap_103=101:100 portmap_107=105:100 portmap_111=109:100 diff --git a/device/delta/x86_64-delta_ag9032v2a-r0/default_sku b/device/delta/x86_64-delta_ag9032v2a-r0/default_sku new file mode 100644 index 000000000000..2e67043ab05a --- /dev/null +++ b/device/delta/x86_64-delta_ag9032v2a-r0/default_sku @@ -0,0 +1 @@ +Delta-ag9032v2a t1 diff --git a/device/delta/x86_64-delta_ag9032v2a-r0/installer.conf b/device/delta/x86_64-delta_ag9032v2a-r0/installer.conf index fa2af8b7a007..85ed43ab48ed 100644 --- a/device/delta/x86_64-delta_ag9032v2a-r0/installer.conf +++ b/device/delta/x86_64-delta_ag9032v2a-r0/installer.conf @@ -1,2 +1,3 @@ CONSOLE_PORT=0x3f8 CONSOLE_SPEED=115200 +CONSOLE_DEV=0 diff --git a/device/delta/x86_64-delta_ag9064-r0/installer.conf b/device/delta/x86_64-delta_ag9064-r0/installer.conf index fa2af8b7a007..85ed43ab48ed 100644 --- a/device/delta/x86_64-delta_ag9064-r0/installer.conf +++ b/device/delta/x86_64-delta_ag9064-r0/installer.conf @@ -1,2 +1,3 @@ CONSOLE_PORT=0x3f8 CONSOLE_SPEED=115200 +CONSOLE_DEV=0 From 59febed528782d14d40528e0b5e8bd9238f44cfc Mon Sep 17 00:00:00 2001 From: wangshengjun Date: Sat, 28 Sep 2019 03:43:44 +0800 Subject: [PATCH 027/278] [docker-fpm-frr]:filter out the file of 'Dockerfile.j2' from the 'docker-fpm-frr' image. (#3507) Signed-off-by: wangshengjun --- dockers/docker-fpm-frr/.dockerignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 dockers/docker-fpm-frr/.dockerignore diff --git a/dockers/docker-fpm-frr/.dockerignore b/dockers/docker-fpm-frr/.dockerignore new file mode 100644 index 000000000000..bd5eecc5d798 --- /dev/null +++ b/dockers/docker-fpm-frr/.dockerignore @@ -0,0 +1 @@ +Dockerfile.j2 From ecdd8667134f586750a7d7edc44cecd9bccaacbf Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Sat, 28 Sep 2019 02:44:16 +0700 Subject: [PATCH 028/278] [device/celestica]: Update Component APIs (#3510) * [platform/cel]: add bios upgrade tool * [device/celestica]: update Seastone/E1031 component api to support BIOS upgrade * [device/celestica]: add error handler for eeprom api * [device/celestica]: add component description --- .../sonic_platform/chassis.py | 40 +++--------------- .../sonic_platform/component.py | 35 +++++++++++---- .../sonic_platform/eeprom.py | 10 ++--- .../sonic_platform/chassis.py | 39 +++-------------- .../sonic_platform/component.py | 34 +++++++++++---- .../sonic_platform/eeprom.py | 10 ++--- .../debian/platform-modules-dx010.install | 1 + .../platform-modules-haliburton.install | 1 + .../tools/afulnx_64 | Bin 0 -> 828912 bytes 9 files changed, 74 insertions(+), 96 deletions(-) create mode 100755 platform/broadcom/sonic-platform-modules-cel/tools/afulnx_64 diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py index 633af66dbaa8..291ece986222 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py @@ -31,10 +31,10 @@ NUM_PSU = 2 NUM_THERMAL = 7 NUM_SFP = 52 +NUM_COMPONENT = 3 RESET_REGISTER = "0x112" HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/previous-reboot-cause.txt" PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/previous-reboot-cause.txt" -COMPONENT_NAME_LIST = ["SMC_CPLD", "MMC_CPLD", "BIOS"] HOST_CHK_CMD = "docker > /dev/null 2>&1" @@ -56,10 +56,13 @@ def __init__(self): for index in range(0, NUM_SFP): sfp = Sfp(index) self._sfp_list.append(sfp) + for index in range(0, NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) ChassisBase.__init__(self) self._reboot_cause_path = HOST_REBOOT_CAUSE_PATH if self.__is_host( ) else PMON_REBOOT_CAUSE_PATH - self._component_name_list = COMPONENT_NAME_LIST + self._watchdog = Watchdog() self._eeprom = Tlv() @@ -102,36 +105,6 @@ def get_system_eeprom_info(self): """ return self._eeprom.get_eeprom() - def get_firmware_version(self, component_name): - """ - Retrieves platform-specific hardware/firmware versions for chassis - componenets such as BIOS, CPLD, FPGA, etc. - Args: - type: A string, component name - - Returns: - A string containing platform-specific component versions - """ - self.component = Component(component_name) - if component_name not in self._component_name_list: - return None - return self.component.get_firmware_version() - - def install_component_firmware(self, component_name, image_path): - """ - Install firmware to module - Args: - type: A string, component name. - image_path: A string, path to firmware image. - - Returns: - A boolean, True if install successfully, False if not - """ - self.component = Component(component_name) - if component_name not in self._component_name_list: - return False - return self.component.upgrade_firmware(image_path) - def get_reboot_cause(self): """ Retrieves the cause of the previous reboot @@ -143,10 +116,9 @@ def get_reboot_cause(self): is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ - self.component = Component("SMC_CPLD") description = 'None' reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER - hw_reboot_cause = self.component.get_register_value(RESET_REGISTER) + hw_reboot_cause = self._component_list[0].get_register_value(RESET_REGISTER) sw_reboot_cause = self.__read_txt_file( self._reboot_cause_path) or "Unknown" diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/component.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/component.py index b80deabb178d..ad6810b14c38 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/component.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/component.py @@ -15,7 +15,7 @@ import subprocess try: - from sonic_platform_base.device_base import DeviceBase + from sonic_platform_base.component_base import ComponentBase except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -24,16 +24,20 @@ CONFIG_DB_PATH = "/etc/sonic/config_db.json" SMC_CPLD_PATH = "/sys/devices/platform/e1031.smc/version" GETREG_PATH = "/sys/devices/platform/e1031.smc/getreg" +COMPONENT_NAME_LIST = ["SMC_CPLD", "MMC_CPLD", "BIOS"] +COMPONENT_DES_LIST = ["System Management Controller", + "Module Management CPLD", "Basic Input/Output System"] -class Component(DeviceBase): +class Component(ComponentBase): """Platform-specific Component class""" DEVICE_TYPE = "component" - def __init__(self, component_name): - DeviceBase.__init__(self) - self.name = component_name.upper() + def __init__(self, component_index): + ComponentBase.__init__(self) + self.index = component_index + self.name = self.get_name() def __run_command(self, command): # Run bash command and print output to stdout @@ -86,6 +90,22 @@ def __get_cpld_version(self): cpld_version["MMC_CPLD"] = mmc_cpld_version return cpld_version + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_NAME_LIST[self.index] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_DES_LIST[self.index] + def get_firmware_version(self): """ Retrieves the firmware version of module @@ -102,7 +122,7 @@ def get_firmware_version(self): return fw_version - def upgrade_firmware(self, image_path): + def install_firmware(self, image_path): """ Install firmware to module Args: @@ -121,7 +141,6 @@ def upgrade_firmware(self, image_path): shutil.copy(image_path, new_image_path) install_command = "ispvm %s" % new_image_path elif self.name == "BIOS": - print("Not supported") - return False + install_command = "afulnx_64 %s /p /b /n /x /r" % image_path return self.__run_command(install_command) diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/eeprom.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/eeprom.py index b6881620612d..20f3db111f66 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/eeprom.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/eeprom.py @@ -57,17 +57,15 @@ def __parse_output(self, decode_output): def _load_eeprom(self): original_stdout = sys.stdout sys.stdout = StringIO() - err = self.read_eeprom_db() - if err: - # Failed to read EEPROM information from database. Read from cache file - pass - else: + try: + self.read_eeprom_db() + except: decode_output = sys.stdout.getvalue() sys.stdout = original_stdout return self.__parse_output(decode_output) status = self.check_status() - if status <> 'ok': + if 'ok' not in status: return False if not os.path.exists(CACHE_ROOT): diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py index 7e597b7d08e7..768a15ce22ef 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py @@ -31,12 +31,12 @@ NUM_PSU = 2 NUM_THERMAL = 5 NUM_SFP = 32 +NUM_COMPONENT = 5 RESET_REGISTER = "0x103" HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" REBOOT_CAUSE_FILE = "reboot-cause.txt" PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" -COMPONENT_NAME_LIST = ["CPLD1", "CPLD2", "CPLD3", "CPLD4", "BIOS"] HOST_CHK_CMD = "docker > /dev/null 2>&1" @@ -58,9 +58,11 @@ def __init__(self): for index in range(0, NUM_SFP): sfp = Sfp(index) self._sfp_list.append(sfp) + for index in range(0, NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) ChassisBase.__init__(self) - self._component_name_list = COMPONENT_NAME_LIST self._watchdog = Watchdog() self._eeprom = Tlv() @@ -103,36 +105,6 @@ def get_system_eeprom_info(self): """ return self._eeprom.get_eeprom() - def get_firmware_version(self, component_name): - """ - Retrieves platform-specific hardware/firmware versions for chassis - componenets such as BIOS, CPLD, FPGA, etc. - Args: - type: A string, component name - - Returns: - A string containing platform-specific component versions - """ - self.component = Component(component_name) - if component_name not in self._component_name_list: - return None - return self.component.get_firmware_version() - - def install_component_firmware(self, component_name, image_path): - """ - Install firmware to module - Args: - type: A string, component name. - image_path: A string, path to firmware image. - - Returns: - A boolean, True if install successfully, False if not - """ - self.component = Component(component_name) - if component_name not in self._component_name_list: - return False - return self.component.upgrade_firmware(image_path) - def get_reboot_cause(self): """ Retrieves the cause of the previous reboot @@ -144,7 +116,6 @@ def get_reboot_cause(self): is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ - self.component = Component("CPLD1") description = 'None' reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER @@ -153,7 +124,7 @@ def get_reboot_cause(self): prev_reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE) if self.__is_host( ) else PMON_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE - hw_reboot_cause = self.component.get_register_value(RESET_REGISTER) + hw_reboot_cause = self._component_list[0].get_register_value(RESET_REGISTER) sw_reboot_cause = self.__read_txt_file( reboot_cause_path) or "Unknown" diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py index d78adf738920..67c7a9c46341 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py @@ -15,7 +15,7 @@ import subprocess try: - from sonic_platform_base.device_base import DeviceBase + from sonic_platform_base.component_base import ComponentBase except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -28,16 +28,19 @@ } GETREG_PATH = "/sys/devices/platform/dx010_cpld/getreg" BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_NAME_LIST = ["CPLD1", "CPLD2", "CPLD3", "CPLD4", "BIOS"] +COMPONENT_DES_LIST = ["CPLD1", "CPLD2", "CPLD3", "CPLD4", "Basic Input/Output System"] -class Component(DeviceBase): +class Component(ComponentBase): """Platform-specific Component class""" DEVICE_TYPE = "component" - def __init__(self, component_name): - DeviceBase.__init__(self) - self.name = component_name.upper() + def __init__(self, component_index): + ComponentBase.__init__(self) + self.index = component_index + self.name = self.get_name() def __run_command(self, command): # Run bash command and print output to stdout @@ -88,6 +91,22 @@ def __get_cpld_version(self): cpld_version[cpld_name] = 'None' return cpld_version + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_NAME_LIST[self.index] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_DES_LIST[self.index] + def get_firmware_version(self): """ Retrieves the firmware version of module @@ -104,7 +123,7 @@ def get_firmware_version(self): return fw_version - def upgrade_firmware(self, image_path): + def install_firmware(self, image_path): """ Install firmware to module Args: @@ -123,7 +142,6 @@ def upgrade_firmware(self, image_path): shutil.copy(image_path, new_image_path) install_command = "ispvm %s" % new_image_path elif self.name == "BIOS": - print("Not supported") - return False + install_command = "afulnx_64 %s /p /b /n /x /r" % image_path return self.__run_command(install_command) diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/eeprom.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/eeprom.py index 1e10848ca439..dffda1a3c050 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/eeprom.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/eeprom.py @@ -57,17 +57,15 @@ def __parse_output(self, decode_output): def _load_eeprom(self): original_stdout = sys.stdout sys.stdout = StringIO() - err = self.read_eeprom_db() - if err: - # Failed to read EEPROM information from database. Read from cache file - pass - else: + try: + self.read_eeprom_db() + except: decode_output = sys.stdout.getvalue() sys.stdout = original_stdout return self.__parse_output(decode_output) status = self.check_status() - if status <> 'ok': + if 'ok' not in status: return False if not os.path.exists(CACHE_ROOT): diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install index 8570fa1eae84..2ab53302a9bf 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install @@ -3,3 +3,4 @@ dx010/cfg/dx010-modules.conf etc/modules-load.d dx010/systemd/platform-modules-dx010.service lib/systemd/system dx010/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_seastone-r0 services/platform_api/platform_api_mgnt.sh usr/local/bin +tools/afulnx_64 usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install index df78b7a34ea4..d50306304cd5 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install @@ -5,3 +5,4 @@ services/fancontrol/fancontrol.service lib/systemd/system services/fancontrol/fancontrol usr/local/bin haliburton/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_e1031-r0 services/platform_api/platform_api_mgnt.sh usr/local/bin +tools/afulnx_64 usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/afulnx_64 b/platform/broadcom/sonic-platform-modules-cel/tools/afulnx_64 new file mode 100755 index 0000000000000000000000000000000000000000..c32823393c0805484f1a5ef37375c0ca3384a72b GIT binary patch literal 828912 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

85zk~l~w4ssI#lf-PD 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çn`XBg*0RLeY{vQOtWO(?k)<%(X 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⪙C(Fd| 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

d`dw-^gY`%Y` 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%0AqB9aPU%OA*1um4>=htBCnItu`JHf11$5$ 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

HS%YvalAm+7;bTFJ_QA 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

H-+dG2meCmu+M{q4BR!KJ2nMlp*?9O1@ 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≤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ℑE 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%0D8a#hmr zFygdufAE;V?GQlj-ZT(kCD~i~3V&2Rt)tvmtb}O~7B)IxHZPOewNK1ptTuQ|G<`v; z@XY$ikChW(d;*ngs96C`PYJz=N{KJ1*`9dcB!4m|ijV8qVuw&PHwN&Wu19XF8U|N zNMJd)Yjn7O>L*4sE$3Z!PC1Tdck?Efc|Gq>PwR`(GXFv$VR6;?<(P6O5xEBI2g@LK z%tf>rW=rDW?#=j{s4+6)FQ@43IC}PAZ1PW{=Uazh-~{=+v;yUA3L0a}Go4DYx%pE3 zr6yhwHLMHuV!S0@prY(-uds4Mw8K3U;h?bA+`T_xUIxKxQ`S~VS$55WyvoEp{txPH z)Vu1vp{rhjxUDCl6e&ALRv_fP8PLO`7Arkpsl)6FtzYzdZ%Y`nv(DD07TWz%XJJXy*gn;~jp z+y^l5@J*Z+8wdtlpUkK48x#%j6aRtB=1#DJ*JjYf%)`8k{Tp5n!FOeRaBv@O2BolO zRUV4e7&-a)fnx?HRXrw$qv1m_F}>C^ccZp;M8DSsX;8#EHBcJ*XlwX->m0 z@h*7*Qab|F&f(q>nv=M493v1dV;>yRvSs|Ku+}3m0do#2Ym0VSMC7Vj6~HId5NMzU z3S0X&)LT(eQIi-p90@gv95JVHLh`CXcyB-+E(B*;cXnFX{FgM7l<*pSuzat$;biDd z{X==MF$9xd#8$ET-m?0;WH;LNWrWRZW&G2{Qx1*T!QJM=bC9Rtje*;XmQt6WTQbs7 z43O&1lV!|+52=0}+ZFmsrgQ{Y2}IRWybH^-@B@KwqfMeF-cdV=%Ez<#Ui&VezNaVR zqJ@BU8P@t@SCh2glp*FD^HG`6wuNF^m})p=NgxUDfrjVsHxj8uepz+wA)4ZkaD0B; z+oCMJiUvgIUR*IQ9=^jd0(?kHt+_2uhxPR!heH}n%|yj+%#jo9fBKR&cf0(n12=BFY1j=`8 zL$KxT1ZT@QygJmLmJUxtY$}pK645{@QhVTo5g3an_|230$;t<*hAeg)bu0*YbC{r6 z@hw~FZ;C7@TH@Fh0m>9Zq?Q%FDMY%_Y3xc9Ve@RUuGGcQXgY^dLhm9a{vztIev9>$ zSRP)Z0ana^vEF!1!6WCFzHhd9t*5o@Zw@YuPIm!At9G~?kvTZ{G~9}X>z*Wak68gP zBd(!ewR6H95N4VHmcS{9_+_c zbOyHhTaBIll{4f1) zMaBYzN6-i(C6A(sqK7%VOouZ1TWQC z@;L$Y#u;#JlszUb`088C@)>j}RNrD`7~A#jPLVEj_-MH>P7Gu~%t&tv%r2wE6fH>S z!%5tIBRVWIM3;sL5B|X)RKAE0(WQc5@nn>(HkXob7}Fj!%APmj@&IJZ&En3;@7%_# z@$&^gfPW`&w+s7XO&ko8K-|qf&v@(IG2qlCaA|w#Gm75vJ|ee(CMq!Iv3DO+njx=+j}Jeq+8#BJFc&}=t{F%j2zR}7|VJ4khyqm zjoF)Z8lBNGDwa_b(J>3~iiM0h(K?P1{~2TEV4*vUL=mZP1iCRv7PyV!+*DL|DeHkR zy>7U8z%fH^Gq{YUKGyfl(7*gkk9Petr`Y_jl>N)76QBM!oTJtLWwh|uo-{hvvEJ4(S>ZbcYQXVxW(VX&&<$cSjRcjJrrbWo~}TZBGc>w6L+YEb6FPL76}yaTHl1Wl$R2g*z&M zzzJrR$J!kOp$TafML0Id9Up8drQKQ+&7vR#TL)1D7XQtmU4acU@TYPGC^zwnz zei%W6s!z>6M*1*W0~k(oz+?Dplx<%b!Y`Jrr+sde{d46qk=VBKUh(_(%6jp;dnFl; zQTE}=<>Ggb`itNZ2hgn4O+@!2C1;bh;k?3vZ3ul=^e@{%sn|=lr`j5E7lKK&JwVq< z{OWgrB~rHCDD%X=#`?7JTI_WOhs?opITm=~TL&LqN#+%~uNWT&ZjUS{3HskxmOhN% zf~LX`3U;M=R9-|P{~6b=#qq)1a2sr50pZ~^uU#7nQpqv?F6QJP$Z1-G^jJ8fqdXig zBX}=+g9Ca?k~i?MjM zb^f;GLIN0#5~9vwmOW1}H>3aNwa=T2S4TpAVi6}JEE5Q5AOeiCwOK?;v|M6fX&MH~ zywI6D=|=ns((x->>9{s*MjAu$F1PU$Fts1lJ$<7Va#zE!gA|ky(e}5 zYGAV?i=qrVK|ge%qihBANe^iS?C&gG0tLMhYmPkFhhAZAHFq(7)*{%Vo?K-5&0L* zBFp7JrB_GO3?;Of{b?%3I@1&vM47(5*!b_E9GIo#mij082yvX|(YNQD*tQ7{CODuj zI4PDtX6T1dho8gRqJLJb{k(zl(bm0@UD~KJd)f1>Ts-T0@)2Pab`pcy+J--)OyoY+ zEKBP5vHtuR&kw4XN|{bhy*i+T+L0#tp&IHwhwJK6tVt_RqEKUz#?iFP?u+Xq;xK3a>Z-n?RZ_r z4_HjG)%|R|T37IcC_%eHmbi!|&cg>V{z}WUI|bfDqN_+-eYp??p!!zzXW+cfSOlMB zJvFI%EH?1bZNTq|iee|Wv2Uf2iroxXYJ=16 z-3zJSm9P^t(75dOACLbq1|Om=^!e22MILQ(*Sxt13>$=0V;04>W4_8h^&fjc$1r)~K`a zWt-P}1i$`o==qd~Ef&4RGO(jjzOWHMT&#q-+d#CVo)fvL_9dDw@|;D(GG4PMIKj}q zfkp4J*0XAg2H8?~*%CgLM#l)l5QeeGtfQR_7h0*23IFXsaLx_GeUm}lGF}GnX`6Ym zo?90}+ar`P&(Al*eAx_n1Yy4sTke(6HB2T5mmCj5=uFXB2;$@8=Qk5q@tsNZi}?QF zKCV{Rm^rohF>5`Hdp7psU|xMM&Z)RWsoMj%jh2M(p-W%Lcbh}eo_j0WO%!3DOK5y1 zMEuu%u>kL}{u`kATa|lnLmKeG$f@dy*4TUj3wgo-d@v3+ebv`Eija|=PGI{&KV-)< zARTOxdnF@2RN5_YHs_kxc!bBdu;btx!A}AJPGa8ZM6tdsHjl+DzCpKd4SwQqbSC_- zBa8%5lCl2+gt*7zt4#e1=%T%d`^@u@cBLQi+q=BbQ!(UyDXf_#yniE9)g#*s ze2cU0#q>NeVglQ;h!`xD{YyXm5kw;1^v;iz&<=LL^Qh*g_jeUu5P#r(={eL}nDi$J zUjm5f2u^3~iouwFCL+^5Z+HPYv1Rbvv@i2si?&K9ZH>__-V~|Lt}!m6!C-oE{mZW4 zmv}5z!lYruAF`9^niAU0nz%)ZYpuOhPo%G~wXG^pOK_nZ9C``Psaf(AOKS~StpY-! zg3V#E5;nmnsMNwV!DIZ4q#u$C$4YoPx@?ysRp=#NCk{j_aR;}Nr0no4;|(l!V{9CO zUN#_DKMWn_*fqx(GmaYY6^!yiCqT@UAZCDq(^}r5BZsWk4(BpUJlMIZclJ?27YNMb zm>4f=ODlvWOA+1i8p`q%j}lk%9*RhDHguwzRqR;obFeU3^%hPKyMD%3<)c0uPtZ95 z@rfvkl*oEcz*FpNpf34r(%4w-gpR>wCGeO8n{}XU4lJgdDPZ08&=I)s4yv zS|AyAKY{}Twj&fdTfdvI>;~=D=5Zc!e#v<#sN>=qyz;}W@oA~KNNo`Fjq#l}f)8bA z1x4lX^l^VigCL{&WVN%jw9@aRkFv3cQjKjRaW&yXYJc5S-%!L4aR4BAjP2(My6HT3 z$$#mc`AUSYE$ppU?$04P;aJzmi%1~@4k2NspeP8izag>XWniBBMC*))7TGCH+er8j)lTLhjhI z6jFG5rm(@XQj(=Bd3pZ{g#Hz~o`7yC19!KfA6Lh)Ukkc?W4?Gje(_!sBa z+su)yD#h&;=CjMIjm9p>Fbdf~k7Fo%2_;wt`fW7FALaZaiwM`Ce9=OP-Lui{6MATX zIM73z?-h1XRL1T^qMVN?X3D+u+BGpM()PT^;8jhqy7jjQPYE9(Sh1#0`rOo&te%TTvHi=WmHCxt~PIG+#}6Ran| zM<^`5KoSsYuYV@d5q<%+`J*-mMhL`lvbws@@x!bGQR4Lb`ZOWk4M-7Zx!sLkrx8U` zNOQlpEu?=%7=&Cyp!Y>d7((wM$N!t0N>P!G=~&Kj{h=$Hu}Hkz{dgIocm7)mRUq?0 z3@Z-O!x33OB_{P25ZZt_$ePv_DXdmOQY878{z;~O2vYJvWCWWzKA?vX<#d z={O4oyT*N1qRQ$GUdBPWMpOwpgMLto=ajrL=VC*T68;yev3s8E_W)#@S)W4J$&xkx z8sLz^{9CvpB)%oQ>NElC`KThTcS-$&$D~UAVWmY7I?#{8FcQ#mix+#&gFM?9f$2@FG^rha`zpoheBnaju zM!PK>jDH8=Z-aJ!)Fht~?A5$TKz~#MFBa}4j0XT%VIn3J?WBHEV-6F!=h}S@GssA0 z--hhQPBXI*+9&R`1rA83r)nGV*yui|(tiAQG{L+I;-Ro3{H8J2tt!|c2W*7*ZwjDF ztXsY!H5&xf_mR@Ga0hVHO9_3B?}6{?WB~aa5)HA}2}c*aVr-I@+jguSD4~BNN3tWY z+1(z8dBuLHML=8fXac~WX%8UGLtJ_f%)N%gmkE6%t}(zbmSC|KHINYKvSTjqeH@F3 zO+#~LuY*mb3MIS=l${)B{0diwSgP2H{w#_8mYHFQtsUv_FKgZ6S7QHw-JhMZKcG-E)9#e96LcVYri6x~!Pxn1 z73~3Qvb_{!IIW=_nd5H+0UrVUFLp~zlqpC6g{VEdIIwR7n0_DQ{MzX^#oU5f z%5NbZP@_<<~#mt^F@F+Q=lhX0RwT-Gz&U(1G|v zRE0ux<>*H;v~#<%+thalzg&UwEW<;L(crZe>!3zf)n?Mn2~=36w0z!F`_t70=cp& z*p)CPtu+UjH?WsNbLePRd9X>n+FY1#j)B+%HAgZBZWa}-i zG+&7xcNwjEr$c!V4I^s4^L?$XaEBgqCIOKHqc`<9MO7~WKJF<$zCK{>xQkuIG*4CidO88Y9sVxe^m1Uv4}C`NpNOK zzI8@EXzNYuX3%HsE0R1kHN7%h;B^appN@DptgrW^3YUuyc@F(Iz6=D?p9_BkqC*SK z5+Aq*&i!ri38?jjKM;B7aI&LL0kO^X<35RU>g=EnURjK-oLV0%IDllz?JuRRVtQLk zU>3r<+KXGWI3N#o)oEn|53!E{GAq;Cpb73iDbMp9&-VBWr}*>`i}yljPf<0^?buWN zc5;=|SgxEy#6eCQ2(|wyYPuaYCCBFHJjrUIr)XjJ9o^@jUR2_p=SfF&I&N{yLJGT= z+1S1KKgO;&T|=m={ZG+>#{g0|q5T{rrZ3Dpah$~XZ9?~!$iWihGs&ZWHk2DMa?RY} zXZUz!jbE6~T6gOsj9EO(YK42vxYTD&Uz13DpY*lzx4v>BeUn{?>aT>iW8fnQ;v9ox zc-%!}vga$xJv0@IuJI^KxjLwq;7I>UuS3stR#(|j;@q#wJae=?71g0>)RiTn=A_)h zKQG~rYiD5E^pQ?%^O{>w*m%>FmW`~qDeGGYrV#Fg}I!Iir$ZSw#T0q{ilBj{02%1 zW)3b>I%od1W}aw8fYj0A)VTF7wVyW+!TL^a9YohO> zuK646no+6xGz{2xo4(G{zdEPJ^sEzr?NGBKu0!#s0Z=x?-J9xCnu6|G`BpcqRA7JC zHgAImP%>tUqOZn~1>-xC=tle|eanDszB#Hk+<5mKGZ;b%Zq4!d+thQ6xAf08>qmO3 z=RoIYT_i{h!ylMS!^s60NMYx(ge&!7qaAL&DIeL)tI{{e$-RoL2N~W8dq^&pbd5i^ zp@|85+%7aoSg+jcC8_wt4Ub)$!R7w5jz4$pKNE{T)seleC)Gr!NQQbE z7Ffg}$n%%YoZ$@7NLl9Fao_wa+DQEqr#c+&{&Z*myiKQ!kbN?>ur~)#7)|j%!8KS} z>lli4EbREMw(bNV7#hwB9Du-8r)rD*qOc=MrQLBt_iZt=%_};sET#1(RufCa16C6+ z$3xtZ68*S}1*eS*|e={Of`|6); z)(`bm`|CWZ)TW>JvHhF&aa%kFQsYV+dX;Fe(M35#lLS!QI(i0ptspoXzSSApaJdI+ zfS8c`JeZoIb-GtRJ<65^H2x;G>*4hYeRXLY9st>4eBNQZ!4?)0v?3@4?(XA9dw$ZFaY*=g1=Vb-g@BBZG2X^qv1NVAps>NZn7X44t{DXIFaN+kFTKl&K|*L z>f8{Y;T;PuF+4s}qglm$r2UL9;X#b20jC!^G;vm`dm4E(I;}k_ySXnpNCMwUR2$8~ zSI~YyxEHmH!4SKF#r4&Cr`5^rsM;=j@l|FQd0IGvGwXv0k^_8-{x?*_&Ve{!ZM}=- z>;H=ms&)sBIANP9Le@h z`|UH7?oa37U}RgWPO*!ltqt5)C% zixf78m;6BTYO&FphX5j&0)!XPQXZPVDMXFey#QPy~((zWsk6#j&}XI zWU#9UPqujf9lSm##IKkah-2MS{yT~2@SkW$cPUEq9DZxj@8eHFegeg2={-D@F+2!l z7;&vbb2tsJ0Jl6qc9`RqySQ}f!8aVu?*I7i{V_`Rq<`Ix@EaPN%EDMz>Hvde2TEiI zV38Yj>=f2RP_KUfGW;#3%ltwVh0t;na zc5DU!VZ9d5;Y_1t<7L@ivi;a7*-xRE$GDPGo4+28rirz;)6ukzj;7kNaD|K18)WJN zrcOXA^mS;~gc2~Db}-@$y>o^ViX*X$m`t0P#IIGyvr|Rx)%og0BqQpZ<^v?7lY*en zWR%}F2p0%)m?b(h3B1m&wXXYp60g7P5cL&n`5Z5NdO&{Sc!{t{wYzRELo3CCJH?mV zbZ-N_J%6Hl2jpO$5TTD0wiUD$jq+%F z^*h~%wa;w@JD!E{#g-(P4<48gJ3E@a+V}C?Y>BN!qznVNBbfw!e0e_bp%^}I(Rhgkd^CKvL!K_+LfjXMD{`G zFdRsv!(FK$2l^n5{!^zc-*Oc0{*XMIni>lnMQ1e6gwe}>2qXtD{CLeAqlHgG#x3Q5lx+&5G|L79F(7M$bqsx zYXy8oHBWFa3hufa1cJ{eif~RQJlDRqkvN1ea^Nj;%iLA+=v2=tZekHtt-2RaCxu0Sf_#NLHVr-6&)q;L zN;K=AXtp8~*vonzLtWv*nN1%)4bX8M*&5#(bhOG^bEn;v$b-IL10!nL<}%1baR<(E z0hHJh|LaW-45jcG9e-NYEb#5>bWMFPP**!0^-QpO71_dEd8iSmg05mXQ*axVMB$T< zj7qE`?qka+z~?z^{rZC%RLE0*{b9UGclIzF4-VAoviX z9+9>8&W6vU5Zo!|3@m8ce|i>$WcT! zi0CJQwHRZjPy*GS5WhPb2iT^yv{6TnWc==Su^F!`e)lreB|?LKhT75!C8K0sLs>gC zh(``!-uy`X?#6z|ImHn5Gk$j{a;L(F>OgHLq9hs8b^=~v$1t5`{4NK;jt~13iM6?y zLnp@Xc8maZ2))K=5=ZkU<99hRPm15&gv5>D`;OR3G7V7p3D zz!fp|$o6A*;FAr?`RLeB2PpkW&oj-`sz+W*T zdqnyg-&%EhVK4E3d?h>;^~;zS%p|#3BlJp4rdTm7Xc>pA{S3=9ou{tsa#V&z-5tl9;r<*dSKmE2##AcruSX)0+U;mvMAk24v@T;DYKL>y)uU)yWNpBYSAIAyT6Y#wWwb8OV7H@x5HpK# zUBnKB%aJI}4OJuY1L!ephjv~gu?B3!o*KJdO^oD$&aXwFwFX;%#EXbx!olZ_l6 zh#P1$mtKqj4A?2P#SH-33pB}U_CTSqULB5C@qxSa67>bUa5E&T8ZJ|soH zh-Z^al{j7so17K_NOL)r+RWv1@YndJ1Lx%9IQ9qd0jI5=2{t~KK+nm?!Iu@*i-uq) z{(oyZ6&1LuQ1#tlbp~ndNHv2RCCJ55K<|)eX1#ekt}TW`#g)Kni`V~egiC-EAwHp} zu@_t0A%E}i7~jNqC(9dOW9kc_ps-@8=TSKD?By}(|3YPi<5IwZnkE(OHm~v;uYuv^ zqW-4WdemGpESK$n>~B}}B9I?CvH65f99$+l@wK`VzWzf69~Hdk-+9MFgdIg4u`5x` z?hpKnwYOjxtaAfc(wpa~#AeZ!Cb+SM=zSi|ax zXVU^aD5cHlh*#W=Cj45T!4aNTG)XVQUW`=ifi*g>*OVCNx}X#32Z%cQp+)JX7K(2@ z?eS8gNZ^BuHQ0s;Jjpn26J|TzF7OyW*tn|gSy(OOu$)8u-r$=WDP86=a%cvwT6Va= zE$Ok*WmfzELhY~yKJRj@T#NC5+k8xeBjCb=dc{nAu2>f1P4rAJ8{?X1! z;zMt7C;A1CFr(3JZe?Jh>jLuvdg_(%`=1_H)-H3rObCwZgh?>*z zwu&z!&w&oRB*HR(B8-DjMxZOkqg1Rr5d~uA%m5n9jG>@^Mlj;q$C_2Scz~N_l0!Wm zcU+1?#&5Aq=s%d5)rn!m8Ro8+|66a1E$?1rzX93D+u3JWQ)PC2mE&5;yo}pkiKMV0HYDwCYN63bR$PShR>y7$;Y4G2BCIR+6dU=~6hV5f2%_8=NQU zFkzVU#Ek&xcm*zVfQ!3XS^5pS9Q%U(9=IMVQ`!+kstaQEEg6b~!+|9K>pCBZ=-Wf| z#TEkP-$TQVU4mJE!g^+vv2!9$XhsmDj0Akb$Wh@zg!^g0Z2UIubsN3s;9*rQ{^*}7 zMn9vuX|Ib<{rThxe%j8CRXOx46s-@FaM8`1dNXoj8PeGwgqzLlCNji~1OMlFWXcoZ z{=p+-YHrh3-GYii?ZHF0sWr2)FxZM0tfin*d4)9qmyQDdhMHARFmdZ`HCM@v5Wyp( zG__WFuqAlt*Q2g2<O7;%N1F1cOy;tDTQH+?) zZGqHl0An|jAa%PtzX7pT*fy&?v1$Pli~)458odMjn-jv{gD>Md!-aP!&Ndog-SorV zR27%bsl!Z{4|Fy*{eMj5v8$G&98gkL+@l8ZKlzU&g!-V>NgN z>OHvT1lzubU_QE(ItnPg^I}DRPduEX)Nw1e-g&m7bERMJJW~n5kAw$Y$VB@^V%Zf_ zh?g-d^iC8J`lrCYH&%`GgUt*U!kGgE?Ni*d?pR5B(*^|o>0QOA*diOQOl2uIk;Zla zHGzK)l^<{7$Iffjo91DaX0kd-@0`ZbG%yB9D^x-|U{YGcuj?E?D`}&?tP;kSwctj|vQnnjv%uea#IusfF zOeRPmO%Iqq0x|2u3eGFF2fK0Wx@&wa0!y!1G^^4RiX-ePbiE*=10R|?rT z!pxy4Z2C0I+3at-!xO&{dYFzYCfnu?)Q5N1zBg<0%&}e`Uop)fUW~mb2mfunuRQm1L33ud&&X**A;1CE*JT8Y z(LeAZA^Rq@X1$GXPV4huWH>SrRko7n=feoz&Jt%CQ*f7pw}Bfk&;`1QiIW6e#`$>0 z`ldpc?cnkFo^tO3LwzV~CQ-aE)|_(Pfun>|r^s^ev%vXyj}^9)N3-^PTi`B6DpsTj zh5IOMY`91YqY<_MD*IsAx7b4wQGb! z_sUgk@zPL?4Em>y!RAKbUQZM&qdN_e*%-MR-;=AqbjZm2VvP5V_JZ$HNR06+F6w_t zEXR|A*3K`+@~3+h%_1lSAezNS2~!qMRfC3Q``f=8}QxCRHVP`PpS7V9Yh1y8TvL~!cB(uxrk4j~V)mb)UsP`X zf%V2&d(#mBhqIz^Axf%$iR{PQ@d-=g;vVlQv2*Tpr>sS+pUM0F3OmGl1G@(4!rgo=k3DD)0d$d`2YfgMPm$-;LuFUp;?6u80^J zsc=rZv3i2_B3?O+M|vZr6~QEDpU~H5P4)2~;v16V4`On`h0D>lFQt)sXXHjFK&-UJ zB|!wz5cWB-!n*5Xu>b*)k?LV#N31uxC9pV1obPCAj#vefgnvMuCThOuTS2_wyq>x* zIl}k)p2RzYc@N@M7z7y4-sC-w@1feaaj0+iqOWG&GmRjI%EVgV^C)7yD?15|d}y*5 zZ_%-f*||~L*d5%)=p<LEcOsN-Q0!50>(n^5f~0bVJ=_-Z73ls ziW}XGP30{mx z=M|AOZX`*`zE9zUejx5r-&D~yRtu0H8re7;$npl9f+UR(z;t=6EN+xo0Z5HYUm`LP z5ZDvt+=({@+Nb))nb`tMI8OH5;9=21HZuUi3D!eEF48!rpp8HdsxO}`KGSZ^i7{nWfPqZRjNfCXVvzm0+QTiPdh{9Md$ zSCyRL6Rl0js#8II zVf_LzG2UAc^1b zotP;&;7)iH^kco%i-@aZ7&o(YZMK{~R*`ERMTGh{&4R#jH=t|~=p}NM@ar7e68uTc z4Ibxq98hR)KRo>4OCKx78e|2Z$rY>2*33?k-XiY_6?7Z7{ZUE0XRmvV9I$llSa6!M@janpX`${LVV>I{cWXSKP~DR>G{6? zPW0Uvkj8dm-0Qg+Jk=rWi`X3?-!7F&S>H1R39=oZrK;~XFZvKN8R!Ei1#!B3@pFN` zm2V@l!!^gPT^2YrL|uS8C`D1VSlShVLpLc~zJ=o5y6 zZgs2a@|ok-IZ$pHE>rKxbqbd+v_os91jR>q36^-n9YX33(S8{j?QG2$A|$I@iXX|3 zbm}b_a#*XGD5ZYX>KG#HirosD$992NWfiFklHsOOpOxnaV>=x#q#A+4N{y;*=5S+i zTi{CArc2OaOfOqg`Fp<28&vK#wKbK;l8M>?l#V(`J-Fg009JvcLvNoI_ z9qur?%X2iuBn?*y$c-p^$8+Fnz#{QsqBZ;U35bPB2|0v|A+X0H~xQnLWSj>#!B-Ua@eed9tYVg>o-#zL_Ci-LIR_fS@6ug zXk6PEsT1m7Lff6tKF7hT3GKs#_V$E?wyk=+QPyCURkNz0zD1&nVVVKR(Xqi48(znN@q>xD9a$0W?tze4102`oM=ndu0DAt$V#dZR0?64*Mz7 z4tT{upuYp7LJdH}1W=`Qb1J7Y#Ey{J-^3g zYGV`HHwKn)AdfINPDuX_G+@+YM%P2QXE;0=3t!y>Otr z!rG8$534!Gtw9mv!h*xB$kh)YRqC>6hBZ5lirm;?vRXM$VK;VKH-Ux3J|w3+j-P9v zTV-DhMipC&j{;8A9DfGc%qpDlYAuDQ5g>)1Vn55Mf+dDp<10BP_Kf&>q^b=Wr`Z_; z%(%EMTDFba=@v@v*prmgX$i6&oKMX89=i`;+1?mbs9qMCpN&0?XJCD-{0DKeHg=G< zy6}RKaC|=l+nTVZ@F{wA?KW!}DBiqwTl}rU9reZ-ues=c+-j+W1`~$)?pOzEPMgo} zSwj-Pv~D;{pfIrD*pLXW?Syc&`Pp7);I70F?I2i8K^yFmYdm7^8Qo%B&%{6&RgGBJ z(;7}mtJY%zDUwjDfU(JF9D?cz2rtoJ&ekxmISwpwV%~B)1gAj;XX_jZ6A^t2(qj{n z*}?}y?@zsVGll~ZL?8OX=lms3f%;7_hS~sv>OIK{|9&n)A{bWOH&VouM zC{)J#>$7s5+U5FPo(%N@6FNSoWzl%I>P_Oqyvl=jt<&C@867270FAcTXH@LxAzZgh zcJWCHtvvlucV+1c3_Zkx@%rZe-mHAHr`pG8*^=MAM}F`?&gq%?=x6E2{#Ug{<}6py z;BawMzWa_j5zjMh!TJHR^Yr-N)7~#qmfj8t5Pw|qlf!+Kr8n_C zV!z*}EWIA@vAggG_QBySW$BfCpJl(pPd|k3lf^rZf*7J79;4I^W?Db|k<_sokqY!v znyzl_XRI%tjqT#L)>;)KRU1K~qe(tiATyYp=cbT5I>vrV^`n$y4MJ`B+rl@%c-c5|gS>tA1;m zr&cwV%AH77#Y3KEwM-5P8hPc)pyJcWfm#*wh^e`XRi&cVKKKJEtjiBdmoo^;itJx{{uVb9$Si$x?cmYU^rsnq_2@D$cWsm-W+M0Qj0 zG1+;t$NI;C{H+{w$P!%1gE_X=sQZ~Nst?E#YAzR;EUkp)v(`RKoh346^s0G-ajLXW za-XY`t0iNl{n=S*J{>b17He8fNgkm$4SLYvMnSzoi#@@1!fmnq5M#q1x&WIO)$SxOvwMG_ z-~llAL&K^FD{+(Sx6U$>yp#V2>`QAfF2*E}z$hDg@E4X+K5nFt_wnhT47JN2*zyfY z6SZsVJ{wzT^ine>mz&Hu$6Q{{ubr%T!IsstBd7tOtx3%&h~=@ zre9u3x^TO-T7KKxDpmX>w%>}R3;TVd;h5^$xUBd z3OONhMu90;k7C88RaKmFbblm1#ve?a+Jj!2{lW#Bf^w95$hzwoE@GSfO?yQTY_93W z5lGT1F(2$zK%ynutB4=%=bB!^;KPk^^#ZGz^~2MHGcv2q)q;*n`@-)tUNU&lO^aes z3&jL)W^5>bEv2UTXs#(R6+$y6u}ZDg@=@gN5saXp2d$rEaJBgdrslPlORHjy zF{rCO&g6GAeGsssS4lgJW)FbdcbeLXl{4v_8IxglG2n0Es*kmUc}@(Mbt_%T>wFy* zEQ$IKyFOq6I*&vR>1Ksr}49Jl_5} z!3=Irt`?Zh7CXul`#ia4Jk!6^Tq`4wbHh0<5xd)+dAjOURYyKJFv&b_H=#mwXC>OQ zdlKu3?(lqmCsk__+YRV`p{ug~F>H@{a6B`R@?W$RP;UYPqf_Wzy_sI=K z9BSmsM%kVGYGAWk21#TH?wzpH{<}+jVE1}CU#zmsct#mqC!VwP_ThOm(}(ABdC=JP z)|Bk@DOn{ujj=mR_89j_aPGp!VZEfyg{K(zj^cTkHf`K9jP#cX!qQR2GHsxA{)wmg z~lm-0{&dz#NiET{!;)dEue zW&O*wfDDTiupwzHzDB>->-R_X`$PP-6b{MNEV)()TRDG)lFGh7{%#C}m&>cd?cq*-d56U^Vq_SD}NX~{IBpEgQe zqdqB#%LwtjfuDtKrWSRlMv114d;iAxrigj&fG?4U^rh7P#jaFe&}zQTbaB^eKC%^` z{(0)-h=39O3tv~}f>c#}nko>O>4|jLURX~Ft$RP!ad_}k83=piA$V1zS^igoZ*V(x zOBtJ95!$n%G|(do&StEdt$4Zg#osL+IO5MD{8N`{XHo}nDLZ%BHFILgHPSonY5sbv zx2X$;xy8RzmWBrh$~t96Usq%)`pq@33#QC1qQlVj#2q}RRo?0h;cT4Fxtz@T3jl~5 zGv40DtY)+ew+|aAglgP>4=o#U@ojKdFUY;;G>=cn#;t0G|J>&BY#4T!%D(NBw3d|8 z>f2Od?ks$3*x6cTTx@*4YP!b6ZNeEqZck2H#Il>~GZz1fv2Y&Xk2}%q(suwCg_zD{ zk04_|f?{F$%kW=yiH+zciVP=1+|1)L4P1mee;_&RY?*?_lHc&rIhTfw`=6$TVLCI7 zd!`B~zvM+tKvYI|At}~avSoXiKlUGSi~wIr9f$GuqwWsN8ADxeei1#~{A(ot-Q;&a z$RUvX;dk=kzxm+WYh&+Wwl#GS_p^8CqDV)^ob!yoZ6{z8D9~qPNpFfuFi_y}@KgVW zaURkJ&Ze&3Ma=NL8@*stX9eBoVdHYO$ek})vh9|Fs>P^(I+ZW+w$Ney zs;=j)`dr`jyhfj2>w11hpP%n~)_r^ZGhNU3>i0FNXGhL(men_QJ&S&OS^b8t=Nt98 zwd?sBecsyjTq4i*?PyxNCH!Sw@cXQ?$>>s2^8Ho_Eiyk?#_c#p^dh)WdquEpuW(sR zgk-B6{R_W~=4Xmpkb97Lu;#1UOE$`j<_Fgek}dKdiN$^z1G3A3u$DjVEO zlOsxzZM-{gEfqA|+hTHSq%b0Hylg7#IxtFYhg&LCfx}IU_0k^%uz%GK8$skG;j3c_ z*Js2Q%BrQ^Xpk%}aN3c>Ptk!E)mG3MHW{TfAu0DDe8yCIsB)5f5Z(bSdN7vgjaZ#J z29xvCN3~>lpU7Ops_b+7c(S??Jx*;jQe{u;#LB($E7alRt5h9+F}?*f#`Fe;7Da(T z(k;JRYvqfyz$xpx-d+prT6oI_KqmSoj#!Vc14>^ab6F%Q=c~LHslVmK^VI`A&sVG6 zGYA$(YO*J$U=KI2t#Mm4cg+~49pACHuR=zBlgu?M%A`P13KSzcoYv%^hZ7;~hBKNB zsdK>-56k1LrLenMNhXQ~pGSM6NQ?=|Smh6ux`$yR>s8w49tC&v`uM>Qn-wGaj38A` zjRUBZa9(LS0w(Z z>v2nkQoghM7z)w5F>s8nK`KenS$wTj8ec7yPO6sE_@RiTN*&=dyc1@2#2=(ya-{^N zVa-+iARD8RYz$S}eYW?QDmMxg6{2{EP9zz>E)>7J%v>Qzch}#SkTQ5k+#>wMnn+-; zzZ{GF6cdU8ZjbG`;!32Qx61!~%pBEdMOO=)F7mE}Slo=}AmYsbF`zWVlFaVFEfu;< zPLo>*s}#f^$atdpj)#R6f0(MR{Lk(qugHVDr5(B!)QG7bK~fmM7&sPG8!6P{?lGvB&b>2A?cJ%~TkBMi_~{+BZ1 z&n``OQN#(ioc8t)Z*jTBo)jxnZKlhFJ$*Hn2nCBicX_ECB1Jw=){9k&lD1K96Ohz9 zKZamG({uY3ClGh}5r{j~+avDqP9c>|p=$f>S5aJ-tMiRe$Yx;%m7&yZ8YosFC-j?j zP)!lz;WBMIKDSKIdxZ#2=Q!e-G`DYR4;8vxxk7*`BtRXqu5Yxi&Ngpo#I1HtZ<)YX zXQw7e19Q$B`z>O5VpSBG!;7qnVkDp8TzFY(4lhlCb>bu!yQrOd=1c1Df+O#dyPf}u zo)_D_%tc9gANt-`*P!!&+(G08neZ+fv$7sjqUgi9Q5b!kjMUz*t^m!wL|1Zty~8iY zPd&~YG=4@)(@v&KZ2N5%w&6o$_&Sq+m*F$Ycid(Uc!4+AWrZ?YnqDJcdW#0l9%D2PwV?2(PKtMp~y#Frvo#HR#LeEE#N#PhhT6^gIXmpLcC6lo$pCHKUa zB2vVs(n)Z>frWDKjYfD?259s@T zR|%e8B%Q>i=%)4967yWuvR*K14bO`&)dj!*C%m0F8?aW@pm+4Y($ijC8K1 zwI3PRwc%VJD#Y|5!%UBl2#k{^Gb`=ell#~)Ea_GAscO?u&-5QZK3Py{Upij5C(L#- zX4yO1l;zqtUFY*v&N!u}Y(0LKX?E#fm>!;$w|3=e(djlk&~-z-d%pVh`3GzM?(G2QBRXxo_<q^*VccJnJOt@hr^Co8;`4GOh8Rj1J$k zGTq77Jym%}1Px^bW$s*NKK9_Ia(-*REJt@bD<#Zhj!>{HQH|_5by8Yqf5Is-2Zv`l zh>4zDZ!DF4iJUGN(dXqYCmn>}skT2mwoeEe+t#<`P+rXDt<%LSBVST?2FO)Co@Fox z`%o{Zd&4UqYMzAdA?9p1!}F;OD1})j8|14I`xc|H=%}QHcW~-@*UPSSw%@!nU|zw6 zHe|rnOC@U29GA-Th@e^FbLNqB_ay?`Z{>r+hJT;P`_=Xjv5PR9<7F6E=H-|~+skNm zD{q7cMYE&}KoT#b8p~6GL0|K8YrX{K{--(2oaRd`pqcUZ`Ke~G@{P%U$HU8h^NP^-KwqI~ z-J_zK(JN6xXLJu-cB*Q@MQE^A_ZmmvI_%uxDd(CTg6RO*Z@mOY@6-dTFhJlE_7&E+ zU9^@ukVpAs_L1BE?tt7AJ8;2$RdM9*aH+rAZr=BWq5AHo6bKBJc-?<#s1~wo6(HGF zkELU{naG%E)Hmz8fb&~~{@DKT|Frbc*HeVEjtE>O4@zp4_Q`aH3TVH|PIJ?Asdo!! z6EdPk^g@}P74k$B2-18#;8vHg%^{}FB&X9Ae#hC5afIw5t=WhrXg%>1fgiN6#Ew^r zadrq)$?&fdzmxq$6<1thP>!bz=X$3Ru^}`-)IjXO@H3udx*oFIq#uLxET?fivTuo6OGEN@K5*a|L|4rU%+?K2#tv(PY&Zo&J25vGgm5}lPbKtiK`z~ zuLQs1UWb6m31sL`G#c*B%_xZ{mr;4)W-kDW;6LWxw;cXiVwI~8mI@;ur`zWXu*rU$ zpKnd(t(^eP6mG_;(=)_Z*qq6-gNSt9H}xs zrk6`erj1k8VRM^$DtHe~8oJSRjOSXNBM^+%u)N9nkhCXHa39DkRpJUZ;ugD>*TY8K zdgnz#KIS2_#eaAi1eyy$u}hob8*hJfWM5L$9YiMBeaHLi|A9Fr=j@-P)^qVj3s61_ zvr+EC;G&1nt#KmfkCcO{@$r#_z6@dt_$d`BWrx4Pi{xd=%kB5NUY#YcI3%APv|sLe z*_&g;Azb35(cliicx2xgb8MT$5#@U0iO<7%?;9eTdu~Ub zrPhFF!wjwJ0&8Rz$1D}E8BuZBvZl4^%w5W1x|x$_R|V`Tg~~6)N59(@#2qKBT-LSBeUayj?mp!(AZou zwsp>hR$0J0*=VJoehSrBCc|y^d!KqJu_o5L_g7ieRj~$3Hvdllu9DA;;Y~Q*Rcy6N z9|4zX#;c6YWCo^W{%dm{GLH@!`;Mb7L?-Md3Hzm|pbfb%&eM@J2i1&aiqLqEW>~m$M@~&u?xDQsDSOQeE8PSnErS^D6d}J8| zP-*|}C+g{7RhP;dBUc?+*B8eFn{LKEvCn*YhTkE&xZ?M9Rv^s4ACbXe5Q*8~SEo<5aAx10>`Y)Sv zh17_i2bg+%C_zN5K)v*72FduWfaNp8Tj{Cu2-%mJhYH^^H+A2qXkqjhm8*E-Hxo?N zSo|bOA{AbnZBE;Y<)C0_IG6E2J~FanH^fT|wtXDiY?Xf&V2E4OD}+dtKAI1E9lGm} z!{%=_kI#9*Eb)@^EqezVSmz~K0TgkHL##FFBRmcaqIjm(FAd$kAG<^MoloWCYM;hs;-Y0tnl`m$k#f1FMnlp4nh&^5vR2ou}4`UdrIX~p*&{^FRk8? zTlEv42;En$*R{5#*FK)4mo2?)FZDIEWyNo(8aAACUItaFL+Fv4$b2%VBr>1Qt>;$C zIBc*+6VSzoZsgFpN9He1#NkvenahICJ;3_E)m^1^Z?y&r)X?Dk*UXByS4w9hjg0T! z!~`8z!Qeym4!w)@P3bsT|G{Sm2xZ7haFvv`cQt!b2d-Iy>q*BHL-EmpNF&>N$wPf+ zf33SSefBff{Jj7gCmbiNe{5^|*tg>oPCo{tsZJSz+Z9U!zTcz2OHRQF7)~7N=w-xa z^8#`NPUkj0DSQlwi+BO4M*i5pU(*H8cYwzlC}68HOyM#!U))DFT}CNgQ_Iq7$I59# zb{U?x+e0#Kl{Q*>37tS3KIa`F0gtqv!H8R!&1rJ1P<~T7XldG;CjN&_+Pc{+UorWH zOf$^tVmOT$fq%ZogAFqiVP_ICi<+QyDj<}#OZgS=oBdjb2ZT;u5DiA9HSu}YB1E9E z9J9e!ZUQZ-mg04`Qx=~k2u!KE0779Ec_O0#o%Wlgz zXFwt+r6+Lu)^Y`2e>NdT-I&bak)}Q2M11%l*K)%(*~cERUQQ`ktuU!gb6thl!WC|| z@H#lv9gjwTZRaJ%gUtlV@NYBfGNaqW33F_{HMT9k)o2(HY0U4ga_@mCtLZA(F>smF zp0~~x6L|Ov$KY1hFP2s&DM1AvSks=5%&*7t6t5_8>XH`MBnAjS|El(eRICx3d^N`x z(Dxn?yw+33Xz)eB8Om0lId+ZJU)xiYC@ZjN>2TUhk2ccY*fny&;^O;ccq%q*Ld-|L zoLEl~>Cv1vtg;8ziZVuQ`M$$&gl=HzWp(XZkWRZ@xf+FJr5?=A1>!;_y|V)f8jA@s zAc#WTV@n^*(CjW_SS5KXHemQFqA*!8>(V@jYD?YG)qkm{frc#*gHZRyI& zu$SI@Eb@=^Cu9cux0nNE0)GtyYFYufBk`W8cLqYH?ySg=Sz({%0%tZm|Ay^BtyaZr zGXm)&i6%1)G6fD7bh)qh`*e{@<)rgYe?gMU)AZOeDI44DIs%1rHx2h+5@}9zrpg>2 zTkm=ap{2b5@G2Xt61ppwN zUz14$b5CA$&r>7&X0jg2Y@5Q?EHXa_Bk*&CEzQrtA25rQnt#eEDvJoJGqd7xBYH9n zo56BVL3R-HMYp9p!~sHBjS;;J12yU;PfNv4DQi}|&sSZDbC_mZ?Xy2aTwX7VgY)10 z`jf-MF8pT2qc9e26$PRluTjd1i&zk-$-MXUU`+?3SZQy#nu;r))b&`Q@f?jQsm6LQ{=zV&6TP)U_E~xy$H_;nBidJOeUg-FJtL^Ub}jnmq>N#aV|@w zR_M1a_C?d4uPwgBtat`-jeY}fGW^WCG-L?-%6D`i;Vz7JKF(zBHT+%YT@+Jy9StR562v0daB_P>7p{ur|luyX2x{007xb!!?ae9lBmV^jUWD4b`kcK z)bd4lDHvFVyFWDQ(o3&&PYPjVF|}i>ShdMF0&0eqRtbcm8?ErFb+d2glpA5nclfuV z(boLuf!G@RG-lCO#WR!aRYIGtQ+DW&aU@vg-)IkuXACh&q zKS6T5$sm>~wYaoZ>~tQJc{?qmJAXHQ0e_+okEK_JGFht-ON49J3D@3d^_QSlFl)HL zAQ^NU^b)Ya5L@&HQoKul0WCA${=j$wt(OO8gmf+C$uQ zH|=>PcV5Oi1vf2tFE(hNX^=&HtYFgIJq~1YZ^o}BIA{k{7k<@gq6%+!GmM;HKkqMS zPtE%wtnXiEG4L5zyn;b@-aDtlB3mj%fr_)jGpcqvSGeB%EKyR4%@`pl}PTk2pQd%C!2h2$`d^htY^yC$ETz*bIN!4nyiWkBfHawOnj6o z^?^B)wgRK+SWxlo=F z0Os`htE`F7@If@k$?&6-?2i)41gx>o3rXA^H1Etb)8TFAby?qV7abS2nq>0U0##{`tctw%9Lpy04Uh`sc}t+mP?f`VD_ zHFlMAR4DPVs3#R3Ts^Vf7LU5l~pxmWVDO$@lqL>qdjvY zS|>S5XLFNLqxEbTka>Zkc)m3j-_Qlq#gow{WB`-~B6 zWY|#Zjg{7Q$6!S{dRyVbe^H-Y9rOn#e|J1iDl_d=b%-6B$+lyXDGs0WpsKddKhxus zrd$#ql<*@E$Fm%011dZ0P4X7w8wyfJl=gaj`Bi_a?YeWxMZhE1y~&7XP)adMB_h-g z=t6`99g&xAognsCYUZVgg%nZd@~^bVzhcsZQ&@gQfiBPr)`L5x7(uZ8$;~>iQ97T4 zVl|drFc1AG$SMKjA`n&EhyJQvJ3;^nzq!+6!Ni^7BTW?B+uiRdoP*8}gtv~6MW!)+ zcUIz@9_z&@Z#;e{1}>wHk!6KCf4bvgi>qH^Hvm>*MZmVu=Y&|l5YMbpE@Cr$=S`x9oM73M9EAFW_o0lTH{>+{1c0%vpV|diRvTa;|Q);!(;KO8 ziAX}$S}AL-kgD;yFXsQ4bcsT^xm77ERdG)#}Btr0_wB@%+&QkbU4 zHn)@&NGoP#kr8`R>eUY|Wx4XUr7X|=87x26T4~H<)-9uo_0ySO#0O zpO~r>Dqc|w9xbIHPj{dsz~~GRt0@siLZ`Wv#&5VaKIsS_VszCiN}vGdw<=5%hPO|n$m z?eIjcCq*WS__Rtz9b+f>kB4vOFW2OHYkfczaB&BoPkiu}i(y z)j8H(xkjt;s{d6pHkGet6W3dv15tGEJoX--q1Y{2^nTb#VWYWv0#7hPG|tnkL9j#P zrSuijo;1U0BQ#n&FFnZ~=PZ)4*Qg9#TY8NVTg|pt%psLTUij0mIXEwGvf@&Cqy@df zpE1fRSuKDVi!*7<>rD6&ORJ})^g)S73md6pe7L3d?zC&d1Td>g-xM1|8GroRM{AD` zm~&eFxxqBw4m+~fA35OX?^69Nk=6Hc6u2X5)Lj>-Jz7kR4=ns@j}`*F zCNASXISvTjz$FX-%K zWX-tFfkn^CU|afN+<&zYKfxSgqmeUHyW9ZLC`9%gEFWd^$k^Dn%hQ}^yQ#A*+h}!u zN3L$_s29P>C7!uC=23I4jD|Hg*WVHk#Q!5@#QrTrq^IH<#>5lv{m_)_6`DzLCO6A^zVm8HOpT8xf1NOMGbUgm8b(3-ARg zR@$9gk@mABT6u~H|C)X}^_V*nb%jZD-s)Pl>P$0Y(oH@syrH}cH=wlQ{W1o0OYCPVr ztEQY~E|2hr%NZk#O*x5Ui#nQJcqiBt=8jL1f-eYYQ6x!MwQuQa(`~NJ zYXy%qohLdYmq3&YTB`?3JvsF*-!)$He`ck#+BW%*nsK3Pg(Ws#=m3wUR0>- zh&GFhkyH&wcHR6v?4_`V_nS5x`>A9~L6I$eUMu{?MYA_8JXr4cuTM{RnXTLUYl7?% zfy6y7WjJqjP|zjeJo9^+%L^=$ueNiMuSs-jk-*3gSyVLKVs~Vwd*?J{4688?Ebxmb8X)B6k;Y z@?BtM-2(+|vDONKnORHVLy5i2jnzU7_&V`dxKF4fU?0ncRM)%cBcv;vfmuWGjy@6} zdEDHFR(+?rL+uC-qn0(B^VjDeGF>Taxzruc`We?1hbk<67ccVrx0LKMw;97ni42(la%0U4Dc(iN;CnkF4P3LI#m%y=D_>?;zTT430Xg;wDIJhQlF|XON!8xnmjQWKQ$oD2NlFIfxfJpqO(D;8kr(=@ z67Ea-1mWJzq;Qe+_=TjjGE-7o#X?DG6=6wf6}L-DtN5;@ zbdV-VN(X7Iq;!x*kfMQ7eqdNk;Y&5uo3R=!DH*Gm6>ku_XbDx`|D7fvbO|yfeXi0z zzsexEQ+gk#Ce+8+zo#jwZ>OZb7H9WMd7XIAkk=iT-$+V3{E(!y!}m!_I~-FDdQ%Xi~rkJ$*}40%MV+q|fV9eSSXG=M||w|IF+2HQML5 zcyeLx;Dm$vsO2L`eQi&LFT16h$?Nv7zAN=7Noh}?l$7@L5lLxJmq|){y0|OfysmtA zbmgn*%J&^fDGnz{N^8DWQd)DFq_pPCNx51i!1Fn)(Kp+@(OY@~Sk5x%bEqG$bXjdx z{7%V*?)uw9E_D70Z|G@_ulB7Pc@H&ZPO`xLYhUrQ97%C;I`)V0Ylo_ekyuQN_OW&G z5uQnpGXvu*Inb=KA5mw)j2S1_9Dw6v&&~69Zm!wILzVr*-N@{!|J4`}M)U(_IX<_T zP}ROt`*fyxIzeuE>V?>EO>Puw`##c-3 z8T~5lFQ0sHFY@+Cc_sBF2(2iuuO);iuV}*D5*q001@*&8 zC$uw&g6J0f@$01e%*0^P%VSYu)L}~!I@74@JW@WFYWLN4_A_GBU|AS?Z@SvwZ{=i^ zpQ5>x9nQ)LJP>_7B9@*=!`1f629Sf1B9@-y8BHGhKKB(^KwG7;k5=9ybu_zymCO!* zoB1j`I1PTYa;kh$Fm4g#hs9VFm{eRvz-E!Vw=n699_Key(C7k(V0pE)o;s`gn8KQLSunQr`kq9(i7p<&kH& z)fpifs82(jq-*@Dbv`7BMV<237>?@+E?6#tE8TD$#72_{ANJr!y=vTGPe!!2Ol|$< z4n;|GXowqP0~DQWX+WcR#;f^Uf@5~Lbm!0XSBiaGNh|kbXa+YH$P+T4W`7;(W=EQX zxSZdBT23Ac;-zec13<>rNQ%A{IG2Dp(P1ni?-TOUyh=#VSxTAuT;}e&TbZ_rE!{&i z86nKYb}Du_1fH^2(ffxmw-KVvIq_uTR;rbg3Hi0F?t;cENlDxNg%&TCVdeN`>`H-x z?O=IcMk34O7e@4bVIB+oC7;h83LDFa7hM9aDsS8NQ9S1WHrX5m*;8A+A-wBl^V5>g z=e%ZpQyPI6L^p?SDoheiI9`p3LHG>MuBRjg**~rDxM?J^T&R$4oVYu9RFBhAl{oG&< z6tMD}?Yq&^2nvL~I~_u20XLzk}vB`L1;DO9l;6P-fqOP30$JX@e&v`ms$eUEqQvSM^$1dF=l+C6u(=PcUd4qc8~E=$}YMQ;9zaaNwtmbC;=ACHhzJ4?0k^HvJYK{7qHFkxCC!Qe@eFvu8xbuysxq;Z_;H3iv|xpH zq<-*TM65VjC%yVtVWY1@tPvNaejJ5p0V3hh5HwA!C|$4!8s)Fu-Ad|*G(asfL^wH__yI7OKn_@_0^>@ zs)d7lBK}q2$h&HEMgq!O^jKnXP`)CAbE}_2L&c&86SEH)gTx;(Q+!QyT_D06I=xyd z9i-E49hP^T5y+}cjsSznPk}ku8NwUkGW&v?d}XvWdA!|>pC(h(Sw-(tpT5DT3FGbG zd7t86_=NfLz22wk@=2BzuhN?-IcB{5L+^7bp9}XxEYYmPI3 zi(E6Z>{Hq201oFB8$)NAVK;<|Gg-1VIuc}!IG)m|)_KI`Pki~FbgW0bVK?4F28a^| z65Y$_fr4Dx%u^F@>naIsU%0t&zkid!j|K9Pz$Edv`>+5RFoMW8;vE=D$${|uxS-Yu zy*K&C*&$4QQ{a`G3F^<~?rr3Y{yW7a8S8iKgGY$6yX1{fu2GkEqfycBJBX(oSHUozbJ6w_AKaxbw%p_~dlDkcWKGn(B(% z3;!lHMiBf35*yupMJnC|77#M@z*z)om%_cuTF`cZ4cyn|7(fib`pAV8yF&nWwyoZonsu+_hV(dP! z@buGNlSRDBPXh?t5^fR{yA6hVQAzj!e+b^pO2bZ3)F55*pIf>@C3b~xs6f+_@ZvU^ zdyb6qufrK8{3$^k0%m*U)ieP?R3Aj|#{CtV&u_-eS=8WWGf0^r3Nc14zavnFk~P_`H@diRDcxPU6+WtS((iJ*f`Y5h2nw4QaUIGFXr*__Iqs6fD~^`y=+{dRX2#pD`{9y-2{;4 zaYv+>dj2JqaG1~+aZlVD|S-%QmaIpJ)E-d7?EkWQr;SoVK?e; z(3T1l+gy0Dzj|Hlukdf%m&3X<_or6Y!{#d>VY0cC7$;W7Vq}If5u0melHr4%*^tbC z%bQ@}9w%S3*sKYd6CRSAvE(Fbh?Vv0?#J-K6dL7q8+q)@0D_F+k64F1W-SvV%YG4p z)|ngnmsXnCdm_JZ@B7^c>BU#&H9|IQuM1ibnOYfoesu-Fh!sYYG(%WAy~CIVr<*6m z%fEd*KB1SdWQTE&m=)(I7>&TT&lV+(i>T#J?qz(8DHmx>dm)n-SIHk^RFe!B!^Bxt zBfq(LMYhJved*ZirvNpg-=|zW=WLHo34VAjiGE0xfAUcm#GM5<-1TxeCnCUo~%AmF68ME;-mihG3z&FGO-tQdVnF6kwtEEj-DnTUXXX z^cLnJC<^#nBFW3=3@{pgc?;EW)ilfd4=G^OJ#dT{ki>aL-HX|jP@yEhqqeiZ6Q{sxuMH_@9yer9I zSSkO|>pQI8R`oH4I*%~fc`_#T(tSG({u0j;wYSfod;wxfw(n`*4KlLU$#(`Lz=eZZ z3_`$v$Q&Ms-w`m@o$B8P`5pyL(~X7)1oG)6ZSK7pM#KH>JV(~2IhItt>O!enu&uvX zRr8DcFr@Fh$4r9oy@>mr^)gxHuKzTCM}xd0$tc^-}3_J2}uuoWzg|yWzyV>I^N}ZuCQ%8>>wRkeJCxLCGV1F ziTi~Ia^dE62k0rIDpG#e=(?XDRK$E?#LX+6#}I>zI#b3~ea^5n=Z%?AT6QiGV#)C6 zuzimZAk%Cx)2w}$FsR7KnUL0-Qg|j=BQ0r?1+vWY#@;;L(%sj6%LGQ`-R^1a3;8za%R!)F|KyMxZL6jHX9FRA-*PrJ2tbw^uq zyW@x(ECYZ%3SH+Ib(8$@pSCUKR?|)<*qlU2PrW`cXNK9vmZmb#AD$46=*t<`; zvE~LICYqb<>pk=LBcVA6DtE?f`Wkg*eK82CX=(n1QMk=Ig&2m)|2D#pDlpv(jWz08 zkCb2Q&kZLKy-PtE%jk@L@c0aFxts|LV5uybiPq%&$fiEB8mF_YV>FPLRcXr^HJ@qh zOqb8K^qC4QEkv)Da_%M&W{F-kaX|Vc>nXnNUF(CZM9vj0o`mW(n-{%D$pfJe3fr1K z%r0!x@8P|vYfU)vmj%H*)4U^K{*+4?2&{Bj|7?mhHT5;G&9pM|dOl~FGcwHK**)T4 zNPL70WcqBzIH#)Go<~uuTCAJ6za}g8mb>3CCth5TuVUs^Nzep@Nn%0G;)#rjU8%uA z9;9ypt1^oKz(GBV%~UuGU`keN^~8vyPgd`NyC z&0EG#4-3yZMUj2AY{uPvllj35xqM&r9@Mb#@KY=|=0760<^_&>@iMsO=Z``k_W6q$ zS+`(MkmY_^xg9vi-hP^na1Y!{K8Y{V&&$yU1Azuk$T8_QYoNfqXkRw7Vc5VBYQg_t z_&rlTp_0ouhL! zfo~xjVcu}n7UHvn0pP@UjBGuR8;FG;%LY2}$w=hE&(cMchE-FAyP4b=5H|fC@`+ljnqN@Ie9;&y z0-1V)#u^uHBKW~fwj&}?R`?RlQmqIT<{oWuyEGWOaT!y70x#IKYAvGm%8pO%rGlwf z)q>k$szD-oe&qMRTJp}FS<2rVVN1s%8v`W?bKWgyBou*rU@*o_$dDaO#`W9j}h2L|GJ6*v(eNab6_Mu6S?8b8PmgPyo&1{!pzW zGx3mAEM3ChYbkw-di|-A{_rh@mIW8_fsXJxqiUl4(JH*MSd1gE=cKtYyisG{YX8Xg zv1W4{+CWZV%QiRqAq?^-md8Y=m(4jG6eWZC4}RUj<6rBC?E@%yzDVf_Aw-xQ?P zJ-}SpdgAD9pi6V5HJ4CAGkXxp1-jl6t+`4d#&C_{HYWxEHY>7Gwp&Huq~I%C*&@O= z(L_CLYq`WGtxtE>$DMC7ccfiGt)sE?C2>A)z5b>At;Z0J8n3>1Q44>$K0cDnHAWub zj0}OxSS+rCR{vTUkhs!c$Pot#e#*!Z~AJnFrX?mNLU2QM_DK556woEx$ z{qdwDj3v=z$fu5jS=3Jm4BW7l!Bo6$Rb&&i!dNUeR02mv4Ahc(pWS>`(A-qgMqD2v zD?}v31Fm5yeHIqBX5}$|XUY0GpQMj{pD^_EGyE+Tuc_==u~WoFV=+WVfSrtZ#cTFf zBxrH@o}X#9w^Xc=MhKSDEpHIBfH)>r(UOvPLo)>F;mj(+FxUa1AHp1P^1KV*_(We1 ze|S6|7*fH#Hsoz5R5t;DHkcVpC{{hre)X?n8vU3QBC5?nD{WXsqeSuzn3s})YOC#M z$inwX#Tvha8s=wWV+kYR%G;b);ZZwzf#yk__PX+!e9BISv&3l;4@LX%TJ;6$&gAZI z+gk($;lW2Lg6ZM&B1sm#*Le|1;=3kd0V4oHeO>cY&^LPt$dcg1;OkM5SY0r-%~vo~ z)771S6Zb-`q6S~&-v{zPLF&`+4;Ak_r@Op;2KT4iqMl_T*8f58dd4O(E3)IHT%wt|Lw8fnI#{ zocc8wR~LQkBa#^`K-}iK{@J~$+Kq?i>URgju1l-!OMcBDU%a#vfEY62MudcWgjS5Y z-r~e^Kgn7KBV1@r^VM#>3WfFn?;adDDev$h3r-)Fjyi398j_9YeJ%WmNti)~$R?s| zE;t^s)9`+UZBzbDPu}**w@x26EPOCNf~)N{@F@`rM-NZMyxt|%)Rv}S6@E27HQk^1 z)iPQkn2a0lSLCaSlT=_-F;*kAs;VA!_25u1`{Rp$*8XJ6GQ!Gu6Bqu#>brA z5jxKrfGQEIhDaxJ(ql5LodNE%>`V()L>y*v_+6_H^O0SC~_c-3)VO3_Zj#PCE#Yr)Cc7DicDn5GTt0LnU z^Huc7XO;KKXlg~I?v)Kl$u?&&A8B}!JqQmPsWr$8Z@!BB>8~lqp&5e6vE?S3p5p7W z`dc4Yazt{>S?Q(&M3L3ZsBWnaGa|-Q^CjK`--V6URo?l326)cxA+zC~_;kA~q{^>- z1FCIqrsr(#ho zgEh~yy_<1s%|rauJjEaT!>2`4leo{*bL}ILI%?MqAfBO-z9TMVrglcneNCcciI`KV zfkbg^Z}CZQMGKv=URCXhPh|i+{b6KZwvMKK=l`1uyGg(qh7or6Bm0%?`kj!^ZOMY3 z97NLgi==@6=yY3k#EmE%?a zCZp~frd^6}-rG`ldERJF znJnW*UB+p}8K)98mUnV`*cRTG7}>qPyPjXE3(&!r9z%D3w{9FvP);Kz`yA&WG?kJA z=`PTf%aqFnB36Bnzy@K#sYXL}a-{|~DqS|&h}twPIf1{-ET#p|XsDgOeN3&K2nuK* zw4V_@ofpz+D-i2ovdEGkk49Z>1CL9~^G+>P^_O6*B!ptaCKelI1h2v?&4UabvR)3u zF&fm0O3qifpAAr!N0pUrsJV>AvgnJ%`e%MI_$wY@#C|JTx6{TciPO5)1EVf5pf~{j zB77D6y@}lbsvN{H_f&YazeI3eSLP1|umgIGhI2|@;Vc7Op))CG3G6N1H}${|aWN() z@6cbiD5!q|moV-2or^x_Wv#LJZc3$wxw194Q~}4}|V@ zuWrVxCi3AGMqP8s0V6I*88$O7IOpUmC*++vJ6qD>Q>HI7TLmk^o1Cl3vdnnyBmYJ& zMiqS|W039d+4>ocvPZ3T{)Kp8I?>JM!O%n|32|yTe)0N0QSdqY8)j$mfbeXjVDvjZ z@B8!c7oH@zLvaAVCWl%>=9?dKpxXdlhz(M(YFxGb>&HO{*o6}^4>mE}y=3}5{P4qP z@H<*`gDTndpigQuKQ!t-ba8T|dIpZJ^=D46B8y5z#y z*Y)hGaMFbu-2?LVcad-CdLciVf;Uk}0O}(Ek$I2+B#gnCA=t5pV2+(l4yRBzlpZAaQlh;?PG@b|0DkP6wUo-{`Nz@%4q**{&o&I zzQErQc)J-H_g4EhbAky!gV8k#-xCFeBkazI&W6~c>@wwsF7r@))K{@Lri{mz<5#1b zHx@q$JqdfehhL0Eiqpe)7dEmuoPuGL@-5bdwBn5P@Xcb2(h@#E53>Ai#Mi9UX=>Ds z7Jjxl{G9T$H;5GYMSdn$02#9VmDsdBrxJvya*3`a1oO)~Wu?omHj9~bAoQ%xE-SD! zV#BRkOAgNe73%Wf9a&e>-`VF#I-H%_ub6F250_tk7X%2uGTZzwtD%9%lE!zlB-G?x z{OHO7;pzXGAC3CI;zuXrDAUc4>SemiY*juq5`>`7`YQgjrU(CdGVv#2_QK?0_~jd& zxy*b}1$!%mXHKCO<~qkJ9Spl+k4} zE^~?V;lvKy%^Q)ozJj0Bb@3AvZnNVBaPu zNYGK{qR&Kj4OJ~DBt?Hh0}2~Su}Funh-jeXWqlEmbjPNqEPp)%E5h^2tNYSu3oFKBHY>kdH(L=oMabG zbcs@{E+mIkv{t&j@Gr)_G65sU@454Lyfp4}_tRtYM%T*%_2NBHdH$gtd)aoz7+(C- zS?Bwf=Z%SUqMLhGigqG|ib;f(4sDjR9pYy+8uzLyd&ST6bu({7sTX;VXkrxUUM~yx zPZy}gb;N$0OKW!Z5}Zht(6gSdhyxC-@J@P$K~dABQlx4V&ZsBDRsIX?tBY zf(XSfo4JXV(arlUIIV(mdm-px8S#yO0ebO1)PFj zD3mY@w=04kMGgH5GUPJ088WaEBm(=36b2E|%Ca1yM>1=^4taQJ$MWAC= zzt1!>Uk6;M9+~1u;bw1~2*euKt-@?vZ9{=8`-H}#STB~>S#=zRi!JAVe>_x)HBA{~ zk5yCnC1{9HUE$klDJXRc{SuO*Kw2(5(jxW?zQj}752J3BUp6fl0l<|b{Ndjyjf$2! z(Ol|R* zzZmc-hpnI)ctEo-j~J1D_lkPpo?J_ zzbs0g`p?C4T()%#xtziT{6~%Fiq=X|-V{L+ZawaO7cHZd2tv5K@Bhvs} z3b75a48`FUb1sqYg&w4m0_$`|&OL4`1>DhY8oVba%`dw_kr(kffy97i;M-boEPjKZ z*f`f83;!+hp+B5Zv?rb|k*(E|9HxwFaS<6aSer8B`6!rE3UNMzyle8{AvLmhthtoF z)cg|Z(f;}Wq(1!q#1D6MeYmCT!@W}C7Cy*+VbMOZezT&uhwy{GDVkSI3SHD0*6^W> z9Lfr{(&Q%T@qi=;j z23P(AB1YpbLj_^ZMZ}^bK0@Vl5$acpWw#Z0sPqR$^ma(R^hX3R=hu2BPgWE0Nik?? z(FPfvT_349ZOs^5J0Iv`!bP1q-Sf$4*kvB|D&N8m3PfRswcZLWp>Men`@5yRj3uM! zFH{wjv!0aNDRwC@;Sss8K7noaIGs0|&4`YrDqOOzacy5XBH_8XPq>6`_tSh=X7vdV z(SBp83aYi=9Y(`sKQ0Se;ha^Bt=W-CXnv;aP+Ajnp!a{2S<~={ zVFi4!v3)0M2UfGte-$=AN}hCca66IZ!#%oO~zSreA~;xisYKU8dfSlbDXf*2x|77&5(GcL>|j`$GJ$Dmj2 z6pO@$J}e6HB12RjyA?&DI$9DJtV&uNib+&CoNWxPp}@#kvS-@!t9B&EOo*e`G6fzv~u(C?wtJ`@F0wz1@abGnP-(+|!>klQMg zVrt$z^3BD4Xz3rA5!lEn0VSEgQB4YrD4?iM%3J_dkyhQ^AE04(QuQ|K45RL5&+pBs z8!78@aZ~tH0{2`jkHtH~`;`av)bCuG#nH!5fatMKsirh2`$L4b3$VDOvAGQFJeg*Z zMlrU`TC|;pYcXw(WI*y}tGOE}$|*8hHVgiv{#OL%{H8N@AFyFN05JsL0?ZWL9Q z2qeN$otHVS)V;V zT$fEv2p8)zApy=a#P8d$YtQV%7@O(Dd<(-w%6dad z$Aat_gJ#evgrQrrkTS3K19@hobn#rXnLE-Ty4Ze@>@H2Qn~%y6?lxaZV50sVnWwC3 zp--G+ysw-%NiJ$Du*X|E9=V{iqy?CAz14*wDrsfuByY(kWAR^wBi-x5wK>#3MP4q$ zm`X;R2uY`)|1p6u^@((<{I~0DwyM< zFZ1KVHw!oQZ4b>h8V*N3Dlprdl7n856xa_8%C~837S~87rgVjQE{x z=D}JV6Bdi#7%y+3t{TRFCcsRFK;|+?^F-P8ZDvgSPM2`!VnEJoX9(|7>sKUEVD2&B zrO{#Y@+#-WjQby=#$i+QZZ#H*PTmo{jk(i#oH7h?wooi>Ri-$NhkvF@tc)yIol2!s^D+xJ8+FC;NgPP@i)<6ZD_I}j4;ED5AbYuFcOIda>NY+j zz2>Twxk15Gwtef*Jl8BEHtz@sa@S2HltRD_y7_z6)FU>>Z%nVUzv*U|Z&($$nd3hR z8s+brqD3g%)obt5=z@B^&)-<%?#=J)awdY8RJ#q-oc>}oe4?NZ^cUN)s_?@Av` zQ;1xr(7O~kTppB&?N-)Zh!*Ak9Qj%A2?DbdumPNAQ@xD}T?9 zz4*Dw;k2;p^1Ki|mo-E%Fqhv$};?ND*N} z*Mb6!H?~n_5$zQ<9Ua8Sz3H00z~4GxxA9C{8b&eF*{DszReL{-9sPg{0NhC=KA73{5r>l z#_n}DdgF@q#Bh?6CL95rV35R41VChQzUa$~bLILI7H8)>@EUVhVPn&0gI=WHwfU`Q zq(;cOkvikiyjtE1MNBlC;7Vh>H#-`i9RV z9|v~4*LR109wM`%f%rFL{h8rD>GXxC_&9IE&ldSadB%8X;AfE!CqsjED1O7)JN`+X=C07Wwcmn#AEIg^=lC}z`lAP{y*tUfDDO%Rhd(ZS zt7^s|xky@;3)$o4Fyc{awL_@s8CB;7A`~gMoN-Wy3W!j@s2gNH>HG=Fict*ZcfDcU zMZ}u`)>*}KMF7iYmn=OFgy>otjsQ0q#(V z$MyZzdTF+tMSBHA`#vQQ7JM*`|gt6#{CQ63&y=6{xU5iv-ows&mZbe$+{YPGEd3vj*;C zX<=MY(HIp2pN8K%Q-F_26LPO8aK6p3(7@s!P@y9?o{5Oz>nW<>v`okvMG$$>b^Pno2s0ZpGY(S>&viEsXNw&{Te94;q_?&y2kL0w2x=y+aso;lm!vBaP`j z5bjKeU8Xi&&H@~ElsV`Lo7AoRtQ0}Jd&nYRIb?GhP8_lr!@*2bsoYrsBIfmt9A&He z4Or-xH-Di4CotgS;G;{+f3WAn+f*CrxY$^7KJ_p`&|ji~hR^|41|+&%c!$Rxl$*pN zym{daK?F>WwXqenXFp6H;RZPzZ?a4>!UaP-JYiyyGw-a0y+yw;`&0&cCem2ZF)mQJ@H7Wd1JfN1*~^aSdrEjZDHynU=ITR2rm-ObvSjEfg>tg|dd`@BF*6 z;ikC9>tErm$N-tVXqD28gB(Ga8x!BewvQ8)c+GJuJ)R*aSw4^3j;j>Sb%Fhyt3Cv_ zTt6X8GqDn%5^E0~E_wy)Q%FM*?RgiJhD~7?M=tnNxM7TBT#4YFxB+Sbf)~PXhgH3S=D7F8@i5a*k z5FWes(dbUMgHt0cSBD1~(LC@a7W#SQ8B*))X29VQ?u~!6XbXx=IeKHc~=_tmTb;?S4=X2bY!A!VAW5x5b_B zxeLJc*nCmpEa%k!L*Bc z^F@XV$-^HWp$)CL3kU`H-MM&C4QfS}=C;LXs+wD6LqTNGQjrbe)S46@cB!M57P#Mk z5JoXtLipQ4`i9Y)!nXIF*hb~`2;+4%M!odW<1|_1hdu9m7s5V?GeuyxUwvD9jp`bH zNrilN+~QkUEX2*Z3>6TP!aKqrY_m8%oX@Y4OqnoUA5V?vZ8EOX#TS z@N`Ptw?tNga_!&DkueMPJe|8}IIW+{cMn_Y>+47@|Hv$^UKI2XwSUysdzEN#IBP1|Nrd}Z^lXl2IYgv6A7i0NG`Qdb%boA&wloD!q za={7KvSpHlb<1O=)y{V`ad)$=kt;Z>D!|HMY_AOZP&Cms#M`k~^mxA@iI6rNiKIw{a01dLloFq~eE*_=#hQ}OEcF9R{YXk=3!M-n|4;{| z>e{0ffIal>zd2~g=V+d(y;pWI$xFn_T2D1)^xneWT- z7?+?2r&J)0x#jk)^L5wJ%&}UZM-HD>LDz2hkt08Bo`Vk*L53+py|wH{DVDttx}T&q zJf8up3Kk7l^VXm+sLYRT_D4Td@8$TAE;a#-sl-lRYCQTLxwInq&j{0A9ZtB4fOBe) zv4=y{6izBN;Kh{0r?N2)Me}b8EmgWAyw_~s{J!X<#H)Iuf=|77;W$xL5v8a`CGKV@ z6FKYBl%r&sC1Nc91uvvL$XB`{Azv}(`-vj$s-70C&L|2mjcn6a=jX6R)oboz!jY!f zk`JRiHjvM{F}IFOVKW_-ZN%=wRTA(^!=J=w5{Kwr8WyDAgBYa_^TT$ei*?l(u?Z;m z=sdzVi;YKHg)i7=&Wb-@NyIh89nw@JY*GxOQ~cqVV|%j~&4^!`tttCBoYR7$^I3kX;B;ca z8=aloTjS$>aUBAGFic{*;R34Gomy8A24rYV+>-bfN8L*CRG(4&x6_N?3k@pR8K2Z? zl+>$Lk3=a-1>tam=`;AU(C9{rnn+G%edvObiOwCawZ-yD=-o;7Z49L!R1V_8LcqK%oDHc_YItm#129kLj|dA|FC4~IH0Hp`2L zcu}}E{!=2VYa!0Mv0iAjR@K*YQBumdrJl{No3EIAH@`RdL+FSkPDje1H;9;wG#bP+ zg-$=Z$NaEq--xDnj*R<;$J$1OH^w>+*ErEw$8cQ*9?^EO>X(E%bAQG@j%QnvwpLt=}&E z`Wa#Nha^&|N(!$v?detF4k;y_{;VJ32H%rgM>-+<-Nkom1RSDIz0|MjEw^)Yy@@jr zF=l~;rmwpcv1J&|O)O(B8}~g*5kj!|3PJwkdyj1Pl*V4hdrjh_DH6ltj=UX7o3}1c zrCNzr))H~Lq-r9S&OR}f-NTICzJnL&uPrEE#IX&21QiYV;wWFZc}+qNM-~GEUGf2B zX+8gy*;5_ThRX~WLy|Z(nvmxR8by(#5^oT|)RoEy zku<&2h2CG*azJ$Y^5F0Pk~yir55=T&-jE`9mE=5^oT>FeVt_D8?~zn!S9{Ag5ncCG zhW~Lq>(Iv#s?U#S%{KmtZS2Cc<}iGWrSHM&9(dLrJOpv-;91WiVb55GQU5flwhw3o z6uRx8HT>O_*Ao#)2#Kk+~T6P5CKNZ#}TX+4Gg zr1VB?-v|H>P^7S})iRCE#J2XsjcU43Jr>ZRY!DF$WHVW`U+>^rbI^MBhDW;AQz=^TYv{rhnq zPf#OPm%Mj?PD$QMyW*2kHL=%5U^T^0w8q6G9syJ%dXO~~%P4@`!T8i&-Q62>`E~5= zFQ^hi=sh140mgH-ZNh>s5NieuIM6!`_+=%b!hR*cDHyOwD$R!RE)3ZJn6&P3I<_1uq-uhL;U?$IE8hdl47KfAAT!3FidBz_qtQ70mtj?GgY@N zd0Vl){v%1$-_>pkKPw`jb~8BhQ^->I*#JrPv>N=ZG(+QO{fW2fe(9J;#7z>kZa-G> zG=BEx^Xb)HOU^B)7$Q@q>>hE_hyocK2xSMssb#6|GKU9XN8`#_GDmD@iguNrhR zw$w-MHBPG7XPxZyR0_vUsY;cXvXUk4)l$X|Kx?kgT2a!tl zXaB#4&#e(>_-n@J&ij89pPRz~6JCmt^@-1gIoBeoX!rkv_}mZKMxlYb-SD|Dr(Sf! z=Qi>}<8#L`;+Q_2FBgT+t>&%^pIeZL&y^2dpkoSTl&0Zx$CTL@oS%Wu{Z2>~TSj4N z5e07RB`g0lN>^7qM(G2=Gj+r1o`YMcaJp(f2qui*usYAh=@RQ(k2X7%iThtD6X>WM z(Cg^0&&2CG%@){hQGrqaN4!24uN%wJ4y8m4KMk+@FWUDt<8^N%swa3|gSrX8&yel_ zulsGTOV&wmb;s+@N82TSBsS>&ZwY79@w%^LY++bWysjM6s^-3F2%m=OJj4|Dj@Okv z<>`1`QQ4<{MZ9hSwPoOSe@q9v_5(w%@Ve}CO~>mNxp>{#(l!=QGVr=`7(VU@`x^Sf z>lVr6`cv_`qa3{Mse`^eURMB3MG`}yw%+l&o5U4mC>7!Xe;&MU0c|Z{$_-xkLZs8p zYBUTKxn+s(fDDcs)c|v%y#ii+iSYqMONo(2?aD1>Y1D3k^Zzr*DW&YFC^H*n5&Z-^!aBP_{;@qR-$7P)|NRa zR1`sHZ>Ze@Q-`xn-CQNeM*T_jS0)2!ltS<}!365k2;PEx?oeXN4PtG;LGTXksx}kB zdkQ*_Kps-l4Z)j11C%eDK;w<&WBA)``ZG?JCszAq`lIIz+i%Rhi2mPRuP%CA_le_O zii?GE1jl%#M@AqzxSU=vQ4nn8u*Wm$n95h$+<<849a(qX)%1dKI|_n=h#Ap_65jRYw?@3l;S zDKUhn)=!t?$I0ZxP{C=El3luOfs>YGET z+TQTIi+aKHj{1^#Uaj6tt=G-|jK&vj+$+i?N?V`i4;H zHEVi7`Zit2G*#hzl_zV&{!5Us=l6~CRgMa@6bUVfRdB(@+n$!f`CfBD3U51+P-3bx z`oQ^4)yZj)#`(%vO2hez$*6xB6{3;83Hf-sTW1%>*WXp=M!;55SPI?y>>-j_0KX|x zI31s!aejjF-JyReFT8XN&KODsVDI=$oUi)X7tS~S6OHqI8Qz2QZA-)X9>N@6RtDC{ zT>ins_`~P>Q0(wASNItIAl%N<0)x`&OGd^ro_9G19AqQ?X^+S7Xiv#T(2B|J%(gs$YP#G77~Y~#aw4N*HO-Oj9e21 zbOgBG3yGbl;d-OP#fAbntl-AM^(ui)!}ShFE{vtGN(+>vcf<9*bbe}Hz;GJJFsg6G zR%ApTe@f-)#wl@ugX{eOF;3Vb%ggixF@@_rRP+GDLE+$*1G2+d3ln-8>-oRVFxH8) z(J|(3&Z4K;bzqRfySk9Q^0CEuy*ghRwx%I_uP1RCZ`2iKBH-SmTyXCyULrCpxnRH) zxHpFA$CoMJidJ8PD(VUD)f=|)rxE)+1@0}<;NFR7t%+UW-tURkQ{di-fP3}2l;C^y zR8}Cq^3jK$5Z@v+X|COJrcf0UDjbOKH7>;W8l=8n(_Y6V4d{EUC_kuz5Etm1mpB)x z7ZrIXiWb((`e3e%F1>Wj>YD%=&E2fYz*P}^uy_JwDgcX@BkY7?sYeEsV}kVN;9+qM z@NFAhze*TP9>4jDEay>r$1X_$-?n~x49I3SPYpRDnzRlZVM znFlLI()qvPgHKjNX_p4goL;5jeV@hRYP|0{?qt5@;(g^CywEuA<@bc*SK;K# zZFEC0ah_NhzD1!!LbBIc84d>sJeB3=UI4vy0_e@~QWF2AVZC}IOX4CSTLAL1ELxBW z?KLN<(UW)-&rXoTZ;~@1->(oJ5~PwNw3J?+eUQsnWY+7iHtPxX3V0L|Xyt-Dgt z>>uNi6g~r*ebe+gBg)i~I_{J(VN(EWMtdJY3mP%`2s`6{oSI3d&P0hElA*c(0Y6g9 zMR%nC_$`IOiqLFY!Zl@eq%Hi`R%b0eeVT}*aor129ljP_zWf-`XD}GPU}D*M(C`TG zPM!$LuKqsmAN(%G=HqOn_wGV0BPyKuvz9lNZc3mq=ChoKW;hYKB^ ztJ_!>!x##5Sf=_ebhrSVaAbmp4vWE*Y&^P{M~X@|fsq=5uF=q8v8{Bg>;ZS7!+I=Z zV`Q~X$6t*4IzI&nfOw(EPJQkr(4Yat4#z{xXe2zNznCJ{Ju^{3sf*A9Mq>Na{DaP`v$jMPFohZOMUgEdZ%jGh{Olv!1 z&&dZ4f7M8kw?)<#J3tb%y4aY480I(-!%}-!n>I7eI2jCsYZNAznx{~jCsC(0x&oa( zM9UTE^sn6X1fAx&pwp3nPV+9sl68Sj&s(lENUZU@nB45s#xOJ=ls_rZ=`E-|?bUSy zoqEeEAAoS>f!3;*9u&0JTK)B4I@50~AHlo=8FQ4&o)lcG zk+Gfb2@<9fp(8{g7xe*gr$d~%S&+w|s+rpr&<4R((>qLCgIIZa(;>Rm!9m*XZ-JiM zXzp|3)Ms9&6hw@Up)HBhCQ&~AEHpMw38#gzF|E2Z0v&(3UB9M zy++=JH_*U?a@NS0||KghpitMGnn>L-2hMhNw#@mO5RERdTgPy51M z%pygwdcEv2@nO=y)!=Q)5L9BfVhzpa0}w{TX}okeI{MwTLF^3Ph9?&(;6Yrw?*d2` zIP!g&aOA%NH)v6GbitAHP7!*5BTIwiAE-5<)>z)iUq?tmB9n-(uI2+)mbW00MOPFh z55ez)1=&{C5>EOFu;~K35AEQPUDd%4M}43=+Bc#+G$MJ5Ru^GAAubdr!Z4je!Gs## zT{MES)pABgdwRf-U9R?|p8Nto&J(g}gJ@{tH-0*U9w-xn;}e$%3b~Z~pz8F(=OR_o zBuHSMuUg6b8SNh^?6HhF`YI{ktslKf@W*SxAHNi)P*EKY2DtzXvJlmULEelN@(T)i z1_QmIio$a%>?0>DF`;TfAxj2O$W;{;_JpyH{BZIxN}j2MqKI@(udugqmCCT_8@wr{ zOh4xvx&ZCg=tt5@p5`GUE_e7O#u*Yi{R8zFkFHk(3Pol<0r0e?=@W*1_>tT?UZxN3 zdz8L+2QQpVY?d*Btz>X78s`qXJV!vxCy246M%{TdLsipb)cr#gzB6NK3c1CL1=ji@ z@n6(3y7BQ4H!~v3F?LwqWm-Z&;bFqfW`(qy;w&-H><;O*ro9j76>;;F3 zkr7o&jSng85-1Hr7gnKZT^*wf)UFAsr=Hu!lNi89nDgR&=)4VFS>y&A4$FF1_He;^`aa4@@J_R-4LCZ^8)JX zAjJtSBwj^)9aQT)aiR!-Brc*knnszRYZ?_0d337aZqVgyUO3Q8y^{0ohRj)4C#YXt zWH;#LD`&bdx?x|R-~|f-dGT}9#uHg~xlM7g7$3yg;EiLs3^5_#5#r<%YR9Ye12(hG-hXk ztVa3;B(0IvQmjH&Z(-V|R8YRA3UIX}kPVv_9SLn|7CIvF7}se^!(ErUxa((L(1Y+6 z0l%uyV>h()`K2hlEb5kUtEU@UIz`i4j2_U^Qj@qK?=Jdf?2~jlj0PaTor$aXro5g2} zmY9Ly;+avTm}DHZQBaMtai~s=;XOXk>aZRIqB|WwlYJy&g@%y;NWARHa>{UYS(*Lj z7__HWY(hg?sjpxsG-ofxU)RIs9zkjMJHvg^4XK=%B=G6BJQ^nvf3@1oEY2c0eulV;SH6Kv4l z?e3Gc5=_m`gNg6*Qesd}j#y)xZ2#2UWCM<~V)jc4Pt*53@YKg|6_Nb^3{U;=N=44+ zJsIF=L47Zaz5}Rbv|%03A+IbQnqXB32lIox1O+(zpp&$BB?c= z%EeJXWGs7(9tKC<2#)$5g`>Wi2MVz2;HY`i2acK`#5`O8g`<{_uZRk(uVYB}f}_6j zB=tBQN1Y@~297$Hk!;tk=;V!#pJqUmxCj0)6_m;H{rbbyK>0w{FzA3qsea;AHb^1-BzWs)xxL!Q-0nf{9JulCPIM$b%Unwqpw(#1Qr>$K7ebcI zCnLS$t0COQR|`zKOMj*C(Z#8vDL8SD+deq_Dfnn{wo$Cz@X-rZW-b2?;ctGYPr}a; zNlf7-KLanllOg|q^gQDeA>ivi&$xgQCZZ-&lCS4H<0bq4jNlKMY_w*Vre&<%>efxFvQo?9$FP&P$zZ{LpFc3x%8RdU0#&g~Cm% z7wTN&>v`eY7Y9F$Pt8pFe7R`+GnO;C=BPY4t~i$ZtL}(i=S52 z_KBZ9eLyCDx{BWtW=X?O|1ki9`OD*{so%vGsbcYvQhoSJ~8@#~A=r#IpGz_6b9=`ViXaRo)CnJ0)P`Sa`4mK!nZX1^ax~&@`}{*C=#!S*q6dj7eGWB4l)Bjy+|*M z)kzJ`D#k?OW{t8!mv-v$kqExbrJ$k+IzK;t`cV2SlL0hJ;ivC}2{;>{il08ctJ)O8 zOPzpR0s!js;ir$K@y7Bj{-(Qw5TU?u-}Q@6pFZ75Rw+N4B_?$qxqI&M4MbBkUixwF z9K3WMeI$745Z5%kbh$)c>Q(nL^A>gM;HA0i6)*iLfB}U>OI$=&eRqK@1UPulm zw{)F*+$Uc8UB+4pFFg>t6khs5#7RGnY^CF*F9Q0eanb`;X5gbU&O82JOluMU5T1>T zkA7aP3*9V0SogeR7auM3IQVF89aZ7rquuk4#SoqMmGRLh_}l(Q=kBsuX57f?2eBfLw#yNwmUxhIco0>AH9#~0{+_p z#R?z&6v|L~SDY;Dfx<_>r470Y9ruclu0lOvD^mFAxlmYBB<`^6S*cNOt~v?%){}5^ z)A7;Ob!niJcw3dtdeiY*>k?h1r^b^07bN?0b(L=>u;T&YR?Vf}D&Tt+P z+*c=DJs6@FzcfDj-)LNAi}JD94RGKJd{;)1lgaaH2vk1K3!aFT$?GUV)`m!_*5*O5kT zi*BI{UwJYS71^NK3NTm-;1~$Bw6mxEt(}u$e-l?j1&TpQRSHqvCi<7NlpkeiB<|-= zUm)pn)N{OEV*}uH*YU^K!>BHJmq0`s=LbnALB=tjdk0BR6x)MP(PRG?fuzwf>@@y-AnDuTC<`Fcsb3f*eJ#sa z*rmiNs66E`GOoTPNE(v+J_q^p;G}Hn9+_)}`T_b&uiu1rvV; z-;6D&qeJ?deWk&xZ^U40c=a#1lj)cXub#zHm&{4J9en&7*3Y`(q#Jldc-Fy5*9h5t z;G{2>-H054{E*CM9JRb#2zAu*6G4};NJ1_zlsmh|!{dBLiNJJwheubTJq37u52PeE zq*SRWLe%LzRv0rN&$F2)c85Gq=UE!$c?vzGS7w|-PM{EhJ>LmF#)##yP|D<>JM4K_ z`cebXQ3 z-uh=ue|W3#){D4*a6Da>FVW<*bDICJ#9Ob_vLz6vU|hGK+s}`;9`v2BfVcj^aMs!U}g13eS!9U%jBo1o8Tgz$N;H{-d7jOMfO@flTmykMcN|)LiNk*vTi6@!7;h)&-CH{!A@YZTe|g{MTQra1>gG+uY1D7mi(+^)9mn<23!6i>Y5xBVI*ilMUs9JEzlEJ|x-^CO`$&gV$jqqwF zE?LqkT(aCOI+iAuQKr9ZJ-iQmvLu&(UlTt0X&F7(me}49_~arA&KGc^-gqJSL~%{|+Y(sexAwQkGQHJE`nz!W(=hU9yxt8hytg{j$M=#` zcZWg?tL{(-wcdA>`$D0G)eCh}?yplX6na{{P)F1*O1)4RO!Y#Y7CVaAmbx5LB^j6b{_Sj7ST5VJ3D>R2Ml@AF&fA5?&2Gh|8SCKqHw_=AEOf~4Dw{Q zVx(h`Pvv)J1`XSNmy>Pi>%?HJyOv>v3RZ%rP{BLDktQ%2yj&?WjC=$Mae)?LE#T!^ zae%tO%R_nJ3l4bSE4@Dc4v+glG9O8~y(5|LK-@IV3iz*RR>1!PXm((}F39&qSgg~k z-3Kb|S~>eUKwAAm?LJU1)Opgok8oe8tqjIY~w#Qb;pOqzV(`OUh$7e?C5eFe`&hUpauKC{rzJUX^6#F{ht19~OHGshF> zBoU6h3Ksh4{16LXInig1>+C$;gRyK}j7JrCng5cH&tA!Sr{=#o@l+8oGU@w#^=D<) zKT@rE_d>u5&Kq+H_}3Ej>>$sQr#zmH#pVn0%kT_d8@V5H{A?TxaHz9CdC&h8KXT!R zCq+&m`iyRZkkNViR@TI}UZ(d}V=}XryoSs-4t{FzMgd7g{M%dQZSv;iO)JYEL@O}y zkd4hjD|^jx{OUaHzPrPI5HXQ&IT(akfiHR(vlBUxqTFshr@stB2{5&dZWK7QXIAVq zHO-3fP4>SY)Yu;OM~24L)qZOIfzH?o>v-gi9;eEvY2(M7{&wAKyjd5R4J}$D zEJ-eHX%;rRS*(*Y+E@3=fzDax$*?o|*U#qDwIF5PadfRy?oQt<>*Ox(oJfIE+G=Uh z23F{}<~4FfAC2UGlt@ll*LdsPt{B`^z~B%yPx7}6kntdQ zbo9uwnr6zkOAw0|U+!X_+S%Nv&f7zaiuka=eGp|Oree31e64v}vVEVQi1n&Q-m%HC zdG^YxO6*VoM@M8g3+0t^+~A za|7Ej{?Ix(@}06hYrWB7W~)0d%DI8(rtjC2EgyHyX3noCN8j1pW)7+rE4ld%bA((! zt^D{kzuq4ob3^+UUCW7ni|CA zi|71`P* zv8hmWR+G;y5?Xt$KHpl#iw1r!uyAvH$ zt)GWKvS#kEramtWhGiAoV6pdQv!vDA$`=?*)=`03vZ1Se(uh~`r7t(?j%e$Qw%RYk zTWJUPm6hfJ`$d)$t%`NhyL7^kc)8EJp^yzk*3=DGR5KWlA;!6gf#n6{IP+hMKRHXx zoNFDvSu_7-m29)7?(j}+GuL{b4tJO(+ZNU*P7|_qJVKg3et&GOk1QC;3HzgWP+Zhb zu6Ku;zE)LM$bc3Np$0QrA`~CDB0gq$`^$VYW2NO=-u{NyHhn7u67j)q-6un)RS%gqDL+qt-=NuNFUI>Eq%&eI3{s|6!YD}C$ z+VuScv7IAn_Y_!I1S`wh<>MKi$gKEGP+lX9<+8d1i>l=Kp7Z6uN_)NHM~DWM#>f4x zbIfn#-IOZ(00)VgzE^lYgNGH~B#$quvft*hj9cID+`WM*{cI+our#iZJ$mlrxbG%u zmsozUeCH|XZIbB)=Xy+p7NYGE0rnZoC0?Xx;?t_O40ejgwktBIGia~dt5_*M+Y;!P z7xKC5K&3qyfH6$Q9A`;YPA=KspJgw1bJ2o;as9W+sXl7hRdAU-MDlYOfR{pqKPy&4 ziCbsk}~J2Aa@BuUwwbe1)XoMz3@D#_XSNde zEv0oiMa#BjNIJYfbNbSpdi}UxujUp{f261yr=(%W;7TZ}h|2D<#^t z=H|3LOGGedW^OXP`_4C-oZbI6sLA7eKS1{P#CGN| zF2^7y>N~#5=+2+d!O7+JCt71TpBql;C#9GWiooLIk|j#sRO$;)R7y!^CFmTqk~wi0 zng*Nb`=@B7Em|wRO3CH+heQBrK=L`2p9q7}MUEZ{^wdL5N)OG;&_n3oz;$N8(LG`> zr^|cYz{jPTx_u+}ph>)r0-6$;gJhJ(tF`($iE*TK53GAujr1VeYGQnx(iGlLyzQM) z#a@Jc(RY;o;Q_36I&%)s`k$X$lc|7Q{RdM^rMQ&p@yavEgr-6fi5BCEQ~ zSI}Qo+bhud-Z1tL%G}^eg9{+@)12Ypy+jGNH(8i`O4H6^`UsQ$5P4mw4tMFM7hR zVTlCU9e+xCo;389z`3LV`SjGva)ryNw0+W>JUoVny?4{!0Oa)2O=IjQ5qs55!t2CL zsS?BOj(77-#=Fm|2;isVkK;^DA&k1{#CXmV;xNbF*cIMJq(FJgZ|o{Bn});bw@*=8 zJ!H+?FI&$k&Ut>6R>ED+DQoeOR8Xd}{SH5lRwP?e`aT}e)x5SV{IB>Fs(Eb}8ds{A zuKAe!ZMp;Y1?P)@SkyINJW|gWk96mYN4oRHBi;Gpk?wr)NO!(?q&r_cvak8#=ky10 z2E!?rFq!5O!W!cN^dqw8Hy)UX5Dt#5U2HtCsi|#5)9Z&Xc@0#vXYj_s8%$sB%f8&$ zI$vt;Cwy5+ENl}tMYe^95bJDfAa3?^O>c~loSlmYzij+dJON*>{5I-lFKO=VzvK-9 znVzOMvIf6wJ_Uf)+`Qxs4>2N@#54G5d^L-IH6>^?od;g4>EzrqG@kK5k(ZPDk1r@W5N(wQ<~y;* ze$IEBjR$`43El=XpMsa84;c^m>z|A!*??Pg#Th~~Lu#V&m?ykXJd(AM)8m0bg=>wo zAni?f3$_>y5_&Wq2-a_kzAbGwu9Hcxlx{pWBX?N1qj00qAQM9&QC4N; zO&6sNmAZKl=~1LRv^LDp&lQcvbsuY$)(f2{Dmu*!IJ#}p*zi5T(CDnJuu+g1Fbjgt}uUaaSIizqT+>yLn zjgJ6RUon8<;b(WAvfz(|v1gZyBP8;UaPvOfc`p_<$G!syl78F!`|HPdy%+B+S3I*g zlM4)b$!<#2Cr8i8s6aGS*1C9ttA1b1orO-}Ex#{TCIh*fBL9 z0f&Oed3Jd`r+JDHDG2~xCILYFd+wUM?77wl5_}tp(B?I4jSQ|E%b{k1zM+s&kKxRE z9)4xiu>$97Sj`U!MLo+EK2+JyPz44C=h9p|KbIB$x^ah}7#W`EkK8IdRd>zdohNcA zNOTZuR2;zlethC^KY{IB<2q$0clt5G(`$D6j`7ns9xcss2B!$`Z5P>Pr8fiTn$QoD;>vXq^(!Y8eOhN?G=~wsV@YKt( zyfoJ)0+I%W=-Pk${UtkpBdH{E4J_k6?q^woTgn5!DQd;O0<|13A3z%z@XMd1LTgp- zExbXD=M1d*4^)P?#4qc&ufpEBKMB92tw_1ia1&{7%|%d#4hZqrsGq_EV>EjdU$RGk zufJ#Y=v`(L{*gGqfzciP50X@7^RS~Nk5!+02bJWGGoLl}i&stc;^B_p_xE6>{E#aI z2GrR*i2L`eD((Lsd7#sHpzfjp#~`J_>q{5}>iP716)cxutffV|rScLK_Zhg`%;z!^ zp4BZOqpC)#C!r@J;j!Hk_9tO*!E2K6rQ_49-b=Q00$HG_X&d(2?~?E@83{LLB#eFR zy}o2XHNzKV9hpt|$nVY$T^M zdA_cXRWqp%#pc$T&Cx@2Me=71b0h}+ms`d=>07kKf1jSB=t_!lDe4#fqn1c4=`2(1 zeD;!cq6O5nFy%kGD^MfL?4Pq073)6+uVfU}neD73bdFeU+}<8+dMh~k14oATj(*NO zNE(@l;ApEl+$L}&u#A`FFIt+^U|`pvi194*ki<2RCJvVy56`ip60K!fZsI8sRJ=8* zh8XU}=BynI`*OQvC+x$Ft_#Mq8c^?^*z3E(&oe6Cj*KuK8(RP5f^+x;z>wMOzYPrI z*LXAVYd(ckxH0-(yd)^r0cqIP=JQyycDMm$rN5lF<(2lKQk(UC3w{lp!t#GR3AfAaJG9_x%L_J6o$te{CM zwalxMSEA#_9(4_TjO2_xN=#-XYwS_N*GNF|^B)i`%$)U+xl0LvYp>MXAJsrsf8Os| zR~Id`%1dWir^t%c*m?fQw|XOXNMulah#e9l%S$=ZYo0$g!H3DvOc5^C+laX;{Hh;N z_%I4L*X!3XqCu26Sz~j2Oc7<3uw{Z&n9;`Lz0}grzKU8BcacQ(pH-YI_Q61$ROvU) zQ4LERAc5J`-d{Q;`faD^=+S)_`%Q|aglYDisRxu~>S>Z|KN({?r{JmI z6d6Jku}#}45t9B4_L26yajBK!dpIrX_5Mb~tCY2;*&kUs`rSP(!N}k}>wHH2WXgc> znrg20Giz1z85oG3ish^nTh!2LmX(se8L#a_A?SwN`AaUdy{2v8G5+b=wRwN8(;mE~zR?_R)QbsR@`i9?$;a~7XxJy+ zsd77BQ|I)eV>Xf-%!AP&pQLux(otYj`I%t#Uh7xEjvhsUdzyWGfQp;M&AdwKr@{@7 z(@v`Rv*dbKay`Ir4>K-mR;$fQE*=)~NyJj`<15`3x738(7MIzd{8YEN&3}wPF<1$a zukK&IvN`hI>XG()r@DP$)aO#xqf&QbId|?P8vVtJp+rC8$a^#TstPXSIc^Aw~;WwbVS#v|1}BYN^s5Qc%9pE zWw$F?W&K@1G{rxWK#qsGp%9HgnRML}MpM?3QLO)&t-(}gor^A|u#E&A<4 zQbu&UD`C&~En#m%M^{N-NUrW7tCFkToV+3UGiQA~$66R*;ntd&W!&2?V4d6Ghda2w z0E?F0+Kol{0+ocr%I&|^sBY73HP=Q@a2uN2cS8?Qn$|akFGg}zli4WRt{JHG5YJ@( zCk$1;Wi{JbH~&I>Sw&5XFIy*NjJGcSL<81B&7T7@WqbI`@#nHzy75PeP$UmU%_nj< zY3}Ir)7|FoNtc%%q9(l6!sc=|aQ#F<_)2>s4xyvbG*s5IexEL+m-QuaoNDtW$%{(R^KF691mWXQ{-0 zQ;GGU+{Wlw^4cf(+vZTVkQ7?Ad^4wEPjtFF58zWa*6>_`p7aM#q2J&FL<|aC*w$xnYk4^G<@xTZdPcOIs`r|YO5joggd!D%w;DIx)&nh+7 zT37nw7j_Z_I@cF{y>FImpnRQo_Da=%$$z-!fOzwgonmI#V=1UeW=#{Q}z`76#y*OMf2wy8dLu}eQ4km z(M^|FrNObKS+(cKFZY>qgXSR)jakY-XycGN57wpkjlSu*U(8|S==WA&jmUQP-L@CBlYtS5{Qg|~-WnmYRxesaYb;rG!4*RX(ay`Tc* zut>Ff!V}~r(DZgcZwmo|D{~_UEBzP#f!{h5xLdnKLPsj5spoOupI4F};;8~4@_t6V z(&Kz>s(yx)%;(r8(u5yV!T1iveZMJ-UnhCW>~k*bCyA{|)#UG-8?v9}>|yKdYS9Bw z5wa>JkduF|-`inc88XM`nH`Ty&Zdw1C1#@4i6;>xmSB5@EJZ7%Z?mjve$x(bZ0hJ&HXRKg5^irXlX2h5GW$nv%1lb=bdK+m3R=sg$?2@Q zpDdy$8MpigV{cOrf{A~VX$?*2OhmX_NmV}b`mM>;*7Q;NDz@k#s5{^n2in>JKwg0!DLIRs}% z*Zs>23c5JYy4q*fhD;jX-z@f-SLazLnVXYq@t>-ytwH8y>m+M(DEZv%m1qnfl-GEO z!`tV$w3C7G7iKDar zA?s;AC9o03u$qn@EItON?($<4VY*}vuFDbL(EwgCGb{Ww@`B>svM9Uo)!I3+&Mb4Eaou8ajNXc499|iIm35)3 zprCV9e69p_#@Xk>Yu%{G#Vltg?-9Sk{J81$exO~^Q@Wmv8mP)}m)p0*Z{><@AFDtj@V`9>@ zwDG?)yT%hjHvj$?cO2!$SBhUb$2(n?RCDarI+Hr)8WpMWCu+dTujD~1)Bkn#uMmvC z7Pw-ZHFVDt>`f{}`_0WZ=lW~=qsZ#sY!~I1WtIiZpZKu5RIcAdB$bFi&vc1& zEk(2)`7XlEl8ZAsvQuI!Wfg^zPrLMVwXe3OVb6jKB0s^qVFqC|{5J(i>L5zH@G0Zk zP4au#p7mY=!EYU~=H{8hl-gH{e6FwXMXmXb>+U3>i2}#1h|Gm>v(=sttcT$og)5F` zbcc~MR!U^KNO<9mZne&;ktNEAh^-z;-_~y(%IasUH~6_1VumyajfQDFOy0bb#!-&W-sJ~sFsJ8wL zz@-f1Kk%f__EsF#t-aCTIBgxP-{@K+KcjQY?JJo0y6ucgJO7lTzwfRHVpWZ$;^tUx z^JG3D>jw^hR_bEY`NL4kjlB16R+gUSxUE1gyXrqXujbu?>X`_?jr_x6_ zLE?#wvzgO64T(M=Dz8gZxboOjFL}+JfsS7CzUZnYPx6mif5u$Bgn4ZIU;XqXuqd8& z6GVta;dFR|iTQ9rr$4Ke= zk=j4@&G)ssas2joeC8p^H&gwQDo>PQ6qVj*30ksVy6y?1Ph;=_YoZRdx`Rj9#)_G;2rcq2cyV{sdoduhZItyteE^ z=wv-D`6tNtf!RXl!tH8vrFenCXfPiohO@b^UwEUUHy;J({#Gi&@dur7#{?gf`hd|O z9<(*xZxL``FcB>rIkE1|1F%=SmeqOqm1Z@nGGyUZ;#d03>QFrE=VnlWRFFrN(w|Ja z?Ga6$U-yhxmmyj6thphx8Yh+P%=e_2>QM3_CvK-}O5W|}ch#Bun?9h7QTSGaT8c)A z5L#uqC_)2g&XXPEMr^B$myMP zcXiI)R@qtW>#Pm1Z>b9N6XHOu$Pn~yWCQto~Rkdk1S&{d}~E zD!gOI`;2SfQ@-#Fv!oF^#}@mIYmWzLVio6@#dzjEvp68S@M!Xw#o1EsZ0g5t^)jV9>w$(b^PVe*n}%9zvSU_s8{)y zymmbW%ew56z4GNHquwXg4fNEpLdrx+FTU3A;30CM^z5rsg!F2wR*)aKCwex6Ru{95 zac6TCTaX-nhs5zy`XRilj0K13Xfsp<2N(H;C$&?otINDF;lpG05vfA}nws{G@UB1P z-)8L;^XfA3Ea#21t{P>|8)HS+nO7BX2pcnxhCOCEg08-KPtPrU9ygB8t5luWS~YEY znN`Bq9mRDBSryN>l&ljW!{?VixiY)(N?-ImIpnPVTBx93jfRoJ$dYw9(9^Bj0Nun_ zBCi#_Ms4Ay*j~e&y3V++T$1nfO)HC+w3gZbAXH0p%v!%$>r2RLvn&5z%R}%&&m_<@ z@rAAC#&AdUirB(+>x_m!@f0y=xLN8L8f+<^LVmXRVV&S?fChqr;ht!Gx zl0wDaOJ$cwisu0kk=uzVsU5bP&xJn_aHGd4eb#%HFR_@%S|7{zyl2tQZa69?B{W@+t;EC9 z1Z_Xq+172aB6mzU=yJ2{d9!TWG&+8IyrOk_XRV)+>-IjvA_6eA6=|UnCfoB)8avNt z#IB~{*1&{d(xv@+6gVTGVK^3_sf1dh6n~?$taG|BH}NLZS55y={3oOSELz|$@(bxo zCnWlJ(H+|mGW)wJ2B%WIMg@9&C_ju1-b}v=?jRKVO^F#$l^SS!G@d@ui7T%4jP^@( zdVi1fv(>s~z2sdb0h1inIRk59u_G%s~Razns%#Wt|w z4~sQkdC5+-_4UTwM)(Fu?S8r3qkwbZ;$%+?Gdy3eOtr0&YNLLx4B!R6!Ug_F5wirV zI#9T|1w~InPwgZa`mhY43cE~mm6Z{Cus^zT$vUZsh2OOGx#|E#6mE__A|=p9=R0%l zB_476qkpxk<>M9gtH>UEL8%btywU=qO+`&&XIa!@=WQ| z3j3UMAzY>6r5mzm;~Bo7pDaa~y>-E3Hp|)U^#@U*6=fGkHIcQFDY03e_sv$bqRfm2 z%&5XJZN4XFfY&2ElqDHxLXG>S|_ua%Vbzg%st-= zgnUNsMTfv!PI-_u1o_vcPppzD7L_(TR6Rq(t*HSyb65%_iq%--z*1`~c*cIMz#FqSpf+7nd4q0Z$>OwBYiVG15BhI-R4u3%i zOj8^MbxFdJ@RgwM^)E^SGSG6q2|t*S>Y1r5R&@c7#XL83%EO8rt0WX=HpyO#iq6fH z04-Uo&1Q-H7rtbyxRX>y{I`;pa1_zak{q)nV3uUD=dpxnK(==+;%c%(dn$9(Y?%&X zGclfGIWeJXDc-d0!D=#SG{{afvvsv>P8&uPOZ7P1NAN4kR3NE2F_t8bewaB!G)HH- z_K&QJYGe5wLdp+(`QLzt!Z$)A#=Xs}!|T~EeZ))oB|dJCc*%spyzJJo=TkDWkR}5n z5{V%FqV-oPkw>Hc6vY`vU(lKxFrVXK6pTq>yBWxx@0UsH3v_PXTZ|B&2nrKr9H26F z8?uV>kP7k0f+8JOdIJjEjq5%{gkb*iAtLy&I3M?|iB-~jcR{|{jwH3e0)moew7;qv z(yax@LK^PGOIW4rw^Nog*ms-zoB^-fQBs|d4TfFzSj8C~F|6c`f-$E2_pt$x%vCT) z7z$qt_booyST>0Vg}aQU-T}xD?5ZzqFRdbg+mT_)uC(1st7mz- z3`>Q5+9a4+qD(+ZmX=B-qdv35?~><;qbr|@!$kG(ar_C8`9WjppWusDTxv0}OJSuC zuLW0+-Zc8j(OVO{)A`GkLwcJji9~r-_a{7Ec2jy>mLL#dYhEyap3~*3zpboXc2LP; z46!RZKDb)?H{m0De#`l`iOF*B z^jkkBmh_s1pF3}iOd-Yd9m#PGewN`W3x|h!c6qk!BwOf@=kyD|ge1@OSu?9yu-dpf zJdrh#p+|7&HhvH8P9mR*iLVLWXt=cInc8$F4J? z@37hHf}=Mj-bVd)*&~T}NdP=#^_R)rGa@mm$(_WN^|a2aongf4_(^*M)_4N-MtzgK z&75fV>buU!&32vF%Faqb>SLZl_+>KHk`?fI(_QfvSJU;90lN`FXJNilY*n9zsM&7uqasQt@3K?8jR9&m-2Kny=`1+Bim}EH0L@<}^d5 z6~~E6D4t=}a{LGkF3u_}X7>ZDnVdpx)XU1M%!*{5Y41D1t=FjEAze_MMYe=QMx>gF zERo6=)kR#_5=OwP;iBbCXEuWf@#j%bSp`(ec%v)wnA`YBoJTZ)pYrVoe|V$R^NX~4 zu914^MjTwi4lzMPOb(ip1JQxB$C{jDP9|zQPWg6>cc#t# zNqU?_4KmY5HtUob>kVD;-2SX09@9e{v;?VOy^X#1 z!Y|(-=`{sw3D(J)%c+?Z7!6m6Ypt5Z@!AX$y}npZoJSVF5hj2QCHX0#UDcSFD9IeV zkeTi%oh~sa<%gY>gR*B~Qp7`KBXN}&)6{rU`ruD;)GK{fEY6{<88^C;5y_|Tto{kW zZKTK`>2D~J6eklWLy{`%)s6W?bW8)bjKMstOctnEySew|)+< z!W(F^=;>+Y_90@1)uiZG(o+YWr}{|{Rbp=;_oV!Jd~~`WIJP64kcblvQ4*}zrPwV2 zS*f_-q8}OeuD2}lm{!YzR(a>N6wo|!vh;$u+$clHPTnQsC$rIyhE=0c-@j^1$gtF! zH&$?z#-bX@Rihha49W_70ora9(mqBs-VGvICE^Di=K-!{{UFPl96U{Kje1O?C;T)M zRK|}&Yp{)Pe&MU=vVbw^RU)4sXBpSM&MWjm)>7wuqgGkBRAGNKRlwWiT`y{+Biw2> zN5?W4#BU^GR&CL5(*uPYBg52WM>=bIg?$NrkaRfd(S%CbD1BglOox_NR@mj7lt_Yb zbMo(sKR?KE=~Js9g|8ad$#&Ja?=iw_v9q{EgS$ZT&@}nAeX)We zk%GeY^FDG5OdKQy>G7dzkB|A?H2d{4S^SrI5>!qICXSUf^R+#uOv#IS@`QKMpm?=6 z@g%|uzL@$L>bcegmX@Q3T9b3fPR=tXHl^?xN+#3r>7yH+z`N6bDt}QflNl|K$UhJ{ zp61b!A*XF)tVOxzB=Kts%t<4;@M|0k{}*P#^C3-751w`MQL^B!2H5d@(^b4Nu~cB& z@lK|2JE|-`DUX=+W=zaDnt2f`?lW>Pi>(`Foeemb1^CFQMaRcF2C)3!F(@JfeGL{s zc5|umB)_Ho?r&PVjc0l!NryS@ap;G3X@faQY~V<1(G+u%bPaT0(ih$HW+=M7+Kf(8 zu>3h5MKa`CXO}^%CiKKbVIee22sJVYB`(sF&h1@v&S$q@@BD>8Ar=097M)L(_r>3` zKKNVqHS*V8FCdr@#5pxf+N_dn#DkTKc-f(97n`@uoDJtk0?qAHOk(Tv%54uViI?mU zVIeBrhO9)h$|^-hO4^tmxiMpHa8mk47$`D05dkei(OoadHtQ!f#;?|ba}^yTV6{O! z6eqS5nXxXYju(%Ev+PSK_O%p`WQm-gIRxE_EqhG+!5q1~u={T4A?$s=NN7uOL|-n`m!ja~+5VQ|iE|(01j*uy zq@q|o>D1ep1n~5o=zIyZwiK7%_h_~s{|%#Y5qB7km0Zl?1=Nz=Qaod$DzN$%c^JE% zECP@to*cVH-#ZR!WsSL13I&hHff6c2h`snp%|mFG&W3lRZ=0leA=y@Q*&ucXF02{D zrRMwmvH#h0pi@6xq@T`^r?>J{=^GaMLM-XvUlcSnE*PM;zqlTLDpc&Qe>wXfz9e4r zrn#AT&8)G-*|q1zOTFeZZT-_1YU|?=soFYFwN!pzg&Mm48@8E{jyYlqu`h9lo&q<_|vA1aY=6Q059+0W$>IM{M_Cn>1G_kf~H{Rr9$UY zWgl{gd#pgSalL39QBo2rLYZZAYU=3 zmaLO1wEDozLUe`wJ+muWGfrO)UQ89I9$nZB4@c(O-=-M8$|k;X^g(LPF$X69s?|98 z@d)y4pRUPlP5w^#VaiWQ{z9FH3X&)O_gkp7ur`M+c*R-qhuioC;Gd&HRo!utN6@=Cg-j&9U^4^kq0mrIqs+E9EigfEdn@H%UKKZ3VHg65*qPfmr8 zoz7!3nOv&T0<%{p&KfIjulv6g-aSXw=k*pTXE(?f*fdsksZu5!aOv!;lXmvU+6p)K zwfa1=mo>yb8JTrC$**J{35$De?nGhn`ZxmK)vuFv;C=k zFc~|z``n;#5wlG6p|dAL_pJ&PmfHhpv^A7Q6G3@Na3*K4IP+oq#`aAd=E||?6>X7O z3hlY*XxT7S{{r14ZQ5n-Q=QnwkK&Q}#kneeujH82kxR{v_KlQd?ve{f+FJ{E3|-h} z?ur~k8JYP>A06s2HFDH5!zio@E`;ur<12R*QFlCPB+kYJN=CRBf`eOw|}& z)_3m=g((Ty|K!Z$-Ca;e^C-FD3#tFcA3MD@$Z&ThIQ- z#ewr$3Oq)`4;d;C_QP9v`0u=4BaKTtjGR?-<4^R1nDPTo1kmD$H`knA#%U`P7Ux_!q*->6&Qt&MK4`}nv>0nw}W@CUMU zB80a|1kJ#AH97L@RALa+YL)DuocgVilcXan+LAYDe$_3a2-d;2Ax^RN{j36xCa$vQ z-=!2Hh0ffTWOsYqr%o-Cqi&;Z_|7{xU$0_Ea;VJXzt2Hi z)_lJ?mYH^ZoIjTI7j8B?qHkLjZPv`z$9_TEt*P7i{x&@D6kQupR}Ue%!O@$_Gs?^Chc9|qpGgO|4cH00S3>g zL81l?nktcK6N}zV18pD)qy;n(11O@st=bgu$qd1wkT5gA@pNq3YHOcYioLbh_E+t- zUcjn^*8o-oQF-~GTJ;=91=K_c@aZVDICvA2R2$&wi}E_S);cQI&6xZNO*T zpSdzK_p_#0$`{)}ei7m~0e$#r^d0E7buWW>4VW$|Z2d>MbVHn|GnGyDgnkMys$N3C zeqas$4)oIQ`mc1xzAIk@T$p|3FYC>>$jhx)e)9r6ux;1BF`f3PCG-M{CVK(8*AVgn znxX}_iu2PnV*Qygl7sEw zu9YqFrFjF)x(Q}8@+DCYJu5%GPsCakUx6uiMIYuYXN9!&(SCr_opW$+=)r&56L&(? zkh&%Gd0Nj4%m*vCE!Rs6?+LB_BEm$uS3h|XEr|YGeUBQbClp;rj_)PZy{Fo@E7Sy2 zZOJLCrBaDVM-Qg!sU@Uchs?KAk8YCjaURAFW z&dsKgELhx-{;RH@Fw??YU@sOzrLE=?G=j}RSYtvZ%;qAqIkaGk)m&;eOCq>+A(>4N z-|v@?;i!D8Sn*t4+mu>W|Ik+nUyC&8SwUYB%<(VPy6ot0(hqz5j32C; zGPTM67t9Nb^5{sQ|wKJcqEPnLJ&ysINOfr(66K|iIW=zYHKSM@?i7>{c z(k&ZtVfS43xwFizDqPn{NIrEp7!FaI^4-ZkbOwQ;hJE$7JRiCRjW7e~ z60Z()yrtae#^FYHM7z+$8l#aC&_DE|pvGFNy zLFM1$qM%Z5Rx>|%)tMU>MDV7w>LystO=g#};NepzW^&*D(~r1wQ3q+xx~HlA)_5x4 zBYx^$562x!;x+;Osr;czc%jNiuj+AF>+w}nt5EH66Yk%GsaMMsP{`Px(%Goai^%`z98d6GP@iH}R93qsHZHP*1fKN&dm1 zfLaDeM`5g8KPV${4v+PS5|_zk1D-OGGZ}Z2-P&=I-@$rq3>4P`cj)-VoZx?8Bt8)& z&~y|K565F-;sk3((@)E>SZ~C%?H{^RSnT*g%K3t2r(cimHo~+VG?q?foUS-WKbaM5 z<{Te@0yYq-!F4-&r8rOFII_EZKXzl%SHihU{;Kl*XCJAdY7*ppuaPkt_lNnLr8ftu z03s8oMLIvcp;Q_)Q{s?BT;us>H|Hvplnp(EEq<5zNqN`VNAXM&k0c3j6l>s7N^yp4 z(71ma_5Qa`6UNe?QOrXoev4!{RjaFBVitWHeVb+W@YP^K#4*Th@r#5c{z2KXszQ+u5g}x@D6bg4jqR0a*@is4T@+q>?poln z{t#~$S)*oZx*kJzewY+ll`lvWGm0bwMl`SEUFC&z6c?m}Mq;MC!f$F~lSy}u8cSq- zD!%|f*;&D?tSix>H(kPs-I0%kZYEy3JK?G3&f>ey=fHIx{H7chJMZbQa#b$5P==h8 z9Z`GgOsX|Sf9|=O%}W6fW#-UsX6H(AHB{_JGMNk_@sM<^x0~5Eu(Y1Y+vDehw0L%q zbqxd*4kHjgzVOO>E2%c%h*zn*ZW0HrXps)C8IBh>!`rL|=*Ti=8pCVn{#C7^J<=FN zV>qr=C^drTqS$a35M$3XwO5#9dHycUlK8)dv3a zjd`L!i7?bI3EIY7IOvly!%6ej)5&{y;?W=RGgMwO-g@X^Az)FO|N!EhjrND zIPs|s`L`#omP_YF`hP-vocJ@CYdbzr`lEKi56F7)WOy;{5E?y0rDZ7XS&Na`x-aYl zD($=K)6Mh=P7MT5$+&uVFI5+mUZ(2&@{?G-LO9J-T|n-Pt4>T{Brjv@?s4|&99IYbj67qBM55Ybj}kf5b!aEJ7%+nnV?jG>e2K3+wmLI( z4M#)5ToN8?3_Wd)^XpAo%K3-V~U#RNpI(ELfuWCoX z7bDlfc{qO;N8$PFGW}aHGQ?Vyk+pk|Q z`dpl&LgoQ_jj*_dPG`=qI?``*bhwyaRIr5Zp=-=j`Y|d})ui3?WEh=d%F?g7gd&Ik zk?5L;VEJ`cNQYb}e=1NIq^r2-c9p8gA0cd+)1ytWlW z1tWj5#y1fM65hDrI|wMEIAq8(ec0`hoIg1%L9|M8-Vj-;?4ToHaz+SLQqzG7C<9o& zbPc{dT~&wsZ8l$tT*17M*RlGDEMP4K>F^1eiP6l&EuHuH!ynK2!BG5eNIWNuOFHh` zkNpfqUKeX!_~-FRk~lE5q8}Yf_(#U5U(cZ-AR(4ejOLVJOe8cDiA(}O>Y7%FNOm$T zYRQTi(MDd|()HF`s?C=QDZ03vs0a;DmN& z_Cn5pQZZdD&fHN=`p;Qufn$j$ziIy}*@={anmWtadbHom?6P6$3Ku<8CS2==YEDyq zKUZv?ipA=J^7SOI_;5kbvE{m|?NgO3Q8Qh9>K( z35h-P40An;&DV8$+PrFlc>^%+mG9U7Q5&@L*RtM*mD}l!=mFLV*m~kCE9vV9QS#gn zFprf#j|+MAoHAqpcB^QWx!?XFsD(hgKo@Zf6vR&BScYf~sUy03`7MYZWYSdoRuoU= z92p_o-Fo}q27>{r1%^@nJZxKa+i#>HV;q0fClI>g7W+y*gS3>G>nZ4ao+!ceFWr4h zn+(zB-~h=QCJOm|sq6^eA3|2W@yOX96BtjOVqbnGJj(2{YAmnuRS-;C8R6C^#4k{u z3hy&wkMjlzB2i3f3|Ra%5})$St>g*09A8@A6@I~3q~waj3wyK_DzwbRYi_ZeFlO51 z@;V?1H5io}#VI|`4bwU-^{Fr|=9^=Zy-2MAKkbny#Z)Zu^V$8h>O*D_nG_e1avNq- z1}O*vnd|^)zF9)c(z~+dd+%NDrj@EwTyLsQNmQx2VtPWC9nomG_^IUNeS?&MrPT|1 z+0a(`v8fWsUTb$E`1?rQAQ|By0OIk{slFS`Jo7}hpTw7`vv-%ZT-%6T>r_gEik@mY z_8i&gl#COPs4BEOB!d)YUq@B%rngis&zxa2Df@~fJJt1g^N(9BbiWb~OvMcg5BpOF ziFJIW#FMy}`RKOmN{82#DBoe`eyMQeZa}Qqa>QeorA~XuIr9lc^i}Dn3KkZMh?+{i^b$#U^j8KgbHk<- zB2i_2WQb@75zl*R2ebKB;20%5L2UIv6drH>HA-DG-FfRSZLie+TXMwWFlMwA#oBbq zs?=X{vGd1>uT*mahlw~n_i7YoT@pEw=4sW3;Vs74E#T}V5Vpd6akBjyGbmx8`+ZP5 zp;;j_1Y2fX^}wa}DpbaY7rvnU&e?+`K%y7*Dtw=c}} z=VXG&IC+uo*NHN(UHNNuM?ZB$OXT8#r-vk_4x|k#&j1|NNYSQFD^OX3gx(LYFDp}7 zRn0>v1Ie3`*u~m$NVV+B7kHkV4p>l-&SW5qwh{XmT5|D$=RRtTfjUjU`XYtdP>_ z5q_<+%; zR&ZxyjwcU5jug6BYTJ|5K5ec|KiFxh{mRSA+mv;dbhCrsjOSzI=O-%9=k~Mzj_@Y) z#XfzX{My@jV6Js)Wy%%B)a%*hUt;sCGf|;FMX3!!5$JYrSekX!R>95IS7LiViEXUK zt4Ig^7r+j}7lJZn%Ek(EM}jw-Ur|9X;+A)F>?=beA5E`X?fSWKbg`x&MCnD&W*UlU zG-U3wx6^EREpDA0i@@opLQ|yQ9)DF=t=7$Z0``Kc%ohSkPoq?#kGSlE^tb9@v;C`~ z3ecqBDRuq(#SwYIB((jxi8ZD^t$ZPsDV)@_jZd*|a0?~9POTEkQq&0I=+r%_TD{BF zY9X#xZGGOSm!2UAmMh-<(=D>3%zm1}v}ATC4yKTS{&3XAPorT&Z-|RhU!RwzKn;jx zmozsx!II#zx5Lz|kNu^7 z3H#T+@VY= z;mBS@L&<4{6q#AkY;S-S!tr)PvbMnVQR_2u0tRz5sc3)XO|S=x+-|M~wWU5wB+;u`V)=bG%Jt)GeJO zzid3aA4}oL8_ga3^gEKA_p*7koyfo+uMKREthVa^ENY=3-z@Eu94lwwaO4ahN7u7! zsvK@aG%PGiY)aPoHWYl(NZdsWIMi;)`=YEg?0N0;^7EqQ)BNluM!mAVC+&5b?r$?ZpOjWo9(nHRaJ{m9Km zVuq+~uPJLHmI7iG`})XQ9aNU}Z|K<4PAw4TFNuzDZXThzvU99`2KePU=gC9O-%<&m z`cTU3O`%oS*3Lo|BEqU2iNs$CA&Xv(E|P ztNO6&pmVpb(A{6Dve;X(deX1ATaRQi)712z_Z^oCfcY-}h(YiiS$1okBrP&kA#>vf zpLD~SD-T!)&KxdU*Rc%MQ5mfpB}!enV4n97j+yGkLV&AZD38rTUMRlb<3DA?iVV{( zEX}8+ev_Y9r0rlqE$7U@Z+a_Hwif3d=(ehlG3l+$rLXCiPe~^mh{a=!=_kDXNaTGY za*V`uI!e$@WGvAeA|=e?9;OTns}YyHkKtyvB4$62qc|1gxHO*+^P{&MT<1o*TyO4Y z&l7UbJX-TZVuVuhRL$hJ@kMWjGYW4r;%`w0qNX`s0=1iq+F!sD95NA~aIa}K=M(O; z@IGZwjl{4ED`8gZ>rLRMWcZ_UKedbo^9rgB8j_UYE)l)_;Au-Wgv1<#E0#V$Sb2(4h<%EF&PM;I&axv18#JHqf zct|Hzq>-F=$}m(D>7RFI<69!X)bsW4J8thlaXS_Bj`tx$JNCd2Lm4c08 zMK?bokS?pASNSlXH?H0#`7o`kD+qGiZN8vHsH@A$UkJb7Hlq9$;c)jewHWFXY=wEg z7uY9n9~SA~S$+rkRZ-)dlm~UpP1I3B2Z})@*({sv{WsEh&$cP6A+ZO-r4EiZmcA^w zQ;(etV+q6O^U&mE>rKrq_8~-VU;yzDk$sZ=UpJ|er4Zzz;l#I&D=R<@k;xuc!9blG z1y`O_YB{OQ=TP0`=1KM+sYkvkxLpeKr4+uL!q$xy*41U^>#{4Czkn6Wlsz3l?c__J zqw|p#`F5feIroPo<)9AJwx$NlcNUDJs-StGd>ff;?5k*iYIXfm`77X@jEQO(in)`T z=ur`4TK*FmQ&5-_vSdEU9X+5|j5S$L0vx_YZ5t2appB#l! zT!*}H=}12GMaxr#wOjz&UT3jfS}kuQ1CoVuVZS@(cm}t2=)UMXR3aErGM4~}xcF<( zeGX-6+Fu-C=f`4vmhs*p`s$`ouNfpwL@G{ovdloKpLW!*{p@Ij4prK!u?9&G%^@;C z&iPy8Q;r^{dPd09&-231N6&Pss9(k#-fqPA0vvOjHE9G(U|+|33z-1WyN08kc!9$q`Kb_-c|@uz z)jje~zVAyFO3x`FW^48Me+cZm=`UIbVstTeXn1ZIsNk8SpZR=;#xKioReQO5G(B)p z?}>dz55lZ*rE5%W;okMM4O=Q13 z5xxE^_m z@n$uL$TPEUgpq*hCp5*ym9Z|a81WzQ`2P>Se2osE_{qhW9}jTxMZ0=2U%F@R^m<)N zFYP>WemNyc&->VuXu@T3+)N*P_gAv`CC4nEU>}8CtNhBt#{{j(SXCnK`IFWOd6l#J zC>5_4uo^2mRF-8)Vb?_RZbC83%*Ha6NyVQNuc!V08Uq%Erj>Q5M9XHQd?5KPrUlhE z{^{9xKac-ozpkkZwbkk@mgQkwt0dAkNG{X5K>NESQD%F^4=ZGz>21cEj~+jaQt8*d z{<0`f)JCDg*h2N`M`T@O+f(^WN0ZOgYA%zYstWPO6NfI`^0dnN^czGMP{!=@qs5%M zVRENbPwp~7PfY?xD$ZF?>~oACMMadHd#%htMrXKUM+~rk`mHfRw4{2OW&5L2^-gk+ z^T67`^co4#OT$=L&4KXNyKa{A&V12PZidfA@($K&r@awAh%NkVJ@8(-*iKR4JOT5f zb|k`pO2&T0``y8VUhqEU_~_&YCRiAjdxQ~DaluM4R0Pn7ZBpB;a8{)Ann%l=1w z#64dFf58J-BePjj7)WmLfw7G~6OLB%k+Hob($zN#kLk!{``@Mu0HiC=c=+teC*w=l z`uZ!OLgPI$2hkcz9ah7~S)pfyo~Y={Fwn{QjmbIVvi-VHdVrmJeyLfYY7(?nMbhth z?WukY&i3O4g*UnD`*ZSBN6rFIdjn7HTbjw;mxY(M$7p+~=xeW6_E0bHz_3p1>LTm* z;;=L4Qh3*ojIkfZjuo|i9WLP9s?~x|##2QFWcWw?46l!V>~nl+^Xj7VkJyh#8Bd)l ztAB|I{>fRs$y0ms84rzpXB>NS#^GC9 z)K|u_mT~Ozy=h+MFMpkZp3W3Zu_Z5&JCjd(ebW{`Prg(3)FF(*cLNS`f;2J?4`1*u zqEEuRXECEv*Js3+$~rrf?R#rv8i2b7N*mjI%m+e(V}-G|a6cDJnO`C)*b6*!;La1R zgit7lXDu)g5>;h)cXhOjXp|$CfO^dd1(F+=jEn1>k(=Fb?gJN zrI%iD=Tt2gOdwf1LjUL;r&et> zz4dF6qLiqSNEff`(`PigdrYc!nsgLJniTQaIEc^xq`&{HqyOt}s=?PbG6_W|Xxz`ez6thX8grGl{w-`@RAP*!83r`!ME0~R(G zz>d~{9j$7^MRHo}yqoDE$>XNEIr_61`*nl8=R+F~#-NguNz$DdQ>yRuw2m1jcjkSM z^Vgj!rB~=Zdp-QoiTMw*`;9m<$YFXu*00(u&rta3qJ}!##66z?s))!}*FuAun*qHK z7PLn(Udmpi`4FzL@i@;M@Z=5o#!%msN{?O7JRvikx$9Lej#YwqdVR=x)aMU~_FBRO zf^!ELPmSS(-~-|Pke{bx)5>h^iqQ^{i0lfT;6uJcz%KV_Zg_t0eZwSG}W%u0-}0 zj#W-Nyy)ae41IRe`YI)(OF1_r(@iq-8g-&tgTD_qhUN~*PH*mU0t!crdMsp-N*xFu z9Y&){4RZeH2Wp(ousfH@D0@Wp@OmRr4zgL(M=&DgP?k8Tph6CLk?|EQBL6DHoAr^E zxq$u!#})J?yMR6%R@3twU?N1T1uQlHCwy#GCe1+zp>Q49T`r_ir-nc7difuzWv&Kl z&Ykj6);>TRAy;5m0{9YGwZJL2!z zX*D#O^8%PQg?_b;llu*%V z?DLf>?|czRe?w{=jlSog-j_=uyw$#*E)slbszn| zt<#4uJJmWJ*n6FtTa5T8%#}OI%5>xWoChv{sSh(e-*kFGO|QbQ(ty^KiH3{?9DvG< z%HvODp}Vlq5;a;Z)8*}Ne_{BIgDb%SJYV~22|5?Gp1l32_xS>01Zm`z=-I;&_fI}rfch{3ob*E0CwpnLJr1W3EvNk#6jAcu zTTLRbo)z8}m266s3wK2ZazJ4|a`~q)JWZ9B&&&t^gm+XtS#5v>lxsWP?-}5EXox{Z zjH=Q8!%2q5!Dw68b`DqP5^$x6=-N(<)YxyCTRDFqdZ%~xK()k#59jOwYg&bgwgy#8 zfV|8~^HOF`Lsb(bl%>fpvW(()A=v2;S#NUQz=fPGz>x!TG>j;E%xS1@_%vXWVs=_t zdV`FID$~zUUUfq;!%r$Tp&HNUo-c6!N6doSpMin;)%#}&`)4H_ABmd$)@{M?zPaaX z&(g?3oSV$C{-rm|(NXb(iYME-!>45Db*F((&RYKV;z*2L;u%v&md6l3+I>!0+PmRljcSf45 zvH0l{Kzzj9Z@0dy^ecCYOm~*Gpn`Yot?u|$xhe^1tZ3ijGsgzatIEu?=p)Bjno}yA z3RVGd!;jru;CC*THR0k>Ydf8_e?HdjJcmm^Do?2DEc3Qu=DzeF6|fzNzRJqa>QN5A zrO|>0Tz>k*`xE)c6W^bx?^Sxp9C`o5@6~+Qj>zio{`^*MSPVfZ(`77%sgo&R++=?Tts;+0 z%p!@;Darik7y2V9>azK!EmiYPdAIM7?;qqAn`%#POJ`>KT5#MCdz{P^`xz_%X9Sd#*E#cCMfcY|2Wji>N!UfLj|4bKwUbc7LmTTpx!VKQ0x zwEs0=&GL(qGN9`4JAb3hEu9L^j&NtW^rXU?SHdZNff2bdD)y56cSb}gGC@C#E#JSjh=oLsf~CN9dFG7sj!F|rEfJ&BM@hZ9UmGI9bQ zF20v4N0wzC6v(9-O8BdE23S0Y%dvp`&J^d35+4~-TkM^yi#F~qMWh6Tcwl zs;kj{rqjjIDIcBwqVzXG0qO4#r8l&bEUNU`5;neHEDA?xEd7HX`V7|r&!L$*bDoJrlhSC!`M2R-t*=pW92 z9HH1oSCFM59tAnkL#Ga&2{3s0;(BkRFBN>LAm?ZUEF`jsecc?5)EmHXe58MFtHp!1 za#qNk6*Oo0Bg4)4k~xVqN~xGERQb=FNZ&`Q$4p4w{`51P4+#O9RZQ4Wdb^hQ>dS%( z34mIo96TFT$z`(h->fkNZWc!=(Min|AGyXg>ZrbEdz9eJ00fH$s4<4jz9KpzVTF~tU%tRec|oN1(~@Qxcis6t9)C>VX4s= z_X5d<>t9?NEJk&``>uD4r>J9T31l7(&5bj9@2`431CRDKi^`0I@{5|+Z8d&o9w!nz zJ)rBO0&{cK8?m>#%}?mn)6zSm{*!}U1mCOpnM-A)v3K$%x-fdKHDoKd;Wv#%BH^BgWjj4%QF$`y#Vqe}fggKuE`$0`n6J7*Bm-JT);dyv5vT#DByK zG`g0kXY=R>pDJSIvb z)0Pe6md>gVMKk86BcvW{h{`{c_7Q$gIQ-DA~Mbc&sJ@>dAPjGx3%BK1bkEU5z%&$C06%etvczH5f`;7J&x-k zoaf9F>Y(VJh}I&3tFahMW^mbSJa0O~PJbSH`nTk@?Hz9~7T95Gc^ec16g z;fl!EE;aPwg?Y^B;#yjDe!_*Bb~^bv!5-Z*^|@D#3pjH7*=K)&f9)|jckFtCQ(1k> zZesS)#WZ|m)W1m*CU)WCmgY&5jrv1Vnp*9FB!SGcM{@pPY+YIAiU{MeKZ2&);`*Fj z&%QNNt${LSL_#jam$=zj>;PQER{S!JB_DFVEY2EBM*3$C?Ham;^>wQvL?pSppjM*G zTcu=^9b27^k6fE7lu!6HFH-wE2Avlj#uA)a0B>}CmlP9suY^y~iFieFZwvdO=>>JW z73S-bCpA_|oA#h=Yeu|-c9IWCGaYZ|5eRL*S)PhcO~#~O%cUbku!Z3N0_8_=VR}q` z8S?U)ugYsjRdhDLw0CAtB|qU@q4bu%R0yzRLj zphTWjpfKVGWU@W~G`>^gB|p9H7!9gG5SQ+F`vE82scEt*&DUe^u%zG!gtjL~UdGBw z9F5+UyuPa7&@SKhq0fikjI@;R=SW+6`j;&V-l9dGkPKEH>;l>4yPB%#JacFHevDAK z{cvTM@85596|MtK%8&ZiF54)CX6@Ym`;8}t$aVBXbECJ3uzavf9bjKuIRaP2RT1Hg z{AZK*D|8x6Q6tDN@4nRg-My5uE8KVEdcXUFybHPS8hXF`p}hN4ymX;28XhIqITD5Z zZg=vAeRT3PYm}gH`PxHo4m}#hAn7s6%05kM`xmj24H`iaR1OV-f4=>ko4Z4p_(OZ> zYO{XJi)F1KjPQ|g0hengpA>@G*P#D0d0W0F@>6Omf3i6*jl2w&`WS}zN^4O)`{Z(|%UaaP zC4Ib=unKj}V#WJ2;eR$4sVi_<7 z;`fPGLuU15_NY}GWX4w)Gvn{d>`cKLYag1O&Y*u0$GS4O1N<=~{#c_QJD*iEQ{3+_=5)mKaYvl+0~MJc-Y;;SYe+oT zhP=w~{^&sp4Ymf_eJ=?->mPu>eLqNlJqtC6v-`Ja=2dL*L;~}X; z@shdfoxag;EPI3^$!1wk$@;=jGT6trcIf8v?L8Qa-(D&*S>Y`Z&(CZfK1#Lx5mNFM z(sSRN<>}b-K68|Gi_lk+5lBYUq)FUHmg0*oC51jbNeOsO27~ok~3XGgbaT-k zgx7P_HLdeCM>v^dBxjb?$8}T4A@o06)hek(U_s2@`BX(8Se=4y_=?YE#NoBXTa1&V zD)5yNfqWi+i_Cc;XCC{RxvyLV{zUJe9PGP=-5y;5=hcJ&hT?_FxBEVhIX?4^ey=7DM8B{< zGf*|T_0Z1!KE=quTyd7k%BM67qz;V{I@%aeBzR`ts=o+=eC;r^jiKFpztYI^A4S5` zD841~smFhq>)GSB$37T|kpWE>2glGea?S2Wx3;7OKpk8Qk0lU`9XFEW1FL?<8Zj2H zWKL_Y5aLNbDp~7AUlI#cH?JNlq%1T|G7_Z|Mr{x#}OTq zV~<1Tb{-?gtGwl7~o zPqyYzZsUpb$dnWRFFKFg)$>#qSoM2@{5R>9|6x zp)xu0O9Z#ZUm&(71uZoV7NT3Hh_37r{=QTQv?NuJ+9|Gu=FX?Q+9~eh!rdukFq-BX zOMXQYHTPB;@pouNF#TYCU#M;3c!BDjOopFHT+i3mIIr$;!J50Nd#uzw4|+aI>R#y4 z^K9MsQFlRv#nVuoY^khi;*)+-Qf)?}_rl}jv}`H~wG){$s>SseW*h~u-yHEJ3TFVq z;%C`ofg8Yz)6tG&vd~~eq|?z#^J7%x$U8Nc7>PUC#ucjo6iSu}GpvweOo+ox5--ax zIEG`c1EgF7N{Hk>c(T6bYq|6Lj>hK8*#A`kNy>7-0Rz@oRKBuS{i1n*3IrU%VEh9E z<{L_4nQVXKKh?rg6Ekl3m&7$(0N2Mz{Fr`|7X@NdGl%j23%50Q0J6)t=vbgPZuH^P z0&@*(tlIuQ1@gjw$j+Gbe@nhnRzw^Ut|F-?)WoYwgpdv@?M(hQsIYcLRYn~5KH00S|1r*LQO7_rykMfuY=t4;ID-Y>& zbDgcSsqVCQDf;cwBNB^nto01)h@%N=kyeF>-7BEGlDiY?Q~XJzTb~?%82dK7*61F% zvm%0tO!OP{J^1-^xM3i3=u-2$n7SNlE{U;EIoQdkG1#IbE`G@TwnAy0AMixxS4US) zrOU8DMq;@jxnhHi#82d!QCX7|JM@`;)x!>5z(-mBV4N(k_$;Ys9`&5dj9OERYQ7sX z66Cedt!KB?GgYxw{DrL&c&*B#Q!;p1i=lb~BWIs-Jd1z>6xE?O>5%&!R4E{9z&p=U z1MgeHJ19Nis_zLfo3r;qk+TGLMy2yJ0khDXCckh#TRCcc(M@z~RhfJ@Ap6~_*I*Hx zqby^0AGPhnAH!|lA>X@WW3z6uo2ToswFowPZ0N2Qjj`|USG%UOR9dK)7Jf&K*C4kl{l3J)%_oBx^OGV^YiX^v63fLduLE!v^7um{aQ(-k{qRUS0yeT`j z*CAR`FI(J~=jHZRFEPb5U!mVaoK;ptIn?kCp)GQ-4i?KIUYOJPTVzfPIgP-=)ql;r z9A!y_O$5Jnu%&{KLi;@~}U{zPZ7%LMYC zek62?B=V#qc^;G?c~=8RCVo-56s`bib2H_zw@Z=L3r?$A-F{Em7cVFD)!oT-3pu$% ztbvN;!6>bEPNOsC^dfV5NS#9pz*c^l%}Oge%7hKfqf7R!?<-)glpQVS-Bza5o}}L? z-qK_i6d+}Om<5)z^EEw7D@XMHc8!QogWP%>d%v44Z60=Xo8x-FtB`lE^Dey8h(D*P zJxquaL`Ew?q)`bXjUnfBG|$8}$NxR2)VLy(QsW@r{4L@zLuVYNauG%Kzk>c#N)TzA ztUkz;T3PS^LwBm1j5AvQS1CaHqYS3e?eOv5@7|Di6}+?mYWLAKxOJC42KHZuH92{t7z&m*`)`N|;{Lk*>iO5;jXjv@2?9_9E?DBYGPpeVH@-;U70au;=tK)vp9??(Ggs@0MK5 zA}H@p7KP2VRjai)22RTkJf)I@ykcE}e%jUH%6@~4GWSfBScY^1 z9flC9}Jfu^t*BM@+*Dt=r|d_#o4(!ek)&8sSXyJP84 z4=^A-Olr&ynMk?Q00MzVg01YeVJL%DhyOI`xVdc+N)5b>MEI_HbtcVL6WTfy8s zv!Hy9ZzoexigDoCM-^j3w-T~-K&gsF2Bxf_YZi$5eUMzEet(nq zqePhY9d)(y#$r*acp7>mE=hmWZ!3ON?GvtA5+xV#T?#YEU?luavG-lT&Pa?DR0Q>s zb(uqZcvl1ri^&N_4praQp*tbXYe)lie-aD>CB#Ff$kn7Xw@?L+S%9G=%#{MJ4$?@B z<3=gO;bcKsS{NiMNzvT|d1Vcf{mTlL`F7*C5i->+*;MF?q?3_+*FZk#+ZEg7GdY`H z>0+H@kWc&rgR-x{?5FAn`oYhfR#SXI zHo4hMJbsBigTCcw2vEUV2(d4Ldldgr;&ZMnGH&)_mzVq`0k@96WmG6fI6{;NJlwK9d^e zf@=ju;-uu41P@|F?96JS>tqBZm}Z*h4q#LzjOsOcrg%BlyT5F>EYCF>{J<3$?(J*D zg&A9=w89Dp=tD^XOuV^^FN=NK$l>JMcp>|>m{rMTX)JwE7H|nUXgxCupWu%osKMd% z@!w0MYKmR_puZutq{JdVS9eneRK8}pur%gYZbH6|ddRoLb~m*$Zn=9(n$3vCDeM6Wv&RV;ESa0 zbn(SvU~i)eXwjhaS8bB+3xQBR+H$^Bc0I_T0joev#v@`+A)o2`b6dSUr+(&7Ee_{h zjo<#VD#;RGqSEu;(wW)n{D~LYX?+SAMe(gN8Cwy@f-)Cup}!R21?QKpRey(0E6al7 zjqI6tXXcKXPC8G(_L-=^Gh3Ibr6`(kkij8^pj2|gn4HVp4Pi#_4dGGQ5T^evlbJLL ztBpEpM(Ew$zs}OTL}9riRmwM3UqTTukGJ!qY0cry#>@uS5}tw zZj*xq0`_}*C97U;n}s=T{sQPa_-d%n!@aA1M|hA&`P^IYTK{@|>7!5fYO+7o?KS{fyGjJB_J*}}gR zC+pV_V-K;e_2Y=!iU;}(!jx;SL%o8Ju&8i?u?g4?w6@5cdnmrGs4` z8DxMa6>W0*ZEP{M$+>M*+qJJB&qh*;m{C+Nm9f>;F%soR%IeKGy3%LxvXRFllGE>@ zM1^@MIW~kklE)KxEX${qeWNIJab8|}WY_xz$$MUr#PuQTMoE+zQd_0Dar;|c-G%)g zNK~@H#AcHW%3KgM0Xg0TZHzYoh^^?znh5++oCILVmt^V<#*UzGtp)@&4=Od|63Lr^ z0N4T46p;IqUY9R!<}tp7D)P>pK`wBf&1MI{OM*AX;+t6!=2i{Ewpqz})yew2+vt5L zd3~Z1btFcCd#w3EEKAna{)1h9Bk>}06W%Ge z&zTpc#^R-12{wYo0r;~08s26DXOE3E8%AL2Gv|r=v{oDPbbzSr5LKI8?dXGDU4P4G zPw2NR2{v5iH@68FfdQc?1fm%!QJoZYtblJnZ= zyT}Eq@0iR54lt?CJ6uY+Gh*HO#*%vgUUJ?&ls)K`-3LwfFw0nSt3X%QZ=)}H&H75k zAek?2-`lmX(0cM2!Q=4$wyV&yoRx0O@)vl*`QVA7yiM$n9I&nna)L!d@yuQ7-Jxwm zx0w3#^mFh>`ce*>_#NGl)4MVSa~-RtQuI?|s07ThcR^)Y-9}<1SFG?aFo|AI>7y({ zGBZaZ+_-cOyNE{>`q4M_qe@}GN9ada>qpi7c{EZ#8mS-E3gca`AC>Dzjrl7iX@fDA zvpwX6Bd4wdPqVvgZ=d8fiD3#XPDoY-co3V=$D?F86I|u@t2tz5Wo1aB#h#V1;t2IZ zI6_jt6QNovP{b0&ce05r4o3W5zL08bM*EE=9Gi-7R}q2~;o;~|Apvdstn2*Y=Z*L# zz+zn+2-o=|g;L;oKxZBw4jYYO8cK$u>TM}9N0}UMKyaMMtui@?2G=uA6YX$EU@ke6 z6~{1`Nd%lB!&q`Bg>tAgwr$z83I!H=T|hGxc;@k3@vK#QNH{09_?{70y<~p~pNlzg zj5SCsMeG=`*e|l@g5B+?sX%X}niY*2y`SR6s(Lop>>?f?XtBTkhCne?wa57}?*%$~ z<<1pL0N1h#j3sNN<<)JfPk)!ab@grPdMDS~8Uv>pG?rWfsWnr>fu*8`BMWN!a)FNT zEWv&SE^9#$0Wl%|i3(t6b8%{boke8|U~MUt|5D#V!p%HvsisuDRfGUS}e2)x-4 zosm+`t$0n%h%z4JzEsBgpSv&RXb71g^L^WftCjU|2y(+TzQ|Cr^n=!+jpg0CJIRtS zqv=2~0A~%EG-p)yJIwir7@d;WWsQyT`vtbI32YU;U)gqAFKC_~1e!PPP#s_SW^YLU zU0An9_g%X8J2eXxyj%4bnX5Lx_9-STmT34k^dviCP(8{zXVIb5d?VLkVadT+Y zV~N&USBXo+x#HY_>RY=wtdq6-kihM$((c;Gzev0I8PG012eivI?f!ytxm{N6ep}il zF(AH*%iTsJloP%nb{NLD4J>Y%8tWQ>W&1_^x8CcP1bZd1!(s&VYyNjkx4AQU&ESx| z8A~{70jTL6e3q;wg*QyIu!S2B9TfT_e#b9eM}Nk|`jwn#&w#a;h@aP_590%LO?N8sJP)8#<`&Yzl*)dyKjsC~D0=}sM1Vlf zI&trMJBg16y0xuycZrEXG;1~9a_(Z~7*B0t@$}oMMN15;VvX+GFGW<)e80W>O_VSX zd-8?gT*2sWv%s{))sm9yO0X9w?VG?qS06zv8SxIHqw6(PwHbQ#;T~G&61m$?_m<@~ zLgc<73+ILHOsg7@>p$VeBgBqoB6CjV=QmJbEe?lDKtA^Iv5egfrL5Y-!5T)g*{22P zSJ+I;$;1?gjW!0 zhHBWk2@r5*LR3INcYZwhoTcAq<4?Wkvg4=UMZV9Y6+ZLk6S40*|2;S^J8&$+8rW$^ z8II`kBDWu`_2);!3UxJLE_t1F)v;01P+r8h|HO%Xj4GHoZ`%Gz$qro-M^R_&Yjjqj z;Xf%qiSmj*3ezS?B>1ySS-Gb>PrjnzkG|jaw<+-qto=lqQ{r2Av$6OnL`e9zeAo;` z;2IdKZ4iJ(i+H-)=o{Lv12Z+cQl_B)2@|kN0{gPa3hc~ebi3yb5fWKox-~lv8ByvXu z9Y9B*GnHs`g2|@Cu=5vzu1t5zh`-DDpwUtmUkM#g=J=7`?R=417GFixvF?7xlD8QK zh6|WIbFid6n@U!-kU2Fl_cC^%Sa%r~Q9$nZ42L*8OMz87O_Lg5|8 zBIP%DGBU|GaKx1grDUS8H=s#57JI>GwxW3tIKRl&?+wK~;M#;Adr1w)8Ia41@KW(2 z_q#8D!1r{ig`eCC)aE~vGT@jD^$)zq`){(iD`L9ET@g(L?uuOFuJ}9s^~&XtT5b0E zR2;mUh24w3plV)eWcM8P?oruuuH~KU=6H)+MY?wtv!#m5DJJSpQFm&EF|2ZoQAlj4GF1 zVQrG*e6j8~xk7T0>@Ufw!IiSn5bC-Y|L%}cw^4C6JI!F3>Q7D!#uL4JvnG8kgG`+t zjhIDc_LJKbPrg*~s6}Ophf)>RFvOucie4*A z#1#8ML;$sj(m&D9L0im&{xCM9#n*!Q_ICDoScKkF&KP9>wou>X*w?Yv5AZZET+$7pYF_91@Yj7#1F* zjGAb#e~P#BN6*Na7UPKl!1x;L=e3ZkW%4Dyk~_q2@|%3kDJG{2eO7P92l5gg;v(md zeh}Uru}`&U4*w;RUskS(2!<|Bkc_KB0-Ee2h`;;C{u-l zWTQrEtyL-{gwQjwTZeZ?%bfG*l7}}-)mtpyi{vf+y-)CejgB=z8TCdCu^aE-oUWW0 zMzWNySTTXd&E|Q_1t3E9bx65}b$H0y;Jd!n&du3r*@?bWf_l(Jvks4$#;RB$PILx`j0&$Gkp zg}?@q_e&X{GTo;ZPm^n*C_lc5tJvTAnv1`|g}L~8{zeMRH;eLazd5D0>O-9Hlv#d- z%)QcXr^X5qB4_i>R`tz9T-v>cGw^%#Oz=Q{?eXuyMU{%f=VEaWFo(!>PWjlSQcN-G zs{9_xvqx{sDFP*Xz^zh#?e2F$tqiEOMBxTY=U4PbP)j|?`SL_eSU}|-_V%!pEEt91 z4@1>ukFq0mrLefpS_p%mx%>6w$~rM?7ySuAHQ=fqX?Ty-yyP@$ZN{=yEl9V z^LhlK`7~npVLO6G6e`A9*xH?|q||gr920xdt5jjTOb_r)6+T3f$G>_u>AYt1tbMdx zJ;1Ztv2xYPRa5QRf!^}dvN(@%clzd(s@2V>7?R9+7FW(^NU9@M2USo2@FEI-SI%4* zPw2R>fBc;#{X_+(H+xoAh3CEp4Z-ZRnIM*Ip4-E5isZ5chgF*Z};RDIsqLg zP*_#$(r>T+h*}NJ0Du9=Vz}7~pcLt!>QK~3!An-Cyuz&blA0;{7v7kXM|qLKW~b1M zRJ)Xy|I9UN%vQUMN});grTCuc!0D+%0g@E?WUZ-!?b7M2Jh$u~-a!WYI+MY(TRKyP z@<0k}d{FZ1GMPEZnbHf3{Hi*Cvn6Lfp&<5yZ;@N<0~%!^vF}j?IdiAI;BAG)Ya(-U zK{Q<8SYTH%2cl2;0i~@mpP`r-{HTAW%toYtat!I;@%^>};a$--*cBDL!1zx_0loIh zplYhg0dAAgq`Lhp+9WR4+Mi$nAV`4ac_(Bjz1Y)3f1rY2retUW9#Z8XlyyM-r^Oz< z^7d@3#8z3WuL(ogxVFc>iuAeP{x+0NHF7_Vh!`6E36S}b%9e3LytBYF)GE}|UIxHv zRJQJ)u|UiXYHTN@OY6;pedR58&Dz(%A}JTjRG-le6Y7<-WNNHma3Q5rgD0;lNsU!f zZ)&Xe!XF!20p-a{OPrc{?Pu6pNFNBD#(&DZwtG|u?;;ml*O3S(x|cU8S+%6Z{7imy zF;yn|nyeFXcrh1;Xi%BH&BaA>`LKFgESHa{%M!U1Un+BPsaz@_w#8*~DPe-<;$d=G z2~AHe788;DXD+Ughbq`*@d&vT4nS`L2Dl&AL zY|7^13G!5!B)x+yliku>d<{=?k@5t6&jXzCEjlzo2yo$`$1hDacffj3L*gZ3$rJYi zBc;`m(~Fc=N94U&2CdG0JW(1Hcd=B82=EGTRU82p(@k8TjLte~eal{&-;ERAe*4R0 zj}e?QR6d{FF1rce9m>i&k|PoHIy(1M>*#>CQAnKYjcc>(U+I60CF|*nrvutyEKzwJ zL=R-dkIQ(nx}Zwdj@l<&Jy5B4Z-2s~pqs=i)blJ^Uqdon`zpLB)i5^Lb2Rt7CVC-K z!1>ws6~BM6X!K>Y8|(=bW0_*!JA-P}F@+w#Jk`Ek3lcH_Z$3oW<@nK;SV-!zCl83e z35hY}_0M}Q3xem}tUXmP*D3^&r9P5(S}vR?OTD&;r9R_1y0g|1OPnV^1eeL~1vSK0 zA8mzZ-}ZwTsqnArCD+F3ra)l)h>|FkbueqtSS+3cIEqMSsws9m+lmYcnbU}?^g74D zBw6syUcmCy;1Q>DYgVOoujoZPjtVjx@o{{MEby^fi3PR6a+@#+G4$B)plRbn=vz$| zSq8btVkB=cMF~$?vom$`2d}m+F1Ne^|)U)L$!)uG!mjI%%-<4l^UID9;yDD zA8RGZ?{~R?OQe{0@+%3O_w7%>T4A#8m$!Sw(j`Iv&K^OHCohtk9%afl@GCLDf}cGM zo+I8d+5JG%xiZaDZ~czgRWW#sPxs;-yUILb}7pVY6FSE1B@0=*Ys2#?<1 zl-r)--+rqM%&fA+N>+^dan)*j-A+ADjt;41cEJ-MA)R*!Yf`l1(d>57DzxKMp&gg4 z)bFv-jyZ48wjV`hLmrW z!x*YJN7M4DA{cf+Wfc?t@&IIjOeGwAaYpPNcT)`Lcmh(Veh^$WVbIV(lVSqx-~I)# ziAvi!9VqvbAH^P|WF{y`5v=l33)DZA2;Q4f9<;+_l!rg7h*^j<4Kc9;$a>F|CGNqb zD0l)LKibqrGHI14BGM-*~@hedtAC_Ky|!bz%Exm4iUCpN-`m6xY+EVdCn}> zgud7ONYJ`s>5=k)qT57^QUj&nN7()}Wp3w|^xFQ;*ap9K9yIpb?KKmlAGgo3su546D_Ti-V_!g#8=FZlQzkx)lQ zMOG;ML~a3_3*`B4c^cgp6F<;?Z9ikqA7ReX`}8%Q?aN_*Us!gB;^QQxi0-4n|77}t zBDJz<=281DNP{&M%mX7+F0tLpnwPklf4>N`W%x0L#(&uE%?*#4DU-`$kR)->C#sbA|~RZY%?*-jU^ zo$lBAs(Q60`zmpz*U0I*kqc?$x@((ecH3dMks?ZTW?Sjwwi0MvrN{486}e5o5@=nk z9?$k36Xq@44BXG!kZz%CzHZ@&y+g|d&YvjZt}9jWw3&TcFRmBBe<52<{ZU6!s@vcC zkPYha302-kl>(XLcHFJ$o;||c(Cu#kRtgzk{io1cKm6sXzU8mfm1lum{_p$5M= z1{mL$oBy8dpSSH;uI5$8llWry`U@76SPzP(Op$q3Z=a-c7gdBl-M=T#;wqa_uaGzm zy}mSO6d8wsxXAULO`Rqx>RA2dz&gO&R&&duZs9i3Y&ve_yB4>^eksjyK(uUOYXTjI+o{ZmtNf_f zeFp8Eg|)FXw$Puy@Cj<-)X>@h=kZ8m)~I6sl8M^A;H=Fd@+AF)hhLI4fK(fOV#hCP ztBGx>4sWq8k3KDt_s6>S^@(LJYMU5KRfk`U{#F@;JFPEc!Ax|(Z|a7en`A3szo(LZ zvExN;r^Pl*Pp{14lROW`j`wdnE4Jab^s-KKAMW$9Oi|l;xXh=2+bQn}KlHa<6x-0| zEXeLFQZ5+F;9o69r&#JXl>_mX&aQoDB-`$ZW%8d>ZnonNIbYWu@a%nn*P7^uOJ4Zp zWir%J0*A(phfTyErY!D#ExqS6v=$YSPPX}MS?iC=RQJ6y0}sHKt-EEkT#N{D%6xo{^|LX=y} zmvZ?}c$7bF5nG10-wC{pScY@VW2rVL2yvDtXC!a$f%Vv9&Zkf^5-G^OiI8(QkhcaY z1u~&Pv$(SdlC2f+J2!CCLy)w>pH8z)ilRbadGtk_2;`Yck8ZET_URFU_)$eegDa?y zGnh~wte|Tdr-45(kt-WO#8m@G1=+e+nD8^XvVZr7Uh+hVW*>3ChYE@sLFW$9W5{%R9~L z*@4Q=t+%%v!b{h@VQ(k!mu0BwVTEc&DBwq6JN`n&!Y1)sB4Bap9;>`KXFiQ54Akg` zeaT;C9uJQ5`y(U!@x=+nVqX+(dtZAk#jGWQTgo;7%`WB?Jj#29cCL%D&1e8)BnmObFm)>x{NOl#*r55o9_EjTA81!5_c zU?H};Ju;g{h??+4_gXgw!*51I>DOI2S<|_Xyr`u6?(qJ(`^X=Z9A7;2eSDx6{gyV8 z!2&L0?OdAM%6FA-q=mqojqLM7?V0|j$@Uqysn}NOoAfFD2SSDEtL8VK;mH8rIJ-d~ zH>?HixA>qJIbxJI_v^Tmxo63hM0T__X&>++mCaO#3>7&?_+Ak2KeCP@-w?!m9AU<; zd`!RlUGI1E60aR)4Kti9Si6@F!N$Ri=tT4v}n*hec+CumQy;>BvAZvq6F>O35|OPnp>ue)q%7 zhEjei%m%V#jnw&d*ZA{p>9n7QF>$`ajO5A_6ZH5l6#^+EyoDKF7U4$HWT^33cZ@^> z5kcfUs3ML>rUP0Y*x*Zo1uP)}#wU+`-su0nQTf^wqs{o*e=0t6O6w(16F0GJ%T`I# z7(~Ta(t1VDQGB=vyba%nJZ*VX}zbXKR@wa$ga}*V9$#Myijn2yp{C3 zVxGL(h);~(OA1ISqolWZenLD@}J(j`3(s}J3dKf?B5wfa#4ywmMIC)wN@GSEd2nznDdS#JDsjX5dc zOC=i){Gf!P6WhIbJC~buIPV)$)(BPm+j{{9CkgOY-Ctk=f*ma?#EV3 zXkke5t%p(#!qa9_4Z1{w-Vfn)`Oj)nVdTd^aB@P$|G_UfUZgm~r{$|ET$iD-{k(l^ z18$?70^>`eKpnS}AfPcD!>=UA`l9c^R2OmFS2Sqe8!%_&nG;dL{f7FGH-ZH-0t{p? zEyvb}e5lu<)S*ClJ>AEhb1LnCzoj|w^tO?EaAKh166nkI6cO|mXSYUvEBP(vcLcvd zeyfGvz`|L5BIl#YI~Pq(Q)cdGnYrDWxu3Sa3{`BgkNs89xKzTpHiSAdCJ>1J)ryyi z&5;R8h$j!#m0C;0if8>qcpM)XGd`JO&!aeLI91o@tDb`zeau=Ggk<~%3LAb9`}+YDEqIqey~E~M*Hyd1$iCoN{9pY zGTvk?YrfdV_NuE;9a@Rh)WKq`x zJd-(o{P=V7$M-_j3%(bVwSFTe7Bchsju+%H*)DZt{j+jc#d$QoH&l5e_A(tdk5#?l zd!b{CD$1cq2}zEVtw^}FUKRa?2Pao#om^4$yV**X_O2v4|HKOBTy;V(qNCi8=UkoB zdUVW59}YUSgafIJrSceo{9ADN{4FOkK(IeJ45(oUR7_4d?e{&;_v`~X^Ire&|NXuH_x68paQ=wS@pL`_N!quV<-LsMy_DsR)*agF z_>?%7w{XEtHLj6b+0)mJvR^X>Wgn1V$f|gs>ji0Ytb52bI~0YVVsF%T6i*Bk_)taI z>r78PAibp`y?}fny{3OKegw*H&XUv;>5xdqph9(I(a;-!Vg>?3!_NRs3ps*Lfjw)l@L zyR(l}jj7m=w|>XewWn0Akk;J9lSWmK##YpNSI4rE}Fg{;H7PWG2`)t{d^>Zj? z6-#FO)&P~UpweJTiy@^Wx0opLJ>aY6_cMqO^$n(ZuWF*~} zw5tKrPORsBTYbbe=G)362)!f*bsI;YIkrG}|9-F~+}iImxcC*LBDA}S)Z>?Y@a+uT zRiAzr?q9g&CPxbXpBd{l6Tm|ra^=9?Tn|sV?ahbo!mU7m1ZmasvsWIxi(}G?Uos^U zD$t1hQX^tauk><6h^{sywimi+E!--E13Jn(?Z-7<8+c8)vJ3f5=0)Mi#JvxS!Je`s zw@c}eXY48{Vo%bZF-qhOj`d~3(1m*Qq=wip=5{SB#TJVpDAwr>(}zfX#o`Y%W7sh52pW2+41a`v_C!*G7NR z^i$UEKz&DzKE4SxTFW8ZgXQ7h0(TVcdXKpgq;l)XohBJo~|WkkMEj1zG3z#q=#SBf(sUp_}^6z+IZ;4J45zo zXioUjwKv8c@0~H+pX{Ast>|>){@r01mZ_t)&I)(=@P>n&gKPH@r$=$K0vN?;b?v)>PM+~_KrIRHu*1a;O3+8V z2Q~$D-(dvVNM-{rcOXcF^#i4K?Kv?WcscWF)F_PVaW)qbQ_&7hRgSbTVOpCqsq5mL z3yo-Apnq4=(46Epxw|Uca3z?ET{N!IfXa(E3>1x@oL*z{2Pw!v&yj&cx`(;Fd=~T`JdRH? zP58x4Q}|9``XFwN+amJAMDbb)wl&~V&(yi?xq4za-SY|(t1ExjyEOe*rw zAKuMgH@9K=D0Pz{13mq})Ma1BWqlsSUFe{U*B^xeEzJcZkNiskd=9U@ont%sVpnP0hr zxj5@gy4RY>JVQ`$H^rRHEM^zroB-e2A`bF09x7wJQE@=fO$*SS6Nk~RG&vOm_ty{{ zSJL~TFd)^WIL=RZQnW=y6azy@C^k)Ll9k=9G-ET6eV5e3A=P`7d5V$u8@)<**P)zV z6xcg(Oo!lQ!6S|A>Us^00%S|N&UbMF($yBPi?VwL=4*Dc0jWyUr3&vv08wcdq~NbY zl0h(zmlz%O|6bs%K{6ggSmmhqIh*AFk(L2{Dogx*_ksis{zJxiY5_1=itM@M>U?o0 z-kr#^T#a!m+GSSTn~G2DX7>*d;5HiV?`>QKYmjX9xDW2m9RMA}^H0`1f>KIHDOI#7 z?e1@5bsy7H;kZ{*l(FW+Jx$r?Esy{cph32Xe+D!%AC%pe zeSwg_hle2fw%z|ScyX5kfeg7i5uwviDR`k;CQ2*43L=2==@!MzLe{RKnZ?9$o~91= zEZpMVbxdl2(S`)^oVl_O&6l*xHVbjFzt3w&=6EU?^-SFLNeSM$z|by;eM00C&E+g? zyX|g&s0RfEi{9K7DBWn7P-Ah5^jut^rQ=>&gi6cl476{JY}MGJ;ei9?*!btbBil9J ziZwym*L4hAdZ8Cmc1imJ>u<;(5jlilY1!=*L*%-seNHf)$C(bM;2czQorm}$-E>^i zYj5zTN-$f!6Os@w1#csv%}Tb-h6IS7RBN<+%13@#lY710a<2fEx$ms#Q2dMzl9^H+ zYH$iRIpHFpp8z2g2&(Z2TM=mS8cX=%Eh;n!0z6 zm@YLIv_BZD6$7@A-;X%#18}pffQGUwwWI04u2W!v!lxX_m9g+2k9@L-sL()?fa^gp znB{fiA;3au@@Tno8Q4TlCm8wUR0oewXfwqwOvM7AMfs^}?F*y>Gz6QCb$ zOL0#V!vwVMQ<)76XR!&{KPFIbXNmR>Tg4JEjvbNv4&I9gui!V;SIs>Gh({>qb7>J! zpjan~2izITw}~N8{=V-cH_A=XCisTJQEB(B)ci=w>iaG%9DSWlB<&@ zC%gIb`3`J&Jk&dX$8%Ta;!%^H4B0yzjb!@}jIY-2_~c&_W8%_P^q}wep5g%I&3l0r z4r_d@IzPri+RCRmvYFAYI@@Xcy0D#7o#$wKSlBvLX9sOx7Pe1S=clyYDQw*;_VU6u zO4x3w&KtDF!?uu|sWVQg&Qo-{44F`8oKc-;X!}^${HoJWTdS~LRGk-TYZSICs`CnM z+?c1%=u(|sw25uWGp?)7>$LqGescAU-pO`UYc2ukX`WP_C+YvZh!oIl^{XbzY{8yPVY-ovO2wHk+_rQ=QjnLxOlvupQG{Z8*ZgKw& zPQFgDC*e6Py!BzXy1$Mq1*X_jaEZ~3)G78<_k-$;v?=y9_kHS&^eOgq_Z^;w3{QOq zq^o>e`yVj2TDwF2p-Hl^lc?{1HQCnaPO+VH<2tewXdPgS&21FYx^TX(SqSJCI@X8i z7rx?+ukAAQ3qs$RY0@{MwoH7F;i>Hg@&jm>f2sehLfaFVU-qNVT>`>peeQf+kNbrF`}NPM&%I64=VHo4m9AWcyB>B) zQ=tyWPu0ERS`uIyzx3rmYl+r|`tajHmk9dsrRR|!14G1rr7k>vMt#5~Lj1hT=J;mp zm7bhScnX(Aa>G3p8<>_qr0cRqZ=R`}tN~N(=9vY!#|4FaJPv|YcV+WDjNmDWmK`C| z>2Ei<{U3cyW>8i1e@`D1SsRlkv@sZ1K_kO)t~a2O!Ap<0OIK@u0{R$l8BUI%?x#V+ zUC|0jHOBAJ^)eaI%cLlEsN5Nxv0%3HNY`1;&Nw`FqP64DF6TUEE0|JZQmIXWy({r@ z0Y=0V#N;FcvD2h|%Hi>xHe=5QCUH2YI zEM$jR-A~!j@#4x0oW(8VVR)_9@nVu7km*g&!pjpvQS+c&9cN2)7mBsK@gR=*Ha9lo zTou$b@8Mb#@F!Q#N)-ATYn(d+la-4gl4{b)glacHfC*vFk|p4SJ`+|C4Q-l*zhb3 zI1B}XOHtyG_KZ(;X&1;R*f6lii)&kW-s`1+&96dBcP7LcArqg7hE`<{>p+ zX3Lc|r2$2iQJ{QA($H_BTDjVoAy zQ@@DcERavjK7>kbl|5fWIdOaJETM{{7U(jyKr7pm4GoaygLs@eE`c8_{v%RPhzbW= zi$n#PfNCMGk<=~#&hCZ==PEGE0Q8yu+X8q|!BsD5j9>%MI_|L*BcaKX`;-6^X@R8F zkjw2X>C}HDc%O~6O+yR7r4@w9lp3U6_)Yg)H$t9mH*K>f_PX6famNbkwX?jFVp#^9 z$lr_jP=&geVd4%c0BAzrfq3y+JxFjrncJ<^1A&Irgk87+e$9GVL%-qM#^zpc-@yjd zs~Py?zCS$hn}X6w^^HTm;5NZe-2z@K*D46#U$crcd~i+mJrCDl-%e9M^ZQr+8RHI2 z4!4^Nik=%~|`efmYtDajtY)I8UZUriGg$@-!UGbK7qP=eAFo z=jmmRpvS|wj5#oYFPjkbxKnim=jCN7L63OM$New$I~NWN#};ploS#|RPLrvSXFdxz z3BSzDgPQZ*y7O(i^X;1RaNRk9&e%{U${oz8Njc5hQW{hgVu>%Pq7eFqpfB|eft+BT z2`hjxMW?z^AM%=(+@u1wEb&ddv#CP7Atz1waNp?hbm43%beySKLnpNi(B6 z4%99lJkDZ40cmitm#3$Onegd+*MDjrA`OVyr%I#8>wg1TmQAu>oSL*yDL_b$Gf;D-E1f_MR{MHn#(O+}>bL*Bry5?Ev zH>Nd6F?^G@4*u@r>~|{9yGMg=LHkeN78)v8yI#!1MXF|Mc@f!W>dMT@UJf(l3LB=r>YE~{ zT#ft9<%$RC@?7R~`m(|oXnPPEzwUbviWea%F=o zp3R(u7g&D@Bl^5Kh!fLLkx3!Pb{Du5(1c$bf8{@*r2_{fjTI6b+?UWDzbp0Md5}b| z4bIYkm+I~d_{%OBe%LcX1%-tR1504%Wg3j*(0^U@$FbeY-l~dB?wo)CJO@;s0V>1^ za8=+33MyPX4L4d4{ag4Ucuy-Fe@*wmMMCS3o3D}(4Er~8as9hoQ8*MMhlbp4bxS6< zU$8evWD0l8vUK0lVF>#Sh753G7iC3HnJHJikM;vAEfB3Fq>#cT9W{M@W!tj{C{x*o zMSW0ny^qJs)ziTE$|7p^?}%qUOC;M<@$N6=yo*Ifz28|d42y!v?nDSzZsQ7Sx+)5h z7q2xI9T?_Y*1tZlkp34TGh*$)XTbV z_mv=&p^wElI~n~e(&YUEAk1XnU(wE4$bAThTp>pcGikVT$#z&?myAH@KjrG%K{*YS zr{Z2`;D!RsLb|)4Nf+bD^x*-z*Raq;y8GPiSoFlWYfk1w1nt&YlB+if)@)eo!!73s zj1kjBrGa!1&BUUs15;r7btp$M*lGX?#K~!stD8`W7z#ju{KK^L=L|zki(GdK4^4oI zbO71%DIF|84Dho=A&SxXBsHDO!dhuoa(O{HbT`C}&yF}Ggy*Q#h883bd$5s9Y%1o# z@8_ZFS9+volnSgvnZFKq2Zn;Fyo2LM7~z7`CCU~df}p@Pzh@v#PoogTk)~%cOhvjY z!TCIJ^E6&^fIu$SvOg>LAfCFb@IySaZ{{9^K(0Zw5P|%HuN4KPk2503B^sbUayfN< zWv?!mJ(1<|1h^WkTt0(hACz2vkf_O}Ts>O?1X;*RjBSrz{8gA$X?I^J4X6mC1z)B@ zmn-iDPsCT3%MGB0;(%OEf?TE#6>_=ZEVC=*(gwMdD`#RuaX===n&dqwmmeYu=|V1r zRCQzZ2P-)5%GKL6fz;$uIq1GilSu669#|gJLgX>+zaWoOP4YMy^0@X4#SxjYLL_HV zB%gsmamb#BdRlFLhyn^Ztn7S#47$qe=oh6%45Q%{$5HQPcLyFYtoR{ia#rR7v{EZM zC!w4c0Hrl=ik6hZ_$^R+8v7>rAn5NPd+bPlh2Pu;UX~DxwY0T6**S?x0qdDm>vdoi zgAG%59h9M|m>tj^E43ZU`@VN!RSsk4IaQEZw!_Of7e+nRfX#WARi1?;R}8@dmRt>G zgj|i0x$kzaafud%l8w^NlHT)qFmKc4Jv`k>oKYI-9#!`Ea8n`f1J~2tgLFZRY5USx z!Gn}x0_8fcrQvJ^py6FDOA#Q&Z{zp^OL|nbrolHu{sSi6Yq5=6Y${B_=1{g9ofaAQ zV?3Dval^U`)&U`yMKNMc4{bbp1`y@ZAH0aSvGUz#e-Gn?>_(+7a{cRuOb)jG^`asS zs{RcZoeleiK$DA}N9zy_VXs<{nTfwFw@qpAo9j!ke;B3L7rh>CM^6B-P-5nK$USm_ z{(%%1$d!*195m2T`iDkD(d!}mhXufKs^}lU4y$CAO_LX_`5+`jcPcuEZ9;z^u|7^U z^$)tF>0QKBxw=AB?cn-&^nN03JXUh`F2eef?G!e^CM#rqv35Da%kh2PdU|@#!<%1tuf^jtuZ(k zO>r7CE?49U;e1obC0pY(Ux6l^7~cuGWAg9$%GtsasWu-s(CEgOajut@7-LVyY{U(C zXgXccRn3vt$FjxX)!-GG+^&M5fEeE+s>AnVM1-stU`NVQ*>jy`R*|_8p+uWJJ#!vH zix~v$vwSzYks=yu#sI~oxn1&xZsLwQfelO*ZzDe3*1dsWL@4m>VFZoazi2(cL@+*@ z-3%(0sAOcbYsEAa9dCQD$b}@3L=Jvg0fE&V-z6o=Gz7nLbwpofnVlf4igmvWs#W*Ei)`)B8FW1-p27>SeCNb z@cWDy!U#?(G)_=D@DoYnx4?HNPNBnK^~pSr4l=$nkdUj5?utC+LH5WZsvQP2zVB-a z-36%SE5T5ze;iVQ(xQPX2#{C;IB7y2V#H*;+-}!i=usN8yZvv1iv_$NU@n>= zw4OGOy)xM(VX7QxoWZ6IQjsoK*5j5CT>bPb$Ui7%`F=u~)QWrwmQY54{}ck_e_eRb z0Cz%#@B5w>W1??2s^5~vaX3-IV^m94+y~P}SlfS&O93?xcHNrC0(w-!Ls0uUXat9J zzAt`smXJeffUTPt{QXNU#xeiGZX~wc)yV#W_YhwmW#po!_-CZP>}PqxHA`&a?{yXN_js>sp}2xF=7y(R8vCxNE}p+_o>MnGehZDYp4x<} z+m!=#*AhIZzUtYtrYe27$0xbZCymCPr(#QXO)Zkq?u`B5FQ`K?HBcP&if32-JNdF+ zObyDem*b!q|LbBrSEPJ`C2-HV=Tw~fHZ(NlFS#Fva;w*EZNKpz3U`N^j~$fIn_+J_ zcD#K}nv$O)KboIXfDpazr1pbHM3%kZ{?xc-z1+Iyt1<4eh?mobXrHM0NeyUNf&r-6 znW&Uks4FKZ?w#sVq0K3O6KD1m_bW>N%W@@e2<*&%848^dFs(h8k_YK5x9-Z{4(?;T z(=%nbr9euLcPRNSvs1KG|FlNf%=C#M;P|>5j z95x@3urDv(_N3&_$k~sH6Zc&&7z2Gs3iKiM5}xO|n2TBQ?Fi^ioyh8q{Z)Sw_-A)W z_5RB{mC0hjrgdPPdO9d6T4|CkwoHpBRgrxkU z0YXc|rt}WUwi}GN&gbl}nqBLcg%eCjDXnUDQ{BlVL~TNNB!n46ZT9ZCqOG`6NUE?KhRR12fYx}~(Xg`EUUBIJ-?MFU5)cnR>`L)O*4(nF& zr(q2XAJ1=C)$%v7M5m^1sLF4t#MwK!ssy^Ty7n}+ydti=R{lf&OUhrLL#myYM2lQ8 z3i_=zO=B_xtFOc33Sg2a!IPbGh=Trmes7$Wr|^lU9^>UxcQ6=p(8oe)d!QmL*d z4g0d)YgG46wDbvBm(Aa#=GUSJxKo+kqN03I`SJ90ZXGrWpmavNJJi`NO350fXp>xB zr~a9&k;zU=f~4kekt@c4J{4?_fF-qPJ7>-hzz8Zz{zildWLPcVsBzTHp-$0GgCz(_ ztj59}IGJ)pEddX#SLEYz?hfxV@-YJXqXVAu?UHNZuKXtEexs4yKn;?s>VX2wx1?5` z9iWf?rrIJwC$(Q+$EcU2j@$zPgYNDQ59p~SO;bv?ySMP+VLT=e20i7QSIhr=RLl%Yp zO)J&eC{|=_AA+Scwb5KelMOCv_&Y#_pihQx!Masa`oe)C%6YX!BK(v4f+Ea{lV}M{rJ~W zT3%}clA(TlOF%!4`?g5U4sTLphp^4)5E?~?aEpI@VE#Bdq(5j{f&PHIiM0Lzo?3rU zgF1q9Ls+_34%lX6N9B)E9ToSh(7PQK^F=Fyvd_Z(xxYeK!h&@nwdhr}w%c~)zY4b) zMyxJrbZ1iIDaH*!JqEJ3!_`q$vQ3$dD2Fh0%Wur-RB6fIhGhb69xiY|)lRNEos_); zv8AKAvl~~mqfv$wVG~cscr=ghm(lC`_5*H1enRJmmwdRTuvc}z3SGq~%4OeEX!kJ3 zW9QK#?eqNv5j|*zeGg+un$zk3H405F-;&*oj@j5BEMZ*(ig>;JI#@~BFf=$JVNZ}B3s!UDPgJF{UB!*J zmwXn4fqdj|^iEBJi1=;=J1C<3ZcqMpNh#mr`!_-4mFy;UqFg~92NDCuTj94a=ruL9p}wDVl15BlHC}Wzc=^5ilgK6n@~%ok{4M~ zCu3>{@DY4=qpi8@r&62u2@3~=hp1k!SDK^_->*=dtdn}z=KCUw03C7ui)wz8uLm6+gfXkVreJ5gmxX7$;F zlCMHg;))Ad{*FB+TW>Kh5bZYx@?aW^n{8VCUn0tR(CzmWQU4>g->m;)Cw-*mdr#pK zLR59M-|0PoQHD2TX3o5cE9v=`H@qDJ>hw4`FTWxXAhHVr9hl~65011sFd zNvMQ)nrnw7HRT>#aayZTXNb& z(^Iq;>AI?nD(nCLV%*=MmcNSKXQ+&AP)}^s>tPWtNE9tEPU30Y`fIq*up%*uz$|*Y_BrQJ&DmUl3zhwz@XCdZ~p4 zz1O>vt?o=ti0{FyOf5lUgoYPIeFxU9kNDXu#bP9tsI|NeC~3TVcAYy7EDz~3>#bTz zUq(s)nuJ>6s}sWA(-MlCLn=3-HWH?iXS5Y zhRTVUAi_H(7SrqXE{s+&iJi+yEZ&>ZQSbKMPs#2zCWUUODMSyeTo)6;Z&M&=NSJjg zY>GJ%+@O!l*~b^{H0FXUITu8Ai&e@uE10Hr3yEHo0d(NkxfXa zrqq$E_;Qh2j-D(+Hb-KQRn$!0g-qTann_a*Ta6sPsFrV&%D4J{a7FKW0^>bx{t({( ztOo2H=-VET?=$|Kg9bV^bpF6gLL$!}*#FED<4+p-OtfT(}qXUs)Tnx z-eC7bj+DzfHyrs^@a_`QhBC{)&NPjVCCEplZY9Kmj?S^`%PL4-I2uH=S&LCpOLTB|K+Uv#w=xB!lu#YFPA2&5FD z;nxZj`oTGvHh?g6bS!t zDrIH_Ro82DW<%nCJ!k*;qL6I;0TUZYlkX3Z6?FQ(g|I7oD4f3MAVosZeD}hWXY0&?Q?<>m=ok7+vnd3>byBE1%oBV;U@p=*C;r^6g&Bb}W^M zwy;8VZ$-ssr|*64poB6wKR zI9;%GN`7tGch&M1<%)Ouh8q|PDEXWHG6v<+Wo3-#q9wO{vuma*<5AnV**g`K$p~$D zh{4M8!?^VELktF$q9zHC@Bw2Qk=#lP zt_bm_PvmeSlU>>Gg;E-~p*BgaIr|~0BcQb%t#vV%pdRMXU@x``JZjOhl3xp@F%(L* zp8UO_l{!WKL(xmQ<=fN}!ZAv&l$qh~UZu;mC^vuG@?zE9qL#euoxc7C;7~_-ol+bI zV?*WY`!TMEx&dR_<$r_Q*|M3f*;}ZGfFc|fFBXHj+A6Ei0yN16Zxg zg-YdhjAk&*QRNd!Fp!sLc&-8ev2~w5V5Q8VCFCo*?vAB{~C|mAYX`f(MN#Clvn{wT?@`f_zf&lMTEkDPIQL+9U zLnmc+t<<2i@*9JdL}bVN4YK0345gZ9!y6-(PE^9f)+*Y z-itxQ0~G&UTy!mp8!LzJv-{6)5S;JD?!BIWU|jGH{$2-varpr1b>vm9 zo``Weiv3xElT4fhb3&c(wG5}?m?&v$06>Y03rdMtUx1`7fZS_~3k^W2q!zLi=iVY% z_D+RfgODhbAQixAue`wpoP4|7sbzpmNou*6mC}0;59$oDTs3>N?f)N9F z6cq<|Iy53}8z+VN&})^|T9c@BSP zZ}WW}Zvw!u*Y`0V9biq~;qi09KwftX@(l+lqP+8Z8>T1rn%1>NGvsqo4~>>RSuJ{# zI5xSgY|?R&lh}ufrePV>kx32HZ6dCB5q5A3AEg=DYw>Ny?Azc?pY1<#8e)KvFnSX= zws&Cv#VqzW7`4pBe!AeHE9~Du2Z!BoRXefreLQ7I6ZVhbd5sL&^9wW&((c|&?-DGP z8v1p`{;^_jSM28$dxv8GRKaU|_8ZvnVA1dGRqUq}`x(XVSL_!R`xV9BrP!}m*|{eI zL2zG={iI?)t=P{h_6v&rvSRO4?AI16_M0LA&R5z`DE3bjyHBy7SL~M*`&Gr>1OLwq z8e#XvEtdaR?P7UpZA@1^*JfRJT#;ADV#If{!&9G<-6Yj5mY)|3k-9!#dtIe0O=PSc z84IKLgnC;Zp7FrzfSwOQZ~l~F1+dDV3Ru?q)&#zbkqrLqDg0#cGm)P>ehT<`nxCcK zA27kQF4L$uBi ztusXH4AD9h#^^ipe{|0eFl)#kQQgSTEBtKbr}NSXMX;TpFi;P zHb49LImXXLL$UiAjpYroNerovH!%rJOsA+);hI$Q`7x?*C zeqQ6}Kl$0s&k=sknk$?Luh97?{QNsVf8pm{eh%}4nix_6^@)&PpBSQwpO^S~m7neW zH1czZpZ3LatG(N(|8&{F&yV@}EkAGYvx}dD{G4IK4JW;=0ehX2JJp{hN$3Y6F-~z*~ZUKep>kX znDNmNYK2A@4?jQT=U4o^&d&~h4)Ak|;n6S#3QbQ=yN`$=*75TLetyZ%pZKZgXFoqD z86OR2u+yWUI+UJ zxbcXsCAWUr?NAqu#&EDFqb%Nc@OHFLjk$Qt5_bx&TLzn_XJXkfT(Q)MUZefCJChb~ zydsyz;7x74Jw7P)WOq*)HXTi>vP<^Jw<5|J*_GUz`PU_P;K4?mN5EAzXu=cmlta&I zc>_;$d1oGnM?l_6Ew;sS=`33cuJS>CER*q>H95t*I%C;9ctrO_zTe>->c2;n)yoiN^(wt9Df_vnr`D@5_H$nbsThwB z0Y!QNDy4a#QtFuKsU;23J2@wM>hn-)%Wl=;hyW>`TKwwKJiOE>W!VUi4}5@ZE!l}h zCu%BA(O*>6Vt6a3Rjt7goV^EZjKCBb^S>q2%KxKGv#3McJIbe=<>;l1YGp646HBZ! zYxVwF$43AoXBEhD*1S99tf#*$XD#`vob}mad9r*?;`fv!XaD^~nvURV?>ris;q*=P z;l(L();>9Vq_;2+<-6iFPhE!mPt&lw#2~1}GNO!R4DX!e4Da-$42mf0p57{;^5kKq zA=rPG&e5w*=>i*yzZC5eInZdK7NOYZOg@h9g2^4rz+QNG^gKrR7AY)z*(-WY@lH>a z!WhxoHyyv5gT`+-@Vg!OeF^wIV&E4`9!|vu@QXF@gHu%eq!9u?K~UsDP-#Y#f$+OI zFn&6%Fg&8;C&IVHhJ`od7uz3xpA8znVZiS;;P*w~_ppIqoWL(GfM1+}ADp7%SBC*M zA-IS@SAGjXA$^W z0{B@B{NNN7zqMQ*%qkEB1%84`GolQH-;IIs(`kj_5gk7fzQqz2-i)86Km4u_8o!~y z?^fV99{5c$@QWAt#Ru?OWzR)L=&DDV?hnh|9n{H_g* zpH3?bkLdV`@GS{p;m!CZ^oL*1pz#|5{Kf*mY~Yt`;Fl=yOAO$bXy6B@sQA@kArtZ^ z2nzfJm1aa42)~|z@zZIA;Sn7_5xylcEW8=N#QyN>9yER!?aWI9ep$fJX5g13@JkBd zmt^1vr>OX?<#yey0zpvVC#WNnzp5_$Bp+U)P}VO9Xyn zfZx5q?;!)fAp*Z40sMv-_`xYEe$%ii8~6!=0zW~e8BqqpuWMlZbXs9}M8{8rZy6F6 z-i+Un{_yJ@G=2%dZ#3|`2l#!(z%Nsj$^GGXb`0>7aF{DvC%!6_7#`8_6X9EihJ`odH?%+eJ{>fE7T}i({4#;xBm+OIz|R`M z&uZWYr>OX?#o{F7PY@LN2`bHqG7x^B4ve2pD-4h5_=)f>*0Atq{H*=qcV*D{#R0!j z!0!vd?*Rk9VFJHl0sMv;_`xYEe$%M;&MFWD1%84`GolQH-<5&!(`kj_5gk7fzGYZg zcr$*(`or(?pz(_Zej|b3UBK^t1Ha({zu^J=h8y_7DJp&v6*gG~f}p@pP-#Y#f$+OL zFn&6%Fg&8;C&IT34-0R`Z+L(BT^clg67U-V{O$yPIR<{Rz)ud~CmZ;|DJp(-(76FW zK~Uf)s5B$WK=@r67(bm>7#`8_6X9Fru<&O5bXj#=Q=Hf2Hyk$?D^6|MlM6|@ew*R2tkG(3r3nj8 zt@fidou=tDO&4goKvO48ogtJ2KTz|x+M5{y3plOz!!!x4{|TCWbo0@4iKa`cqepS} zfXZjsK-~+T0!yuAi{Y?L(rW*JCM;;R+CQS{6PiAu={!y6X}U_&)rgdq8~KAik@6wd zhDs?FSRi6tlPrX-hm=x^#M)jdWye_HGxp;RATLZ$EW6-SN-4nt4AYAy8w@3u)$l2$ zEMb8yf&_)+M=V?6Q%b490v74_l@%>p3?-Hw@hPQjVF5BkqTni)dGINv6k)-K^rFg6 zSp8ruvCM~0DP<1}ei0-tP~R9zETiF5N-4vF8qOr)X8y!7AU>sRC9xpL^!m1qS~3hJmU;0hWm}2`UsDUp^|B;m4a}RD zf@Se!Z()j8S&Drqi?IH}^)&oBQt&Crz-Qh>e4ft3XGsA*OP|Ike0@nQzH@!)4A+;= zaDC|v*O$(4ed!F>m(E07UjnJ{#6(Bghn}`hA=Z}yalBlG(nER+Gq766l_V_chpbN! zt4y{VnKWS$uGOASQz}iVG-0ILYPZq^onMPObLgG(m^fYEMudu?pUMdLwDEj!Q`U$#8cu++8${qiGyXBWW5*6K0~V z_GFr3X$qmF_2>7}{a%K+gC=aTc|LCpO=D=nNTk&+(*&JVt36S5#3{}=)ENnV333-x zrGqYdU55Jt!+n7!tVXulZ>4DzO`~YS%&yfwlqTr-TkTOPY5n(;3SK!J;hmb>RgdXG zjQbm&o;=yJ9!5%I4x|p09@TmmnmS0cgQmcUh~dB3Fr3v0c2VAjb7id>aL?SeylNiHnt3-zrqqK>Mn1 zOL_=9Sv@|B=d49dR1j0_Rk|yZ-^ z3D~&2KU`lAUXmf!>yePYzCRah#mY?_O9)xwe-TP&F7YQ~i9hSkJGr)>ps($#Ko4vC zXa}RO+0X0OcXGeJXiTD04y@=eWLYya>cd>gS8mo_h|BKE?U6l~z@N54Z)z_<6O#Z3 z)@KVcFteD5nMEFE76o$F(x>ID@P>Ca78jk^msQ9$UF^&HCiZ3hJ@#cS!@jIQi@QbJ z=Y^tL_GOa)zp|nq$aYwNji(nY4nYF6jLT_jwAKDK+G_tg&9;uV{{|#B{y#-R^e4Ch zRL)9*gtFmSov;wO{BK<^$I3o;mKf{hqE>0s6K%cR(~kN2AoxMsjqL;B>&emQk0N}8 z_2(czV*NP+KhVDnf*-Wq;3s^2Hab5de1!GfAU|R~Hv&J!U$_#QJCiexM&61V0!{fS>U7!|42o@DbJ&1iMN33Twhp%Tu=SPH( zu>KL`N34HD;0NpfgWyN34>X6b4@BojgpaVE5adU!Cq&=}`#A=|kI=U_hwIy;^CQAX z(9Z|?5&HQE{9u31Aovmb>*jF%b##72_z3#$AU{Ii9f2S0w;BXLLLb~5t`CmRj|d+@ ze;njT=#L}tgAI9u;0LoB)c0`xYIJ@?_z3#gAU{GM+lL?3(V{q8RL3F3c}R79s5n1V z9mf^tan;pq+}d zGlE_U^qLiCv+DRjaekmW4lB;Xs^cTY`H|{4p*T;dj!zWlC#u7zIH3hPuQ<=Ej!TLY zI?Stz^J;XxP;mb+<||?j0@Xw^_PAosf(@@6^q#_Kf1x(&T@*U(g}T?L7LIDE?(2fH$r;=bZcPq}jRmYu*6YnV9rZ{g?9b*;eSk-Zh;=Dz5 zj8L2-RL3yIIZSm7QJh0mN4(RmX6}Ib3xlE6!xqk)SvuXi~5r-7#Kqj#nM`D$aXV#}^dm7gWa` zit`TDajW9IRdtL}oMTkSD8)HSb;ycSRvkkX=TOy=s5l4EglPH;-0X@8_4~T^;%|iZ zLR_l}?L{soA?l19TnU+hV^-bj3>-7~RGoo?R~_mMoD(^R_lj{E3vU?XSe82DxT0w> zF7S16XfYOYW{Wwut`K?~5{@Z+(()6!K4To7cQy1G35Grcm(xMrfX7}9od!fB*7q%; zf&jh&eZ~btpOIkFXGCxu<}o`8eFpE0^jrw)F%|~&7;^)9jK>0c42(1lJ;s@U9wT^O zVG!rnvhMo-^!(bZ$XM9?{Ye~P2n-I`!AkdTVy)C zMm7!om8tdlooggppP_7ew00-9Dp7B9OzSKEbKVOT;D6405d^VNb(-4R|2gj!6Fi@` zme_ospI`9vM}F$~Y3Any@rr)l3+KAT`K{_CTe4g^JC$8Tj9l>;3|NK4iGs zG}l-g791+?G+gh}T;ps|`&SM%T&n|oP*6+WYn3Z1u-V_! zI}}$kV%NH-H(9Q@pPKOAA$SQ0>Q#(4u^ZOYnCyxpD!{!qkB2n7{DDu=+9L){zsju(o`^1dXh7<1CpLMqZk7$J_`b15dlAB+^>F~xDN;8`qvxl^{ySrK}T1^ zO#tf#-HWvvm%hau6Y1p34uPSvHpzDmxiF8nqT+)IY+rmX8uzwf+`jnS=pP>tEo+PQ?M1y96h2Tm^u^~2UTXw_Fnr>?tKvQ{ zKF~Ku#wV8*w|{)1#{G3BjeM<<zIl(i-L z(m`@ic(LQ})8BW?m6tKR3BxPtzkru9Ch61PD;z%ck5|;Vvx9N_;uZ7x@IoSGZArd! z7{m<MC;8uzwf+z5Ex?00+wqGfGE ze0wpr9TYxn1p44}4gEg|gyECyU6uTK@nQ295uaQRzWc`~YTVB_Uf1GAz~@H4_<(3x zTe5EpNDK-eb|QW7xsLuH1j6tc>RmPT^WwwqGa^1?gL#bB|3{7c5l+BF$EUkrd_c6U zZK&@>kQfv`9E9}2=LY(J5D3G^>Ro01y!deV6%n5vPSyICpQv&F8jKr3emeTa2Sm%- ztiESJVo>;S5Zecz&(QyaKo~y5ysL(NUVJ!wkBHA<&S3k;Cu-cE1>;7*=Xk&PfM{9U zFyAbY7!*F71ogq^Ci;I62*YQ%ch&IEiw~!N5%J+giUZ&iHEww@ZUlU4`^5)D%i4zf zCV<4C@R1_n(<@iTfuac^gTEB?ci>46J45K<9dWS7ne4de)NV1^vD#;kH`(!Yh&{ouL(K+dTjx8H zyR!40Sog-xcP#FocD|G3{!QmQDegaZzLVj8v-6!i_bwBo=KPA=B3HzA9l`~#I~H%; z$a|!yZ(OW2FQ&F`F_m{KW?{{9WMB2&^UYI|Fd~9P!5;&xix~Y;(_|Y{CwrC&L32UB zWE)d2d;S(yuIARJ03xa~?R22Zk*_-tCZWotd<$1T7ztNRmC0u%h3jW16}W1u%oxM< zjOMDTGS9*y!ZvHJnkuu!aOL|+prENTd5N|N`)kcrQ)Rwtxc)N@0$`zWY`~qM*OW_m zfE#)iO_iD3EYI5Q{eB9bVaz_5-CDVSHTGPWreY&_sTEtWC;#p4amyzl+t1^j2+J7U zSvxwr(S2X#yRLieo@?^+XQhKutN%6AdTZG*uXO~%;(BfCa4ZonG6YFKe}q!fi%**m z1j|ozUR&3D^XAR6oClKEzDpDC<927NPRkUB#a*m>7Czv#1bwG#%34t>?yW$>^;5kx z+`pvFtCxa%lR)YpF(c7Sz`ahm@DUKWXy`u!i*S8HbJfu2MW4d;Va-)TKhJQzS98_S zzYi84uO8(Z;zm4XiQ^V&5X%%?b(RWk>+%K4P0#5YQmbBnP@TqB)VfyN4!QpkH3PNn zDGByc*uM)qyq}7NeG%;QJ@u?yy`DP!Jk<-=nQ+a|ZFO(Q!y^7fG&?zMIklC&t{hZi zjqbhJRG!m`2PVe()8UW1IPXUi3v&3lD+nZkfF-xfeMYXnp52X0KT(Oy|MdIWaAW60 z7`y^xwM<_~Tm0b!JTwI6H zJRb0_PFagvuF*FvPmwEs20f{A&2v)DflNxx%4Hbkitj_3b6P#ulFDXyuA$zorF36| zu6iEp(KTqVzrp_d8uZySIMBHU4fn$w5nhANdlHA0*PsO-kMXzf9!`Qbf)w6n;2iB5 z)aD~OxxEHO`VeXXu0gdPLv_hDDBHV)0qXY)R4`qGLjDtIseH$&%Ihg8`?_~#6D}jp zV!w&qKXakPbv=ns8~XQy`#rldJPjFI?&QiXsCr&Yt~WJj(L&!bsJp}3dyqo!mXL#1 z$d!ood02wKcPlPtG9-{z=80{{Yn}`H$<9f5sRv|3X6>G5;Z)P6MY=^Uvv@DgU%a%|BWX zE&mqgpBP8UKdG4WAD|i~|CT=aXN&>!FEp?b^B=+~@573kf2s#e`KL8%{;3ibmW|5R~`{3kH~#5hX+ zNyVK10M#h@Pw10>#uzaF;D@a=8`H4%FND)+;52If!KOL?v_{Q8dRQ(0iOfGSj*@>; zG3P%(HA?;y`{bW72FySBiIV>iPN#v>sQJfi!JL0uqvjuj4K4pk%s(-Xl7CV$=RZI- zO8%4jvQvM;FP6MY=^G_YDDgU%a%|BJDqWp(4|HL>-{z=80{{Yn}`5)RR|BNwU{)L7% zV)=(~It`pg%|CUlru@?yHUCtZiu_xde_|XZ|DV5)M2)~NZ%^i<3LaOR&FN69~_nDZZ?8YTb3`{bW72FySBiBkVVIOTm{m^8ypB1y)3AG2gYBfw2I^NEs9$ZMezk%6)duQU8>nAxfPOWg?=`c_`w3FYzK%`( zc(oI-czU2HIVcQJlspds@$^7ZG8Q$((*s4xO=@C#peXsZ2m?h4AAj^+q|9%-2Y|sh zjr3CFik%|t2)W|BBJ4bv8AyuyUfe3SpT#+lnjFu~o!{AfR^fE{bfvM zL8YYt1(lWp6jV&X*Nl&LUc4vEHPh3REmw4ibne45up*uD*h4FbOu!+Vo-fK3^}_#4 za>aMx@5_WAs~OIJsl_dLZl>~2aKSk+wfGQin}zK|wfIBYek5$i)#Br{RSDb2YVpUk ztrE6&wYZ(OXN2vXT6~VSg~HaM7I)BAAZ(wi#h=n<7q)J-xSO^~!gfO~zL9%)J2=IL z*gN4ge@B@93+Knw;scBkD`Ff}ix1NFDKdrgWNL96ZKs9pm|A>{wnM^pN-aJ`+iqby zqZXf`?M-3xtHplW{zKRK&+dqvo;sKr-kqpaZ^np)gNTZOP)SBtOHwj4I7h$?y4=Tjp1~W0shVzxg>XF$^+Im{hTjS>mWzS#o$hAKY zI&&N?w4Zgved0NO_ zCT!-KSr2=lX8su#)J*gJ95wIh9K1&k-ZODmExBKdkvM)c0GuFD`y8Ej(9qF4T7hd~q7t+DPc-G`QSEO&qOciWqnfWK!12VG~ z7E^mke%>XycWd4aLafyU@c0;$y&9ZU5&Yox#?nHc$+rQ%M(ZtC zcEe_tk(;m!8M#W25E(fI7f3XK3fwS!eS#+t@Z{=SKzHHUN#aJy$|Ayx(h{7t8C zyYAag-*%JlJ@Cbub$zTcPuN1FB_B@UL)>rY*v06(YIcRDe-eY(nuB@@xUI9a5LYe+ z(%(tnGrBKsU@R>>WAgnCe1l_$L&9cA&u-X4rRROP7}Xq<91SGbP}2~~Pa#6pwCXA1 zw$9Q*td<7&nMB{yx-V{2EG;~3@*NFdoPpQJ1`c5}q-ip2W@*ZUJs?dFz|yC@-XZyS zYTgOu?@t&s*LN3i-zk zi=~Ahn|vF@Sk&n2x`oYZl5hJ#KLiazisqAsr%vv(bB?`Cf^^4QLND)HVT^|jeK@CI8xmLn^_wF z1baXle+^57@~vZXbv1RN{N9DYHO)FlxSh7N5Tm33zZUx9p;Un*;TYB3%qb!XsK1-00!&(Yi?`tXkd_(;@7_prctJPuaVFxR|!#MqBDD>G?LE_Q6} z8yyp~=2;1*4}>WerZ!=UgXx4YSztONOz|+C7p4T5t_V{iOg+Ms1XHgt4T0&FF{GRf z(|BPT3ez-UvcmMFFb#w0AB1T*Odes9VfqP7ctUWl_j@Ux(;dLQ76&@9kT8nMbS$Wi zoQYMHQBHgg)@Hw7Su0m|VdIO^gnLu*>|l0NcAe7bIWBWA7O1Vo*VCO;HpSD8ttmp! z(2beD1+9;#8#DhYXkk6wnE5Y5m*nZj%>O6om_6N?`PX7pA=XEbAFMrjx}j{DibXh2 zH* z^xhMGk<=mlZViQ4SO?E1G@E95NPsQy%joOM#p`VOu_ydq~ki+RftbTCJb z;qM6UgGEAzyfg80a7SgW8#knXvle$BHsS8WN_`3;eF&sJ(bD^8Fm)5)P){8ZKio#BH>tC#gSp6(j}KOA)(6)PEG{(=s?=#@Xb&iPm;r2uwKioCkAAaIl zy{yOabl(8@839Adh2X~^-kGiFS$*Z%Mm&+278o<1OcM!-;VA^0(f zcV@a7zfT2zf>q#$REQtm2!zXbruK)QMaK`9A_VZW82BM~QSnp1$8IiGS(fw`x|$f@ zNFa#yiL9B|f!EMzc;Plm9j{wMGZ^09iD&e(9>-IC1IU{ZFqB*fUJT-$d8-+(s{${< zD)2%o#0zf%60a%!;T5mrh3g^$c*PrdA$R@Y#g-0uCBB6|I>vVrUxC*(;1%e1!}|x^ zmZ{@~6Zrkfmv}ZW>v25IHvnEnz)*4_crl1~<~TE6odPexD)2%o#0zf#60gbq;gz7{ zg^M%-cqJHkA$R@YC0aLSS;AWw+{F0)gs;G>2Y7McM#TDv+dOr=#)f7vT)xCJd0CI+ zDZT;lG6IH@3&D#)yfep|@#+$I308p@QXyV=^N)Dt_J>!Zju);N3E-7z;Dy}vgO_N{ zlx6X6L1P)?TZgZ}s~dQssz$~Ow~gv}rG;iN953-KUe@DydT#){jDVr!Lhxb`@60qa zUflvO!7A`VD#QzK{1Go(e|RP7c;R410IwtiFXS#NUaX97K_waEn}@HV-$nb?1-wvI zBjbf}vW^#yJM>o{#WQ$WkK?Jm0q`;chLQ`xi$T0I$C&Zz5qJq!ffrICUiWHvJ=7mw zLv*}`nD826;Dy{p!)qF5n4|2yZ(+`%?T6RY&cLe^c%iCB#tXN#>UfR*-|W2)d{o8N zKfIePu!MyhC1BJjQG*htHBqoE!5U*i0`eya0V)KkB1NPHVQ;_`NZ@8;uGg!v^q=g6hP?0vPXJ$Wro2$QPUQtld2rU5w=h|=`Hy4n7LeChkQcgYba~-4Swmj9@u4ex z4L}`{5w6nfMqVaiXm%m;A`*SV5UaetW_dBIkQYiJc?}ox8r_w=1{m@hV3F4VQ(mZD zr}Dz=VsO^!w;(B-zXp@ufV{p$HOWsos=mi*w}!lMLq}Kg;%n_jOvBZA-N?%%49zY? zUPPi#NU+MQo#n->LS86^`L#!t7f$0fAUV}_|p?00f>x{bm%v+F@%|90FnIZBz3VC7n9vxr!p2?8cIiVE{mzRV(A|ou^ zbR#d5Ff_Xmc@c>|;T)^HI#^!JD&&PyNM5*ekL-!`uH+>d@{%m_l1zD_cAd!Uw7UHC zTaZ-v_gVI1_M`Lg-P}(qwv--}JZaBkoumO|&ttydM8BAKHRIQ`KQy}E! zC1m~J_!clgE7QlffCKU`Ilcuf3_(@R{R%rSreL0_{QK<{A^b1YaP5vr-GG;E;`#m? zV=A&Zmg;-|jgE>e2bB%~7(6f3ZgebEMGQS_H^!=2u_B%LyHt6yY&g*?xl5L_8x8q4{gv~p!#d5NCRC16CGD9Q-D&+@4c`l}f7sW<&= zLgWJ<55|Lq-Xbr&1OE!EybO9nUYsuKgK4MXFG9~2`PGN}Q!%|&e#k|LPxzNmxU7IL3M(mmezMsOc8@hNNTLL*TKVKTH+hcboeOM|l08_7lG15bY;? z&7oL??7YHH`w9IxMEeN?IYj#jgE>U|3FmW&_7jG2i1rgkbBOj6Zsri}C;XU0w4bn& zL$sfubBOj6e#ar&Pk0@n@Aebm-}l{qg4kyGZa?9>{ej{xgTh5 z6Lf1on}l81&)@AQNZ!Ey>391H-0jS5f^P9;5_W;F@AeZc`1)=?f$?Q-6LgC&ldubX zeYc-r!Pj^D35+juo1j~KnS@>7>%08~3%&-3g}boriIDX;BKdAV!LVPy+fU&BXl@g9 z+aFEBF8bql`w5o*_}zX2k>gX`sbR$R3AL)OFfEZ1$8{Q;DZ zGAy2+de*=w>B04IJ!_C9UC7UpAMeLNenzu|$!{~s2Y3nWKZVFIY<~vwWBP!+Xvv-V zW&E%hBIIXobXeE>L*-`zhWE4S{Sf&@c|W+{0K7#>C;0{Ub0A*=wzd3l`9?_(k*_7) z+;0G0dBcIvlQs7nZo?M6_!f zmA+p?Q_@0nI z7RW;;_*!5DcC?q`)1?x8HGsE4^d9Aa2z){?;tTv1w;FlzM+eA3NT50sS$ln+jq6&T z1xw$O#LKCO?H%Q%3{$UlJhgr^~3c7OcxCatjn8`Ov2WPg};Sgrfx|H*!FuzJwq=8mx# zkXXM2)3NJ}Q=koo1NtGD4lSe_JH}Dp$Lr?XmUOE?NC##0iMC%XzJwru*Q~ysr;`pc zI0*1}w)c~R^1zO=vHvXKW5^e=*6}__ACPazer+(_kZ-5&8}bcHk0RfY{H^JRd^=4y zYh^!xyEa0ve%=zH?-Ilcw@p3bLdeSZ@NklC#qKyEbNTf3L& z9;V@L*jL|%{cfGV5c@*^e=~bNSbd?dghd}5pMvS8zG90$aK211UFa)e(MNk<=qoV; z3Z`2HCdPwk_P%vIh-UALbfK>z?R{vd0Kb9xQZL#2L3sd9#{9rK9zee4fY8Z!3;9~? z>0o{V`F8StK)xaAQRQpN-nP2F8&(d|C9yA4L-#rAh__PTK<82V+{e3s5- zUj#o^${hC{RYuDRM&-Rkmr36c*TPVZEDR(wiR7X#Nve&0xD?<%H2fX?$L`*$TrAn-$qfI6e|xNzd0Y7_l}mo4~ZafRWB`Jwp$vq9gWbLm?-fc$oF02%J)0CL>N0c80h0-|~r z`&OqGu|DTwWyVr}Jr`>-AR{jMWp%bGk3|hKnxxH?F!!<1W7PR!pd^{d+r4XKOJ_mWO$_;r?n^ zZqNcVr>8fztPRC8C67e%%<1Z8-23rqYfE8>JR`RMsIl3GJY@26E#rDzzl4mq- zD>Cp}g^s~^#XTpCSEWhvJc=TIMt$iOtG>W>Mq>VZyb9R<7h$^!*nSUz;T`xRmEDR$ z@#?koD%L+gFa1RFxN+eS9K(rvE6U>e@m7>Y?+>Tjaip@##A|fkhqXW8Rw6O~#?3^M zm;2jRlt=w-INxDib_j<(qP)%YBF=wo!YL4YMbt}(QkrlEM6Gy!mY;D&H=PfOS1S2= zm{j&h@m$K!H(-9j&n+uBzY?kJKJk19o`=(Emr|K5Vy0CN?*JI2vOC4|jd<=y&jsQ+ z9nZt)IY&HSg6A9Pd9-*w2hSz+Je;4Af7wBKQbl#?fmV4qsi*$|OQfzIrC&&H4Sx09 z)}a1 zGUWCl)%+JGM3z*(p4*NrbB~7fZ$0-|*z*@*&tHW-9}jyz5%zpC?DQ3~DMWRonbDyZAT2r4O`yV%XiSr!MCnRqn+KI9V%B#En;Jwm# zMWDK;{lWXiX;D&G|LwLvc;7Hy6y;HW@cz+^qW*yo{U5hJ<3ri|tk1(R{#&1Kki0*! zK9@+|S;1$~AG|q64Dd|-!8bj(H8UHR{j25ak(${|!UwkDO504r zsSuqd#kBkaW6mzvtQQC#`$?O&yX#iElq2zWUb4fm8$N!*JjSRNo?(Ea!dKE@Isbdr<7M2kDnpX~2MaPU6ZF*sOQX_k*SG5pegNw|1> zb^MLT_&Znn`(}IVoOw!fJZu}uGTxH?9@bx_P1~&U^!#JaJgy7B41FK2k8mRxjwBUx zA^K~ekFGx4T=ORIgm^x*q2r|_x3{(Yp>W}?2}-}86n2nBuV+kkY`ZErQ|hT!mk3=p?j#9>FoGnHtn@GSNt z-ocDzBG2|bm(j#!0C=I1pYAs#OW;EM>bW!tVEsjN7dk(U#{Fda%@pSyi>V&$ua7Yy z^I-f(R+P@umMb`b%)XC+o(l^<(EoVWCeo23rSlw(_Lq6?qEw@D0xZFnCwk=+VD=ZN zj%W?jmkE;5o`N8vg+4}0D5uh-aysvtg(3h^MS!63nEMIz53lZ9#&5mb`BHDskN&gy zQ0jI&weTX*!s*n)ucLa@!d3K(M%hNPIOLGl&u5{B&iAOj+1^9z_~-?+H_1mig}{28q~;K5aC4>)MI^&47YHG0ewt)f6f_+x*rpnnspa?m<7-*sHz}v zJ-c5TpaMag?OC0voJuZQ6kcyyUqW1{cxik=q*;Uz?;D6@RY%_!2lPL2NBuM09tbT* zp3iEQ`V+kwk6J=Q%C`pJVxGrff@nD^*Ob=$Q`ghsnZkg ziY|vJ@S1WcSv(KLGhR~;rHSXhLR6jiCpKANoY7KlupbRWKcd3}*z_PF(4E)#5FIBy zwp>Q@?++yeA%y^uuusSz0%VnDN^meD{2-PN0t_)jE*0^&CL`WzhR}JVpuas0@m4d0 z@WJOEilT!BkUbi$fGQCmQGoa|CbEEsMFGkIp9No{KFs}6%1OM|x!F;jNl1s;QG=d> zpfEddLXv5Ad>?rTmJnx{9pnWv5%p!WBXoVozCFzT(7+{)PQRpI3>kF3KRGxVuhDo! z^Cz-Do~7SRoG*-D+RdP9S;rqr=kbTe2VRJv^#%4h3hc-8_#@Jhqga1Hmaj6Qw7HUY z&8_-1=!qr1PlpeiNkG;ha(9G1_X&IM8}=N!-@>~qqCg|RxG;KnLxrScHzeeFP{?zL zaZl&92Ih0o$C(?##u*9Y491v1f7bK4tIRg-`S9^Xt&ZM$~RfK5d8eNDn6~f5TuCZlC2W4A?yU#KHt#My6KaKy13~LzH*hbeTt{{p(SH=t@rcH{#*s!N zx>7_ZB6_zGMMDV}aGs?ABkjkQ%#ElimW++4jL1ysG8xXaTBI@8201x*nH(EYG?_&d zb8AF>BBHFE(&9U3`qRiv$rumI^ts4PX)pnmHPf|-Liay#1H|0qGrBpK(hsFbBk=z` z`0(W?OCy${8|}j&vkyn!??W4SXg7ofp6S6I7@pZaL#z|hrq-41@=UJSiLF7;<+!^`^3rI6`@68e2Ke%hq7MPZ7nslTZsrC~OvW8b z9LU5#z*LyoRL}+^=CiaL_&Z9iL1xczfCeWf3z^T-=Hr8$j{NTD0P-tmLToh>BH70E zKzssz03TMFW?~giDyRKRRERMs;(y5TuUgtk#9z+wzloq9gd1`&8!`1Wi)677$+aw! zRai7)k^GfqgIdu1jymu9smM*wB-sS?2g`@Y$7^y~QuDIGXd zoSb@uqNPO{r2{)l)RTn9B~RLoSShnXG?wunxeN7s07;zj2MClFlOCo!q&VYxjv|Fz z!%@h%nxjZF6B;%;@rPl+`H^=115<+0|6)o~(`1Knel!^=Ehc?^KSv?Ia*iU!O(Wz+ z7ybnEbJ;vU18<(6l@<@Qc@`lL&!W=eK{n6rsHEri(qhTxnY%Hb-w9jaRD5W5#fP@$ zPOSLQ%8C!otN75SiVsLsd}vL@hbB~fXg9?Nm?=KAnBqe-DL%A~;-jvJ<<3g1N&7TU zO1w4~v+v`cyX_xrME~fJvRaRCj#V2x7nWw&WT_=!@05G=+A zV*5J39sjNSuoVA!5=)EQZJrBCi%;7;SC$r^v3XKUi#u$d5$-)|{mOr-t?pJSwZHlpvKNU zccC;i4}qb#;LlP&{++_V(Z1oA;CaFKUJ}388^1>vN{yde(vRU82QxN)ub$~zFgP?` zZ-jAu3)zVt%<hJVcJK9$nz(oeZh3f!*j zr?^s*e{tVCdWn?!j?&>=d!5pOBledJBTVDa{hKbL0FL3m;6e)EVE&_t6u?pabweqD z!~35}KyhXF;^=s#1KYfrK&;Y%gZ}#sq5zKm|6l+G(BEI}PXY9c2l`O}o%;@$G2B1L z($LU>d}w{T@-3V+ibOt6zX=b(;woX z5=FbH;S%C{feCBt9bNaiXuU;XL#c{y@$&k#ArF!T%K^NQOjex2Zrryn6qtQ&utxTt z5<=1MJt}!W0w7Qnrm#nREEeF#t{2xr5(0KN>KkNDQHQ2lR! z(!}421_*COquqZP-O@VVb&3z%K+ya6I3{^FgQ0MI#OTE_-vA$2a{AU;j*5>yq}#g3 z$64b?P73hTIX>FE#s`>P(HP_30d3tQeBg$KZ(Z0C`r`{s8o*FEK4SIa*l&Q3*j`{c zDn35GAkZFN>5sF?IY$Z#md;M|N_!%AKr*nL?c8w1(yQ0zIf8e|x;sfgr-@33P^v73{_YN== zj*mWiai4F14}8Dyt+N~zAHOF9xqEz^HGYN!`RN=VO+-!^-n@pJ+eRg z_kyq^@Nq)&UIvE3@zGB&c76kVz(xM-;Nwo3QFpID&Kf`OofF`vb9|H%K9a?>Jurva zK(igOJZGNA%+s(H4PbsnV?TcqvhERHXcGQyubxEUrA_jFf%$AWUYy?yFTKHX)bVCC zc~C{bzUq^D7#i{=-;W>JeUgqjN;y=+ z>6*B(_0<7-@qllDkKUM)Ma9QfTFvhsA7_o9(LsK?z(-q`_yDsj8VC3vz|LQf@X;HS z`v`orWBv<qvFF$dw<>I}a%JpYL`^-dHdcjt@yMmc9W#dSgpEDn95miXPzOtntI%U;?jQ z;G?ule1O>%jZ%vg=I>*m;A{N$)Mw<2E__CC(4XgR!(Zg+i9Oo56y?)l`f91we#%~V z!jS^s1Dj{SFM|GB>QQBjW8Q6L+oZB|NFCp6%aib}w)_+RPMcgFk5}Ql`A0bb*S{Ay z09Urn9DpkuoyQ?<$m=I<$m*xLbX(yiPR-$^pVT_|?{08P8)72j1OCK#6HYx@_6Q2Y z9}ej;NRP}Rm>!Gt*e>38Al=bLdLN|s=_0)^())In4reT-+R4W;oI{R>bR5G74!|Ao z1`a@cGdTe9{geaAa>enjney*C6g5|Kb3e{i2qc4 zsQ=WdOJi*XV8_X>RZCLhmDBKROc?>ssW5M<=TVh#Zz^)F6Kjh9r@X1sheO$%j@N(M zDwW@H1;Sl;Ry|FP(TQi(x#X2ao>i|8qX0as=Cg|xJgfS#ixoVp{z4mhanM1ei4{HAABrRiDq1AxS6cf()g z|Ac?lw##g`x3E%aOZ}JoE2;e4%Mto2+~Ep(F6cJ&ZI6FZ2a^$C%WU7Z)Yet;{vvck zF-mvpU(*|dON9Lf|EpgDHWsPvPa&y=57-e7SpolL_Ftg(4-xEvv+Iww^^%~7FGK~b zWB0GQgIgN?Ec2FX;jM(AV2tCNY3G8@4-WCqN>)xwMR36nY;gQOxWVxc)Wj5Xz+Y=g zau4mj-Y{k(@C1LYo4}9-PY(cIk$8%5;OY^cdSglxwadz+K@FAsHnpE+uFwgd&Khs; zldqq_+toqd{1JF!e=gu@P|xs$3Xp$S60+~n{Gm4{&k=Znf7cfn#4LCk2Y5x|DZ=5a zM|kRuC6uUm8cqYT(PlpgnnXw zG2qG7GdvmoW2<}WU)UR)0}*(F|JZaeWWm!@fLA1*A{@$kgs0xvB8rM9FHH*!JT(S= zLD{zJWV}0Ty!qjuXYzJKkhjS3j{VDkrvW{~li_bRvZwxty|Eb?fhYKz#eyLVo+bfa zk$8%5K+pUK-1!d7SF9s8pJPjNlNli{DX zAFg*jvY&dx`5^*N@K5_27_#809ZeI7rwE6&9^t7sTwtQ&>0?@_Fz}Q?*y?_~J8Qg6 zu<-T_VXHGd3I8?abbo;-%N*~wnB$q>8yeH-fdAS9aMkM(o_fRiDgsaNU%LYgS@84% z;1!9d2#2;F;i)&O5EW04(sGx9rxt3z?(uZicsohHb_Q=#gS_3Bk>gB zAlD;2^@a%;6;EH$;=9piHwS%PyTa31O;ELBH zJoUx|Bmz(HpIZTjEO^=kctzqV!lAB5c{&m1ppPu0f6(E1RNpRik5uSQufg}P?@VC1R3|a8B1n`Q)Q-lLvkMPtROK4H? zR6tvS2A=**?bkh?&Khs8lP{jZn-t_N3Z7a8o*X^Hli{D&{(qZ)-fl2t!BZ086^W+^ zhrJ%*sW+DRqvEL#>R`6n9Ku%jcsgsm-9@|I2A=+5@$-yW&$KlOJjM15Pli9=3;(zI z^U*!47Ch}h(?sGa!ojaccK;#LjkohHye%bc3EraUC!fGm zOwaIS`2Wp~>EU>1$4Y}A|Gv%Bf+EH{`2SrChAenm4R}T3DZ(MJM|kQD7m28Ny3-!S z)0@D3HqpxhY|ERW|Ypc1V2$75hLjPNagz>FwjSJ zOpKuKE0w<>=%YF+hSRgZB37;RpSBgPWWU8vObxp{;Bgux_Zj4W zU~+f^(&?8FG1_%`zyUQ#{;)y5lF8vk_%lHcPu%4JPuw8+?FM-slRI$=tsqCYTJDUL zJKZ-%yz^;|r{S^~FUb3YyniIQ!yrEdC}Ph>D*I4iG7jW%k>u|om2!WR$>AdTvLGJ- z@&S?Le=x`&U~;%tlD2_lTp)LalgmHH1ypy!QNlAHBm+S*FoI+@NV4FYSw+U^?lRzRxkeoY@k-P!SnCB5Q-rqnc>5#@(&nw&{S|7pD)hePMc)Uu2v>2=}|dsf0)2 zNxmQdKF7a{#HoXUlL&EQEuBWV7B=)A>&&Ko5Atw~lP$e@mk1D!TVhBKf=p>(7%njW3CIM7*xWYbMDIv*co z=%mGgP8uW|X_C=>Gay6fEDm(eAXy)i>@Xpmb@WUe>{yfTQ%|W!*B#)q`1oi__fBcj zcKzY_){c(Uy{UV=yGnk7mQNUpKd$q>{q`Sw$My?~#-cUX{z}^5I8WN(8ftj=8?BmJ zCy&8>9iy_8Q_|Y~_PzE!{s}<8ssC48sJqU=o9IBULE&%W#LnPN3*x-_z<6QYH@dE> z3wz|oN@monUbLfw}?Oo)ccA0d^=G6h*DsJzA`J717>g319V*)a^dD6|t)9z-e^ z`nDkJ1eJd`$(|ErouKkDlWdJ3>jafck?Ow{e}eaCMbl?($3pa3*!KbZkXk?r&4mvH z;~ZaXTqZQ1n$qF z>uM1Zn6C%*ryw)*=dI!TbAoc(QM9=;CHlXRtEoh38W*BOeI)eHoJHQQG^ylWZYnmq zz?RWJ4S~+lpJmct$@D<~C4#;a^q*_epCV;O=szlyStsZ}KxAZdY-f6)ze><|g8r9H z`X`wl=zmzycY^-)CjDZj2l{_3=sQ9GEhha~rU&}d1$`&zzZ9wdLHH9?#&q8a&a-wy zuS)B$!G7PuN^zPt9deB?vT#A?LqA|80ey8h_nzdE^U(oF&rWi-ej$~_;NPUUR{u4$ zw0bhLBHY8&U*ayP&P|f2TJA4ZUJe@tspH~5C_tdC2=4v@x+0&WHs3OHHxs;x$CK#(t~u5 z!OU6Hkqus3x+orhmQiR`nm#HHzuC@Ko{98;<%fU-YaoQaJ^N{)RsziA#7DVJpxI(*ZH&zb#|C@-HUYqMYBfW;g?9zkR zn;_zqxRc2%ql4%(EG_~>EB_M^y^ePTh*tI%h-RV)0hJa2)wff3+Z)s`Qs1_qhZLi+ohi;clM*Ya13;kkk9&;)|AkVCUGWiu;(?%KASg|# zVg$Wy5kK|6g@mG?HQ`TDJ^rlq&1t!d;BzyzQbh<&@r0&iLX%mScS6zBNp+r7 zPC^6GrFt0yMK_!Xd>Lgy5h*8=QE@{TN#(x>Ardpusi3Bs04bzqQ5TyO*Cdsf8_9TQ zX+}gA5i#XA5ou6Y_4qqC&WGE6@Sc8art*=`zEk`vn@1 zgPtE$N{J7|8V%}*rQ%~z?9v&rRMyydy3u3|h z(j~F^`0I(CkH4#9mxbpdrQQLY+?_9_u9z>S{(PDLIU${Bd4|91Ulo+36@FCq|4Z$Q zEHa7vJYqhdc%Qute-=1P@pp-{5`R6;XYqHn^CglwXiFx7w&WJjmfQ+jXm!v+tAiF= z9kkHuFX>N`gq4p#hC)$Sqo}5#5O-KgEYGpWaNsoKC=;gC_d)4g%}l`S`P9 zKK}fCnf_}k5iRvB;My{QI@hJ>TrivDG+1I|qz#GaUKJO3zR$ghHE|2{dSstzacPO_ z1*Du=G1t%GYc_&IGJT(|98U7?QZWYME;6ZNH%ivULVcx2e3w*LVBSQ-6<>Oxv}KC>Nvj7*7r3&W;O{W^Wu-?I_m;VyfKZD;e?q^(VtU*gnV{NuTJ zVdaYP?s|1=(dG8~@KpJrv|(B--RU8f-3pA2>+8v?I^y(VPl@hj#zik%lK2C1zQ;h% zx4RE5|5eNX8tb|ku+zX*jm<7^Z`mERPZ94xWXr4R+xT`D>A%$fRX0OYPUWLvobPQmxKSaWF3jhT&oi z)Y8HaED+@sIN4k_7o1R@E}J}9IThgG5zzoTrnn9?`1fcfBDEE_skGTWYr%))eGV~d z3*@%$BU;eWZ?dxhEyRO~cpfo*yR_lP82=Nn_p}=wrl{3sjK@y3rK)*oRf`KUSDS}Z zPFNAa^(xYf)zXVqs6_+c8ZTn}1;_$#vb0-Puwf7@yVps%95o_|lQ0XVW`^9ce>#=_jpkAXA%^UET7A`F^_Z_|{g> zpP_J?`wq9Ycf__l!}U>N)wt9K+@jl&;w`i0^FCF_R{C+Pl(X4SJ)P;1PfaT(^mtx( zz-DW|L3f<%rwN@=ew81Ky;VXldEFH6&?z638Ef;?i5No5gUC-E%jAz38zhKg5zQAf z`A-6z8AQv# zzjoh=qyA?pvMzm>v|*bm55(S2u_OwADMEtJMK-{WqKu3<&yO=EIy?(9COSP!-4k8%MJ=mL zdAs90*_4<|iMM1-bU_)mIB2#0>)4eC(tX}WPZBanhSK#6Cc=xMWA)`uPhY$sW!Eq? zX*{Y&i26?!p_Kx{9@ev*Vb3l+2dj+wOsD!RqxzzodJ+*cIS_-}W=I0dP-lLrvT8w! zE5^S8lWUQOc%J!lzwwOvdr*J$Xs-X6Shc$78ug2S{82eIPMzpbCpy)ME~B1@^qK9- zC$UwBVsNEY)d7dS8b_#{tDLc`ah?Gfc0e!V57opdAHWdh^YESqnP=)sDH`nh5be>A=0x{kfjmdchiXq_OQ@XQK|BE`6#5({-Z0vXuw zJCc4Y=BC8zt5ckKPNHY%JEsnW;+dAvZ0hQi1cVbgjI{%#jQ~vwn46tou=O_By2xN_ zdUId!wAjAb2FjHD#Wsk01V)$qS$H0k4^DTh)p}+-c*F2jG|;U#I-j$G#oZv6SW5KM~pFNrCBqNiB1o1A>F;1cvEWov_d zzgcH*qgiVydmo10>?-eZ$YzvhsJBDDcq1ABW3olA>TVv=-`XQx>eO!{X(SUgEaJ*Z zKsIFuAujs~6(z_bai`U|`#R)K`}da5nxl?_SkTdK7(T95ijw z50o~nn2iJb8=LXx&RW|H6c{2+F>asf_y^Kqw9+zU%Pu!6FhlrC&lf-KiXWNg$mPx_f{^toW!^>=-(Q=(g znw{X?1;Gb8EsC0fdKE+X)0-#YQbh>g4ipkx>3<03<#((EQX%*MhJk|I?uYzD6I@75 zFmzEHHNl;WJ`XfO{>t_a$bU7-e`ToHGffbiejO-b2H9#*Gt--E`*z-8LRj(t9IUY1 zF`^~w6YZ#Pa!rhltu+ykN+?@0=cKlh0xYtv`KQE*#z)yHPdwph0Q!gYd6z$v&-n2p}f2VTDe#`Xc zB-!7gXUE#1`l`dy-S6ZboEZPL=9spsL*+T;X?e^6#+DN8^Dy_XF6>yG=7P1^M4 zY>YsL1|IOD@OT}PG`r@yEhI0sPT0@^dqG5} zZ=0jm(P3njT8=G!8x(t{`jz^D`Zkys-4xeQk~&EQ&xtVVlMo)Im!)JI2YPuYHbeT3JXVeKlw`;=>m_2zL+lXSdjuT-jv|a#^a)-E1}WK@ZzEv3bAfG zu>x~0N?3fah-F3cVIa0h#7dxOejBkt3|9h=zRvOZ3ga;xh$ajP?*Slw0hY8f1}=~Y zJZg!6<3L(6%T_P}jSfdIU*hQajVFq>5@_TYWE(gY#xT=jotL=wEZ2>$8 zur@njm`IOTVFjS*B0}wFMAO_7Tbb??2sB{{0DlU{pO38SO;DH`PVB20qJmnm zlJ=Keu+E$q>F=On6!V9ZcF$bxCRjS20_9|kXBO?4+giqo@%Ln`o@Mu3r>y>^!{)hK z@jLXa7|#`WblNb>IBD0jVm*m?#M0F{O0|PB=%+b;iP38d<{0n~nX{SqH1R{(Mq6)N zclar!phaH75Ad}L!B<3Z5rP{jG1H~3O7V7(IVhEt#35!i=pZ&}9LSwYNd@XYZ-ghXU#v)=QX&}ja1mwq|S7Iga+afp;!9R-NC3q_q9=}n}}R<|NHQ^`)5YggJZ<{WciVHG7vWs9-sh_x>dsGRDtl^6MG z0YE(sQl}l#c4n+jNm?PBdbEIYcj#*z%_niMyw`W{dqCC5s-~FK&04HJ-KpISKuHzn zq0y<4$o*539qtwIN^M0?Pj75FhwNv~^BaeI)RU68k-Gn8JJxs)>m#2DDRlWShNJ#; zcl(l*Bs*A~4R&Y_H%4D>_jYIrzg&C1dK9i!XBJjsN!n-E5;Ux+xohO3>c40ljKk~b zxcL}(W?*e`8O=_R&1#H`-Up#?Afp9{pASjTCOM&IdEj8SkWeXDC+lA-yBr&KcyEaz zq09Wg1hMG9p>j%&Ca0aNyO7i4s6NT5Kgnr@(=Ee|mn@SAInC)*PRUj|C6k=yN66_C zA*bMcKdQXQFovw=Lr2em+!l}wi-C^PO$<7c&s=0ZTY9w0-G*TTVj*YHckt`3J>RD^ z#VF18bz7)cn|fJKy59l|)sIyb^2Xyefwt`$g#_ z9dX>z53U#&(@xD*7Rz1)u}{QKG^7)%JRfC zT-vZpdT~ZdN`)YT&|JqI=RwN%p>G1fE(|Y;hLp+E+>~-Xw)!CDr=m%DJazs}K`CDW zDZ9W=H2Km@IJ$h_=tcQX4aheqntZngp(P)UUt7DZi9E%VoeIogy;3|isl;U|DTf~rDgLAZADL0Y2Y&(xhqeC zJ!rKI46xR}{U@*t8(GX1n#Pn;s-WMT-TWU{?e zX8crFDjvC0zC5OaI+!Pn9nSahHl~~pxGn(W`7IZKc7|Q4v7@h}pc&xP>su>(JJ#NV zkz$PIcv(w$(p~Rq!0Yp&X%?i`qj%-Q4DcSIQeg|Bpw%?9xcvm4F$$x>*)lOk&|4S6i7O?*iLIJe+r=gn!8r6S~P)dumc&y=XlOFY< z=8slG)1=n>U&ecjTFL4k3NS4CDTOL8fK6X=C+vSt7!pX>M8^KYKte(wp^OqH2NKAi zU1T+vvKoa1nwA!*AM+CVTr7~0(Y-7MD_Zg^^7WYXbjYseO$+=Tnv5mTcy%)t-IK6w zrf1qSa^j`jocMfDbjZ%;D{5n~*b=Yb`K8*x27o5Jw2Qrsa*{SVKD`kVKB(n5YauC^ zPeGz(BedC*RQY*rS)N+>t~Q$ucDWua{c7PBH3u*vIUdh>7iRgR9NL1=at`?rnu^f6 z!||EuFomw#oE@A!c99VmPiAwgnsX3yG>JnEEn~_4RKL*V9opoEpr)@#NY@5ylMj*$ zz+d(8^u-c(Xs@SjTB$4_MW{JDK#)_fuW&S zydA54NQ(V=u%cx;-8VVp)O26V;Gq4btyUcFaqH!CVYa%fO1IVo=c6Fb7167-rv$+n}oMq>*Z_ctu|OillSZE@X8I^xb^Cq{o1&4_nQ4B=jje% z60MGDUwf{--anr-1xOv+{RIfBZCB;&*OMN+DyK=4eVU`(-%3i{XYlY59u_@;h5kib zpz0R26YLT$1Xi4P0Ct?PIgl_Lbj?R@HxuY16XOj^*b_*o3M9Nsu=_g_w48?8oc+{T zwK>nyPfaNa8%wkSQ8Z8*-i^#U}4pbDr}aUwe_dM=N+P-Dlqi(Puz>w_>*OnB1xsKBX2shuu+4enNUN z=N0f|*K#%iJeXfW1D0VC7qHwxOL6Vs3mXn<&P$*WReTk;zSpP8FJYs*VhM~j4Xs%C zu3FE=hn`2%9EY+tF@2Yz|FH1|zskKxLA-oaS+fIv2emm(C7GQpTaGWfL|fy;n@P`T zYc{GG+M0KD*F)O4hgB>VAR~9Rd`y+=j3!Wiy2CDcX)2~clE|xsswvm$lhW+&$?-+Q zp%U~Yh-9NCKc&WMIq&KTFQxmmQR`I?7O+U#&tXD08TnaTR$KD|PyD?jNQ35VqMW~m z5VXlVsOPmt%6h_5mUZDvgs2bDJX*niux>Q_6uWnq=6G%GQ1uK1mA=a=ka9!N1*V{H za%h7MA%B6d_fU4lb5yHB7P9=VRmkOQ&rRP|8J-=`)KLTE#21~D?sFHsqRCD)oAkI(bv%tUwO~JKj)GUD z@-6*Iqdn_?5Ifsi;g%B(dV-?G=o6jVt(d^C8c%@TO7dLma2Gq}E7ErfyL9zq&|43~ z?ng1Zp@HOs`l!eJ&tlfX>qdIQuY$SU`-b{&s4;a-1I&Jr&n#_CL;5Z?r=ew#u`hu9 z91qJkP=0%nUrvMmOVkA#?P0v9tvRTTd)&RIq2yvcft)yP8LQ7}UwgiNyPxdRpgz?T z-uGXRn5*y(vGjCmt(F7bw$a}QtRV_;1)puGtpe5HU&ygkZAZB#Z_>s!`~uW150TFx=;cWpKDgZ>{)`86QFHBE*lPg;*xwZfOQB*k5Luq44$=5wLUB`9-t z-hd{jd5@O!l0K?JZMX^@zR;K2rX?u;H^|7A(Srnkf5syameZ!>>_AIw@^3aoV00({ z-v|J*A&E3Y498d9Ok#MB#DMWD*CE4=CS?4YdmqbVh$)Z47j%aLhkCKas(eNyfpLP=cJgmQt><%IPdvP^$VRsA_*{c>PE-n2KN(g^S858 zA4093@Yi4__r9r~pb`5@?G~qdxoG%^8`KNE3hJPo&=mv zr+OwF_1{eOWE`XXN2!qu4+8Ca(%(=!pxyD7zXY+2?qEbtj{C)Pve&c!fTkj-hL)>Y#;q zDA6x8NDTaVmyt+w>SA-640%D*=}Bqo`)XlbdLs?K-y`TBf~2ZGiP0v%Kvprv@&_?& z=n3UC2;0?BF|b*nqP|FPgzgq&?gJQesrvWR^iEWNhg7D8RlngUqWUY@c%bTcKj4Pe ze8)Gc`3}h|Q_bZjyIkl01hXi86pKvD*#aa5J41HBMn}hA<&=k`Gnng-5&hvH;W7gi z4^?iPxId_Cc6hEP^?_V&A^rA}wq{3&zKrM}FIg=29X!sVf9weAd$WH`GWth0_m6|3 zfBcPxF91OFj~#*j@oU6;8_~>C_P_0NlYb%^M>5Y*YE(jNO=%LxBvIXm=};Fvb*=MVhu{(D~7urPzpf5 zir0i{KbJ?b1{wu0o->ynP=Y5KfV!M5y5l8Fv*%F7U!#hP2D=;;59<5Sc^SGbwR;xi z8rtq}8tvZT8E#~gNA11|eI%MT++=BOVb!3u8$w%~Mt7Q@QB5aPO#=aB^JQOMBp`OFK>y6+`_r8tW z%bID{I>G6_*&*MQzKsTYj13ybhWq7fX>*2cr-S-KsNW45%!Elut1C&Y`ZP9U(%5$C zK^HWt?i%YS-9_e|>y-aak_B42a0hs=&Dlb8o!Xpws!olgFZRy*qQzrfN=l45O>k7)%@#1?GQ$HBlD~(k4)ihs7h04|wjB#Ki1}Lq-sgHUY<3RR#4%IOf13^Z? zCX636t7?KA#yix1amAFJ{dTN-XodTgoF;rinQ*@JV!Z&I^ zi`_YOMR!8DTH&)g0Ho&Z*J5de7*$RKR9|&~o-hU~S}nlWJ%6Gh(dYSofUQkxfsfc4 z_Xe>w6l`JA0JeO@7Wzq(y-tl)S{xaL`{n1|YvR#Q;RGtVb75$--ZX;(ag@-?;i%%MRUH6PzU%m20mU4K%0JzR^>K*fZFtA zhiAEaa#PVysfug%>z)VOF*eGWSaKyFqe=cybr^az85+~@itdS{39u?}EV>k2s)bMR zXt_zXqfs$MQ0K0rDJy2cN43Hyw8ELo6 z)CN%zP)hKwKoRHj9Q#ttvDJc&Jjvdq#u8}mbEq?TN{n6v(_ka482fhh3sKj62bY9a zwbM8)H=(7eeSg61E7xgjsD00qytK=Qs;mE&%E}RRPu?Mw(|H2i&d;$B2>RLpns-jK zV`@)}TK(0*#9ucnIw< z-KE{+Y(9LPf(|XV`2a%f3G&~`XK1lk+2WkD8UAP~?4Fm9&kinFN5*#!NzFN5Qm44} zNAlH(c9H|$P^>w-nty{#_)8qq?+&peRB}aeDO-}@LTw}l_!aB3>Sl6^K=DcFX#>H< zBHNd#&W?Jpq1{Z5JR>+gA`zoPU_*A(6(S4g;`qh(=7h_*5@f(0l*(|FH9Sv}w43L` z?*=3N`5nrqZA$F`Je}`LKYpTKX>y`dsda(-D$x$5r>@4wJXo@}?~yjdm+g{UQtPC* z&e5~`U5pji)Gfx+YZ+$!O;Q=$yKLI^`>T_kV*a1-II_UNP?6t(m+fu8K7+Pjm`+2U@bK$G%$mf)q&7MF~u2Y~DqiF3-@tN0N z=v3iTv!7r`{s)*bXF9P^kNmNAeXzOlVirX0O$p?a=zqna^B%9UUG2fiBX&RC0SYkJ zWZJJ*d@*D=&!L!thSy)g8{S=SkngROvlHCRyd}SREIt$mlk7uHU8^rz<(Jw_NAqui zi58Vsd+AenW1flcQ8wenfZt%6Hl7>>$7u2DV6021H#@XEr+Tv!-nyAC?>6-&m&c)G z!9n9D_>p3eaVVKiyJCETg8HpHL;jWQ&*phkZEfBJoFmJY7p>)CEpiWVpMQ%G>ln}o zvBr9?)^DKU{{Z7h5onA%eHbqut|6v%PmGT48G-Q(1uZ;%YCP8)8X zE%G=`xCm;VzqEUg%a>CHRjOdXyY3Ns60c)5s+K-1q`By$)tBtVewjn|K;HyB!`wiHT?sX+C8FPum-+PO563ak_0_R)-$ljYv`zzM%NH3(v{es}nwRvhrtYT}$PNnGv<-iT4A4*agpE+>~XHwup37c{%Sz13D*0^#i zOiYQQtoqan<;xnsi;?)mXmozP=kkrA0oQ{R8ov>&O@n zoIJ^4XU2Ho<3SF)GR7005vJxNC{*L$ECkx>k<%^{3-i$+L_siM3Iswa$VrkY2m(xj zKq$oyYF&W=T5zxA`aRCo0`@=WPJsFiVOXGkOQ0&O^%Hp5gIov?pX1lWL$wjNkK+vd z8*w!pXW-w6dzs_n-BWQQYq=4}PM%W|+*1><4{pQ}9n;46^7@4l_a}}M z@>*-eJ;rfDUW<*m_4p;uyY4^Z(1O~OWcSo$$(v@pna8=MxTmH_Uh40}$taE+;hs7I z6JsMTnd3&fr;e1oUm_o(b0MyKc@+_EqRI;=0OI6e)<-yzI#jo%K~_k=4M3-(pNi%o z(AEIN?=}(tGeNPG5Wf}wenyCI2E}_O#S4OBDj}W}=oCVHhz8vU3WGQLdbnj^rS(75 zZ75!&&VthlL;Ff4HEK<~QXB6dj)f&2U%R584|=3`(Sx7n9FvvWWdCl=;$Uxdm0x_f z`H?=N5=lPMHNpd2VwzH$=KnEDtOQ}-pnjSMAd`OT3mKXE=@j0;S6r;0KIgE|PX|O< zQ_)C5(g=h~+K1f0%~axs+k#pvq%F=E6lkPQT5BZp%VQMlC*;>Dep)eho9#oojMR2l z^ghrNf1TIh4Cg4?hbBtgKAo0N=jnBw-(L)h&Lwh~OBC&c5-W*+{3A?8wFlbCIuV$> z2aaCd((eF0^1F?+#zLw%bu^r@8rskL2J3wxavqm1a%PbANU+7wa1FcBFto=*|w(DDUkW6ghx7@YkmmKb0wM>9s}cSU5S zk-r$8>3hEbrLc#zDPoj<&Y%y;Ukp>K^(}1*jZ^X}t`hn)Cbq;hGP;|i?v(Zl`4mJBR*x656`jiEB%Jn zhxKe*hxoFH=1a<0n^d*}4Wtx15W1H`PK4-Nf2G)k5PkQi6vrc^aVP;HI*(f^PDF@4 z#!!lr5TX;jX@aC@;cM1-EMq|%AYyMlBDZ;W>6tLb=$sftI}we;mXGW*qW?=oLx=3$ zh3G~jS`*QUh~CXn@@l2Y7g#@$M%bhgdGXSS{A6jwvb2TLKB%>Qd+-lM7U59my_|oh z2T?_{eMT-5(&X##jAL{;(+REe6_nf*e8ym1^g-~^+47iZrc|8Y5rZyrUd2vK{XEIx z=kZs31&bHwV)$Z=b5wkGvw;b{SbvQTd8U)$t?ke4ZD}w52+aD75zc0P#&{O;jFC3v z8J1JXGwdy!1w!2iwX$~w<6=35E3uw9U8Ct3~OUn>&CxCyI4deHeqK z*U5wzIz?}Wa?-hc*mV1LdmYYtc^(S{D1S~+KrBDaiPJhR5WON6y&_!xL2}WbrmJti zo(UF|mQ1K|C;pv_@_;*>+`ZyRVkYHCd!2oI z>f0;+V1M7rv{0l*|5g0);{QZ}`e=Er853J2?*hn0%lk58;+K+lHiz3XCbmi5NgQs^ znApxM(vmj=5uxYR{7@ zzLmq4vL_${WeYJ<=3D6XEpKiKE&mu=_04yU65b_}cP%B*`0?gJBlRGq9<-!Vk29r@ zbuxqnFaP4Og_pl0LIB!mPvXZ%+4KZxMXR6D@5aUmsGwy}`bZ`ha{n*0XS4jeIfIw{cXBJXFhb;dmQHjod#Vzd53- zIMG#je6VzVUQZ78!{O95m6K`IJ6DY0Zs`9Zw29FWM*SoD*UVX{St9<$sI@ATtOqFA zyIU`b7c(fm2pa!;P*UnC<$#oq6Wr}P)nf>HhNtgQPTA=E3x`xju3O3}>^vMseexZI~Nv&To69rB|rIw;nW2He3 z6orYw(s?LzthA3FX&&3iLsn?!uamS;raoJ)*p}&^@o+^*Qkt6>QA{?>mSIqllnU&>Q8TUTYvD=N&Q1O{SZ%` z)*sjZS?f=aoz@?HN7Ua%^`|mAsXygnt$!fbPU`Q9s6V~Yb^Ybg-BX%YsUCiIhRgtrSUWO%Z%|~%47Hu)hzvl z<{!Cj8ROgJ%P2CeziYYe8ROf@{uXLfs6)2DIX{jU2AHtVPR6ge5Qd0U_9w9Er-S=K z>@($L;)(${-PN(A|cQ9k(K^dRpH)l+2meaJn!x<9~ z%Oi}DBiR@^5{;1~9wSG(57vX+SJbyV{coJ7Mu!~Cz)4Lw<>aSYx)uXhvuWBr4lT=p zP_A~5Q_FI?TRqpdWSDvxhp1J>i}S^b#_}sQ7>mR!H8^WXyi$Yxq~LP>$;9bz(nhM3`}Ug|_`Pde{2(yZmLcVC zw$~}A@Voo&UE}81>)B4mv65BT!`_W^d6ZLd9ZQ1x%E-s*0)F)4^v~9vdKm`$+UxX} zr(njfXLa0l{HI8uudibCSB55FN#~7W-j-=64&k80Q~j#i`lQzAONL5!eO3y$8#+l7 z=Ya5iOw#(_;ze;RCuQwBzByJNr8e;E>c3AMs_GcVokQJIb*4}1nY)iK!1v>Wk!k9w zyQ(YkihDCoXr;*`CV#KpclQ(!d=x=H1;Rs-}v*N z{&b~%tJ(_gMy9C$yYrClxP{9jueln07`agCh{d@cYO{KT8MyoS1!_HBb*QIM73K37 zgk7*Ju%V~6rtW>?Ckq!YtU5F7?v4dGO!hQnpdLv*rpvM3&-Cmeb|Ba#y>^#N$~%K^ zCmmHCG4@*83#>ZRFLh69z5UD^zf76%3%f5BE}dYhwW@8H{TMQVYp~-zG?gv29?~1% z4`1*dlk)0Q-;-XO7N_U*!zOWFGx?z0gijk25Fx$x$_>w=x>w@Gx!gWXQeE_v#q1hvGhXb!@ zMkJQvwz=7PZEypL%}(>yRF5|<&9}~z!c_~H*VEvz@=k0-SM0q9j9!OND0hwE{8%kX zmJS0_3cbwKq( z9e2t)4i=tFwv?CPQwcUILJh)@b--`-IZKYJ{sAt%P+NVTK!E5E!{&8$M|#cgBMyR$ zaCBH(-QCHZ_nCMv?{jz{%pU{xsXK}T`9Uqb&Syn)gZyFnb5rV>w?8)Ooh2Wg0A#_B zW20K@j&z;3laznp5TUx(`P3vL<5dCP zxE1kP&(b2?s0Vzp>)v_tgckV&o?ZdP;7p`=w`j`@@-19Jd^5nt-Qbaeopj)*PXLkd z&Kk?VnfP1ozaUWiO#h3$RfaZ@=U{ViNP28dUJz9MEh+rv++*;El(QkU1UbRURyQ(GG$)%!AkyVX#Fu3whr=(faK=Qm0?$sb0f@u|sxvAUpQCS0AEnb4`s1A(ZAosJo83DR72V$rKYv~;mav;< z7Qm6~XSgeguQ+B+|4ffZIWWX=AQmO!@Y7BGc=5AjJx3u>`>Lev0e}JRBO;d;y-JGi z3NHlrjBs0bZTY1tqnpa`Xv=#dV@CKcUuSK3HzY~z;sf)CNLq43;@}kuoEfXwCKj}! zKU<4?c|! zX2jET@P@v5aY<858Dp@=7ikP?EKsz?__urvbu<2nU61fO@6=|@w;6SVU7_>k1h9%# zNOn@3w0#9Xlw@dhQdQmBp7S_zsD)~)JE4tkr3Imz>h5s6Lf0n;kq?uD$bv~Z-6RJQ zY~u!;dtMn(6A9$jCG<%gv=6g{Q4aAOPiGRn0^&1dG*QGmQGi!qzctdRMTU|19FVR+ zu5_Mlr$@bqfjZ!H2TNslFklz(9@R^FalIQ)=SvcG?Y}U{#@h&miKgIR*$h7;WW(7p z`aAr-{3c#QCZNgaUOvB%XI(-Hfpa!+KEBFW>9;1W;KQh0AsuBQdWc1)#v4ER>O@jx z`;7`{eh|#7*g*!ktTG+|EwrOTi;hFj>PlR}YhGj9FY$o5*nRMc;CE1Wm5~nOAX2_# z(=|>dMJM4w0VUxz=iynBhawHo$ib%-Fea*00IJkr4h;Uq)3dA;&}6n^tFQEG6^NT@4afK%$oV7aKA`=jM;Y1)c8|$l z<9uv(7i}qOG;Y8rDdocbSBaH~t_b7dNFK*Q{qttiAupC<& z>t&guDpw5iOWJu}?z74A^2@FW+TEDgXs@gOlm1?|<(LYQp*U#*{O;t?gFZ7A-w}e9 zgnAV9EWF&2Jxu6`PMG5tk3_NMXGNCt=_< z*{WcC9;{`oVH;wh9cNO}!%<(Tl%pTp*W(If)0PJd6*^kpK+K zT`@ifaxp&4&*#Kr_W00`H)R}gnB$1pX}o|TFs}h2+i?`n!$;5*mMMSTH}IqnqM(YW z^DnD}sl?+6HVFkYVCW?Ie_r;0!OjN$`!LK5D_r^ zH#64y1VLJt}29$Ef5mURdetX?zn+!qPrD<;()|g9sA-4&! zUpB!XIMe+F-fS*`x3IR0$NvfPwWW>xWS=iB;y-{?z}SIkbRfTI<0=xP7I_@GF<%3EmlaR11k`wTi5|5` z!Elo4UMqTzM%vvZdfdX_&qa^Pe5dNi#M%SUW#iG{cV}1C%uEj$;W8;3O45m&P#OIj zWH60Evf3fU6&6gz+voL*jd#0SZ2trxBH}}Twbk8tvgOF!e=GAH;IA_N+!wTg$V&j; zd=vr+^bZb+GPr?R3=Wq3;F+n_atf+4_GH@=@`W7kb8E>ERmMg;TZ@jzm+icjalYg& zinAfC@?ZE9J*4LT=m*R>kBvyZ9bn{|y^v??bFAC^IWz3{(?A`!43NY+Af5CJhKX)N ziIpVF;)wrApbLJ%$U*OvU_s9r>v*71zF&@!xq~`Y4~`RbOY~3ATmpj2T!JU?FXHFm z+(1zhgPvJ6(<6;!IffSz!hj2d({wZ zA;=`ZJyr&z28CtkF?@I8!K5-Ii@c(WaA^K$Rsx)rBy?Q5!M`{LknrNjPfPixldj^X zxnC9?O7yX@eK)Z0U>hX(Q27^K01IVFXqT!5JN@?eN%=i)fPt!h+e-2*)Mt%~d$)EL zCPYQMjN6sSFX=6LF3jy&*f*gQ0mgsIaUGV-h=4Jx{L(Ondt9w*x-~uURtBv25s=+cKRVSiEz>%rbdO0%nI(~|PW1x!(;6sSkTfjX5td_?CC8H@$ zXS%hwv`sNjqqfogh4$vGWM}uLS^ItNR(G4*!0P&mV%ZKk^B@>PLbvp4JFosj4f#t7KxmH|1X9l9d#9IE#TJh*=Wr zF%R^`1)gx}EAq?W4KRr9OxzZ`^<-7`Om~fOJsbweE9*n|qqUaut4_LVj6HJ+diudtC;sY^74Ybp@A)hbRd0!$TzK zp>8XgAvMmGQotj4aLhMYtgXA+6}%MUIB`gky*o4uZCDIG5lx_GX(UWMkCQ?1k|EU5 z=XDnH7vYqPH_Tn5_as6PhQ3}Or5I}P`~ zi2iIEVXR~yaH;_KSG_Xxk%acd(~oCtDtMNj*MiV&ZfSW*{8F}-cu=%q;hfrtRdr++ zq>O6LY()~x{+j&KycrEy8(eb#OWj9Oi8*AlQRY3FoQM;A(g2@@tXqu!$l~ehHt1qF z9SymRgGV^D8K|kffN1UU70ADby&{MI;bTC9HR#&1-|%6d2Q_iiW&-{nY+NrDQXh|b zO%51C@TB+PNQ2``K^F0JN*!o;IQ&Q<7~Qyvq=h(P%$n?kD-YI=eyxFq&EJvuF2d;%UqYMkgzu7XGwYlD3q{T}dv zn?h|AM8$*1C%0j|`K$Qk?YLAGfE-Aa2s*D)3!KzKCq*rSZ^P?KMxbN|y^3e3MgrmUbWGjq0;sJzi{TvBS{!^WI$Z*(Dd$ z$EMCud@%=)J%|$h0Yw@x9 z`;<(?We>BGlGPBMAWJc`6pnK+C6}e!66_dUoj^w=Ql1LW3lhCbHFE|>U{{8 zEQ`z=gP7vIVje8!=RnHJ@~+UHQ{>|RpjN9g@S1)FH4Yv`sx*85l<7R3X>t z=nu|uX3TCLU>sb@55$CAtWih!^`26p88RAUhj+Oku^hGOfu{nMij{9~V<;2agImIe z7h${**KHHrE=MJCz8D(;au0y-b$~M)N3SbfB^QPM3DSu6A!!UpTqy0{-5haQEAm{4 z7T{O3;oi$Y5+fNa;AWUhiy_Jle15uW%PEOUMt|qH*s8^FHe9+-W6CQT{oCUU56df{ zb*U}kl%&)(5!SvfxKL>mb#Pe~@8TwSGzt6guEa%(ZZMu=bMcOO!(#(?)-6IP{vmn~ ziO-F^=W%%I9QPiM!eI#Iyrn9Y>QdtG5)ZBBtx&^?cW4oYW{;JAAc0?9UYuIRFHnWv zll8MAk{AOYe1?9dNvS1Hn$$&Ov$r46D?G(GrgiVLcy7lLt^t9dMJv%?Fuy{^0pMw_ z<@~Jt?c;RvaV0KYp-=b{Ljz)+a9oQroVtE<8&pCJ7Ber>qSOP6H;K1H@33}}VOF4q zaAViv`1}!KEBA*=e80V`&3qABRr`ExK7vl#ayt4Kj*K%wzho->uv_MjP!402tHo+i zLE=wH@6ck`5XuQ(A=ayLqpxOYZ){KgKvZYO|tHZi%_vesvk8RggJcad9CzWqz>zAUt6{u7Ty z2$gMq%KrA}bXAipHrvYjEm*#?l|rW?!{G= zsbqC608<1ci4!o&5d$?zU39Z-b`F{qpC{JU2C3%cK+L45IWb^Qy|~PIF;MD1&I=iO zR4PXO_+k=Xw7WCF{+iW5C(r4)v?}F(Af}DR-kdxNQrs~R4_983DPCW)kE%2bD^K$0 zdH>`1ktUEbuRbpq({wK0$xIyYMnr*dn~!t1cCYj=$CZzKSe<4Y1hKtUYVte`C?O*s zQ!}>XwPlxKfTR0^o$J9p>)rAW1kCb2P>K&q3PiS>Hh$>-uF`&?^+j7y8(lMKbIar} zMh2Ugbw>(=S&J{NJJL5)ta7Bu64@bhh4v~9HJOQR79G?bxfx8U>c~R#E?zwed5EpV z;8qlV6}U>q7PN+wUFVl$eb(3d4!d5#Sux*g5<{@E6^|%{1LP>yd&$W+-gv{e=zV^> zm=LtTocE8qBNf51bw_Rtj;T9xhqnB?Ff1ad8ZNP1htZm`qVCAlP`w4DS-`fRm-gk- zs}}uS)|Yrz!pD1GI3iMlLmtQOMAs*|(YG9)HLp8%NBv~KfBryi^|7S?mFEg!?^AXN zxYacH@FC2=6)hYUb2=#7(MR|d)LDN&ErJVPDD{0(7nLZak%4kp#F5H-uWo_6U+CX? zyHO}Ze8KxdUE0Vm@}Xe6cNZVfmQ4Wo7|uD-EsF}m@U$p|+Loh5WF+x@p0OaG?3p>$ z#!KB0QW@do!46b0-0$GQ7aNvzZ$=`Ef|uii%SA|f)cQC++G^Z{QB#V5+x6qp8JL_) z?7f%-Guq6fPf2tbEJtBl7Bg% zdW6?Sr}N|mtUz6hdq?qFj-a*-9u+_x_T$MBhlH`{QiVWlv1^eZ_M|xXj3@FIc9mKJ zFqIiAAH;0fuj3utb|16b{tnxQ65&PwbfO#lL;3wna1W%{vitB0vmNnl>(ksj)~_oC zJL;Yl^%cqDL};Hm3)QgOMH^WI0$OjuU8?{*ORhn*iVe0bz%?^^0KDBDW9^4K7$ylc z529=gH-0CH&}zmr$K+ZStMIrsa(B#=Cdi*Ts5c`YgoOC^%g)Bw5f@7UR`d{h>c`*} zEc%X3Qou-YJ4W1J8MR&zl)6nv(NrdYz()H~A5P1lVUGLd>}n9ZAqd01%o7`t4ED8p zuJ}Y-JupqbX|SI8*Hrp)p8)tdz#b+}8U}y^Is8Az@SB){oE$l^nY*nV+@B#AW9*eS z@+3P(lT@3wY!EOB7Rf{S!))0fE%E^<(i&a#<&iFOd_kgJF$TEb1#PoQ^HZ#Z*}jEp zVwQHbTkuS>)5|<~n&v!lB~|M@Q5?^9o*0Z`j`PGg`a$Q3_G8{hr0QgdiiOToj)?f{ z*p~g;kBmraMlLeykr4x60b}XyF#W}wj6SHP5F;bn#E}>b>WE+O6D<&1{uwJ8=n{6= z#I?F@SVh2+YCE+lW0A>1A?ovHT;=7ycVJA>(39piDC3%1}LEPCTb*~ z1J&?533h22k?fDcz?47l7%|*GI140Hkhc?3>H8cIIU0B|6>)yghT@8vv}KPHyVx{? z%HIn^g(2#KA?QywKuvOH$~%VKUKlBgi`yqyAa0Y*Co{06n6M$mi~33n^D^`pBW9<|8RD2J(7&d4{E+H{-Q1tB|A zh<3mG19LbUAhCQsAwGi*e}Y22F$I(vV3T%GGzAJU(G8d|sj0A5+?NW}yR>ph0N{ee zl?BWeO4Se*V9l#VyAW8VBIuPl=t=!o=m~OYV_}KNJhG%!q704|ZtdRr$dWQet_v~9 zg(rTSCgtCrEO;QRB zlEesdz~~oRbB>yCe4X_g$b-96P`j6;2Z@mBKEe4$^5u=#B-d77FXbalMLu^umfGf1 z0F1BEV6NWKiY_<2fcd`eT41fsjMLkq?M7T!h+^Tk3L-Uht}6Qp(Su^q-=Pq*WHk-z zkZs;)e>eQ}?-;^QemAqjcN_R!js4wOr+;VI-(A_^yEph9&EzG-_l=j6Mz?YBt<7;rsI^Ny%qybZ`@m|?q(=pjjjva2_q)>V|orO5JD zaQg!r2@7&yLa853VZz(nwE9~?XyWrVL?FfzN6FmU$j$kj4;Z#mTh@J zkv?#eh2wL~b9GZ&_q+`+iTe8bS*_DB9H`^4=_WGr7pf^uv>i545PrKy`_R+0byj0( zUOWvlTH=Tp%ClxS^DO8)cF(^VRq&i3RW#5q!{i-U5FHfTN_0?cSp2^rBbgp1L3!9lCy)KX#gJ)Ag@T;H z7_`f@5?2RhVS%F*y~nnb-Cv@_nSZtg0xpyS2ngcp2iyB#Dl%|0L9n+ag|*eCZhbtI z(lx0 z^_$?@8ylU`MU_)CeXO(_yu0(_4sE^3y_8cVjr8_DL#vh9`ITAWrY_*>y{za+AJ+A@ zQ`ZvIRkYC}OjXH^X9gWa50`eE=u_d&+YT+jyy^^4SqM)>!ve2)HF%>P{xs-sidBq7MRdHUB1>qtWV10b#h0d=^UQp&nw4TBOaPXuupwsjBbck5wLrSq zZr%h5N|Jf)87NQY3LM+{7JiwIHsl1-<&+6zpz^2SkbLt5^1#0p<6KSVY@b9%NJg|7 z=g^T;83%J270bV{{bXln5|Ln>aT3uY+dymIIFXotMTxIh;Z1~uC5yjDRzI|;4+Kpn z=8hkLeA=hG(SVc(5Y}bXkD-yxe43?k*mWub3&2PV?zwATb`hJGqv zf{p$HRM<>vF+lW?I-G*fF~`U1rQ;^7 zG?h9KO}9q#f>TCwM&dsdgX>{xCXQyKhbg0ZD@jyYR3HX(+d7V>qY^yC_ES^>2?mS^ zQYBc{Q66?C4%Oo9%xZ!8304Y{n3vLe&@6FWfs01D74;r*ZQhOf2Fn30GJ_U!=FA0> zWX?D{=Uohj%o%Fu9I|r??VJp|o{Q|9Cjp)O%4g>kkha*?QJmhCZI#ExWYn z)9`so?Zu`%_Ckw1!2G}a9|uu`+7)fT3!zzntHbjrc(p%IDAX5t+#i~~=`=%3KF3`o zj#?{1#mk)E+BwH<{NH2e`~;f6EK@)tvzRUVC#bI`Zmw3ZrrL#nhQeG|l6=fD$aUfowv4UJGydf$ed(Te|u~oO`irwd_$~1h}6B z+}n1kJ?L^f?mb@_(kel98%lzOX{y7p*WQ7mww-+Sz%Hlb9x8E;8)r1li?Jgj?KP-b z*;RFA5HueEVR9Y#fqCN7l>XUr$J_|Hh4&Jo!fJ5s+%F|W=2i%7E~R#&YILC&N+=5r z)=f8{48T~FM3 zfTlaxBg|R&0&t^xe@(Sw{vt9YC<9qN->k{8nf#1Xs5c*=q+Bk-^_OCHE;S z_aSnYZ4aO!MZ85WYJ^`G41qkpWPZUSDKpMRekH5l0-?gRbSV!e5URHr0LR52-qON{fU%6(per*K|q(ow*AlR6RS5sAOOjE~I&F|u!viz#}Y2kf2@FP1{It|Cl{pSbRTUbs815E>gibCUZ+>jl1 zc6qIM`f>5rl6}&~Uy*^Ul*B^|xc7y<-I2K>D(~j4@CsZQA~U(S8=Z}`b}!?Dg|WLU zAN8~16?H(N3{=;GU0QKhBvE1QJ4RV!enlPay35AnGrb}L1HD%uro2Z~M8XwyZt=oG zwh)znD?PC}9$LJyYk;r}{X&1ohOfNJiA}_#K@?>Q?p=CkSV@A}i!TYc^~KF%%uxH4 zZH1w|s(m5LC$@y!?EPL@72t3sUg12_)<3u_Hla0qtn2)Ra67U0dG*fLbynFAqu$u$ z39Wi(YdiRYCCAi0@5_K>v20bnnfEVjkR~faWw?Y=sLl+>!F}xZK8xnC)$1LA?O3(1 z8*anC!&FqD+MX8?aaIQbRS|3qCvObC98TiHChT)#ANR|F_C9X7?JDhF-jXUCPb{(b z>)>o<-*KS!dt)3Zwd1={t7uXqB`@Da6A19eJ^$p5y2QK|tvCk*qd>OKakTZ*B0Qg< z$2cm|msM;C8y+|j;-I<*F3Hg07kIc4e9+qKXm%ffl!?}&ylxLWH}d55s~mN;qZ{3| zXh8TC4r8Hsh(9oIaXfjLC?^?;7<=ZRf{KVPUqbXSOg$bYc;X;p0mva_bx+_s@dE46 zLlH}#@Fqj>N__0N(X|?t(nj*z#ewl7{NAg#R{45ii!ti!Y3+zB@-FEyO(7$MaAPXktHgAFB93K z;z^mvkyintj9*?3g#>&6pO01C6EL<;!glRiZr46aT2^#LxHsc) zU`5Mo!8&EGGuWyqnl=WoP7MFisl_r-@OH00_*HO?LDt)M*2bMANP0`n8Ls+jOfh>0_Z zyzYRpUF7YbCCfV;Xp1~ZLO6Lt4q-PF7jth77CPe2mMf0D>lHYoyt4#c#C(c^LCX77 zxpRCzj1bGn*zy%5rE*!29Hfmr#;IHREc}}4h@8ByMt?4IxaX`6+|yU}B!zn-aTiQc zE;Ze|@2XR+n?0~rNCii3^_u(t6G$`%lIJ==a-VXcu=x1bGbOwoA%XeMg2en8aI0X^ zm8w(sILJ~o=~(tR?0`6y( z_16F$(QcyL@C&cY5pveCIJNO2b?s0^1Dq^0RUJPa8~*e_pvG8=Z*^H7AIe5Zy3KME zO=$p*@WkBxdnl?FA>WO*&Opc><%44(-Tz}*{!~JKlxXD9*w3(|DGB)shmh_0!k)L? zW6ns&&;aD56D#)~=k%?*EQ!`#U1z>ZH9CpC^r2L(lNE}zLfQ7%KF_gLx(UrX(FaI= za@;K%sC&dIVbTyPEBlIi{ppqQY-}=a`M;*1e@?AArD4*|$ejDD2yd ztHit9w+H(;CSJuj@~`BN47uipuh{%^V@q$Kfmi7P*lsOff@Qo<$mu#@6#qj`^rDGV zJ!dAxi6Gq#*o09->yR!CLFSi|6v>et=KXv}a`ja{A|PF8LN!M13<~P%t*a+D-j8;6P$wZh6Y6kL2qw!jp>N2@)6i%Bo%(meZBqeuQXNfzE_Qo?IZJXa z$9w_FmFEonAP0J?CEtBgf5cK47V_myiqOX>Cqr%jwvwpx7VgBVQo@s zksT|&iRX$ikaA^Uy}z-UQmeg4ma1!rtjj8D?frLzi~4a^tg^H89`JOt|kXpS1i_$B|9ukTh?#p4$-$b_wdIce(oRXmpbPs}YR(8Y^L^9~y2GOM6 z!9mEzm*pVTl%|%gn14Ban6H9o;3V@WHsmp%gWZc;jX@}1u%OGyNsGpid-?=0^c#3+ z@CW}p9x`Ay1Icn{f^m}0AjQt-C`r46oB)1=1!hMnmeD=|90ByH6M%&D%siA!b@2>5 zG{5|G9y$b6wNrfudN0H7=Z!oIt}rGsJB^wKZuFH|=5HVZRZb|WkqrhNH_d>}ylN>Y|1*<4&?my0-Z{$vUhgenkYpJ!^(nB$62X;^K z?{Sk(Radyy+62U~5}Zgd$9AaZYr5-EO&g|_x>sHwDY^A^g+WvC{} z?`rKWg_7D5C!LqkRYWRJ@+n(!+o`T1lIv{lgS*H>WT7)Tj7T|5RT3vSsN#B738xRL32Q z|Ew3vYLYJtTfQVRt<}r>!eWyF>yjq=lZ2D-C#lBgxc8oWa3JA=N9&3R3;;1YTSo}sUdLra$EO2ayW!>)X{I`U(-JOR;8 z6dm4HX39p|{Z=f$)7W*>AULJJ3!L7BG^YXtC7ErKcAQjgFcw02{hEg4v}JkGwM*jE znG4=_)!w`f`q=CghdZ-DGN_F~hfz`{PwXknwTiWP(jtejL1QwYgR=(GA|Ep^)-mrb z=1H#wd#wZ`4DL8_57-Gy zK}J7-WMV%wHScWZ-HB-^r5yL(&23WkafrcW9`BP*DfbTZUQyp_kvN`&WF|GqLpmQo zdH5x$>FN)7Z`=DMrn#;(eg^FcsD{VFhg4zcv2epX636WWKsVC7X6vZgsRmvbs+D+# zB^R679ZW)BfmGVfY&@EVlI?oFT81j?1Ssq(F0{XHKjEcPRCT8P1Z56n6y=JDISdde z|AetMTwENi0m5kS-zW3ql1w;Dm@h*IbnK}T#zONz0!|FDANJ=4rX(HQGfQu?fUyY` z*|0x{mc$O&BJ&OuA5@+kH|{W}<6|8g6JKCs*P0;X<^Z%}Remn%@u4{&Q>sLN1PqGa zr4f6nW5m`XKL&fG=r5K%UoB++hG5vIEM(0AD33OhFVv!L+3OSIRj=hqC}$x!pDqq) zx)6$)gJ!YSs^7N%+=LcV@oXN0iEnjl+X-e7H9bHPQ;NYyfc`W!N0mv{AJ$O&lyjJJ z8)%~204C&4#*ncu7%W`L&lhdTsP|_-2QrQ2+e5}?o=3>h0qn4uu3=JI>-}0r> z)k5Me!13r*t%klY)KIKBl}E+vW!%zpqfWHy-=bTnunD;4U_xZ$#6C~ic46YfD-@4lQIEIZw3!O(WUlgVY~-s zruM1mI&uw!(_hK3Wd&-K&8_UYF-cRpeNRnK-nf?3HH^#wb*n8VDEIsJ`A#?RYv(Hj$knhDHL zI4MJtN$K$6SUf-`j>da?Km1$$7e;-^kL*+GjAtU$1dM>qu)6iY#8K<|67fr0QMEoR zlkT4KKBSNrr}_FwN;<7v*p4}^hxY-!m~a@)ufi3&3`NhCbJ5zz5U#NTFQrt9SI9WA zPTX(!hj>cv@&q$xZ6Ao~8TZ~_^0?(~r$uT&g)E@|?EtJzhk`tS@fj0X(7xDs3p%jDI%YsK|h`l4)cXSNo*9>cA`eb5HiS7xuXOa*$5EY5OZ6=!nn4rTKkHF}T`cX0{PoX<-jdYLO9?-or8i zFJI^t>rL*Y+23Pmk|CGT@3$Nr?t);egn!vVvjzoExj#hGi;O-$G?UCUn?o}Jx}84Tff7HbFN-E;(3dMe$T@0q1QnezLGmK z7O!<^kn^CVr#rG1?hUO|1+o`?XeI7?-fk!Ks}(@K9msw)pa4X^Vo(|zSsV_2Ujn#z z1r!l$zZT#|A((jz+*5K#mUf@CTt|m;P#&Y-!QGPnVXgff$Wxa$7{7#;5C0)tA3~f( zx8n_Cp;~YfdM$P?DJ)+>u(C*uZf@VLwXm4L%s`xAPd-FQHSOMlmND6&aCc;LR zsH^IHvziB{xx=_Z0g))|@cOo%(8dHo|!O7dFw2@C7eJv-vSwe@E|^hWd{FcQ*1mDb@V&N+J`UD59iO* z?^#jfBip&|f?t*6N)y($xT_+2RxAI!(SD=2ZLp8ed{Nih$Cfy?VG#SX*G5#jft zI2@YZRQoeUyTa?NLXuvrcu;^yTQ1|e-u(EsE-Ryc^A_mGX3;Tgd@iuNbE+x!dhBJrCWUN7E{%M5vdhc))7w3rn@km`T7?ggKF^_0&4 zi=Bt3N-KX|`22{w5k598)F{ExOYtfQ#HpFi=u+{? zVUS%onGAMD13ot#oU=unL<$Ij@lX-_nygFJQC3lONWz9;dkJM_dXi`(7E`%L#+&!* z6EZQHgV0>O4BiSD;xgQx|RF|-F6>lsxP!oSqV4r1Tj zJ6+F(jLER+6^JP1OvXcn$;G&HVEF5xU+g@VW9aglYYZ$}IQK*wZ{NmpK(1R+ry741 zPg>+6-?`%>6(FboeSs;GB(e27r}GZB9{eSH|Lhg$y)3A(lvf{c}n{{8dL(mcHSdpKC^=#JCUVO!L#BpSgkK&NqqD}{!L*1sYtVIS0>x%{wiyCDJ zp?^$Y#TO|bvzmsuQ%1hA{ZW_ftH%q4E!|c7`FAgde^bQhy~o0?9YzL$BLc>cUX-+k z@H^Ng9#dCij7Nq(rcQ=eVT7J?_XW}yLVOH1yJ`GbQC(;JZsUpMn(t!UDek%=aAQ@x z%rkPr)bY4S17qe3H+HM42^c3gp`PlxSVcYZ0%H-UIve&N_!!3H(CJCvu;7I^xTlM& z9Jfp5*C|8nzq$utn?FKHNB%2$!+6rS#FmX<9c^c6%g%$`44=FN`x8iL_tEo)vh{qK zo%V9pRd7Oy{v5eQ8yj#u#6qgPw+dGiEdLOep%_BvyvAduYx>}i)1GKcx#LP(-UBs? z^$jR*56u2Wr7h(JIW&&Q%S-$LIxlA#eY0_a3EaQYN77;OreLPF`W)Ppdwbo{Zo#0< z4@*uSLS5SOYf)v=|3Uze%5}$*lXoM3;hrTYb-uqhg1<{nQjH3|K~QBxorZ1z$AXVS zpcj;x(fwv-q`4;HB#DeohY=lb)Id@L4!l(1j+9>^+?#V5I{e4ypij`AG9cJG!LAV6 z4!Cm!d>J||IqGuZ;^SdW3H$z0)Y0%`Ho)4UmQbgl=r@KT(ko&JiS?4}kgG-Cf%>8- zFgzFn{V&vJn()W6Q>ga48zwiA$?>6c!0|aI)hh@8FP|U@FlL+NHFGdtHVgumjB{Xp zGxPWeBp|kelj_M7VKlotDbD38?=Y*9Z}&6hg3fFH!%4j-Q>f5Tb9$Mt#(|jY}^=Y7A5NFmD)BzhkNx zsRs0Av3UhkE&youW9sjnkdlW@B&26E&rO)SIH?mrn99T9e=Eg3aRvQ{PU;=!?dwje z$w@&nSl|AMDIENBnX8yu%+#-$ssn)LeN0J6qfFstop~oyIV|@xC&d7I4V(_mDNIr1 znN>_BQK31KDOvNiOv#!DIdAisav{^aSmyED^O=(4(Zfll$+tGxvh$;Cs<3Kh1 zkWhc0DX<#G-^m-plmU@s4r2=7WBi%QVTyONs4x1-x5U9=+rZ(V=fq5<8x?FCTIf!}V;M!p3GY{~B{+Z&GIz8@! z2c%2oc1NzY-Zoala~7sTAQe+lc1oAA+^ofPI0vWxg9F4z4b3P4B`}zx z70icb&ogohZyIY1!4{jGX=^8``=uLZS|0$-3sOFs_r7s901U4~!FF{J>jl+4CH?fW^zUGE%{Ua~M`M&irn4M-?(l>GxdUb1A~Bc6c&2H+-ZE?y)*@R) z@VZQ_)}_8QeI-{MSk=7;ZNvwy#A|Hs3&bEHT2P}(8>tuhLcJMxlHb_+69V$xBkK*mF1~8u`B;%i>7%w>$HX3OTyR#VrsFGc|a>)pIVu;N7x#FxXmA&6mEk`%;3lPco|@-Hiq0S;lYY*ed>Bj2@O@5 zwXCw_21XJ`KYyV<6D^75Rz7a)k)RyX9xV4?hEyM)}tZ4v_ z_2F@__@Zc&*xa=#)U5;;L1>YC@nO-Smmh&x1>^;=31&7h#Og~Q0k$=+Ivy>!|Y&L zmGRbhtPeyB;yJ2M{L{@kL{p7x-_yaZDMAXuGAG{-LsN$3i>n z7IgoP7HPyYP~+4v;mTJ+voD?nFaVKda5O2=xFh?;l>-j)qm=r2d<(I`C*y`6wcx*iRk z#gB>^nNJ7RN%+&K>TK#zXWz|d1Ui5jZf2nWO<{(OklkziTlDXm*ilc4;|m) z%en3&{AbrWda3`eZSG%wTY;${U0e)%&_+$L= zg<~{3%l5I!Q1BWcl_8iwNld~J%BAIK+-{FvMRo->sRco7`;`2m0Oz*AMif@P5Q8mQ zN8>2{K@lkTLO^REiOPWP0^<=SFcCSMUK6;#l~QXtGHpb}vE>3G3q%Essde_CuGb>{ zfE@^zT)xF`4w`kDzd_&R{2)K4{IL`yd1?j4eB|z;T~_Ub%>krCGCTSKw~O=eXw*hI z7nqljiwRC!L^f+)ikB?M^6J8g23Zeex>dt;9b^0n215nF-NdyRwX{=8Y(~EMH2&D% zNz{IRnZ@j(`5=v4N=f-!o{n(a{?g!hJe9&`Rs{iF@mFb9w|O8)(VC--EEtEfXybI; zu~5F=d;?magPdE@;`s464E-WH1cbusnUQD-&-RzPTgsAGBpyQ$Z@Dxk$Tn!`lIgPh z!OYh#0iuZpV3tYqV-TCI(tNEwl5$tkiLE(yia?hzva?;M+9Okn(k3?(C2X7ATj5jn z4@5oiq=DTSWD6z;>Ydt)-C&$T0(Ms~e}q>b<%yR~mg&j~xbszeag5tHCP{&BPz@EQGQWb zu8+zUm6iIa0#P|yA62N29VjXTA~3F~5vo%IwvUr$XY|9-e-`?EX@H*MCNs2H&(i03 z^vcQN0@&u~dS-};uqRKz`H_jf&^Wy^L!aYE@D?!&H{EB7QJH#WmKc?#S7wX3etk}% zn21-|yyA9Lu3lLnUKgVZnvV4;-W@`jf%=?M0e~t8Gk>7W4_-9s=7tvt)7+)hGw~!L zoQ5a4PgGeZMh(_0%f+Zty|Pk_D$^@Ri&5ozWk4?*7atlR0^&o*Nj!|I6hlW-pKx@< z)b++|D5FTg(I-#BEbNpe4Xu#-J$mo9PM34jF9YV|AuC&-1C*5vbAGq!cAT zOhgHrA714*Ht$LJR&J1&W&~kcM%QYer^5LXTMMCI6c6?hA)u`pm^N{BhIXb2wlAcuUz(&6T(L#~W#|fa;qm?=Q#<7_%Te z+T9K0egUNh=VuJ4A4Hymx_D&_W8P+3IDmE0S`H=_cjyxJag^hA9b6_b!d^D&$w7Vo zr;@nUHPpKa@f6lKG&%^CX5RVTrN*uJjY;!Y?p#oO394M2^p!M<(sU0mXY z=>ZF@Zm}EP;tOLdxr;B|@+FM^DKA&sFFWBS-T)ca{j!LO0R%pUFK?Qerd}pKqF}N1 z*XfPIyTd&=nT^KM89NJ`Z}=$K1+9J{EA}M^B;OU-B)j!4&ctdFsQ6cnrx(+J-z|K8 z1bIf6EeC~PFo~EL*cqTv{m?KUt}R=_)NsVRzq78==dSyq@1#D#12N-a5*V1KpQEiF z<*Og@#e1Nm;`1w#I#F4?T2gmU;qb{I{?C|UE`iZ`} z8&K~psBGhc@1t%Aa1rp}D83l)5p%q#Pjuk|mg4pb~%D$Spw!&2^g{DN`R zvg>}}JINZMTw_1mBZhl1DQ+D`#=QScKut^msuf=+9$`Cxqr8n=cok~bD|U!$M8*61m>mGT zcyrLBcM@*B;{8Kq5FzreW>S4Nii#S z{cNx<7N?Q@c)<0AzQb`ao-3Fe{`4dOcZ*~76MS`}d~SV#SKL8%7VcQ37XuTTD(iZz{$`(kGi8E)vqwNUKnOrA6j6+T z){~+4jl2ceq^;Nn5^(ll;m0KFEMlF(eAbEj>ZjnUs0m1&>^9{S0!UHxBi~5~APHgO z*%>RyDB+)=2itMABsiJx6TfJuU;Pf;A~(YKq#G9??vZ`1AEA0W!Xt*t9@cn7aqLD9 zO3KcT;5<-COb3VRAl*agDdcr1q^+Kdo&uhKxdBqwgMdhhSIWSt9s$%r2D%BQc{cDb z`8&0S0d+U}+~y6GunvFei@YKPI{pNdpqKyZxb7;h^ah8B1s?Mx1jdR~R7|x|F;$^r z22cSpOZd&l(RY$f#ruiB0up)S6KE{es!{k?T205^6plpnkx zJL}zWm~wd;Xt4P0AUt1e(Kcg6NvS{Bxn#C~V6bbf0)B^(Zu9}Ds)0nqA&xg!A+XtK ze;KSOorStS#x1Uq;hOcXd7G3r2g;Iqk+xi#92ys_kqz(jq;*0Rq^tFdL|fjDz|3w{ z#tk-XT9jMe#V53A6WPV*7lsVvHyctOLHP1E#4^ibL(||kG;*!j3-@yO2Argdi%fr_ zNRBhSR_g;8S^XkFTg|$^0H`f#-SqPSj(abp-Fcz!@KVFjARAz~iijh6re8rVL5641 z3r1}S>;LtMXV9__z?@HrF8DpZ zK7p@z&Km0($f>P>$@l?ICLx%YXqwk6e9S$+d*U3*o$wL&ysn!Qn@#3@0UPh1o0)}6 z=#+l5+1zX(BLsgX4{hJd-y^)Q604fBAkC1XqH*OtxO5BM#6l(VJ_Z$x{<0Ua)VgwD zt-c+rBfLc0FL8IjS7SdHLYl=^WZ-2wOXO{XDOC%9d;m7F>NiA1E2vmh>^aSIBCajp zj?sxt*@KxR2Ju+^Ml#e|1!>-91l8;cG`GYnIP9)qb!^HfSYNGI(JTRH6mvf zzZ?2YTAgs@Svo^Oj71w4RpV#XEm-&HQyN8Y;=&eeT;DL{mZ;t!q1b)&82nr$3~yr1sH*Q z@|1OeUmU}vFV(Ksg81+ytdY>$gHMF=wO7m1!bTx(!wql6d5~?uA&{w8Yyc*cp>;-q zZ8{FE7gM$=6Wf#xszoysV69|Fp*Yk_BcK(#%tE>OAxKV)*=9U3S9Jw93ys-^SjG76 zjt~S?~paBj2F+dEp5-q z=lQB#Vc2recnHIg_+0936QFS6XjK^SLyVQ9x}5O3$!1@aNPYjq_V<3iPs4kx-&VHb zYSJ~+(07bk`Pyb>-++b)CHgXb0A{y~G5#~J7;oJFTU$s#Y8 zh%XZVv=^1qT0@PQHr7AS0eNG4m+4hVhd(+HHo4Z#5Z7_9z$32n#;=q5an*Q6H&x4V zF2%7tZ&*Mo?e%8e)SD*(*n7T@8iMX-@zr7MCAeKdEx8pZ2RMw19FdI&xxX6fp5nVU zebsD~QQm8b*KI)6ukpiy((1SWWa^WR>y;p4C`k8*c z@8TmdpRW6gpi=h~txZOH-(iSl7S=spv3aWz-s4VP*AAR?v-YAVFg3i#i+I-dv`zj0 zYuYdP@3cRopUWcwkZko0?U(;|+6P)v)+^u8e&v6w{Z6Oj-x~Yxkq+$fFZ{o3KfIUW zO^mH%EW_hW_XNU$(E8+4P6;R|xpF@h|(YwO{ui(O>C*t^Kn9sQuCZo%X|f z6#FTC?Hk5_@PDU$jDOC5)PMhft$p`@)c(N#TKm|@fdH2D?}%TYevW9?N6ps9-JPp< z+nOku=(#OVpZpt6ycg@({%P6zZ+(>S;?HBgyLDeLi2UyQ#EgrZW0}86^K|2(kgu)J z|Nm8=ngF?8<5p@eEo8=Sp$sJSX&5N)BlPLDqZ8-1uTNvMhq&ut_6-i_i3aXQ{!x7c zlUF?S5%iw%)v~GqzqHhc&>N`Cmo}jm%UNh5%GTw`CuDT+qX#sNoUpJK9jB^^2 zRcxWE2&m#Z=u~9&Vk4X(hhm0YiWw4mhtHZLQ+6a)OkWvIZQ``{#_yk*)&=fbZU0?W!CwOjH-3-n(xoA@7tClnq zyjKq3&uew~Q-n)Nai^(VwWv*lbM0>7^r0`@<_W!&*cq$r9zN22{#jDX+PdedC4d2@ zEuOb}Hpgq+w>$N2VxkD^8{evNP%&q^#?EwMO~{=vjIo1346nRflV}VN;agV_+h>32 z@i>-A!R|5nYrI>2EZNY=g;Ql#(UwH7cKX9TYvHEs@KIchLVtR_7mSsOSzEH*YsJ?1 z&@5_$@uAqEMXSvoE%JMop}q;z4yIl)lxk;|7%ENKVrb?Hy~hMVD@J+5h7R!bW;Ss8 zVM=beKY?@u%5)}-1Ar3CWO}`Ofiny>>{isPqdb{}9@ds)!8X%v%&)bq#liFSp6u2t z{t+2#aJ<81UW39o*z^l!AA;&kI>DXvgzIe4ngRgOB*9u6+T++;q&*f`r!jU4&UoT* zS~7SZtPEIK#7dVM-T!qoDY`Hp_O*b!WV~0dqhb6H!ZhKXnOH-G-2_)!X!OOOJ!u=NC6G8i6IZe%B|(N9T?#=~??|o_GFrht{TrN*Oxo zu63XS;H9K`-Q4_Q`F3t!oTFrc3-voZ#jnH8yzt)R`ZBV24T+xHjbO?&(3Ghy?Tza39qw0MSGfR7 zTBI}cHgLxjLKeB(M)N~(Y6cEfJWs(vhrp+hj;ZNDF%6;8H4oAb@+1*CERo{*heE7e6D1BzQIH-SafIcyXm5AvFf| zmLHP$W@1TCl(A!LSfTPyJ7j(jq`6|rI*zT}?6Ua{aKBNxkjMez0MiEZeOd*S{)FE9 z$It+%RF0M{u&33t#W*%nFbHp*5G6j6g>L~jX9B(JN90F!(wY#M*29( z5bfqOC`GbFPl1UXQWLOJkov!ogHPJGwiOYhpz$Q~ZF`+0=f{x&I>ylQ8g7y^nythS zkI()DpCJ4qrS;5Yt*Z_ki^cGGdKms| zI1}ly2Fv;xZ!~=@hue>v1eUC0qg<^TaDsNF@EaO$_!89{2;qr*_P3$O5Ihqfc&-`$ zT0cC(YWWgLUNj$k;x$iq9H;7F0qS)q+|o&o=Sl-&Qwrhoc%Z5_AK#8Qe)-OEO0~qt z5}(GeKnOMn(*6-|c^_HR^^5fG(T$cyw*`#`{CTdNsYgT`x;Ca=^5V3z3y<&O#HY~3Wxi%jGS9! z;Rjh5;@Let`Ca2vxaoz}HnTp=2b?dJud0kiXdGapZ{}?D0AvOI1hxhL9KstK3yKcX z_|lnT;9PXa?%Oc#quG6vU9q~QMZQ2Et?GX&+r{P_oWw1DpkWJ?9H<=*%)-@j^5$ex zPUvE7QDaJfFjaNvya$mS0VY7`1D2{RNzWl_&b9EdicjB;l*On-49{3V}2S{uV zkjU)1HdrN*quqNAP+|38in6Sk`N&f8p7yr$Rc>m(jK0X@IGWVU+W8ZXfF~?gB+0Be zbw4D!<)z7>xM0^=n?^5b8vG2bW4C*-kp_v89d}bs&e}3sT$iCQb>Ut7I`89$5Ch>l zs2j>}Jld#Ag?6l*jd~KBZNgN)(q0dqSow?xI+Zsz;jD0DM!>lA7Du5FS>Z4ntB>B~!y1L#H^pu9%-Vg|fE-5ECh=3dg8aJ*4(#|$AM0@+#Qfex zzY=Ho=DCWEdFRV{dA+-MeJHafU4kcpg5Z~OS=BW`)z!edYFL-*m))PvvOmpw4?f;*DDpLb{IbA2QXlcAlHnlX-YJ*D?}ekD{f@5(1p zkLc7~18ijLLzr2U9K=lHshe$N4~;!IxC~}x7=s&Q*cRO!r$l$fm;Rk10{_CF9?v_n zq^S{)IK6oAY0+wwfOoT$4LBi?}CJzKC08RFtq~t1|6IQ=7y(fnVA7#Nmr8q$MW6bhV(Ai2N0%Bc4f?ufvE(E03HW^DIhM`)#Ij@Mxo%XFk;t*&MJ6vE^1)jGpAI23+S1R^ zb;Wy;dzh^9mh^m_Z@*N3>$qT4WBwcAL=Jy5Zt zLGQJo!L9H+$FN`@u1V4v5D#p51ii+xFbhl4MLIJ!@vI>m(0P3h_Sc(%j+p12I{ZK) z@d!Xp*zg97_208-ioPiCuuuW7Q|GnW`#kOwc?U$Frafs05npXgT#hZy$Mi~1O7(27Om0_D2tPdi4!*MZ3f0Qj_v-bH* z*-BnBmUe*SGSu3+xcRovRuYO>=58?)hv3~<_X4SsHWj|GTpo;`){-oY$8NHRaxG?% z;NaLCZ`^eaYPEcfURsE>*dY#!cMm?D_@CNF^2I~Y%oL@aN4|I&&grPIXyckbc&vQ{ zMdWQo;dBDxHo7mtyy}=wEPvWT^a@4HjxP@Hym(Vd53coa?-NwWLH8gjn#Yed9@s8b zeyAx0^6p$$xJLs%a;wcJ2S0d}%Q@~v6Q7nNy(_U@HTq_qCFm`B(lb`Az&y)%A8>EC z#Oi3h2e-u__W8GW0Lq9yXdM6cC!laA_2@ks@eY#G3s>_jeaM5dWF^YrE$n?g{?3Bj zMH)1knK-M1f;sw-=h)NU3;8kjw`QPpp+0Cfda3u=!_3KW?p)|EfO9o2`oi1NqK*2H zTkyW!!dJ@BUlds<7U}@-IB{ABQ zD8!p9UBT|!i*Svdv5M$L&Hz$&%@Po=_=wH&m+`x z*(zcd)0OG4ap3%4G#ek=1 zBQTlIH-5;e9P=-jN>-@yBbZxeK875-yu|x(H)iTmHjPg!-2acZbAgYly7qr28OVU6 zCu-2BL1H`Jl7a#iDow^c==V)D~hu^8fz!IWu`k+x!22K7U&>=bZgsd+qhwYp>1O z5-~*bj`5Z%?=lV#n2cWt8O-snQ=Nuxn9nDv-ms_eTG@JoetcdjrSzl3D<`$je3vV= z*t5FJT`)JCigFd;(SZE=?_uwq>^s56qOpAM)!^M97s3J9@3rcqPmlcXmcB>4-*tb# zz?2Vp_hrjhqg`252mKJRRh?dn1lue(?=Bv*@=+l7xc7WFKW}{m$NT$*Z|fiVEl#CYm|^1(}I=3Q2?d z_F42>?0Yut00V>E z$=wFOq&5CC4LcJ@N(8OJu7OLQQ)Gy3>%@^|te?;e_8|S*<6``EYK9}{pY2?n9=*+c ztuQ~>=HNqQy(4Td9q!bO{)d@HJ2hkeVWu%oO~pUVRN>Uz@DDTH;MA=AhnZG7cfSdY z$al`)8{nhL)RbzF7+{$2uFauMFFdDvMP=0lS_vaj_&KWYAQ{$%z4}jzX*9 zR|5CV6-jiJv_s!+y8%y2zAfS#((3Q^?e2U1o(;h-^MQOj6#+pK1$NE+ z2g3SU@c5ie$`AjSxS$^##3#y4w-pXmv`yV0)Ldo~^PJU0xKak?Ieut8iy_1i1m;RNKXOpb%H?7~wDFMf^Z%N#^h;z92G@aAFy7Q)6ZoJI8r=_gLe#vTh6neG#$b@8~*1BiQ>W{xVVOpiK z?OWY-<1LAslx=5YW$Xm2;e9gRznCgvLuM~#RM)6?pW>qon_;%fJ|8)>HIx{*`ov%G zm^U6f*w(t-YaQSorw;YMqs&C@8uhgG%k?YxU=LoYzbDq|@1T1A9;QC31r?2@d}Zte zuuk?)5$^NuRlafe@wfK;N~Dtu=kw?my%0dr-jcYOSYD-^1UMw>Jg3G@>@jKMj#26I z!LlmHU*@W}WBFDC4sv+|wy}2l+vha`!7Nlyrm1T82p6L;HS6!y#GJT60Dn4hu`^iA z1jE6|QM*^ir@xiBAw8iiS?Wm%H1v?zR83{8SF|aKcFDpJ8}4Zvu#M04a`S|Nq^}8i?~8#OJ?N>fPrAM#0)K+FMvLO9u4DfDKx^$^ zsQd6f`<}IVpLG3?_qJNf*`Jv*yewN%2l^|1NW)jDFqo>ML}AKI`*>%NX7f->S#IXR zm2=zZ(m4Gg-ZxM(rRZihPaP?T`hA~*3_41+0S?hOPmzEEcs-ss!Q7Y0+|;ue{i^ zCX}p~9+I8*RM#a|{R<2#)m35D>tr%f)$yb6nw0o#s%soeOrOv*!`9l98TRUP1fIsO`}FG<{1< zL<~o>lqL=9>NYYG=dH~O?QPB!tA10PwK0?HcWRsEEjINwA0&v`LD03$5=^$4{`f#K zy$bCO`nBwAjgwxkZxoycf5$*;o&FBGhrg*$23hrjrJ;V^{TJEu!nCD{$>)9_5ZAk! z_ron>b=-laIXs|1W%r9DS`9A=49^v<*PEw#RLKHs&8aFmgp#4X>B(=WIwmf^ft!P0 zgyfroC#s4QW!N$$?RGO-QDxI3(~p%Pqsg3k$zO@#%-&q8-R^(8AXm_vs{F!;2kDcx zrNYVmJu3Ewlb)XZi&V!DYi$@JV)FX66g@>x{CPA@hsav@+(>^^=P;_;sZ|(w$JN%t z>1vbwaa(XXuN|$gD{H^4uj4hx5AoI9^6{AfyYsEJXHZ$HYqnM2MMa*10-18Pt7+0N zx=uyEnXRz4A(yaK33F8^yXl)~WnsR%e?`7H_9`;D?>rn-w(y&NO+QuFK1YGTem-l? z=DO0;BQkPN<+$yl*nF&;H~3Me>sZHrl^1__qSaHYGx$yYRVarN9fV^;br=c}%Kq@P z=Ha&wyK>e^eUSP`d7W5Q2oM~n*3IR!tO5&ok2&j%ok^Vn>R%eTX$p{}>Zsj5&=`R_xR5tHN~`vpBeL7T?yyu8oV0+{ zLT3qwF%ujrTEZb7%WkjepV*7OA_Jd&tYBpPuS<3)-=owrfC@ve#s9i=BdNuJx!>3o z;bjl5kCAJmnCs0m(C!n%}L4RI!ox1nH6KAssT*dKk@2<)VEH`BZNWnB0B!OQxbYM{>LTT0nw63=%e@_mp)E!<<{0Oj$8A?454i7 zKn=v2{0tLXocT#m}%m9s|ml8C&kOqmfI^0jfiF(mM*Q213(f$-hBL z=PCB-9u8>Q@i$20{Svy%7>ApHj3$1xwW(2SYFH8Du%B&yqhF?|8=q2{GCrq1?m}C8 zL@P4%TIx%oq-*aTc1L9F9mPvuyH=bekF9HiN7-|cS(E1dvK@gAg@Kt7Iumg(azlCc z7Psv;TmrJiSU3`JQz-!{;}Hgax)=C)O8FVJn}aexXvw^4_P>kS<2UiZ+;uCp?OU2P zU@Be#+dO`IrxKgJh=)9zsY*)g!J^C zb)5s2Pq&_`38j~YQr^h)H9PB$3|M}aKM(1sEg5s_<(#oN%}-jEX>N;fhj9AKp#eMU zI?qp9sjhg- zgsv_epPm;xrKZ}Ae1@|*+imp4TX<6U58Z)if63-c7=d+F`}WGw1M^Iz6yxmgeG6pG z&WFT+yg9QQnsn^7NZU>zLrG%F{rZlvA0dH&HrA$o^B-X&*VLjq7mV#E+hpQD3~`=@hX5VUtk24ye0BHz zca|MNZ;iheqr;1?(w???;fQLt=)lPh@UQ~ODfpw5f ztKlR+=fV+l+i6Px(x8yzs1>T}S-IqorudKTxG$J{r?vDJtp*0Q&}A7n%2hIV7s&0Zg;nztjV*ho@lLV z5)iJr8W*>!&CawYo3lz!1P))&yLHYi%0{{1eAaWUbWVv^yZ=2VYjoh4FS}M8akA=X zh}~4RG0*teO$etaL~68a_%7ihbOZ{V+nxAndR5t|ry-#?cGC;$PhZ+a?YjMuzETP9 zZA2~JVNY(S!kZE$Bin|6Tvc0VyO-ozp6oi)c9@1gOPSDi-2l*9W-os(wWT8djJ0M2 z(@=N&&OCe7(FAwCn|@7uuJ#u#Ws%yGC!Z7PN|Z$1GIeg64$9ikq@IyUvuc+!?Kyka zi{6ctM_;mEF8?rn>5!g>pLyOMF3Ot$F=z+Mc4^Gs?j9o6Db9eYrXf_;Gxv-db5MG_ za<*6-HOCdhlf~WRN9(mV=2r|)9I9_Z15L(ypr(gvoz}Rcw1@%qI zckJYI%5A?Ept8NkoQLyAxnUSyKJK`MS+C(`WDR8sAVSv0{(gIj8R{+OFlttyVvRlVpf6tp*({kQFmZ=c#V8=kG(6{_e)ZsMqV zky!)@oT{zv3a}S6;SO+FRss~h(eCfX#mA`fSr8d)B@ne;c}9^Z(b=yF``5F6ZQMo- zvhQnd>zA$wF&*Gs*K#-Yewlla+gmk@nNac|ZGxaQtK?)8=g-||{bXm>PH!=N+g`wY zcuSyjKE>1?Wql#Dgdn(A!7sGYng`v~UQ{?;O{gfMRgew?AF0m`Pq$(#l-568UpWlx zoJ6le`=Du4Tm&C^*p9X*y+gnbXEBFeV2%TupC54J1s9f3Oy}z#;MWv!fOjW)|ZW2qIt%_(%#9F&j*o* zWyqZE0w{r*9!66uT-@c16|X73nqJb}cz@TRI%u^FR-*%DL{%sr^|a=zITUPTZYhgD zv$S2{v|EtN8ot7;c(?M$;5Fy3A7*mw7LQA;yK0}1esy{6t^Cy9E2cTM7Ol&C9qxZ! zt*>9?t3RKx;w?ECbv)b5nO5P@j+6LqwEf2gJn%6AGG zXSnNp@};85ZK*9~na8l7Fd^n(fLuux&_W9H@~>g7@z;a#CW7^rfElG-U*w8`Ye)oe z0OTyTswEkN8T{Z@#tC9?tjYo(bDVg=y8HhEHT zwGW|&SNHagwr}6(e*Fo9MZ))A3lWQ)+oNa}_7K(_7tLO`(-|MN3t384FW%f#kzQG_ zHS-mB%u>Vs*iSl5`vp^?_Ep8s+#>t>Qm%$?ovdY*XHO;=Ok#va|14{5us#y6@vn@& zBG$FXnT(GLbC5Xk#tZr>t+{D{&A0a}QtySd#P7tL)gd;=6au^0S4EO<5p9DhOF7q< zX8tYp&PeWSM52^?1q{NDOy{h7)du%rIZC`!W>4m>rH7E-l-@eoNbIeXjp@2|vP_qG zsW;lWutiVV{uWfbiz$s4OM0UE);iHIHqkFO(G+W)=$D!3kMa5vyXq0AYQre*3Tk3` ztZJ>=;s0z^)%G#YiU)WYPwrSb(Wc`@!bA7mO?0Lzr*WDJ%OMVS8Mp$vHM2cxU zo$H>UYX!?A++R~Lf!iWC*WgnRnCzr>~c!^xO<8*2N%-&tfRg~?^Ry(=Xo>bzUVyb;{?4;;Q)cP{Nk+JkE zU7V|5W&9oiA@n}~Hk=X8Y*uiDrR-d)Re44?{hd)VBqZDIFGuYwBR>4L1T()8 z`GBZ3PI8BHdsAkR;T!SJ+xx{ouqrzZwsMqvZV}hoaGoBo>aRX!?OZ>)r(fWBr#_i@tN#67rL^kbn|N!_Qy~HgExl*@ybbV z4QmMWn5dvnh~vj23kEx7|)d^&$&Ys$G0?wp3t@1kZV=jut@`+2vDv1 z3n|u3z!{W1ab}NkH4N2KtSWNGfalJ%D8|eXeqmKlI54YOJE)-&#swM~-C>%ngwyS5 zTiriT2f#Rsp&MMsl<#z3;sb4?BG9dL<;g{MIOcwn>kdq>sA1NQ#Ffspt!b_{M}sOL zSOjNBif&K_XbNFCUaWRk-)LT;@b=P(eOt7fG1j>KHUxZ-nyh-6u+iaiLYU+M1lTVM zzL_httyb;OTnHk%x57S#YQR`W?H)VQN)d=wcu;WNi(;d*cIMU-4wd*{Y^iX!u+K2| zq9yOEVy+!KG^)#eWP~n1N;bK__8)e*KjT60o3&FMNmGsB9&Om|KUxiP=`r>kbM1!J z@K0JAw{LZ>iV&s8ng&nY>giq(8c{ry&*!>M(2Gxm9rTx$&0&vR_5Oo5OEiPPR=aax z=pj`+)D67jNEN4Np=mYzhG80Z{m^mPb=Or;HsTx^&&Z~d<8tagY#M^=Ao&6X({Zy1 z0=NVKGA=y~7&WxUz3zN7WY&&1Oq0}-o^Z^50ltx5-i1KZS{W)+Y2XkaX|27SEdG2j zWoAkSQ~qjANih%Cb|rVXC-6Xa=7U-33o~825%8UF5UM5lqI2EOWvAb~y@D_i*@=G! z8HkkS@A(sVk3T(G9C+xw00-9daE%)LF%N!&ra<2&ABNhQK5r0qPMfNQBHkqtp-Eva zgrNV)zK_|L@vfn{QC;35Lo|yJTr~VVZyxW4Zp*)kC>G;KogPux!BVaA2gm^*t!?@O zg5(1Tl4g^Fvrb|AL);+BZxF>v4w3+#by4lc_k@i9=&%w(B|E1V#foRSfBg@7Z3Mt& zNScbRWmO)-vfexIEcf@he3Qth5Qun4&=>Af`u?>>p2)Ts(ChovKXNr(2kCK-$=~Tj zeabhNNGg6@rb&FyKAZ{0YrmivME;2Pq}~~>5pM*qK0V^&9;s<(Ogd7dU-#jGW@pI$ z*nSxuY^wfYEn4wasCx^pR&%dTjOcMDC3T((nKL$~^vDyiGqTc+?{-Usb5HQ+^Ng^F zZffK!6q&xzjLmX?{YU^!>=H%3?QeBz@s!5a3;_;Yu>OpCG+w z5nvo2a`9$4)KK-2ztyX@ptjoKsJ3n@Re}kY--+WL# z_Nb-rxb{;EY_Qj{_N;kY`)&BMKQ1I=wPRg~W?}~KF4Ej336TH!xxv&WzL1_)oW4#Z zVak4I7&kt=Y>&+@zi#`oU+OP&f>KGLPggSBwLI+pDf=-|l)kRS`FaU;JfC^Yv{x00 zPmZiC!;b1B7D^uR)P6eD(C^H>5d8S$=!tok3qsMS9E2&9{j_D9JN>R$n}A0$u7-OqZc za!RNySx$J`3ty!UOpQ+TuEv4ZQwfJJD*EJk}zTTktBk~@-=duyuo z08(oD>d^KOM!~IG3D(9*A$+du2ZQAmBR2CTPc}#2BMa4K->|A3sg43T%^hXwiANz# z3&XV!VIQt`x6CpKz_IEx4jq0e^>zU=I+#%2Q9TE{xm!uHY@%7S{-?~MdpLhYkhL_n z=dICh_EGIV_U~C@*RY0_g=ATNgo@LZC1s)ZYEHNROL5lBh|=TB0;%u`_(ms3 zU0{j`dQ^-sSpE!G8@O-k>#VKx2cb^;nzOX4iQM2@pSThJMdZk8_X+=?4D}%uz@Dq! z-}qmQf8zMA^Ot@j&+us&<1b*UCi=V7b7MmXvI_^=)0(PlfV5lmTeF))cupxK(>S5W zQOXh~z^fO@_{bybDl>C=zV}BSf+@-TDVX>tKBwuBeJkt?Hca9bCVG1&YVgOowiNrz zSz3D+%yt*d%&y_nu_s*1W@z#)ELF~pr>C4EL%_5)_L+?FC|o@oOHqxx-5kJ)E)3P)_>(e_+dr=pU3hYB zlR@@>BmJ7IWpZ_2xi=UoQC%@MXpu>0ET$3UXS5ojm~3;Ag%@MbpB_w%&Ry*yvysvW zF_F_hTiM|l)fC^0wT&}Pmd>k$z@6@X zV>XbV655_OLUaHrW4ikUyNtZlt>_v-_}%^to>Y71u)?vX&u9zF`mI;*ImJzL>B~bY z#fSZfQJiGxc#r-kMzE8dImxUC)6c}o**>Es zd7pbt?fxxg>}Fk$+5s%3s%#B_7$A<_?1#iw4>#96SNA}XjW_su`jX|ZRqV!YT{y6s zsFKz0+g}SjFu8T8k!U~|uV2*)`|KR|iYtQ^#+Vo&l4+*D^m+07(+^e7hO2)R??`;f zda95c6OaHV@ns|dDt$WYzYjEQRhx$I+xyBpQXT!QdKu?a9sRBP{QyMvqr3--u(*Oo z23=ltUx!Ryub7o{XPIF-)1ENk4edxZN1PIS+7q~RU5Bb73*u94cmX`Ft$cr7DH?ST z3hHyhYWK-sWtm^SA|$7_m&HFy?s>co*!tx(Y7Fh?GU{tEmq3%S~l}U2aav{Jo`xUDQDUv{-HHH7baBjg0=Uny&epkTyPZx;*5B*EUX|^rc3`c#JHjSmIT< zr1jKgq4cHsO#Y$DD???zw~$%iP0U-7nYV7a>GsXZlZ?>5V4XjsX9RLnD_hD&Zkj_o z+LCRH-@e(Zmuj%RQ0EAq#FhZ=H&pP&nYCG={P(#LpyPdBUG~S_zxGBm?)Is1R0C=@TtLPb?LqqN%xbEpraRE}ul4@KTFuJG>6t^i>MkBg=mtJQ!wiqd z#?tOCA)>1>QW%c^Spe(4Pwx!Mc;7^nkj%bL;`-*5bO&QKo&YCk3pVW3jh{+H49w$m z+}pC9OvIRr)RAcN)!GQD3n$m^gdo+n@yGq))GYmOek0sEsT5S^p7k>QIH^i<`+KUb zldwiAWwd@|#!gKk5nHqMRBEbuit#kfJPqaPO7k?Fr>l6n)}AyHUz@D1VfxP=WTbw# zwXx+f2H0gyX~_l%$kHq94~piKh|NS1kO$gaoFr?rYE^n}#i2=&5SD`C^q0%zikCdw znafox6%Y|T856{>Z{C3s(`+h92SyDYNiFlSFf{Cg0AO70Mcqd=sX|T^NgUW(VMG!3 z3+F3<`C{eg!Y+sK0=f{dzXCg9_4+cCVjP|Lwu+rjtgd-W z&qq35J{fn-QbsW^(|?_Ie=iW%!n|p50dnKaf&%uE|FHaRGL$O!8B~L>OUHnnc7Zv? zV4NwGYHgfYnA#R@tUAh5|Hi6M`03YJb&MZAcBMYs!G7ovx~jdBmc zU$&$9<9zwu)j&5!HD&S9DNb3>*fSeAI2IzjRD1L5`RSP_=7pXeJ1;hmJCf=PMD7XB zu6@?2vH54bLTvHWmO||mf6SOugdR5lY?w*L_`&73(Dov+lZ!>4j&OKr6c0`zqncNa z5v0KSu0G&nMjrw6yk(_^UDbx1D~s(B_;@r{o*Z@xb(~?#a+i-zDAm?6pvAz#J~=x_ z0UyA%LEu6qB(M)aDw*Zpv>(jk`bo3*&R<#{IRoosH91EsYR!1_?+?LV{4|E8>&uD= zorW?{e!A$vuQi?Lo2~DF9y9jGwHgG%LK+ZW*q8wW-^MNWLGNjZLh49A03&L0zPDKK zYf&I(4BGbnk45lYyD_Co0vok%V!uf`d z6PKi~Dm%Q5n&lQ;%7W9~Mp|&3wPeBV=(XT*j!P`0s>K51{gNUke`>)^MmRqyILeyU zKMb5o=eYmA7dUN*eTUX&2fsOJRRX)pE+1M`%}Uk&zgnt)(qF2JjR!!K&06p)L#5*cNVxz;I>NAJJT2U+i3fZKbV{Z?V8Rbt+YZ=7Thd%2=&aM0oT? zJjIqxW}#YZXVNB1dnjhM;UG~h=(i|i1$?+8Y}H>w2E~wIt&hsC^^;la2gs@0eukTB zP9|6C?T!KM+4X*a>CCOqLLaxMhycuT(=X+q1A6;lT9`K*?4B>o_5l=NwpDMUUCfMC z#6L`E@z$2VR6a`6QXya!YH}fv{?Gtd89mb5qVkW*cj5th<(BkZLpk;}AITRv9IAEu zbn31AOi9k3g$2PzN+*aoA*(diQvLGH{p=A9s;gV?g8{hC`r{)u6KlW9hiHb{AkH`%0{m zS3`KX4NQ}!Da#88&#)}vS+s1JxP_Utd9g(jXQ4mKi|ukle@+WSa{~IKY`8c0Gzj0k zecnVkclY>@^hOi-P*U^toB5o~Abp{aI(*H4tANtC4zDaFN0emt+|X)6BvCI3t=!$Tj|064ha@UJ|8As+^a{1&fp(Cy1ggtu4p z<(u2#n^$CU_HXdb0#R?#7U0cL#XGUnpSK&N?8!TE3!83uC-E3Q#XDJC(Zn?Viv0Qf zb62^gVO^*G4)dM|O9KAMxF0k86JmXWzb@w6_@5K?*f;<9cGFZR{PPnnr(vGFDa1e7 zL745{O<*te?0EdsxYY&xGds_LEcO@Ri+uIr($R+2uI4q6#-f>sdSJM zBE+#=FGZwdxn5c*S?)6(-uI}tw(dAwe;+ZQaLC)6OYgIGHKE4Dk)!&s}&v|w@=Cl7BVE^K>i&_%eKh8Xt$Vd?;qyrLh0&hy3kGk&dex%CEVb=ee&uWK*lBREt7+b<=f^pklU;mG1I zeE$S;q!){Yi0>oNo?74#Ud-@)(B>Cj?-6Zy|E5CbgXd1bIbRXpRINHfxa6~4^+4pnyo<{LBOX&;`nRjE%BGE zD_=@4F*nD2*nBKsmeErvG-|i_Jo-FiI3d-9-)K1g62S(r0^OQn)HZ(L|+0Tngr~G-d*g(l4V!{X%7P zO#bJ*jV+B?Yh_4a91zFE)YP%UR0frz#NroO8 zDlnlvA=lxU_f3+RN;B(qw-wecv&7Rc^11lOaB(SbPBfNd-TfL3>+auZSa%^75;MdL z>?mM!NuANX$)6LBe;)rzhED}p2{Wk zAsP!wkbvaxHyoc{m@Us7y(sBPFQhLl4wyNl1bWflirbe&*!UmMbwtfs8I(_tKm3TE#7%E@2La%91;LEOe{Q& z3Wi&hIVUUM3l;5C?Pn8{(pM-ji76*f@)tU@D2?Xn)|zZ!qgkAe{hCD@&>e!c*2Pmc#G6JTj zUoY;KHv;`QyHw*6Qzn~Ql zk<{z?An}<0G1!bnfXo$a1R8lK{)faOnTxhrcis>BgH~Z{&9AjE2Btnn4hilV z)zGG^-4>}U{SFWiQeBe)aEdz8pGl<4GLkVS@AJU5d%dJ5YECN}Pat&+GhdPBxHL_A zGRTsR#4*TTgLpIc6U2VFaWQPUvU(POF^vGWu936FwcV30qCZ>9*e2kZ7qzHDtNt7c zYYU;_1rXc2xL5mTjOHfwKyGFqK#Oq-^_94HZ6|Y9>(4#ZFqiXZkil4!Xum=ZTIQh1 zcv`K9za01lt;7Vdr}+(5B&UsZ^WK7WCd9Y5k!QcX|1qoQ-*WG%F8bN5e(I7p`)o## zpoNhkUCAv~dv>a;5FHg*a^GE6(Y_dLLqFNJ%-BUZa~;moJN6$ioZ>2L#G*jY-iE$H zo^D$odUl8Rp>*89$Xe!GW=gGkPW*`@nswCAM`|hg91==(YNmz)tQh}BlS$J&##*}# ztdO%1AzOexTSXF;O3{CYTN|eqgd3xUBD^ih4>k*PN3#LczpjU0I@ zt(PGS^HW;hF&21OcU>i@fj$X{*etKZ}*Zh#JnrUHb&5&akyshiktg`RqB#XGgyvyNgQnkxf+r7!!=hi@(dO~fxt09qa=qI`ZCOHT~= zkD9P#$FuPy6iC9@55y=5N>Jl2Y|hchIXMy;FiK%fb=Mvd$DmlyMEyS@N9ozfe>xGy zC}ck#iSRD_vEh^W_``{^JhI_k-b!&a1j{K}>kP%FcmtgX_++v8;q|v3 z%wva;SQVsV2i2n}FOO|J#(A`xSHI3Q9Oa74GoDU0_fHSE;u-7CU3_~?fyEhJbWdmF z=^+Ar8h*w?@FLgX~HpeM|?KshW;mqXgzH4a~Q^4AJ4!wN=@n7Ns(&doc07d z{N9Z=v@e=_uN9``@MNgz$$0Uv;XKMB3BvG%lSRHhcHcYR6Mxb~B&HfcB>o;epIJy( z8T@&kRvB*;0Zd@4!tS+d*%qd%Q9L6+Bh6ZXM&I)vg+{7H5tPVxRKem58WmfRQG#?! z#4?DKMWW;554bZ=*v9Ng@TnAM1XXx1Z4au%uZ&RMp|Vw zV)3>1P^uIy~6~ zi}3d9N$b`7Jx~7-N6XLaiKEm$hFPV!kEac{Xl%?M3fpLArj|X ze2}IsPOgWZnICQ}HuBE4+|&zE-O{rOrX26Sv# z)-S=I6CIB5XX4v>VqAG%ooe>kjpWZMs}4glC6g3+55w7PEuaL4il958!px8OUCcKnf0tyl>0j*a*CS1fidd0mG!EP}rQ7w^! zPohBt$SWj%{asI}U5WL(5MT-{+u~)6{d?FhwJOvIr+2*@>8dZ3>4I!uD3b#Vb=8v7 z8R|_Whi-_L;&phN&s6U5pAA=89Xz*nC6?Ikxx5{fW3Na7qbRm_hIW9?MN2N*ET*!j zqcIxJdd+WW!Y+RzE{mOE}oy5wdHwipNOM8P0R+pi!v<)0Y2QlEX< z(lxT>JKkCneSq~50b7S68yfo8M+AIW2?oS{M8F^968eaMD{~2bM8L1++UO&gUQPn@ z?DOFxg0L9!bVxNLs;fs6XtU_$h18hQ8~VqO>tl z7fGU#_~C?ZD@0J2b-svC(WTGPu@WOl-50B)8q!y=eKHbj5Ny)`QU|+o^3-?v8fT2w zox`B$z}@s-@*#zx&?P8f#sbLnai{$FV(w-46~`6MNNeM1C|-=fJ|X?>@qn8{P#=e^ zHIq*uZ0x}n)zCTETAQGaRNIgz^Ju|@#>Vp)5Uk+BkW-hQE2!D8ts`D(bDP|T?bA|k zTryx^d@ugUB$XdaPdzDg0<1qBy$no?gr45hW{<$1n8B2IA=a{yf6p_`b`<)c(Tj`2b$_S z>yiT*b#poHrb(C5^*_|iR>op*u@#V|QnphT6Yh&UQ0S7ODDoHf?J|I*t-YcR378J) zrK6(Vm%jCKv;y5-&NlY0QLkWcPQ8At?&G7R^9e7&c+__*~ zt|`Tbq}wLe8Nb%X;^7W>=kL!|`3#2FnTSCyOKPKO>GpSGVIm0vcw@2-kJqJY$ zM~n8Y%R{tZ-Py%NS!)y)7RV1b;nQ>WNND5Q2q~E-1N)Yib|6;IB>U*u?t_n#o?U6V z2WEPxcE1)$w)Pj^OP~;82YtD^1-JmrDe-;yBZI=ggL$HqmdpxaEc16Zq=R#9{)#G2 z&ko16;!3PLUjo;)azJYPHHw#YuNmP%&oxsb#ElVbb6;pWpvsLL;FQGyYW+T z9(&+t^!)e>;%inaPJ;n{-rgHOZ{hX-0zbvW=mYp^)f-b1h83A)f5CTyr`}(C;OCQ) z&Ip9+?V_u>`KE^=LzwTp|K|I;93GFQmpMF^Auor=g`dXb>#}%kt+^TG$lESZHFu7_5=BxaZx*!gY#1TxsXg1aW|dTwy&Q{L5MQ$GE|U*q~c&zC?n!2)KuQ0 zK%it;L7iiaT|#Gb11W^>5^0R6+he(WUdyN(Th8J&kY~icj6zc4T_$-;9ndyfmf=Ud zNl49TUK@*Me5sFG$Az8vIzq!>tt`Or-#$5;&u z7@)s0`zVFpV9wd9x8AiBgauqCG|>bQcB?EHQbe+e&h7G^5c&zC&yt^JibalzqoGBW zM=QchU|4JnA`S1+xy+g@J%)fina7m*`sa@sKJ)lw9yH9?J{$SsD-$M`5iTP>XxgR_g=D>N?@ddwB=z(lZCk4HBIFJ}VuZ1+@a4UCjrv=>6Vup449- zduKB7+cRgvpBZMvXUWi|0WINLV_z}S0aU$SoN<7YA;B@Q@_jKw>ySm z_$ol2U45`gm3D@VMLr5yUvsZMpmz*jenaZ*A&*H!G{+eYUD&_uOl#w?=C}I;^we9I z40sPG)b|j6fsrAWzFiiKp+p)xtRqR>I@817qvTWm z9>lTk_7A^?A#tL+m0~@$F}xCv?;jo`NZx}C^>6Hh`)1eU`iFmxp#vb_zF*{2Y5!aH z)-h@ss7YMwz5gxBf`Q3u@O&a)>x|?~`1=7|ASsKi`rnBqOv(pg-pdgDxpR})gUEh6OS=gp!{ZNgCt=KzP zXbJtw`L)AkXS@IP>)fpNu%%1hH-7E@#Ac%>Dk3$T+KH2KHA!Igd%5}GkkFo8M|_vJ zAwUb4w>c4JRpK`D=3S{qwTmYrQH+3fD$Ql~(+_*QAY^!*qDm02wb;ow%4uop4a}|u ze54X%cFkAKRG2yvM)D|jxKHv)KquGuYJTO<$@S~n(8J{~R*@LQmwu{V4V!@Wd>%&) z#l~E=C@>qY1iaLW_&#RYY3b50l)pek#MMYsT|dd`fQgLK~*L87%!MRART{$supGUJ#+Go@w?^R%>|q+{abWZ&L>lPox92D zcl1kZqdqK3o~5ruF6--Gq^-2x^i}Gup|2kY%L*f@81W*b->|T8xYqoNN~?C!&l0vf zZa{Lbus@2oCT^3X-3!*8B~*}Jnh#0F)kkWCQzThWMhN*AH6JWo-RV0-^k;1XO?>IB z`U52Ke8Zs$aydGxHyV&FV~3wo4C1S85n}a2PIs+IC$L-45hF)J12LrqM}^*|@ov95 z-An*og%iBz*RCt(8h)WZR0WQ3Vmq}?o_8X^H{%v(z=i^2;2xpR1BGJFQ(X*eAXZA^ z3n)WlP(SP)*?##NIP`Y`gnx&Dj12D|`6q5A=hDwy=AQbovh6UAKc-#Z99{y!t*q7- z=BIXIC!S)U5K9F+v0q?HAg1Ad;2ppLkt@7fmT5qjw8iK(2JMzcN{S6-73O-DDbC+X>u&* z19k>D2Sox+8D8^qUtXzAeQa*)Fx$>CfH0a2BE@X;eU&UoF%`OPT5H3qPYGOFB^*)- zT$}PC)sW_J@_qUlHUee&4)Vm<@PlG6y;dtuEmx^}9r3VfhS*eYK00h3+6y@v->d*A`JPh55UaX9ZeC$UkK zB^B!!NbPsTdtU*xzG7sYla8DSi!}*-cBT&G68dONPm{n6v1e0vEt3H?-GJ2#D6`{H zuVeh)>HJ}*E|1TC)qU9dT2*bj+=qMLl54Y%gfJ^tqK_a@LBc=g_eLV5uN<*WC$$|} z2I-FF^r!CgwZ-U9z0cR`B9q+t+Al$b{|2W&Da+{tx!3UdGU8#}mm|cV@*_3@>w59| zbpX}ycL7Gvh7d`A0t?OgT9}K`q0DJoa~D_OKP-Ef;qTh3>85v@B>Bsu*En#?^z1;d z`3^6XAO?>%wBVV>mzPQ0!U`#|HeGrwz2w+}<{gprW?y&eLbTMbe<^F~GH5~xI@AP~ zl~I%GU!_q3NQlN+cm7!~W}}RH52`yYncw4BzUr`c+SawcOKgWWkCk4lXa>r2?aU7+Gri9bz zIFS$dTu(k)HrxHqk8{&^JU;5rV3v>Syg*h_VkLJgO2#Aq0zn)>$w@uVmmCxN6HMrI`xvRa%3nhX!fhgCl%V#k5_B%) zMQ{Owj03u7n0oHKgZ+~4(Hs}}kbihLEWVs~=E!%*m8*~N*XQ?RFpiE?GK!F2eD&zx zz^-n0@eZv-BcxdMFZ$2M@y=>6`is#)ta|w^D3|Zs>1#*yLX>xJGA+3}(2IN$`ZOo} z8(yQ)ZW0}M80+odh~I+3SE-cui%qs$xriB2f8#TbfjC(Hj%AG!c)KtFT( zP(=@Y2yhsEXa%(e_4lIV=tEoY$)VHn==lF$ACebRRv*f?yQ;h0Kp&DY>Y3AB!T1ej zo70^y3l~GXKIowjX)l77jXw0CzkdFn zKJ<06^wx*g3Z)S8ncV-M`p}Nv`VhBk`Nzt1Z;sC@qTWECRrJ<}{^&2I{}1}mkA%`a zPJ%q|w`BC8=XlQQL(lMR^r2140I1B$?xPR=L}|W~IxNtKbi*uqq*UMABL$)0Fv!VT zxMoX)qaau1bfO1xI+3DA98V{z5YM}a70iZ(bRvQcbn8S8L@#RZ)QVmJKkKU*z2Y;o ziT^9j=yv-3w=|J{h4V$u4eQ+3AJ@%n|=0M3PXVlos1~=NHZF* zTzxd7*Yl*MD4~yLv?G_$M>F~z2|YEVBJZ(o%}Dn{cqj4)&8WXLBU5!BhW>R`ZMxh? z5}285vk#{qn=8?W(|?8p-S6qg8$vDzd*(YMna}yqdM;nkvB^juz8%^80JEao;H2({ zos>wo&3z%Is0jA$O%6t3#fK^ z<<<4?`VBvocx%+|QBUj8p{yRE4^c}NTWg-=xc~zs?G!l|$157GI~C4`*C=D6a&vNc zZIVIv8Tr4Drq}otHmnr`PYu^wQ(~U;laU(DJUEWvljl656z{A2@#XiRTq2eQ6=qBm zF=w$=ecCQ+{V`j9oDXTxBvZFD^QSbG{5HKQLq-^Gf1EBB z=<~d#Lip!1KeFFQ$oMq5SB-3Auega1MqAI@}7TR&s6 za8`G7U8S+&Id0}Vy}FwYKUz({Kiy+dp^*l>y6C*#_bd(v*VFhaLW0{ec6#$^J(#=h z$+l8jxucqhe6*Ozu<6S2VecZotc%|iUSi4d*xos6_u+3wI4%B7ZPPSIvGX*X&5W6o ztQm!ib%IoSh$7w zdV!tY)9d^58>@B)RUPTFHZ9ln$g&TV9zK-5;~1LPE(U#=k&zY8&T&srNqS+Zyfq!x zPCy=6wM(S?o#;SGx}rQ?+GuwaV5GMX<5@9E@hig1N(rTiqd^J(ie+UhbI(2U=PnA# zd`D(nX491y<}EwZ-fnFwSil+}mh|w=0JqCuE9@(_bNf?k`CSTBzmyh#-lUsO^$@pw9Q42l>;pkWYuoNTtA&q zkk#&R?y%M!lUt*@QSoPaL>caIe}r^rdTSRXZsFb+XK|5yo+lc*7~K65Tph!eF!oa2 z0fQC!kbhrS?ryx66aTuQX}w}H6ZS_l)be-{X-1K?cXbVVgu6_~<>?-pE!Nui z$-u~2Pu$kIu)wvx1jp8_SdDYEmhlfsby(IKKg@7sy{4aNs0%|2L)^sY?z~*tIY`#E zUcK_Ks5eW{Z^s#=&#Nzv6%Yb;5+KY>K$M-M6?lzynXV357znKce9`=~NbBo%ezOO?&PqzhTouLGnrR>ZP~d{J%jelc5m7mMA0>)N>q>P%ADCPPn&$9*7)J2 z2{RYKFVsVwtVY)8s@byS3AoTA-QF_Xyr;DY0!Gs_KMStPB$g2M$t!oeSe15G>;|GF~R{aFZ z&{8x#FTbn63^gE5XM6vo>U{Wxxz%`LzMtazHl}Be|HRrfvnD^jE7?Xj=7S4%A-CgH zyC=0kT|~722mnU#!UU)TWk5(l7fRDN_ZPPpQ6}F|WUn$o%-V$EEwt0#k{Mxbnw4jN z9Qx2b#Ru+n6pf|G$Az=<6evq=>rZxECDZL@G*w6K>vfd3I2|5uZ7NM!o2rhrPL2rP zt&@$ZIrI_n<*(<;tGwj>q_S-sYIom2P|U0svllAkNbY`RyXpKCI^Ip6B#=plMBlAo zN7bS?B@0q3B6(K5OoX;Opu?({p9HlmT;ZPBoQ+V;T>_`79P$q{B0Xt-tA?7Fn90bC zm}YoRVe7;qU60%Qdae)`MMYsq{X;wGvmar~+B7E;ddA-G9zpbG_8Rt4l`2)o;Ey^% z@>8E-&Id{*d@gmMLisnpP!V!N`|SxJc>yzksw z@zqgJ>801nqBXZcc@>c7Q>JBH`-|^#C(;fYhM_UG*QaE; znb9R2JmswVdBVAg;Z(;li;WMSZ{y}jt0BQ>MpnyD9e0|}KHv0;^*Ir?CjCZ z_vPWaw5U}t+*jJyN$Xk~ai1WS8!xW@a_x%X%WupVj=*yss;K*NH{C}!Q36oU8#}rG zY@$Hh>zf1(S^+qv_P(qf;M7PIEkc$d$c$30t6Bh7k32s81kZ&kv)nh{Kn`k6k3Yi> z$J{lb3cX=`+wCohE7Ie+St!i8$~m*Re}ipv#2>qV>!dKq+SNMAOied*XS<)9l!a`A z#8c{@?M{TWQ6(K1^-9o9;9?s@81+hR6LZsbp(e+@=?YWY#OtiR7bq=U>d)(Rp4}@x zU|yx*`0=q)?-Z{WF7>QnsHvdT;Oypobdd!emQGu_ZhQ`reRN(2yK*APv^)2>V<(1} zj&u^KVk4Rj(V5P@d){}hh@SItI_fylQEYe(_-sv4I()Yiju;lXEbrP;O%gtG@>uWs zmK1ff?*QJ^Z@wY@5j65RP3+D!k!jWa*wS4~_OFZ$v^GtR4YXSptUhpwwP5w@P3;4) zx6X_W+`lL`@KC=RfRLX!4>hN49EZoFIzUm_e4xO37-4(BPCyV{ePGq9 zLu@WT&2JNXAq>YGYOVP%-dXWM3Y^b`h_HTFZ*uZJnoi{%eyyNBR!vq4MHr|&7fNZ$ ze1Z$I^u_jL(7`eQTRLiYdHZ3%F;Lw8aF?qZ)uUN6LfdC+bJoba?_%sE!z_hB8Jhbl zmk??xqfK=eE?O#eg$9ZO`6OGWG$?cHDW3eVa`Kw8D^E?fsTJ>1VNrY^LHoq_?=cm_ z?@K~0#7&urKJ~JssjNN3+Q^}jGqDh`^A%@a8|QX4Ufz{-RSDfGiMLzzKc}MjM^clPf4PyuZWT+xv$VLGUNM9>0-${dI@$E}=UNPn@?nt>ZHk5I(v|z|% zDexRgyMzk-4J(~&2H=@b`)F+}k%o?+ z&hw35?rN;=;@)(>G#x3n1AKhK2fUA#>B^B^hjmV^C?wI5Y&dt6T5C@eaq$b8`G3e@ zPP%j?(MAdlp9+0MPcfU^z~E};bP+%jbXwto^(qiL!ZZ})&BwEVjyq5X&@?);y>0nb zfIqlr!rEA+9Fh3T?B-&fweD=u8a&9UA0uZXRd0+m4opW!mUqUVUDmE6InmU+q12*S zBs7-TmW@Tp$LXrfdPUwB>9=3bYWT>PIEu0`0N9}|p?2Ye^7`1JUjl-Lmz<;{}}(tBOK9k%`Pp=u9gG@N@Fb`{co)u6F{oFO>+Bf z8oR>ZSa05+5Vxtc)C;_Z*`$uxi#q^TsXp6_j~Y-sM-Q^Hlzx4C1eS=dWW>GxRT&`Q zk=$7HrqMT8jKKv>J?>lLVx||N_PUr!zwQJ7(#ge4jh*G_THKSOX}Cac0c|{u!aiaD z2_l@u6ZAjs1A3F@X1hNpwu3>)&jSgF>qa}kl*xU=~MfP-Y7r&xr`mtTwCuJ{r4UeTZ*KmueS14*?L0I;*XQy9$%<%WTp{V}SBP zRn!XUl=1k7zVY}%6?F=bZ7#$m99!b~JqDaQPvbNfOql^MXTYPHvc?eKj#wpGX&4uG z+69@d-TW9E)e$1OP;qiSCN+sFcBeN|>$d7u8GB|%LU^mP;cczWX9(#_&!)@9>XT0B zKJx%rskhr_yCdE;q7T%p?&lj1vm?l@HzVE2;1tg1F zHfuz9BYc@<;?qU0PKvsNUZyBaL74Qa_unk7zXQ&p_jU#sD?UgqreAF{+}*@WH~rG| zHoWPl%y4ghw7a{B-{jy^?Vf`547o4|oP7U13!INKCb{=WzC12ygS*u=B_oBl3MEM= zG}4nco5t*9k@p!5a9N(wFJN6*6-L*M&65Q!vT$6D`{G-H!7w?PC11iGFAJ~6{VB_h zL3Ha4{#84zd8Yw3zWU->5Bbg47o-oDX)*ntY&2ulZ&iN3shhG*afevLL*{$5#$CV9 z@9K7QRNn6B0q?%+wc`h@*YnJJeU}jaw-YKc@fjdFyJn6Xy*;}m``1-mG>%QWZDErm z`C5+}`!0wDKa^!Dd*!6?z;*-uvKnF>hVZeZKFZv^uJ`z(S@HC`to;kX|6_u45d-ko zdOt1Y6Mkc^Xe`Ee+yn&aN4C z$Zj`t$c*$T#w7M?;{w{azmYa_4XH8xOV2&(RzcnR+^*WY)eRI+b#k!Hs@js;TAaHE zuvhzi?kero{-byIZC~xmeufM^r8lzlZaS`}w-!qY+X6ge{}`T=X$wKGxY~@>?dUt3 zz3bmkZrFDzhW9OI|B=O1jJ?L_*S}H+v83rZiZdaaUK)08mA1dinI10hZ0^iY7k?i^ z*5sqk*v(&CuwcPq&LK8;4B6FL4j=k{d26aGYfpRf@tTlpPY?ggVXp1_p&d$xpR&Ihu_u%SSF~!qv`*HE zguF~+AgAUZ3yE56S~obCMx7-Z#Klg&b4}R!R*7>$fx;9J z#M_>7be9)zwWsARD~|ukn)I5TZ(n0Bg1nwJr+tgeyK4WY)4qP?_6e(7;%GIi4?qD| z*{9jFd;wbNpYG3-x&C0$m9$2;%=zgJ0_~)zqMxmOK+ksoAcN6X)iW?4%c@_i&$kqr z^P#CvLU&Bg=_8x3KjF&MVGk$Rjv=9EnmdciTW)F@{81?Hrrqyw%(1-rrl)^B0l{@w z8db7u6;nB7haLSndw>M0Xd%e1eMdMQUW=nM7J_u;Z#gNR*VXXKijn}Xb7pgouB-T` zsUuuWmwZ2KZ@zAe59SYoj6LFCix@M&5(da6o4&opw-KF!c1{->wlkjA@n!}I%(?vX zROb-xC*h;~3)To<+0o-VKOXX0CmL^HEQfltCzfEtQ5>QYSGEfOBCfgD1gNnN*#N14 z$V;!crJ64Z-rgmqcxs#E2BkHn+UokL?clu&@yWiq`2R5X_VH0w*W!03j1n+C zgw)2C2-u|3)(Eyy7{M3p04Bi~T6?RMi?+3pL0Sz2W(IOR9Eex2dW%g=S(Juw|)M5^h4&HefI0x>us;S_S)``!d!Z9 zUseR}-B>_7rjg5N1Oro9y0s_Y4L5{R6)pBRuev5{x4AW3mTJx9yW=*54l)+-$67KP zPj-fGFC-xGPH8+$p=B#-nU-}|ZN{{-H6rJ5e-phn(Z4rt|60>_!S zkz-QW`N=42?J!+JzuJhjb!#&Xhw7~*M+JTpN|m2;zFNK26XMt|kE{XL^XN>HGZWV_ zVb|%+aZ^Gic1PVHe_C02S?dRNPta8EtCRIUg~pAx5~Jan<3>{b2omzRY1&%b5^A^B ze$(z5S8mQHQ}HY@-tHv>6v)LSR>H!C3fVI){RIMHsKSEnwa!|5l6~mBt&MmRSjhpR zMnBJ;0TO4WaL{>$r*RPoQzvWYj@Z7=i+lA&g;&M%Hy8~;kkf3=2J3C-su7|OBqi>a zw_kLU$JL)rhD-0R7X!vbR9d@hq?l}bLJLl_*4Jbnc$o_wa`MIrNaW!fdoz^L53Yq>*2eKcL9*WTyahu%7V8DW|+5ydzNqGJXYcs z@(Wad%&&dGot)7HJI6L@3m)uF>S#DPz*_P*ASlrLgMfOib>2x<@;5wIY+-p>+&L)A z53IFe>%1^u<9sEeMCD(J@59ti>4u1%FHMC*iY^|k#&dG8=Cg{;U z;lfb3Zkf4#&?#IL_r5`(jmrI&D;^yzQHgW$IjXiEeUTW#TfHktwGVPh;{LkJaosGo z*0M5IKI+zXG#nZ*?@RVO=bsvz39Nu}=See(ZxlZDyzptUZws!lXpOx`$BO`jwYJhe z#0`h-;9)WBgUeKF(hGLsuZuASGz4z}!B8O;erFBjH}~Fhsl`5Itv%#?R>smj;b#ow zap$uJPoAt=u)6a%$jlMsD}XqK%O!3`jX$t6{(Rnnm%QtFhL)&Wtj~Gg-%xZxv``MB zZQ%pOm0%tvyL9J7zdO<`?=cd|APf2uaO1es<`n*A@6~6@YJMCW?6^^r@CFIi+J^fj zU3_aO3f6pC+G6nKNDh9+xDf%xdD3~ljIkaixU2Oj!=WFF8HjmloRkCCmzGmg0X2=1 z$Q|rv6r4smT{!c6uEfuh_pRh8=B;pmJPi@+RKQnKJ|4>LxKA)TEum#(7(r(ux+=cJoQK)-K4G3FM>^ z(UIhFmT&=YUr<82{G5H%TP8w`jC~NVom_@q+0_AAN9g)!6i@mu-OZkrsB1H^hgVOd zPZG664t|N5uEZU;!X2~xz^;mSxql(N{J`s>G)Nc78EHS4b% zc4ome#VZbyP>0wd*|by7>A6{iZBki zt*j3jORQYZv6et^?&KcR-<=rWT06t^xAL#ruSj0(9q$CP7=APHs5;<o#XVWt2` zdT;}Xh23jc7Q>&axc6cY@zdNw_d3*EFe5DTrIG?{qC6*hAy6aUYn_shA5=xo_WxA=76L8rSjlmB(<<*_Rbq?w{`ZF&bM4n-DeZa=&-l-$HPk5L+`5*QRjgfyeaUCd`B?M)E_`1wT zDApO@RBCTlF5ZMS*OPwZEc;Ga^I19*$K=b-ADhx{IH{v=CB%%HfeYr0S8po_4Gu!A zqyzHw0^DGza2vd^NS64lL+qVTikZoK2%^B-{8VB8L~Qe3l6O-q$l0MsWxNFoanZ0i?9uJl;*=_cI^tEg(rpBuz zSY=V=OR-Lz7EXoTl(mI8Im87mvJms>KuStLys{$C>ZNzy zEvU}zySK08p*A`-Gi4~QhE+0THg0dZn0okJ_I|BfJYs4zeeU+RGt|!4vUjK%zo%P% zrDoR>Yi$?e1V?_Y+`E)WH97hha3(xZcK&^Tt!D))u>#DZcJ>tC_zp{Yhb)D|lDiuRF6?q9@3q#R z-f(zf-5H79^G{FguDifm|8!jLOrQLQ{aojxK{=_nK%#x68VAnVPtVQ0Z1i2}j#fI! z-XQg@za*oDJ<;i$$WDzu9Z0rr}WP!hw`qzDmwcdxo&(QF{8OKeEQXy z*kiLtr4RFsE2jnTA`i2pIm@kn%8jtu9_I3KM$hf)E%Gxp6MH;rS3i_~l0d>b#~5%Q zawb1)C6>Wg+9#aQPO$48z2&A(iTXv;OS46+#1Bp89eHK1EIKN7)_H@`)@#ypjS*7} zqEy*Ri|)n4Qjv$ro@eH00&}#tOYS-s)0lmj4y7L^{-2 z7cyh^&dxnqd~O_{K@fSuT6CUMZQ^iE$s3%{@c(U#x$k>=pFZJ3pqT^xw@?4PBk-$r z=PXE6CD9mea^$CpYmlv+2eIWBRR;M^{VZ zGZ3wrHYFWHVM2YxMmMTFR^q#g;M? z9Ts%7UzsP9IxYPgES`o%!0wPGW&5yH@-{LH0I>d-eFP^~giJn8s-u-UtK=E{bi>!U z;l+0HFoys?lFl!J*|||w)-$eos<oL$gL;1Bm9dDV78&xH<6nd+>Pl&F)GeA8$w zQ@j}Xm?k-RmJ~>GWLL+6%`T6j?0mLo=YtdZLW) zp+YAz)KP?XW)#`Y4UFrAG&R}Dn|Zu3QamQq&N4ge|3MV;LgyQ{masco(kM=$#-u<} z-cSd5d(eM7fj3*hE8kAkZ@==t^>0ir;SnKhCmS_QKd;uujMe)Cf8r@$?=I2_xd^@>PletNX>ts6<6|IIEtk+D7CDRDW)Zb92p;Sk?L1ioc+LQM$I=UHvS6vq|PaMmaZPhnd&-crJuq08I)8M;e0@%e!; z2rcM1N3dbN5{MIi%wDsMkCJ}1Ols{Yw@^1J-Jc9I#4VeBZ*^h+`i3*H)Qm8+U$oES z#dcTk{Bi|3cHOo@?r#4`n{rl3#j+kmO4Vl82z!<5piqhk^dNUm3WyGX#fuKZj~7}? zzdW2f9LTh=?4`;MYw3_vF{f^HbO?~Ccw^yj&&HL&WVh9LHrXAm)~S^pRcGQ5XSwKL zWgSuW38xHoYKM&E%cde~ORk`{-pW_h@fwd5hhV&^F-}s@w=zQ1=xX#xdq$C?98RF} zc{-ZXJ_rNxrqf@QPu=YWvF|@H%7^JRV7I8PCzJUW1D0YJ2`~-x4Fd_^Z7@3C;%i#M zH1`plv&%lwIa%tdjb@7Pptp_|@NQ+5D}1iMT>Leda0e%Pvq%c~xfpO)h)qi}6zs{f z2k#l?O_VZ*-)l1EqMXICYr>R1+fUB$tp306%3_yr_`1*8%G13s za}+Evm|g}L=vOLIMB^DFhTP_~0I=C)v)IrXaHg_Qp$>_OU7MoEfqdTijcpx zc8w6PwN}Z}TD!`S;e1UqEFmeFM0Vu?n#79`xvhVB5i)Mn@78*42Qy5=7tbunlqOqX zmI6oROT9B`D^YlFDM(qrAl3|VD%Sh7bR~22T9CFN7vWo6T zDC=1)``04e99LwCc<<#oRnt?+?Ys$!rjk4Tr+AAwrQzx~`!#4J3JpWMnK6r|+A7A< zA4LN#RxXHcJ6&i>`s1v6n7?K1Y&_qmos!k4J{b8I`*xzG?lP)0`bo{~5<}wYX>USV z&|Evtq0|--cLn;97%dn2j8I!I+ex;i7m_XXp^&sqCL`^Ho*RUi(F~+JQ+);!9cs!; z3$0f2GZa;-wma-ql8+i&IiG=L)yU`2)3A<6L$ff*yt;8z+uPIMzLD+eRtf|?UHUl+ zYh`wa>EQi*4Snb+*u5L6$yp`b%(_tPkHm#TfuB6~qYELO{&pT@oFR--45aHV! zL*CaV`$Tr30KSzhXC{+d%miAARj4@D`tTyVEtOnNKCy@rNYGv-7=BMh2hL_nD4ys7 zy;+!;uU?pS#-8 zTGUS~NAg^l!y)&I4?6iZekXUG?7WHVG_SAr7&neRK+<5#Kk|$KQhQ)Qiq%rbO;bcoGSX( zJ(_ys3yavjc^UcLJ@Mp%W6O;DM1L-!4EMnT+hhlY;@?6w*}?4eZEKE5?`Yfsx&^?W5*A%*4AX^bRg@dPD{`GhDrw1D)t9d z#`u5m+aGuP4@MgcjH()j^iU3T1eA1C@Jc(JNr)OeAGqIBN8soKOw^uwbE=JEo zAjC{&&kHWnpevYZR^lFB;)(>I+($r($;_xGUy}~Ene$OFFOfJzlK;@fvB<*E z3n1wgfhdVk?=k(oib&B$aQIb99J-*t6)Ge|;VIiyxz$>FKJ|uPa1>}Vcg6ou46jL_ zOUO~md;LfdBvmmlNIGVbcNK~{ZwEx0eFW zJxM6wPdXj?#pHT!0MhyaQjejB&ohRGW&ul{l{kf$zVwib`#UJ@lS#$%4bAscX1cRR zmNwSPHuM9bGmf6#`4-)oj1{%WtmQD}o#L!&(H#EztknaAFRL7O7 zMylPRQu*J4@0nq(6Cjm6V@>KZI)#w-2GQ?TNpQob5Ul-ZOc%3!%L4PBAS ziql&{qUlq`7Jne7oRpB;3VKWUP-;v{!Ppm=v@?uF#NOO~VW!;l75{NlU0Lg=cXUur zM=Q$OZ0(|{z9@FOqpuCk(hM%1N398M{&H2B+exZ0cZK< zQeKYN(tJ^Ul<6F=rShPqxX6wi0UdNS@3_TTkqD}pdXaZVrAd5KyPI!pddcnu!Vip0 zt(jf!tHP6BVgyDNw#Xi^f)Bc(PvJC1yDXO(QiL-~@QqoSF05;@j2tCcFe{^r_Nl_T z^j+$Ptp3QlGpMiCS|Q%ep{Ko#oK-ex;j8i>@ERdBSxfAcxysJm29Y9t03xkf@##o2 zvnc8dPx+cNbLY~2{1M^PvfF+~| zY4V)g-|Pg+hu#USrxMfa{P@QFfR-T<0thOen@CV1Om-piOm}l19!6LeC#6(Z70ACEJ&Z~UK-F7YHNOK+V9L1f_|$a58|+`h9X zgSO)LYn}3(3;ux6OT5oeF4v0CYh-y;gi+SW;;V$-K9PV*&N8ki-+_f*&)9?g`s~Ux zAh%sF8glEhlJ`?IfL)vm6aw;KwJCRqvzSx8!W+hmS#v`IdESFisn40woGMz329%XD zEm2>}WY%2IC^KtB0H$BtOE*Q}lw<`Cl0}S^NR~4ov`@;L*OlaZ<&C34(os>0D%LXK zMPh0AtFoKv6Pqvp+7fP#fUH+68ASHv_UGeGn1qAc^fB+f(2Nsco3=+2xWC+wO10+$lSdOb|7A)a@ zD55TBQ3+FNp-;k2gu*!iPa{Ujg$K$O+jy2#zOu;rk(WN*8{ONzk3Q(_-bsDC_gU?p z*8}PYdf*~CW2U-}y}$M7aC^;kI$*E4mcOmuaA%dgazTW9xBR-2T=62t5k*x;%k_e{ z;+Zm|ohdq>?g~mWvTlFNSx>WuZS7dQ3YnZ zS`QBAs`*J_Z-Vq$wX>XA{s9iW!7MYkC!ina;>n1==i&)R!hNjCs!QGrq!}(MJTy%Y zfU3VkmgS_+J#VJotTmD=_XqGbL~kwqiRin^Y6Db2(f=*T9(utr0|u7ooeBH)cl5et zM^A82J{Seb`v{B`;qbRCX3&-FN<&DY#;h^qQCK=_i~)2dr^&BtliulGA11Vz{6@ZO z@R9XR7)scyJs7sW{hYrf3j|ahsAIrkuMum^@vMLVs_{`&=L_^K&vJ1n1m@B7NyD^T z!dfNXiOj1z6y4Y~kf1Dch5Ez@gOcETY2m9;VYnCzTkI(0}$)EpM|1UgP0WsF`4 z#SEW*sECtSaP3_FW5s{NMq*zpMTyr;F1F1uzUxxcxupPi$nm-54CJl&d?~H7`$_&| ze*jIwGKD7pQ)FywD4_klKp}uWM#6PHO!(8@FWwGd*t>$w8tKjEhZm+k092EH@z)9) zG1UqA3p#iwGhi0P1`B78_I1ByU(%ca#mBnjY4B#RKV4G$gO(6@XG>h2Q$jvi$zMQ< z-rq#zVQ<&*YJ)b)fc2+;Q6gL?xUOY;yR5rfxUT0((4`e}F0SJF^)Fgy7I+sjZ}e>T zS^g;6&k9DtZRzkZZz8=3`k&2pe@?DD_L1ug(r14kB1ieK;@zTmt_fI)SlP;%An!1R zjEd{Jdj%$#rKUvFn|G3YJgZdRyL|YBRjN$JYu*rr}8 z4aOR4^S(>5UMs3ZL4mz_S1BVF)(VGDc93ch@veT;pMRarbAtKL)@EqgO2z~-{i#>s z$6D`x>dB%3s)c|hedQ<0T_$+*EQJHO`=+}4#Cv_JE=bw= zl6lzoz>&<=SK%ZE1THbK-9*o!wrD({7lVo1Ot zW@j@881goPzO?1xvgCG^83*$?^XB&I6;P@es8O7_Dju?i2)e(2qo(GN!-{$%6&;Y~g$ z9}4`Zo?<6ganG4Scnp-IhZ&+XUY+YZ7-?$!ENCj@oO__1wpkI~D7-XM$fPBTD0`rt zcakM40vpDHCMvBEE*#hWjX6xc=&ig4QM_b+f;GZpJ}9lkA}Vmyv@tR!XWN~)*i3Bo z*x5`Uo%H~BKpbZpwJ7WWK}N0*Oy{Qw;@&09&i zX__wF;CxLWGDgOL8)_wHpl z-lbB2eRZXuhV%2d%7mO*FO&Odw0DOjr91S}k(7!(%A!`TrXERilX4rTYM_#oS#!Vs z6-fu~2IE5tXI`wk0wC|dch;%5Ar68l^Z&tT6| z4KU-$bsP^A81Iebl~kv$9RF&Eh2u=5kT?Y^O>@Co$c^r8)LkAswXXl}p#=?xuD<0o zyT@AJ;yWWa?A@J-GeUj3J$Va5C`l!w{0Ib6YOtY3pwj54RdlD4S7yIon|-=2`!qfK zbba>e=Iqm~?9)yDlii%)sn@`t*=yEjvaHi-l+#MV7<^9+hu+ye8f7k}i$y4i?dsey zmEdRbPiwj*V)w|1g5Dpe3dQ3gFO@`!QtIg=6cKOMo?v)qFBLDDc%+E5kV*xUU)L&RkS8T&&?hMn#NPir77WEyD{&^gIt#N8q=ebrji1j<8KoPO zu%o>70`QpS*S|w!C{TtZgXZdPG5{%xeLvo;z^J=AsA_w0Z&l@snte7+O?qFT-`?VE zCR8LrhDJ75C97OiLS6~m!evjU)zAmY=NC+hvh^o9XO|Ptu}vmQ-b5s@UfoE3W58H+ zP-|E^5eE=Ky@h3)We4!fyoOdu3vumIp4IpPZYNPkjV?ym)YSG0ndDEXQOl3iei3PC z+3OTA^Aj?*60@bET#-OzzTeb&^AuSPQ6dRBLumX)XP;G@{sp!w->o*gwe`H!m;oHl zog(lMFl9YaIx>}w%@#92`?<1%TpN`vU`70d3~8h`PtuAt6bxwxg?T3{DByMW$RK^f z7@srAH`0IM64O|*^_}E|klQ1|vm|oRF>^gPnCscWTz@Z^>+v}?_L=K*g;M>w{&)zq zWoFs5e#~48Rh!1SUd*3zM+w7Vd8o^n^JTiBQ79lgg;zY4MPD@v}&<2Qw4SF_pu~w@;AJ zC&;>(&oW{~0o3}pPt26Z-)C<{IELd2>nZCgYc)(j$=$l7H6V68uOtNXv4HUB!b%ni z)C}#(mS3d9J4$^O-F|s1c~E+zTc#D=BUcHZ@m}Unyjhu}cvY)kM?957`Xlv5YqkfL zw~#6nC!G|KT(p6~>YGn-Q&<`p>NfPYg95qq0?qxABtvr?^Gj;m%8sps&|%R2TX^LJ ztf$0lkS{9Xe3t4xN<;oL%7vKo1radk3lup=&FV!8)flgn%o<^c>C?6_QiAg~t8}$f z>>jJiBAoJKx@EvP&`QcM;>}UYp!-bV#aSiw5?1KB^n$teU3xoKI(i0ay7KRNYpQUWB(}PPI*#?xXj(jYe+R9?`$S3-t0qXaSrkP znO&=(of35oHCl!UaBrU=h(C>a0!E*>&+;)=nz9oAE&L#$YHuQ=`{xS7)s*oShCVXB zO4S5c)ur^UzkEA$!7D;vs_s}z+k}nj^92$BX~Eas`6Y`odMrjxA=IX?9U#-9rx4C! zgVdea$4QLXScWuwZ7gqGDI$ygTsvj-8DE=eX5E~tlHng(g-T}lWgl&B+}SKF#EmIk zZomfAQ2seavkxx|0|q=Qj?tE8e6s$QFHpaBOJMwIYF4QhOeydBgoaf`75`krvX;Jz zz0mG4TBB5As*{fQnTZyi37^lS6cGqdbfBuR6Y~`$b|HY=J+1HKg?PE(^r}hnS0#g^ z&(1d;SH4v2u$!v{FV@IkJ5}*4n+?qqBt`$0wbOvDly&;E68WoHRj5dj_h;E>2sAQj z(EE2%)WOwl-Y1p4r8^9Phil-?TG8_1@1)Mx>|YDHNe~}Ze^@C~i*yCfTlJiq;C_vY#{ri6ZwkDX*e4P!i52#Sr9X zN6Tn=qDD!;vLKabl>LalU<)8UI8Y}9`s(TIqE zxhq?)o8;@kb>A{wedUR4S8rEuD`AsCR~Jf(mcyZSv-I<7saE@GR7d+GRBP`C;2_X* z#FL+Q+3LLx3P8Xme+@4&P2vuAw`_+i%ylvR174?02{?ZGLk#L!c5kOr3S7ZKGupC) zR^xiWge%xG`q(=M@)n!U99(HDAC)sf0xp?}3?i-%uuj3k*_T27C!5bcgEV|t{D5zw z`@X`Z%+huRWf)N7x5(~KOD(cW8VWQxru)%g%h-U;(PCv?0=mu}9ne_M7WGlsMOJ=pRyZK2=O@jt?2f_WF2g@oCH85mAD zHT{{J%#voE?Df_c$&3wV#$>vlWPxk15;4a7wJYRtVpKuK1f-HT@x?F(k$a4UwCkjL z{)-0-nlUU*tmIns{XiqJk`Jl&FNIjh*!m)M(XHDwpMW*Hs0~{2mo(mZM%z7pT)6J! zc=O$+)Dghn%YYo}`38$JLt%D-Y$6hC1#6HZqW285ZEOTn)OWF>8_E4JHKn_6S6J9> z-W7;J!PGyKY$zRl>C;I4BGBxcQJ8)@&_y0#8O@iH5c{v=`6|xHJM)h zfowkG5qz|>EJuRDJqV~jRoM74@Co*KI3*!ymD2T|${TZD!Z%U;E5c?D)rhdUo_anZ zvBb`i*=zVXwk$A;YhB^nO7m#+qEm9X&QXbCE8{lOKeT1QK|9&SXTOUBwvv4o?{@Md zNnNW*-1_%$>)w6?+ISTrjKB7*=99j(?mb~Z2ix<4^{s#B@YuHoY;Jw6|A3ChWRIyJ zs=4|lIWcn3q{tfAP9EVe(@CgD`n!8XyrmE-+TGkivN7!1$;~_?X#Agj@-{8~z`2S- zD2R>oWVfx4oHzugD_bwyDu&ih1&Klc2jcN<~RHWrL5_4oIpE{0F-2}_}YWzFN zJA5YQGpo3-={kZmCum(OgkCz-pe^o2JN_p3j+N)i6#^cRb zO7^;oP!X{#h5w0NNmqW}&twe|Xhg!Cy;^n)xo{Z=gQ!dvTn%ijjJDW z#!7rfI{r_=eF0Sp(-h|PuYu?|CRuR@l1gs+^h%5_oGxC4bG~d?e4m{nfx!b%qoeG$ z;k;5SDL0{Hz5EifG}tDtA&-6EXc*UB+6GpKwEO6)$u>5`hT*#<+!b=QeyRPYoCZ4UHVM6`bB5scq_1QJo?u zXv-`@tz-gf@QN9HN*Cl1NSF0KrFqigzaEvk)xl+>u+o_Z7Ub zOh*>>?Z`MPSHr;z*BpbpNAO1MgS#n&b~HNstZC^T`Mu-(5SH%!h8=L)*iACe~9-lSUedklylDCR_ zxIEnKF&Q<9ou+)lEay!Pm}5%xLGYA!>yl^9y2DqUui}HYw(aU;!0-=t`TKxjgfynS zA^mcb&o@TWd(6{!WqC%-(SxbxG@dM^y3xC{3#ptX)J<>*qo(Sz={0PxMsfD?1l8*? z$Hli~KKOl2jlKCm2eIZ0(_6SZMom2av0nQnv{^cDPB4w#!QGU)q#`injt_p{yReiB zSZjE{$W^FlkEM_>qCo8=y!>2sf?FUKrD%HKfvjj4rp#L=v$xi)514-l*jN_=*Eh+V zUGf&~R|ODGOGIrYS1Wl6o$-EvYmfn{*?>Spk{%g%hL^f}OL3pMcoC`H!{45W&6Sme zj$o1cGt4WY+pH>u-=rsZ`<*vtWGj(myy{{gpLzCO435+J-lh6<(*x6G?^+c4V`*AF z5%w=rQp&86L8s%>14L@G5=$UI12U0j-VWi$+DXkiJvZw$eX^RF^u7;z8tTXaJP|rB z!!vE+#TA(+)hn$H%nX=(6-!=gy+mS18s8)K1zDAf{ivb?dlje7{56H>c;1(pg$?5I z^rU(`{ZuPbeJb`vSv&jnbgnfF2AMO`n@d5g&K46QZEXnh{D%R~cl+|0?arYL>}#YK z#b(=wHO+?499u;B-UAc?N`0iu=(P~AN|)7;2i$11m+6s*UIBAHR(jD_MHF^JUETm1 zASXg)c+RKCe0tO5vPqS z#Fk3q3Nc$6byPOQXua|;$|VU4hf9XC0jArH*PtD9NB(~w)q3K_3BhJ;dqLFfu zVu^FvP%=ByhBy@jxSLkQMFHar-AjqS*mMN&6nD-K{9D{hGS0ZhByqlyTkNew?~T11 zZ!afUun@j!&G?~k6_Z^3w)hCg)0}fTUOaUw8PlUoSGfmWE~?wu7O@g@P3GQcUe;0(D#wQIlJIJ8 z<3Xn(?GHNa=+1bIduQq6p}i)?5b9BUN44)(s1rPdhyFQrrfW0FK+yw;`+A|)nP5-%8 z!gdL~0`DQ6Pd_f#4LTLfORDuD9;HzAV>dVh`2V&=gyw2Ceiprrv)&>f9q{?jG5yd` zZPZeej=%3qGKqJVeA-Bmn)J}AftbM_E2;KQl@`4*y>1|J!zh3=)2`p)C3rKQmag(D z;>8nYabV{e0bDnR%DMf49_MlyVH);-xEWSG54Li4%+Vu_2 zt>t!oLgWhZkT`DLH~~E}6l4g&5mq`&|6JHoO5CHtF5LC!wll z!LVm&FBsaMJ_Zci0E07QTPi~AHDIY{R<>5WRJJwVHoW!F32yPKb4VwKTI*}!vh9SF zwD=3<@>kTUzjr~x_T&yC!^98g+x2^iylAbsNmke#2XRiz%j-8|C3m|_NzeKTDr+_1 zFA~?($=jXD9dO%JWSg`L5~bQ$XJ!BjG49yPmuE1ms=yhum{T%qrjyWc@CGX}pWT3l zW_d+2{AUqm@p=2YXy2#MnmQd?kr(Y%QK_MNlk5cinj-P~ZDDJLY*?fsn`hD_=3a7W z<7*@@vA8vbYu+Nu+>1}JlQ&5Xu_83=$ja`E3kl~MS%$~6q()YYD4M`tF-v&14g8u2 z4%issHVO@czEZYE*GMJqgcETF(dzW?1*}59Wi6eDFAY~&E&dU|j(%{5CPmPjm~+Z((;prNUD}<)^G4JC(^`0t#lG4tMXNQ!heNh@0x;+D;2uoKiF%ol-6QJ0*Kft z&bG5wvexqLL<83qvdMOMdOE8zmJ)iAlC zLg-fFc7C16-7=1!0UA;CIG4p0PUG(7O=R)P${8!I6I^X^4PR{HbvdJ{mNdo zV|No8)u|~STSE|%@Ng@>LwFygctvp|hkiq2XWY$2v%<{p?yf2&#Fdc$SHeLwoneg^b3AfPubh#AbDv9e-! z=RHBbEad-}*sTWg-XgO3-+iuJtv!G%kFb^FIE=W-&lS@X}Wdr8*P2A%p zPl7Wk5!#Wvono0G#lN~MoJmDvCl$}V*!^i(E~c4ZWS@%f5F!142?|wy7<(2B67;Ei zP*A7tzrgt{+I-z$y|+n5tL@QGBFGk`_uZZC>B^SQKR{r#S3LG&b`c+tZp8}3T|`bu zjrK|?9e<6DDG4Y7vI>nrF}oz6&`4dOk2#Aa+Jh`0iH}JB)R`^ypL}$#BOObn<>9jT`)x z^oH&9Tu|vB*b=k&TEHS&>;e9~^tL}0ddq3Q#1jWLr+%edJhr=SxRv}Zduptm-w)aK zE3L*4kwNayhO?-MG+C2&kWXZK;T;Z_+k~GWR~$cs58%Rt*^g|;J@j)Jr$bp}!Y2pspoyjXXY|g0`$^YqVkp_ z?!+Ukew@jxSsax+Dz7V5`df+rp+svw0?ks7#k2jOs~Z?&Ap|-?!QhXPWl##_qc2L}?8{o*4F_t@3j;v37|1z~#_@sd@- z5-Y1Pc7n)~{_#hyg&0Ei;gR=>LV~w3e??i%FM9^DYsZkfZwqBiE=qPgQ;MwRyLgKq zDz_3HntZp&(E|)rmYd3R9=e+sWN`b~*lJp|62Fy&&I)m(36RK_U zf5lm?zQY-g98BKA3s6SYQ?00TP=N1F@qO+*af(THfp5+rcr`jTixk7`v9#;~pPg8f zQKzitx+O>A-NUU!0qWO>)>F^pM5}c9_pkmVg07i9aBH zc>~r^sky9WAEI@a?W}d@hN4q4v8HtM4UlVOdo4?Vve?UIJEIP|-R9_&^n>OD>5#JB zR@PPal5_bTN0>Vf5mj&Z{)P=)=&_<(i2Oa_6!ypuU<`{FL2!{oCDW;4S)owQv+z*5i-KP}*nr=cj}2XL)StRejn0ZTDrsSE%KWB``{7rsW*%j8?D zOo1*X1V) zR2ba!pJ^*_x6Z$byc_AAB;3*H4J@mBSmI2Q4ktdN+~#HBeL_k3n2;U)BwMBv$Wj+U z%CHzWhrRTZbLC<#AGDHxgTRnnPIZ&hEJwjQE$L_cwxvh%tmFwyF+3~Qg&ec1n`nS2 zCBoKcN;_fDAzt4!##;Ut(z-#Z*uaMRm57-&yc5W#$67AS2dDOkGa~`Fw5wJ9PQ0ee z!)Azx}i~nBF?in?zIBc?Dz`Vr?Y6D^*oc zLEq)(FZRkpp~$vaf8R{w=wUBMm&*3jp)L-1xHgl@zQIQB)1Vab`0c05Qr=vdYVJpg zYzFO(4}uQ2@p*Bw+bCPz{`yvueesF&126oy(5$tEKEQEreODH5CiY0e6FmW+i*2ja z#rT4`?!~P3bfIqRvfQho6pbt8R#}OyvM|i9kbd4v{69hg3W)#Tcn*kvB(1A&zf-;1 z(JIq#?h|^F#k)66YS*T@LMyksn>pi4Xfam)8zq!90jz~8y*JoAvHK$l5smA#>MjQ1 z-cp#FSRfPPsnkk7F9%aH&Zsgs|7>RoK?UcZmkq79y%s$HMop@NnNo z*-Oy!@=FD=$=eb-80d$^i)_NvV+G<~lb0&n7QW}5MW$Z8#M><%MaB*jS?Sy>bAvQV zh%33X=4OG#&&r!9+J}L{S34c7|aA!vtZc+JyeQ9{k ze#6z>aZ9~bcy$Zh5G8B#I@|0QS`QCz?fkqu?sM_ChnKyYd>+5Ci-y-&m$bF^oZyBR zMbj1EK~~P#=2Wj#(|G75z60Dz9SBf#`A`RpEwbH8RDDFv?2#J78sQPYLW033P%O{e z53aKki*6A09dq2S8G$)26U+~)VkolBLKkbpAugH36^G0myD>tI z<$@F0Yq$G0He=bja>sN#@=LZY#sD5UfuN-THJGz-OX{--6} zYcH~2VM)~zc3{!p39*>kRrfALH{4bOnxiGG#CH*->xR?T$ViiFMgU_Vbw&;OI;ujs z;m688kabH(`cG`VavcpQN?#+}84~?9cp3lUGL{WziGCAX$?A56!^*@*;>b4d8QgwU zFBI|L3u6JfzG_qfSj*+Q%gTY)V!0g2N+d)IMOJ#(2qhZRV=NK>;kFRxEJ%`CkT=2r zT}%Tv7h-q>zTP{y&mi)34YjHT1<8At=ofNI+swk+OHPjey`XXON|o2iVj#(Mae6bw zja->xYx!B4QsCU70-P<(ec{kiV#LP^GS36R${sFJ0pFc_FQ*s6Fy@G!YfKT`j;Q=n zOt#Ah%A-;8?t(6;2j#OUb90d>daIU^!jhnEZ1rk4JjhDEi@xcV;Az!eMNs0CDz;QS zU(u3Y@CLl()%eDK+`t(>e4@4FAG(ZXQQRZ|Frm5~PBbXGc~ODYWHo3=04cf3oL4bu zNObJc-fVn~BrwoT;=-O)XHS&@^tESnYlpFCNMD~IS|@!KWv4J{e1I^=i8-y@_pqc&0BS ze+a8~$NMtLI~93Hy{sZ~RiPqB^`NmRt=E1oV@-IPrMIj$hIl87q~iEgKUAJlSuD$S zDtB%V_Pcc9WhGB$!(YFYnc&ExGKv;MbaQcks$?#Ne+K$r$a_$RH)ADpzI->!rP%{B zvF$z`v6Y7di zP5*^@Wzj?T;ofC4UJgCOAyt_1!+emQnsrY{*-K?y+qsBMX9+<{Lwj&z;3l0dhKGoB zUGOEJt8h6^VPjUFiF{omW|ly{%Bo4uZ>n%#4TmU5Z&+fmyxq%Z8Vr*5lCL);EpkJc zAR24lpGA12RR54C@AC*SwRU;8plZ;;#0RifBmR8hiR3NY2wD&Wqw|Z$+6k@XJxrL` z{D0U4i(4aw5%k56Ipf84S77Xmb2ifkQHZv4lp>4dovlb$qjTGBp~D<4+-1L--oICl zF$t4cv0IdsE_OjaghdfhnpZ4kor8$a-D~E?)$cV$ecYih{^PI>M#w) zUU1eZGvOG;M#uuBG`0Zjzvq>w%V#F}!`~4fU*vousc0QgCXVi$~*hWVYdW;phxBM-Jypn1MY5O9?k09z4DGD&g2%2e;BytoJlk5$dU2JGV408Q_`>EtC|J6_W)3g8nQT% zX8GV90HJ+e=iRP~qpSvhpjgIIw<%qJ-jU2zzUAa6JWHV;i!x|5SmpT!m7`@Z5v*7` zDRlSi>a0XW+3+Qz_dblqe#I-13VLBVq%SN>ye|qP(4|b}Dv?D-JekW!xHTkI6_#aC zT;&w5WH-yG4Fw>$@oE=R>${<8 z#JG1povuN&G%;O2l8liKqOWY{?K<9&&Z7OCh|dyapQ~?qAK`X;Gr`_T@YaeJ6gfti=WRsB=}Iu^2!T&7>b{W8%fteCafO-2Te+ErK+nAi zKP|vg)+|(URblQb)vF~B_D5as{~d}q{W5lud5g7M-s_^X$C`SrM(4;F1|z{McKdxo zz-ZT&3YUa`=jP6n+?cSAlYNn}d)EKK8m>f!cfK^Ih;4AlnekNRwRiMbi%)2c|g+5g2bB6!bQ_U0p;CW^x+ad#{B zZW8UKI+4l~1hTn9M)it<*ohS_#5x}A>p_ZisR>O+`?)w|xnGTOX4jNS!1inGn=`d1Rb=GPK&3C%G&KN?gK}k6y%*<9&Z^E zO+WDV$4Xx*5#2hwK2(B>*_i9G)x>p_1>Aos@jv-$EoFa@ zJfCz`JNf1Ov(ckm{Y?)#?NAURr|trpEVkKc;y%s?Ox)d(NZ=< z;S=N`eGi4XVRTc$HFQPrvtX9ov!1R9^oCzaEp;PK$V2S^O0IkAT%EO_1pIFhb*~dR zbgq3;f0i44*&E4Q?+BaZKFme?MhSf+N+-zA!=+X7lZR(tQIJ*@=B?O&6Puvj*1{gd zj`-W5heCSqc5)+ya*hGqT^KG%F-*v9puL-?>wKkhx?R|bqGo7eO9KP4YIxMOv**VNl)lbH<-B2 zY;-?scEq_u*^2a-%IuAcUYEUc(XN+DAL>er=4Kf+F$t< zJQ6K)JIf$A2SFjK(^U(UYe-OtN2w;cyPaYo`$Md**pdK(-plol+7NZi+mdA8n%j@( zfEkE2*T+XROut~Vm8RVBvf)ilPId9vYJa>Vwv7cuUN&hTBTR zOu@@J9bQpy*xWFwz~KM7$G{K&LV;0ELkB%!esvbTudz_tJwhhrHxv-q#R9<WwH@I`QG~gPyK78K1Q`}4MbLae)*LnTi zIUR0vL&KpHtfhaVRyVq(yRE;nY}|Wjk2Mo_oo}@6Yu$BQ>2=nh@Ne$jygWdA){+^l z5X|P~DGbGIUNYl(O>}XTge`UJO0TV%mOeRw^qEjvj&yxOZ`!`Cv`+08_D;4n5BxoQ z-}c7j^G^8Q`>(}$;sv`u?kEB0n=ZG*4;7th5dhbf92~M}Bv&lE6GHj0&{3f-p#bja z+QJ(qgGs=eJOyh0;dT`+m@5=nmmdCY)kw?W)$!L$@VOI;Fb&CG5c^7oM2ZElugSCF zVu^07$#5~0i|X|3+jy4ULoRVIwvun6J_bE}KZnA;D4h@rvl3mD4%nCkoX=%rtcNJA zj8FXwOo_V$w|vHTJI|&BbRZHam0!->JC_u=QwD>xL(Rg;ir*s{uTtlX>49?w0m7tz z{utZyh26!zp&MTnw97yjlrd!m!rGq!7j%&2)#>D|I!K^cEc&9vr3*a+dX=6lfCbPU zR^ka6ZBBpHKg5b_e?QTU^|B-bx5SDDaFa4Xt;tH>0TBi>R6p4)uMj_F`>_CE;S<>a ziw)bUU_Ce4@Nr$weI#J^dHsZ8nK`e*!lKpb&ps1yu-MRba>4h3zl zgKn<>|H`I>KYhrJPt=japK`gA+snviKN!k$SL?|FxRYo(b}KtJUzIC_y)b;K@}*Qr zW)#mmI1pJ^@PhJH_H@~EAvl&>>yXdbB58Gqdleg*1Gp2uR5;eG#>)+RTG-2; zcFQVB*i)!V*pt9%bUu%{?8(C{8|>q$Oz-E*^gxDK$rkiykpSyt`QcN;s2*Jns7$~1 zr-~@vmq}Cmu=wZ9=7qKut8WEkeJr_Ky5wW^GM)oED9J;&m)kSMel@-yGg9blMg{&h zbyXp=A<$G+R^vj4cm0|{6 z-r|-)Xj=WHWM9RTdrEveYr)j&^u=}A?|3QQNk0Rf=Gyr>eu5Dtcl)FEYY%malyoA+ zV@NKkrwtUO_i)Z;DzDr-H0g=$7y{iORYTwoO z>hxK?16bMOT_T^2z7n)A0y1c$#A}z$2(u4jSVN9d*gauV2t&z6CIwt66lb#y;%8r}ccR2jUq&pOE30b&BSGzNNkSWC+rq4bm5X2&3qNz^%mF zh+fkR#}Y4;GcU@zn}I@rvVY*&XT+lRa>^~=H^Ba#{)1OAw|rr4^U(r$9WhcQF|vw# zZs~<}MXL~S>s$HC+1fFw!$9F|LqPU0*Ex^S_3kIIIzi=Nb^IoDWh-&HVY<$h_x0o$ z&9*Qc(DXhWt$j2GP1}?nxuOgbs7}Xozj+s<#VUSRbbE4zPj-D2M~#rNl+xu9R&q3u z1cb!w=;Oj@gFu>RHfR?KY=+)48%V3}5$G-_U%}z4X_;5&Oxr!V><6KW4p&eEizYSx6^dXG!0; zhi-JRVR^~x7+Ve>Ir`&lG01d=z|ZFo&q_ah{xI5mD~pG+J+Pa%0H|BZ=d)AYK=y%p zKjR93S|W4xpwv)@|AZpOl0NO;q@D8lgQ0&wMnoIs+de~3Scl!4Ex+aDAE`FztsKq< zQ^w#+WIEkgaC&$At)ubw(Lt8SeTKImmd8nS)HL{d30DlU*V!E#>itm|lI&Noap}wR z_rUMff(4-Hn z(Slo-h6&@11GW8CpNPebuVaErv!juP_}S2kUyB^B2x`d~3C4)D78#*BZ zc%5v4GI;BX5A4nC-qWu)0j#c6Q=Nm41NXM$!u^>|LCe7XFb2UUfB9yz34?|zo z*@mq|T#S{uSScL9laMuxW1TFyMxy7yrDW--%PwyTur>9q%da}l_nF!6Kv-6x)#=wa z215nNUK=#+(`{Im4x;!k`k{8-X7_}zfqeD(JkT!kGE%LfE5Xar)#;OO%BfZKs6vW* zf55QUo6ofW{XXq)3EB_HNj4Ay{xH&O7h`JlK3&4)>zChp=g~NTEd&u|btLAQ<#+N; zH5EYGc9V8rtS=R`AKK`hDoX?8k6)rtN<2kcP@>_-TB1`fhN!7dU&xieS?S_!(TtK_ z)|;N#AqMD;`QCfxtAOD4w%lSI_E*_E(tDMsV043XMpxpc8HxIJ$!3jQ@V)#upum7< z><{El&cr=}51=^;wAGjtx&VV8_450E6G|~>UHjR*P@3B6uB8I1kvbOqRKzzob)>>~h`KKN z`=Lzi8Q&m?dU-Cbi(zh^Hoo@S(sOTcSd&xw_8Y7fvUFqB+Y%C6g14P12uz8_BIJC# zKqkX3{JBqKPHjPBk@vgajBty_Aq;j%JlquW{(}#?BJ&3Fehw$5Zcju*XJ>X z!Xf*U;7OR{^vU<&fMl{I_k#GZ=DYoBxSUhLNHlr90<5;?|r9Q*hizI|MN)7^&;X2Y^4 zenVYlAF@Jr#}hRFq#?ROW^J6Z62Iq@wRVt3a0h&*q1MCsPPl0rK57?+ekCpYZZP<3 zyBCL}?nG*dJo_>6hWvsUGsZRHnA6ARF8xrOyLRZTBL_3r*d3f$_W9N)?C7kfIFej2 zJ3LDukbZEu-_2i1ba_16p-0h2jIn)HP+WXa*6}IRxxv6s?CtS=#Z2i4Hc8eNVM9cn z)B!qUx;`}E}Qy1|tjW9Q(=X06SSw}v^=;yG9;VxPA=M$-6LYF}V+2myOskw{fp z%E-CH*e`|O8Y>fr#03p!4wx?{v=MwLvd_aJu&G#=nY8#Y|9;QA=GR1lhZ%1XWlEh9 zW|-A^{zxBXC~hR|)Q4@9e+H>LBB^kxjFDHC^o;c{I?iOqttqIRZw48wOvS!wr#lO= zKYot!4XWJ5`0!#Xh_|t~5PL^FKw?AfwvktshH;`BTU@%}6i&4bIgj8Jpd|wDk1Ud zU$W&_(p2o{@vWK8HHwIel-!FT*x32Y-rb*>P11i?I4;INSm{vtmo8Wh>tL@;GMf1- z1Rf>ug;J+>x^q#Xb9GVKM#zw(8sBg(DjIuH@!Y}gq_BNykzEe+-BhSB(|JSwl%kfE z_=(=j-#@H$;{5z_#xFE|`$~E>jiWSEhH}VM1n{AcZy7;D?kEv{d1a7Y*qK^5%?+Q8 zr^&5P;|N(hoqT1pi#it>;#!u~m;Lwwu;roF`qOb+u|MF*>b&5vdt2D&WA0BvHb=ML zC~I|pI*fz9Wk=-bFD*@p@>ZLkaJd4rGQ~c)6~BXiU~ji$Z^S!8PPu#O5qr*&SS4b$ zGBx+>a%kz&9(zuY6MMs2Kdj;K!n*SkyXTKd?B>$z$QvPhtGHK}Q`8i!+gh2L^NyTQ z+bn>RK4tA8lCvo8g)39`sdHb>eVg+}=Qi+t#vArlYyCAD@Ug@Dl5icPkOlES>^I>s zaFrLz4#)SMhts5qppa2aQ+(FHcK9 z`)J_96xnINWF^FK=Uy}{71_z$<(bQEt_5nZcLBJmwbRn4Ty`XrYI}%Y(Q|5*1JBi* z4cU&t9v4Qb}=Qxw!up&4B43s+j za`QNSw-f5A5~%eU?&8~rOjoy~?9m`%W2003GS|-t&wU;S~{KzMQf%_Nk?iZ zf5ni{M#e+j`A$=Td(jD(`)WbZfl+EIQ1QrW5UZrDAL8nOd7XyJH$K>nu7dak}jf=Sf_p zn)Ls24~#?SHhmVY_ndkAx|FdFaaXSss~3421;ic@$%^RrLX1Y8DJ$wFOGv%6{>ThkFf%+gz= zu4m`L1ZrC+*Gml@e@OZ51tM;&#K)Agmha&21+wF9B_7vDN^?p~9{WqSs&XPj9YtglnCXQ3Ey3~20oIL?;xVCi z`+&*=iHAYx@E2Or{aQNniJ%dGovUaPGJzc}(EDEAZu8$x;LU_$lW&B0<=cG!TmME4 z2!$w=RLs|u??~$lrYm&6i4vwG-H((GuQB-}(pbk6w4>3*R+Mop&R%F5GpgvLw-h-O z1ut+Y64ZAES6#g%7T7l~CJhzSRtk0|D#maFM>f-9$t36dZB9~1m5zU*xIE)NKDo`0 z8h43Uj>aS#zym{4){?bCKtfbA{wE-+27O#gX~;Tr9V}~dutd1ZEnaMQ8U5DA%P1UgE3Dic`$(I?b4OqimY7jB zwV5@-PBSPlY(^XfA3-;P+q)p#qWU71SX_ee_Luxvx+AOQhU}${xPOE=oTFocGP(SV zlVu-pJXp9R5etZrv5hj$y;8YT3x5hb6NfmCXclE1;#h>6-;|+F?U0dt+*E{0C^v8K zgPn*}-bGF`S<9(TxbFk96Ob~_p z!*Ds5)>R6*%_8?Id;A%zvdoM{0&NTp(^0yMr=h#6ttD6V#k&jpT>b#wo#E7$I`<06 zg<9R>sc!L|S$u1aePkG-e^N4^9ehlg&ZOeXtycV_lj+^nVS73OCC;L!!iKurShq=} z@5J+Z@6}I-2d2;FQ_1a{@W1TmW+S`1t%`6*r&F(TUcaG_hiO9^w_-ofK|$I1k!Hjr z__dO{QGE&x9^PB%B%XspqbVc>7Rqk@5I%HI#67=n*{|l5{ZdZZOH5hk+v;A0i6_t1 zE8LXtt`qNscxSFlLaVqWxayMdoZT`D%-8|&*L%I(CVBEGwrVV&emoQ`b(LM<==og;SMDYfanwSh4v_7~?~!6YABSi+qO z;$`%vrS$118#M9B-AX*F#uZ3DV>qGrUnB(htRkkD98CmauYk&Zd84;=5i(XJhqabq zQRZ5hwGDem;EbVnu@gpIga(mdf+R%M(hpox2L?}>3?M;QAf^h|s#=E1>e$9cM z@vSAjA*c~ZjR;hgN!}00nd&d(_y2f%8~CV-tMPv~Ss*~*Mu>@J-`1rSv-~5)^w=4F? z513`^dYa1}^iAt6I0Pz~v5XQq%|Q$$sFPP-P8&Fd!t(EAgtITAe+J*l)T?gjI7wXk z0dg%!v?5O}D7AUF(Sw7$R}Z%%i$Y13uz4FI zD9d1MX64T1g@C(3_uHUC3&p3)g-;X0@eNu?K?N%&Taeg@A2nvG3S@7$5<>{oC^piR zB}3OV{8mP`8gGK^R(X3=7?ZU4b-ZPU7Z>g%H{XO^VCDrg3NxVYUj9f6_hhti7tL_; zqv<9kMu+T{hnrG^?BydsX)hloe;<`9CypY1?W6KFu|mF7(-3cEUvf>d;%EWS&5?8RV^=z@?SMjw|)3*)CX!=XM99h%FUzJdpbt!f$ z7xTTLF6NV7NGunEl`nsczh+TN^%Wr?+VQlnf-(VX;x5gtaB93nMw+6sw$`|&tce}Y zWJfk0k2Dc+gUesnz5p-6=!3+HlU>q6s^03(h2E-vnFVn0x_-6lC@YpLlu$r2B3^^T zG8oy44UuHC7~S(3P$7gNH_nIc41 z2%}dQ*oqj5>OxHwJ-4)?4@s)h3Z^u%RjLd0UPUVwpyZLtIJTn0g)zs3Y{E%uOF+wj zw-`{~0FG^vkv^^CzA%@-%HCjvKE_LstyUi0hW-6Ltf;K*qHW+q{t zJxsl{q{?XjpP-ndZp8K5|GD3OJ0Mz9PGu|m!Ot%mZFrRC#ugw@GE$i%Uwi;d{^W5WA@iOMbTS4&IM`!XZ za^zy@=Dpq4UnU<_a$)s3Y|z&9@aZ4lqil+(75_fkOIGC?F*dE0(+gNce3vCtI=Jl3 zx#D){s4eQKElxJ+i`4B_>9ptJKwJ%69K;kuGZJJAq9LW?i@=Ne=ggc{ zrrb`P51_gd*YF^}&TxW#`BV3$=gBm^72lVr1xe6TWph%lRr6V!;x|1WX ztdbnR07m2^7ogq)T2G`deH*&_qK%6fPXR7Coultc1pG~UMP0%S-o#=h9c!kf1>*&v zdQR*!7Ld52OlX2Cr6s!7D)&xujl=Ys|#D1n*Mtf>HOBXgpbZg;{EnAF*>6B<>Db0cEHwkD3~)OWbZ4teIxqw=Yba zad%RpHwTRUNxWT|M(U*^u4bya<4aa_G;dCIXboM!8L5J{+>?2b%o5ji1DxmngFi;z zW*mW8G(1spnmsNoS7F>)LNDcwsThff^K7)Chsju`+p+Y~2IFg=%m|2*6o9wXA zY=!kQlNDjNJ9O1@knmF&VrxayDeWnoq4g#~r}V|^^yDd^@cD|Kdl_Y-^3#3pNIBl7 zW=Kac^Z3Wbnmw3#Y=XQ#dxWWhUjj1^*;->}9?D?{ThRX)+(ejo_0OyoX+CBRSdGxc zl$qj(Spsh)CKrsHjQ8>fJUdvdV+@1IFho$?28+1UDO$Jx$^v^JAua5gA@^4H3Wxxj zfiSk#43BcYPU-cg7Qn+G>HDEY2$Zi}|}vSKfQIoi%{I+@l)+u7AuDZ*Gy1|-0X z{ffTc&hTm37I6lAnkf7+OD6qmcWE8tYnEeCq1qJW2GobaSif3asLUkp45)eBXNrgr(H=jGGXs(oep7*;LQ(fz>MWBvw+sV8J(RM2)pQ%@RMqI|tne36IeHq|@2P&> zt@6zc3-{sA^R4*}SP5Cu=oAr8#+pBt=fhg_Pe`k==A*wCK}&!nW0|NmJKw0kn-Yyt zAGs~7km2xHqN)(7M`Rbp%~rISZ;U$;^vFLY`i6nPid{fqBMs0q|vF)5tUwfmr6iS=e3H_24pCs+p`e!~$JfXA%QpU_NmWUSOM77u?9EVN!-uxbwFF=%AvZJ%dvmw)SbjRx^{~kq^NGnnJ7og!}A&4`bX(j<3~P&Zq@!$VyF>d$=LhcM+f~qIincA1rJOI)0<`u?cPwb= zL2aPXk6H=Po5{Q1&ge^bt*8m*z!2tVgD-Cx%zs}7mF~`9{$gSNAqx6h{z~2}#I(!I zYiH!Wvvb}Pfc8~tg%T-YGZ&N51bW1@mfh@yY=4TYSyzwM8mh}>&r$W>7vs^Vl z>v7omnM_69Su*mk3?qCzRHjNAqZMmK7?@gl<@&|wbsC>9{^=hf#F|JDuKW$Agzsif z3B@{a$6y9!sK_eVoEkhEP_xh@YXihJ`+MywRnCLV^diTKcd5|_}|DWb4fWr>397rFothUrTbfCRadGw z!-H@?N?rH2*}4I3A2Cd$?MOHOov*E40%gs-i)u;rPRy*{Z>Vz@)syb*Y$@n(UN^eC z`mU=$${|(I-~1|kPpW{w)Nq)`#qQbS68HQ! zKj0-X?*BOcRN%a{QRzDb(%p5q0WEXDY0(fqH(Pm(iO5N_-QURUOS#^K3sO(&XK7pN zSBF@&f7*^jGgfW3E&B#&JZrb!@I~1Mze9x@pbWSTV)$UfD8JVfe{SAmwCFW~5;KJJ zrymn{%U8(vqMdz(%q7t_nkRTMrtR7hn@{Ya~8}(Yc73WR(g`GH7RH zpxr2FZvw5B_X2i?0UMSEi(LdnVvu{D99ES1>C<{IgWclpV0a$6(>Fs$=ZYz%ZgIy= z5U-H=fjAl5!ngSD&piK2+BQ7uJ|t$48X&6}y@55WU~{`!B9~ukCT#9UOlA^~R*6`V z?SUd+s*^7j{j1}0VpYnL-(}qKdErB98eprtY4r$oe?U#r1G(5;1G5PsydgbgM7md> zKuoybf@nUy3_lgS&yy`v79UR8`U>O{qV=Sux_g0oy_PCdPn3`3?W_s?y!{RX+*xP& zz#qVY(wJg*ChF+$TI0~tjIbam8x_&kmKCd~kBpFaZ$!c{Z@1RcHwPemy2>eha9-)1 z$&p>l)WcMa8PrcGBiVdTn#i{x8Qi~NP%rBmRkj)9UdV8@p1HDM4ji-v#id2I1b)d7 z*?o`Se@KG5&-L@;yoB^Rk4pGE2}dUB3}FtjpWTy?=l@3(i{PyPBZ}o>d>WD6WmOkS zIcipac)EMj1^2B?GiNt*o%FcQ>~ar2?Z!*vbx%dl>t1>%yO-u3>vcw7U*oFIxReCu z)u#GN`ye{f?m%}ZvdAcito`7NcSc|rn=I1*`4&7l@SPo8IOIT%HocDUtg) z+oHZF(r8@1%)kDJk1~FO)yY5lupG`&F`5!*?UlITAz zJieHwcuDM!8zVIiWS;OiH5lpP2`zva%^m%lBv7PHRg1MXW@prh*q$kdoBUT*0)iK@Amc5lnT4PzB9#0Kqi-F?1 z#F&s%wSx`&)N9qO`6uK>_g}uSueI`S*$tK;GCV)d#mTn#Isl3lMIPgc2WazmX$=3h z#a}ny%7~}TzJDL$PyW*r{?pU`Q=|X1%71#nJlW1Rp4#I7Ht!uf5~{)uJ2eTvrn*m8 z+iaFxdKxO7d+Md)${WriBY7D)>@zwfit+B0kYeIEF@3;`Mw<0VXe>hRK z3F4_X%WB9|RNC*03uRg-0cHuREsx$h0neTlEW3WRh&mtM#TA%O-8iSKhhVz-KT>@x zq%YtK4)vl)&(T5^!PdWh>hkeR{_S{c;L@GdvUPyP>xpl9N$DjY4p zcd4vSI|3h6MJ3dLjViIp_C&MOx#m69G(G%8d7i>8f-~&ZB7>8cEd+%UiBw!mCB#%i zpCsl_Uh3WiS|3Rz3Rb#{B{E?KKOi%bcHPID)S?t2Uavx8!0Bb`f1<;R%{U5)QR>* z)Jv{gPqDw)y6-OlOeM-(buwgH#VETI6uJj>qs}Hv=BQ(l|0q5M6_JVO6QDM_TZXEE z$V~@clT3pyk+v(*o2$O01+V*4W>#|TdUbMYX}T$I$$aZ`e5HOA?Zt#tCZ0$0Vu`5G&O$TT=;(pCnxK|TB4J9ap$ha;CTyHPa(d-rF*(`t^L z_K#B%H-sgWz0evT4H(v!Kqr*p6x`5rpB*2e-i2d(ZX}baJUc#$kGS_=5Df2zns(&& zZ05C**XVn%DmY;^F3spkJdEWchMV5yVAusc*EhY_qvxi0M?<_q;T3Jkl}z$1)RlcJ zZc$m#vCl$p!PInX_e)yPCqAITDp9Eq2{cMBHNdb5`jnjzP&rlb(nNd$}4iqQ;cKi$MFyB_%u3iKe15sIMoouCaL20YW-GM*r>x{&8w90Tmo3c!# zvc^>YdJ}U=W^U=c|0wsw%-o*U*QOZaKf)8p#N!d%Z$rEzGKO7R7__0UF=v%zbmt(b z=w#htGM{sIh{tTTFh0HXV^Il5j!opKk4?JY{UO+naCrUyGp_WgVkACB3mKKs^&uH* zGO`nDrj#+%zDpAhH`Hd>@d7o}^TrY)}bU@@*iB+!-j+CYBjLzwn*PZd>6^0#Mbxm1`4~Gwy?i}U34TdP+sIE zv0U(S>B8pZnnn?z?jQN;D7l#I-s@i-=fB<2G00Y;%UZfb4Z+vRaef=Kr@O`zWw)MA zBcKBfUr;QrS7nt>O)k5|>}%3ysui`41I%Y3c$Fd!zAdaHWcI*HXJTLw%IsX zEkP#Ox{_~}&F&6D+o@Ag5628ntNFEz)lB>Ik0J?_+UHz{C@y0ivdBh7>WvK^`!+9C zs_Og0e${UkTnDukG{mbmHX>D4p~6)ib;Z$RZoM$?*Ab~gZuHV6ElZcwlajLMO3%R8 zicHLvDDUTpwKRz`=#wbW){hs%Ew8F-s_Rl`;+4v=z@sG2O#DMWxQ|Kw(1mg&nEHx3 z97-wDzawP|s%XJ3>@#Feq1t9ISFxAm2=>3wXH%vS@Z+9by*aN{El{!vJ4Dr-Q7eSG z7k9{@vzD~NF7)G!b1Wna*3(Fv`6Djjz3ANFCR?xpOr1T z9lGM*V{~PdRoX5Uzf?+5W|TJ#jWwYM=(MTHlGjuRxqlM%FoCV~GPoQCC4b; zDzL*v&&k4qYdyH*>)yZYWTGB9+>nL*?O-?DKd5pP-&XAJR6W{}$3_5! zRnOkp5KX}L6=GN<3LijN98hW#5t&7|eYcZY^uHAKHD*z^HB`!as~HUmM`&X+>0(}r^}>WCv-N5&s_yUB z{rhP`eertu1NT@&!rn)v-f3=1&oA6#p_JAK#P$0p`|3sJP+hFb*xO`Hs2O8)M3`%} z)$6~(B#E0@Zlp7-k{9Yo?P@!l7F!|f{^78+C(AS|$t2o6lh1Q^BH!kULecBCYT>Wu z%YE>ScrF8r-cC#Tw0tl3_Y7%IB^q2p^l7>7&VVU04yH_02UC=FEN4@koz$7|K@T>M zs>8a@Ypx{#z7@w!22F%DK@@O{c%?y}ZF}u{PpK*gsAu8+h21^5%Y_J9?zkhNigpYV z5<))b-~zGYOR29LqgtNRaHy2gD)nSXNe8jYE|d>S6J8wdAyyt7y)xn+Edy`$Dxo#e<)MIQV=4FQ z{GRICr%7!%9tJ{ZpjHYthj*)F|BP2f5S!Es1$;LN#5m22)hT{8^2^46IYNiU)|Ao()ff0C4 zZI2s6u8f8~go>594je5**Bi{Tfh((Fa%GyB`SaN{sD^Pa9pbJAw?d|ju;k_KG?~?k zL(Q+h$kfQ=^1bBh4@XSN`ON2IuEz90powACN7ok65xDJH@RB@@bVQ)osK0N-st&= zC^P122P9O%c1FQ}C$II4`aCD|yWBsj<73*d60h$K&Y13uEe^0TqbfNO^#BDW@>l#0 z(T%b26O>3;kwW{C@NB*i98(hHw=h)y`va?a4iMe)MnG@T=~u|7wpjRae(Et+?O6B) z0g8oXB|zX7BgWX98Vj%EL!xpN`KQgOnVQ`27A=AsK9UHm?~~^5!EnZg3#yWr-KusY zByvv))U$o#?CgygCmkC5Rd2({`Bm07jA`K;C6eTP?tWtf1_%4)=3Bk~RZ}JFUR0sH zRgFz9>e9O}BBk+4NEugFN%6wIo#p~{%F2dh_CCCcu-Zni!oI3f7+3b=fQacVEY6EyUlP zQL{!kvO2+CUcDvAnmde3vpMdWZ`*rIw+1%^Hl8vO>!1a%QI4ruq=feK+ z4U2Xz-bY}c{JUONFsZj@+3O{Ut$$uLGkzzxD>(~;_20?w(N-B2lx>v-#q_Vlh_+T% z_KEJ;-B8(w-Izhbs;MHZC1LD3wSO~NJgRiz5Mp`be`-9JO%i(ldHscb@>DuUS`?b@ zgqPj2r!v2o=z1D`TV=5>jF|y*u9e+K;ivjHT#6(vLptK0lDJQ8l|>3HSN_(2>kKQF z$JhGr^!c)E19fg!!DHvx7xq==mBKV2QMgRJ3N5_B71i|2X;sOGAJ_bg@dftd;%RDu+oS$h&HG8K{7}W7f7+o<^PUmz`@Zor7nOcFrB)x0AMrv~UZ_ zC+)4jFu&OCAuk>s@+;iEqHz58diP&h?|JUltoH)9E&Wb#)ncb6NC;lKqI)!X(Wo=5 zrLRH&P4S84C*`SqGEic_Gd{;X-PA*c9V8sG5anF?Ry}O0Q(ZEZ?OH0z8f~mR&1(2x zFhy?<bSK)whLhTo-{~bocyL%a(#s4_2=Qpyp3WtTTBSL&yu>#xl8T~q>bZ)-b`aLRiO$h zOssuSc?E6aGqO^~NB0AA2|IhV;i`JrN22|E`S0ghT(K1OhWi%*r(LQ(KbI9ZRA#PS z84?1!Katdx0!sgd>hB8PSbLmPlfz387IC*pvfqE*gw8J-e8A4-ASy)xoFgf}BZd7~ zl_gTNfBs5{Y{gsYSQRH&t}O_**%yZOmF4XJs^s2AP8)1BA_?56Mpq#8KQOGpwr*8Cv#7xpu4kjrYkHdrg^Z#ihDy1x%Sn(O{e zUWJdp%W^Pu=xOLcxWikE@UhuvgEdvJ+WmM=Bwq@H_%4A^<=&XeJ~^`IsItU;gb!)b z6=f7_NSFG97lc{jtq)9`#Q{9$l1*#CUzaLU{Cjx$A4-gLW^5ASKLFwXi4p!=wD8{n zKiC6RP+6OQgP1YpLv0K|+Sk z^W>7R2SSPN&j||??X=v^V?iiC4j za-}9OF+L>yFTjbT<#JcMGSAajTOxB+{QbIbCyp*5Nd=XROmixSRXLRzqOEG6+P^J;scB;)^0TjroAYH!r?o|sFAllPTc&v1dFrx5p}5aW=iBfNa>NED)y zpMpcSCI;N8GSqx~L+K~g3b&jDxgRn^e_S;cnlm@(LVtY1z-Qbk{Sg)YF_U72gJ4K^ zfs(gEp1VRSqPTHX{eX6fNRV%bs*e(eqR> z^o8v8fvncbY64ZF07g^GJ$1e z-l#0b3~8vOl}2yeB}zf0uZ#2*s(X6lb`pI3>gkK&p1v5L=iHPhy1=N1D})ygryfKv z33VWs+ed0oBuh^{5Z?YYrRKurJ*>(eb`Q1*yWMCN=53Bslh3sS?mVx4lQOgetz{>8 zrCb|gUkcLHVngTXdl?GiXSA{mqgWI~vt3={$`-J$6ojG?(cKZcE=NK#E^8K@p{|dZ z4asgvTs0#8=Av_vJ_!{Yf$3r1R3alxR1#p(iO`|ol)x^D^jyqM1LL^{b9nsCy55>E zpO=qJW~!4vecDX^BeQ}nh!Elt{rXDvNm($_b+a+^e0?Ii08C+fz4gR44j|dv7QZJK zqf!zZc{ZKi0CNz7cHyAKeHDk=9zE90_9js+ijP|GRf*f+y2Qwi1tXI0&sLHl-guoo zvbMz)T1s=5$!!^8yA>qHL*&TJL``vN^PcX^P$J#AqfKtPEs9g7Zp$lAd2JcwwdHxX zi$M|7me8!Lv|Srr7c%uR?{cW?=faKSW#*ZBNGs@NIvzZ?32<&AQCk@2An)}Ih{VPD z5&`BadF*Si*E8YoBx*R4a00_GF!J)eNVuz+aQly$3D-;{OZI_unas(;CeYWpiS|#e2upaqhIstdCJVAG^1Q-)y z!ULKy#7=*TUT+&Cy>_@`8NKPOG^v*W?TT11B@@Zvn=?x6UD%E~!gNk(DDkd6MABY+U%KT&V0*n3 zmHLt33EVYU?n@lyTuo){ZIYlI=xyVLi8|bOr4tTBK43&}Wy;u^WbA6ywW-%kzm_$+ z69D9Vbm6=JAg6Wymz)oZ=(^Kz0%iU`ea70EqfW{bu~$URhtomBkhdeE`->wdM)wa} zJCW2#A&Sy+E(&)nYbbz`3AVo1{#V(a=mD#)Z)&*oQ#4h;+g&9PA`us3eO|$g>3Y2= z*h-wJ$lH*@-lb>oz{lUb>ti3bIs?>)(zW#X=f?0Tsx=HA8jkWDfm*1Dewm}^1sKKL zx&Rw3ni3g;k2g_)u8*7${gSnVA5s;$UkC=MP7cztnaufS&opSU_l9H3jo_A^VL(W!})r(8Hyz$8PmeKR8YGhoDaV67i|V?Q_z1 zW*mXjQ%F~~XiQe@8q$-cr|(aX$87nZpSZKY^Lvg|e$PH4H|&ewA2~TMa!OYMzXvg# zf#zZpd$N-Fw7#QuU`K5s>OA=y#R$dP#mT*fTN%~WUpuOA1*gcRUG{#}i6(o~5oJDy z%t|EOdCtBp17lhB;+;>^qBeZN`~ zy~ppP;P)?<5$`=2`v1u97abA5dr*eo?GKotqx=6uZ+GGSS>A4?i|6H{#2%InWGk^H z2XhGm(`r$C4>s@JuKO=yIoGw@n`T{grHK!exNu_hdVI;rw$X=Zs8TsN7))MIQGPBo zL$1*bU(Z9|B&TA71;afy$l~|^u+7EyWwsf_utreWqdLjTSx2Hb4Ho|1^I|Y^fjENp zZrZyA4c~K9WVVtQcO8rQQ#;aY^O^45u#C~Gm8T7@468A&^eKRmYW8e;I8ghbInn-% z*n0;Cl^>|RNvx-|e^TIYZEF^zQw{s;61})6?9J=ia>O0y!6IKSoS1=Ck^Zr+N&m6K z5<*PmZRTRMD!{#iq7*)bB$j&iKkAwX!K}LG%`?5O5r$k=&30HU{wufayeu!pu) zhQviiCCVC8uONrDa>njE`Ek;lR08_qDbYP#KR0#86hwGYa-2CpCF0vjj7&Y@=}4#B z>|dXdx3^n_ThS;g6bU=sZh2k4{DLn9e5&oYx7#g}iftb0?sN-0enMW0Z(r5WaJj8F zAI-qhQ)*PI&$7(_?kODBP(UQy%kP;sEZ9&L&_|%{hd-C)L_0)@}*VR*Rp7yJ!e4dI2OO8G~jaN^7dAgA&K^Oax z`egCR=4pn#wT5Gk7$N_(f}c6x=Xci}>yySgR==Ketp2^`Sds2LPs-zEGJm!tE@nV5_sBgG1z$&$WcP&a47XQLZOO@)|x-=CR9e?8ZE_YAs7C#Ipl;L!81Pof6=lE_o(WJ(CeYmm=r{#*tpF7X(7H^ZD-Dp` zFJ_foBtT&SYRUu}VSqL%plJe>FF;v!>TiI4r+~Vs)5r9J^u`haqB{0^hcct@HkPh0 zZFa86y+t<6cUUDyStXYhTP5#VCD#{NC7)R(w+)+PZT~C(-r?VNXKDq-Z*wN`v$Z9f zs<4*CU{_|T{jAb!8m-cKo2=6LJFL`Fc9%p$LDwG`c(qIrMOnFRxF1@@Z8xDeKg ze_E(gTK$xHn@q}9QUoFS+Ds}rToo|7WD@nAVv(fCVU=uGUG$i$j};#r6r|@_n}b%# zOIB$=UF^Y2Uk9i)VI>fdIS@OqxLlew?_ zNj3G!0&*bB00mVypCW_^2OUnOerk4Ki?Z_#NGYhcP|YFg^mV zgs|--PpRHPXxLYpsQS-P@7fbJXZiHb@#%eHHaR?cpJ{UV^v==Ub7GhD4wxK1y}caS z1t@yIeuA!#Pj7*BCY_i`@7;#pszK13l4134pP}jft*@dtaTgT5b28}t5M3-Ex952D zh6Z0j?|zdInL_mble@1$Fa_LC5Jrd6`%CEEr!&37rhPuWbA5WBkWCJc-n)x5MSOba zYI>j0CA}L>4xip$j_d*yy&p8NKD`CjnRG%Xy+1SbRt0Ojf4v*eX znjAj8Lz>=2UDCVW9`WhhUDNltF6kREIehwhIkF4T^4XXxK79q&nRHwxefJpp zss=${N*4N_s_A>)SJAh-p>OvL`rgivQS|NZ(H9zg1$~utw&!asg-v^W`u6bYdu(>|J^Jo8wwO=f9-6+#c1hnxlf$R4mm|9XEsqVXPhWv`CLNne z-@S&uszK0~l7+sdn!e>PyzP)_<4#;l4N8d9|4xhfgG<^qjN#B6U;nUa4 zkzIh6znJz?AD_Mg>r5JuN#Fg3zN$gcmy(6P-_Z0u=d0-3%g~oYPCoxGMkFcv_VVZp z4Z5T+Q=I-|4z6K-A8@zwH%;Hqp)ax{o4yiSDvQ3oefl1q-F%O}yP5Dy4xhfgHGPln zlD>^5hfiNGM|J^P{u)@Hz5?q^Iy#fS2Mm2xgP<=Z3w=+~^ga8l=-b=Sw|548>kvtb zzP&yALW3^p%e=Awm@n6ex71z8-!y&y4ShqM>HGdso#>nI)3-3Y`5t|rG&y|w=4<*E zc1hoQlf$R4mm|9XEq@K{1Jqv{{hGi!lL|BG`-P#eY7q3LWT9_Z(|7n+(U(27g7qKy zne;^@Df;Gn^o0h8rEj9lK64E&s(^a}f3?Hg#BW4CP=_hGo$31+Q;{tG?c>w8e|Gad z`p!2weERm$^zGjzeJe~3pT1s>>;km>HLyN?1=g9=Ka;*+8v3dRL0?Md@!KbB`kwVw z^zCEl+b4s*w;{e1efxOyg$9SG@Ao_G`5kLyqpmCWe~H6BP2b(nmsxeTe7M%?MBlzX zefwoM-=puDCWlYozM8(ckh<^(1xyZ~zFv;(0<`>P!k;C71=g8_KPK%DI%w#t8U%eQ zS?GI`rY|1AuKhu5s#pBmH-o;nA|e%i`+D?+23^qipgsSf4&git2U<3LKZU-yi?Zn( zHtq54U(2WOQQ6J+=)0Q+%ChnKAQ%V@^>5y9xTj;m*> zeOQm!=`0nqa1eCxUR#I;uF1 z2et0>nRRpUGpmj^TJ)nc8E6;n|$IDd~Ru-nn2kI(^ zAfgA@a&-$2?(fK#F+S81&tp_fk?<}B$_hj+4~mwLs4px<{78MFO3$e;tV#S?eW6Z| zt2(hbA^X=9!6YVc^Z=_As}&5jdS88Ex#CUrg=*zMRJMp%v3-1TpElK!5w@OZum3%M zqn-=DL&F!Ip$PU@MM?;@Q$0YST*kd-wh*l4&mW>fnqx?d9)Kj@QV)>gIv&!jl_$*j z^fy2SSpLG1(F2fxJA`hkoO zlk%d%eg*05FAS0V_XHbqoSbMX=uCz|eg=(vR#N;nClQ<@BPtk8a3(VaZ_9$t!Y@R+M~}}28J~I4R8MCz z(;nf!bP4|WR75o$LY>IbGn(qaVBF5NED28ofH>%@M%}MGp0{8)z_JfYE#E|eCd}3ubg9;xRa?< z-)PEmCL^kUekgvQQB8j|9F@&~b8PvLwl8>Zn39uTpI6Bl{3^+zjPYV0HOH0@9=+_N z>?ye!=~OXD0U7k~A8eSy1^{1P_lH5%2h+a(L3>J%taP2MyIt_{Z*(^)l4^VJ-8;R5 zAuC;NIgn<~k~`L7A1D!25ZNK}EH;Bh!Mb84CiCU7EP5cvx_2`$$RGK8zlKL--AMW! z--sUQYu)>OSxSuEE*Wf*7WeK@86=dDb^pKlE7IWJ-U{ky{9AmdgxTJHCZ? zum1Qv3ha&1_pH**!Pg|cVm^N1I@(${nw7k|(Z%v-7@C))TR(`l6yGt}Pj@C23&MK` zDTH;bhZVR3ct#jn_x8&8806Uy-ta@V{J5HQ&7gFE?vKv$V^k){f8&M zh5RYZz?nI|WGV9S^5;E{2zagZ^--7d=jjaSPWUtRjc>2Sx`wBWNr#nJRhfCb@h3~E znM->a@~XIN_`}MpU2H4!7|rmlRi?Xx9apX{-{YmUZ=O| zbicge1i;hsNz*Icezo*0B_9Qddl6_d^`GXqO!}&&Q-Ob%lH8&$;M4u5mi`3(&jPX9M86+dM!T?uSlU>kwe>8iHg(u<^DC+WZN)3cTiBz>Hu*Zb+JHlFKS(od1}*(M#C zr(L&_(pyr-lVaqJj1Nf{$D^dD2*TigBQxD|O=5s6hz$Y}5(uRa`i(ZOHF5n2hTll~ z`xGPTzUx9#?w6E}lH%*9M0)Bi5Z@Ds$AR$lTjKlv)KStemh^_Kbbsn2>8DHjT+(G$ z*fQ)c7J=111-f`Atv67wUg1>UM?RvCOef--tj21~pBMt^R~_*|E< zq;nbG%3xL*d_00OdQk?;oBc-bK~E@F-h-ifkd_p8F2!3P%PNJBM^H*nN@0<&-{`&f zd|Ql=F?$=Xk??bgPC)`(d|+|JJ_%4jNMxy$->UZBf#DR z?8vDM?19eMz4d`C?0h@|?A^hRl*_>WKLnG>qKxMq&%(~fBf#Db?A;RIKLG9R`3E%R z$8^T;d55#`^YIAqhrl0#MKyOOIqH^GbI&iDg_(~>fH@b;xjyFmI%D=cf?1gPcm$Yp zz${b6gNEDB?2OyG#x=Y%~24Ps(NSocbjDP5-1mF^%7*A6^(5PI zzonjXdAgP-<@>l@eUg2--&ddTg8W2%k`21|sZaPrR;W+1Q}=f~=@u#@*{g*|Uzu$E z1XEafVeUtOsk(@~lsQ)HQTd|w2>(cZ!ZGt(^+{?cQM$xlXTIR0t*)8D`JDoGL>ICL zoc-ihY!a?~`_t&VxJ@dUl>0k(KiPm?*Efi>b?fHWK9o(rOZwu5le6VDz>zp!_DF7u z9w@e!ypIb*Qf?##6_t+`tg}jAUG^-<0p){LGOcd`U-P}an46+aY?mEoEom@$hv6e; zyR3pL6e!s*tDz|S8UwYF60DMI6;zQxiB0N5jWSRVDyWMTR9K*zGNA?-sQVPuVe3VS zyGWHb{RCfe*Y%S62$c8(Xf50n+a_f&ePM$Memb1dZesRD4*t1AP3} z?XpS~(sxMQo`rCULKyiYlV|BvC>D8H=)u1YQujB+)Z>)q$Evd;80(Q&Gt>7-6JFR% zAw#4F(v1s?ow3IZlVXQOTddO8oI8#wbAQGr7`^TLX4wI%X)cT-jyYPyo*bBlO!SCh zoR@UUG42*7KXaCqz7%}LdSMH(2Lk7xls9Ktw6!4Grgl~PAG7A8r7r;;d?ngkP`c4% z%1S5I2^~X;L!vDgs9FZyb~Z$L9HU^YPP3kC-w%FTJA!Ghzw_kk~8pEG2G@R?;7zjFbcwc9;#Yd%Pz|Tnxm}4K~ zOi=#UI{dFAJs>lmPV}8)TMY|yoC(VLT8Hy>pa&xJl>w4lt%ua%O#hO-E>eWw-bCMq zg(2H=CMaiY9nRS821Iu&=sCw~TXXCgA!mZ}zt-V@m5A+vXIY|eq9)h2>>0Vv1m$n7 z!{7RlhXVhO)lVjSJ)8;3|51ng9+jx`n)z1uhJ~^|0*G?H*5Q1uF(CMtC4Ztu0Z@lL zXM*y#*5Pk0^Gea=(*7BNPt=I2>|xIUrSiAd;cv|~(1-eGfLG`hcIEFtM#o=c&x*A0 zFz}RdiOf)?luNrg6O@0p4*#qK5my}u;SIm&_V>F)5kcU)I}?NLJ@?w+`W8Dw1#`%>7ZUo_R`6?Ghtvfb*xi&Eb$FZ7Ek{A`00d!rVTT=)bvs^9UDy@=hPi%#V2^>EI`B3Usk`G zg2W{v)uqWZ3hYZ6|s_++4#vyRHZS zX7q6;6h%`fICUpj@wK=_4nrTxs8RG6c<6sZGIPZy ztGk9*^cQ&OKPZ|icIt|)_%{!Qzh^*$NK3yxp8U*F^%j3~-+O9uL}boDWag@`nes!+ z%aEU6z!859O8UvyPW+uMAG;rlFGD`|I81&mAC&M@Wy^~s zEcr4(;n4I@^&>q~o*Z*%dY1ecc)0X?GKPPH8vUvc27gV#VdTSc0?~;defUGK1&9D0?u9z$gL@$Q&@ zVG<&53-sGUwKRG6T>Vxz%$ZP;+5R#!pJO&9t2*ZcCKEb|%FSF$R%JFR{4&*M9(ICB zzfPw!(NpOZX#l<;K@ber0Br_<+1?#ify`^wyurHrTGF%4du@Mqw(lk0At$dnZGxS~x#?o1hEtt^+DWLD1SW+q~wCPLAnp{F7{IMT0{*JqVA z@}$qNgRl^U194&$m2ZxWjqiz6DCD3P#78l`@bC_aejJRP%2K9%4fTrDAxzlB_0>WOVO%L(S5nrl6v%l{VIV7KFJ|Qr{>GV<)QeS_DnVo z{gBke<$3bPQu!miF*!?I{zbHrm2`XN7m)(4Jc^u~IF7f0wQUlLyt#BYH&2#sj&E?L zbVT|Ko!UaOn<)_eFc{t6QTr)DF@!S2$7$8(Y4qJ(dsl6rlxxc8jQ!gZoKDIKMctq( zs@6?CVbUeGwpUE*q4a!AuFUhkn~(ncyxhG=b8|CL|FHH4m zQcI$V4CAZ(s%Ukr@EScx#B`yvmt}LX^y_#O?dEHqj zu+yGvgFt>Q=~hg(SSChD?474oxa%3o4^I7(;BiYsi5J3)03n9VFuN#B5kzjS((mto`gW=I0lM*{gmN5cc{x)-_1WPqxS}cSuIt zhbzX6UBmC5W*+43VrO)yWtpu2$ds?m9Yn;*fo}pymozZz-1~p#=KkhjyNGX($UShj0ra*>o8w<$_*&qt!5!Y6$YxPco^uM}_UGfo@OX zqNmloBr!a^>d*V`eQNK==povI0?8|Fws$%Cr(VD1d%%@$YDx|Q730CVEC-DM(n)`7 z+CRvCqv^vFn-1hSp`)TZay3}XszLG8l)Wx7x$^9n?5$1vdo*=)E9L%;(p@*SUt4;> zeuveAyrxeEmA12-5GrlCzImAx@=0kEx1C(yp-SB7T$~epE%*)*-t3e$>16`-aG$lk zo${QqM|0bkDXmGD_7QcQ1^)&$4{Q-N9td?U6Z8z zMQ-!KbV}JIN1J=NF9SJ!hW#@4O>B+s45JbXr%W|b;v#GQrK6Pt4E zjZ%^5d%4}-q*oBD4>mV-eYH12VQx%Mj%ptQ~7T^ZB%YfT4oOIw`K ze>tK0(pK7ZP=QmyRj-qnb#>N7&Czv*iUHsWNur_k&%sIc)}?+D zvg~)i{q3n@i@iWnA{O2xKac32K;rgdC_2o17ORN+rumZZ0aoPkR_wp!^A`5rCKemLrjLItsSvb8 zqf#T)dg5RXpGL(y_&Y+lrPcYFFp<5D7H;dr2`x>jL8aSed^%%CK1Yu5^^L*-&e$FY zgH84(#RKqvaj>=Y4STy2T0l|xoA*1RCgFfx{DEyw3nuM0p(LFhZffu4Ov`yo^i5x` zf<;Of2Al2nruO56jhprjDqA0IKl-kd?R|SUGYDRR^GhW0V33fKrJEiuLqZ*G-Twf! z09}bX{)m+wroCeFRq^j4LU)Fl^;oeR1ZrA%k$fy`r2bXN^C|`qQR{VAzfLy7?9IeV zz9=d2^l9uxgyyQMo=!lqBK{5c{!!d8kPS~(vYjxxuDE;~CmtxE{GHk#js$JwUMUJ@ zmhkt(SxjswBGp>nB;_@a*lfjAI9BK}RA}*n>P0|@AzFHXd}eu5zay71p)dJ)u*vO( zXjX(ljFnHr%(#CtgWr8iYn$Ox9v2Wih=Fdc6mrUKZ6h{Xu@?XkEhon};(ONKavD1v z8h*_S5wS<4j?ZNTp>1nVTHGc{T$j4853#!bL?xZj1@=KX9unC5w)DOeI?>)uCmMMa zS;xm|v`n$YwD2_N-f#@yQmZPO9l%*jGdEZhKK6^wGlpfLo5amZEr~!JtIb@c97w-$y2SCRk ztMXH4d{OE*%D+XenTF<6C4a>FHvLcM**DWX!s9iHS-q;r%jVYdnfS5!YXZg0j*9q` z{8&fKB~$#n!dC5=&o7#&hB9j;s$s{`fBIc%UKw$;d$~6N(`mj!P}UoT9MPR~nL37Q zs^;Y;M{G7#S#&;QwqWsl5;c7B{y+u6^afD@dt2Ft8Wo;C`FmIkdnCHPH45CqJuDvIt^oq45zu7JPE8P$ztR zr;^%FnamZue_f{VjSY*O7)8?)1FMqu6$d)9npU9kLWT6X3suJ2E13Ff``fGc0HF&- zcceBOe@R(mO|{Z>pl@pv@=^cd>k{9*E_%M=tw?Z}_2&yikv!+ZQ1UP55mU3Wz`3=E zH7A*NP0KB^o|&8%T%VZC4GsnNg@r1T zfARdYwI$ct-z?jbQC9SZP>`}JL&@Ti#GG80FX2bI{^z>r1v!x|Wm{6OrKi_(B>tpV zd8%EQfhS$(fz(;Tes-Ld{5}2FR;dR`r5-YsdH_|bA(N3mU5}rTKe}$9EXU$s(zm18 z8&^5fsGUXjry0zG{K#K83yG2++*K~tM&7OEYMfcm+{MKJy`ZtR@``VDOi$+CAwev; z>N{BFjPE_YD*3|(6}GzJs$Ri^@ix(;8dmwN-!-FGu^vFpaNMilCd@~w>r5^LqL_taJv~pJi0#^IY$IVQ`wdp z96U>vAoiq$numMiL0G{P4w>>p#)qUPCy$Rv(697 z{>kXyXYT9BP%z8v?Es4e3auLK1KY0|=s#pbgFm`+ngc5-?U>~Jx9q5Yura#s3MOj8 z?;;zfAu`S(DY|nwT5BxEnAD~slkHm;-bCnExe6(t3d?nL(bl8v@t^Ra(5^XPt>mH; zd;Dj-4s59Du*dH`#bWf?<4?B751H4W8l1v453>_0u4@}bi4IdLuC0RI5`jP~YA(8N zxY#X5KK^6Iz7D%3WoHTlq1UR@0T*KF>XoXk>3}V?MV$bd=0BbTk+RcCpX5`IIYL8>&y&BzClX$jAUqu2|8c< z*Ic>LW(86{^FA`(q)U-w*%iiJFC7fsa0?Aj^s-xCOO3odbZcqiil1`3Lu9ZF!`9b6 zPE5`p{Hc?FPa^+V=B>RGmlq6Xiu2RlP%kKwMycczb7}f%1kD*W_iru5d2^TL4bBVh zP40SNzaB~Yyel?Hz;3R8rT*~(yMJ3KEOf?JS7eWrxchk}Uhs|K;la;KU&MYJ4rhts z9NR(4o?LdaY~`VPUN6N!>QC~@M@1it6>*=;2F1E4Af-U~D?eHH7Jc@jFaaN=BwauDZXN91utX=8ps>GM8hpSkw9S=M~ppQT~awBtmbNw^~s- zx5xQcmG*<+{MrjR=Bi(EPOm+){Nwqd^0oyhlz(n5IaPAB&%cCf3@>eG^24vXVUe~E zr+9si8|hJ<{P{imJ7%hyA3a^MCRG`Z<93wtf22h-<24uhXezmX6?1ow@h@sQlR#MJ zL^cqpHL^}?-)7xs^q2i28s#;m7;?lHyN)W1>KW-is<^g*{e>;8IpvNjj_l#v?zOKo z(|lIU8vE_fer3ge#nak1<(rHW{Y?bY+V|xfJF3jLx8>V$V+ZFwE5?YxMW(E&xZtF` zRq|fek;?b<3m2OWpx3I11Ao+U>T*5$GPVUMd_2+CqG(5c?VHr-@pr7)B~Wq{C!@#n ztLyprJGCFvhPWIe%;tZmvb!)tuX%y02t7}gYoG`$+g& zz9jAq&*leb+u~i++I~PTk+fnR^hF}3k_-grJ+ZB{rQTXGn@g1Hr50_AXY*J7Yg@dI zCra#STfE-?rnpR{zF@x1u^;#gk8O+JHy;`h9MK)S+7>6xhv@oX+v1&G>S8Ho?#D1g zvih%zc+#8CgVWRun$7LtwaU3{c6G9&{+}|Jx}_Mptt)7)zgqA(RTJ%*W381H_})33 z4^x@Eqk1{tzru>ie#G+KR&)!$WgTT3QfG?(f?Ll(Q03dlsS6ZY>SKDTc$q1}H%4)c zeg$Nbe81-xUVo)EH=qHOJ;$w`+r>A-SH@+5R76gR!y5&>YXgq&@&y5`#oYMwS%2y6 za9aWpG(g&VC*o{zUZ9@rzJybj9$1v&=gapH13hnUpqLgj39L%a-{4Ejci4_C*Kbse z8X0+G)X9-8vdXn~zc&^ciE-&60U1B4nD_#~%fPVsRiJrrnY#5|Kp&tT0y-H`?l|v> zzRkl?@B==J?U17{ujhJ$$?#wH_=k3R&@R3mA3K9kI;0lzIaPbPK+E2~@M!k}Qj{Gx zac}*;pta>|oOX;;c)$Hq88~fs zzs_G7ZEiQJuH}dHXi&OIq^oq3Tm@!&6r!`~^-O8zjZDQpB5nz;04Owm8HHFY3+lNI z<@5UeJtMnVkB$9_#QOcP_^)|5>_GeRo&G>GqwK1y=k=;i{_GCZA(33BObo@@#nQW( z18@UU&ERDC$pCtaFATd=RXZ4Wr!ek%*vB#6nnT`@!@B^KK*#xIxNT)%sezXId%FGo zrTy>|?XNvr+CEWOM+UHP^E3P^ZY~lqdPk9|1$Uc(PC!Q~GCj!$ujbRj6P}$aqw;8+ z8tzXdg+U7|#qZ@=2zWU9$#tBHe&3Z0TF7P#sv77-8QFqLi>S!Sx;<)0SWAjjbFEk* zzaBAa-}6L>+l>+wJO-B*+!q#mbJ6L0#@-YxuKfm_ooTJPntDiv3BlN#4aZpb4Wu=y!Xl{Knq_8Sw_ca%mm27|N9eQW#Mqm6x|r(OW8M5{C>#{>+uIsWwC;-|L)>Ky z2G8CyJ@%X^;l$Wvp0%FQ(eMj-)17M{w5KKWQ>%=g(o}k077z|YsJHL-sv_--EKO4? zgGjF2?&y`zd@&NvD|^$GnxStFUmtO{dG(<-?hq(-3RP%)u7ir7&r`jawE=6~CUp~I zTae)vXd4|8mCbb}jX8ONwB1G3$+g#e)sH6`m?X|S zqdI9XG(3VGs=tcUgzEf1&fW$-s^V(=-%U2K;Np!MB-*G!qa}(Zsc2aN4Uh#?qDwFd zzF@6YnxbtHb^$BF;O>S@uUD}JrLFdXN}tEJw52Uzc+-SHHYk<|7Ncm5f_ksPif<55 z+5h*<-3?%UKL6kE$49gG&di;cGv}N+bLN~gn(CTw58Lm#C7i#LZE=(*%Z7Kx17Z7F zju@DaAv7z6B~%ep6;NaHh)F`Avh{kMDhn_?)~Si7JGZ+H5U)tqMdJTvGgiD_kHK`Og{X%znh1w{IM(DLU&`)kd4x9&S<)P*=ZyR=jpLcS5r@)uEG+6ORZc^zU&;gIr!-S~A;KFZNw^W;RCO^HLQo@Y%zD#$gPGHm>?Uf;nL=&w! zf0b%7`yU~=QdndCQG8=AWejjKXsX)&#fre4XU%-S#X(E;~Dg^$L|9xk*0^6Pi_UeTufPTqRRAlB4mG&Oh_K%N}1EJWwO@p z=T)!&+&(sxJ9V2Q-!N}G82daGF;u&&Pe_hO?UG7iRx(g;hlz-%PZ-dZI7@wE*qQD+YwKBfrn|XO+f0(RRd!}$peEre; zBe$3Cz4El^PfI^2-HV0SrKNj`ZKU;CybafQm3Quyd1rB2ZX+vJmNwTPt&8Sz+7@fg zLUzelom^u#RqG+#@03&8jGfp%H%abyt@a{*(a0>S{HAK#3`{)Tk7f7;iO2Ugq6 z8v7gTD)xi@2)m36B$(>0KQgRw+WzSN`p>_GUoYPUkIs1old)mZm(qpf+oOA2cm$6| z{E{X2c@kBtEo)eDkB(Kbap=VJ{VKG7WOV=fQ9N!aT~lfAoSmix zv#QIic%A!eq?4__;H#0-iS6JuFXQVuJ9J9)-=)o&Yn~Xcv2JFT`h*@vM$6Bzh@bT` zA%_mJ<}CG*QzB4dy_Pcv`8C!}^op@%v)4HU8J|FJGqX>q;B-D?wCBl?tZTXMt9yt$ zPL8YVgTo?c2aiNQRY$qGls0xyk=}DU-{&*+e7Eh|v#LE{vpKZ@4c}>w#gJs37{?h~ zWUw6E_*0iv+rG@uqwhe98k=-K`Lfy`bl2x8tCr3VP`)C2{Z*O0LozbdD${o(R)_7k z=jmkCH#tG?8f_qQWhgFW^JZW5W8ixrP-(BdlaJl%Z_ZR7 z*;%`60#<;_L7&=Hd{euQKlZO?ooEl3wm(Ty3x=!c4MlY}G$Qu_R@x6-=n7kVBZJJ? z(^MlWX2}ZMzHz#@JWsKE#(u8VL__U=^CY6cAueMdueX=>E$_gbbjRO^%!jKUTm6Vp zW%#3u*8<_;+}g)AuC;O?7*?T9Rq?X@tlI(6_lLTSxZD!06-uRhpOfpPIOmdo)_9+5 zqsb+s*cEf%WoP!Z*TZttsXeJEv+aNQErgtG?i#;LwW>aI_QXEF40~+SWVQ6y7J$yF z=Zarg91o}iCbyf8b3hF_N~2;vSItJnY|?^32YYR<0JVH-%O7!I1@L= z_eeCJ8J}l`k4;A-Z!DUx^W-9=1#YQt6%xly8hK`X2^ZguKaH5ZZKsb6qPcGN#A%V?0$Rtp#S9tceuZzL@GTED;#V1;j` z0sAnIrF-ia^z%Nqax8XR@xJt;zV2m@k@y{1+-nQ}QJph9HFD}@pCzk#2H)`Jy6|A? zYESW21SLa8=BWfv&>?{pq5bwl@5w3@sL{w{oUf55m_%tI17(`@961tD%jF~7WZUNP zg5ZK|H&9;VXEM|U2N6;LMH#|L1J>)68SUhwYWs`ZVGUte!+8{@7rp(etmZ9j?}&V! zx+xXyRBiU7SGx=%+UcA{<(c-ez$q(nK4p-?7wZ@F_deGlP)X=OZR^ILGAbJb50<3? z@mE9N~}?9a~mf`b@k%_KoBoyXr~;#U6hp(mLT z;~RN`{LVd&24H0t$8|pEvoOy?mBgp9zVeRo4Vp;wqUJRU5Xa5nU@v! zP=%;29KjNbC;mXHtmT(W<)X7{c$XB_78~h}ytkrWS`ekeQ)4C)m*fvntn4vVmmxpPe318KuP~ zU}-alcKwplx3~tG9*T5Xm*70Ksy?+=>b5Wcj@*CEi73h#v#MU9Z(9N*roX*qfL_?H z0DRokDqM}h~#j<5iO1Bsq*#PEEAiVH|}ZFGiM}j0NqVX^5ht4 z3m~S>CSFsn_z6ClAp}aq?oi&{W%-lL#hz8gel3$6dT=S=@JA<_8aif0oX(mWkG$=N zceVL)JyxhOJed>Y_CKdjjH73mp=B4kcg~l=zv5TWWKtr-B1iR0I#&z%tafcovGZ^DbfCiLcfHibVCm?v`YKBbJ9GJ8q&t64xQS$q@vGm3c~yxU`FjGj#F`CF3~C>B*Zx>KcM6?zAxi^t zv$_#~oAH>I)HiY>F$8w=YF+0wH5n#D^)g"y_{7))wrZfYiC%SS(gG&C?zq>efP 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 z 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 bjbqh$;CL>QjBrF$QjVDhfqR~n5OVcz5?9k+ literal 0 HcmV?d00001 diff --git a/dockers/docker-platform-monitor/ssd_tools/iSmart b/dockers/docker-platform-monitor/ssd_tools/iSmart new file mode 100755 index 0000000000000000000000000000000000000000..c6bba0046024ea421f2ca88fc8800a536d6d9930 GIT binary patch literal 120064 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 E9}TO>QUCw| literal 0 HcmV?d00001 diff --git a/rules/docker-platform-monitor.mk b/rules/docker-platform-monitor.mk index 617cf39e8b87..5eb26fec2f82 100644 --- a/rules/docker-platform-monitor.mk +++ b/rules/docker-platform-monitor.mk @@ -40,5 +40,7 @@ $(DOCKER_PLATFORM_MONITOR)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro $(DOCKER_PLATFORM_MONITOR)_aboot_RUN_OPT += -v /usr/lib/python2.7/dist-packages/arista:/usr/lib/python2.7/dist-packages/arista:ro $(DOCKER_PLATFORM_MONITOR)_aboot_RUN_OPT += -v /usr/lib/python2.7/dist-packages/arista/utils/sonic_platform:/usr/lib/python2.7/dist-packages/sonic_platform:ro -$(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += sensors:/usr/bin/sensors -$(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += smartctl:/usr/sbin/smartctl +$(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += cmd_wrapper:/usr/bin/sensors +$(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += cmd_wrapper:/usr/sbin/smartctl +$(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += cmd_wrapper:/usr/sbin/iSmart +$(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += cmd_wrapper:/usr/sbin/SmartCmd diff --git a/src/sonic-platform-common b/src/sonic-platform-common index 33b037d38f1c..cc2dac5963a1 160000 --- a/src/sonic-platform-common +++ b/src/sonic-platform-common @@ -1 +1 @@ -Subproject commit 33b037d38f1c96264729b966e777efed143ed01d +Subproject commit cc2dac5963a14d04dd15735de35df9b30cff1e41 From 8861cbe98edbe513aac5d1ee2c5943bf6179c905 Mon Sep 17 00:00:00 2001 From: Wenda Ni Date: Fri, 4 Oct 2019 11:20:57 -0700 Subject: [PATCH 042/278] Configure buffer profile to all ports (#3561) Signed-off-by: Wenda Ni --- files/build_templates/buffers_config.j2 | 8 +- .../tests/sample_output/buffers-dell6100.json | 240 ++++++++++++++++++ 2 files changed, 244 insertions(+), 4 deletions(-) diff --git a/files/build_templates/buffers_config.j2 b/files/build_templates/buffers_config.j2 index a5212d979fcb..bf74b2dcf52c 100644 --- a/files/build_templates/buffers_config.j2 +++ b/files/build_templates/buffers_config.j2 @@ -131,7 +131,7 @@ def {{ defs.generate_pg_profils(port_names_active) }} {% else %} "BUFFER_PG": { -{% for port in PORT_ACTIVE %} +{% for port in PORT_ALL %} "{{ port }}|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }{% if not loop.last %},{% endif %} @@ -144,17 +144,17 @@ def {{ defs.generate_queue_buffers(port_names_active) }} {% else %} "BUFFER_QUEUE": { -{% for port in PORT_ACTIVE %} +{% for port in PORT_ALL %} "{{ port }}|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, {% endfor %} -{% for port in PORT_ACTIVE %} +{% for port in PORT_ALL %} "{{ port }}|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, {% endfor %} -{% for port in PORT_ACTIVE %} +{% for port in PORT_ALL %} "{{ port }}|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }{% if not loop.last %},{% endif %} diff --git a/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json b/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json index 5cf0472f3f11..38e2b8313eb4 100644 --- a/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json +++ b/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json @@ -111,6 +111,12 @@ "Ethernet1|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, + "Ethernet2|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet3|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, "Ethernet4|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, @@ -153,6 +159,12 @@ "Ethernet17|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, + "Ethernet18|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet19|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, "Ethernet20|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, @@ -192,6 +204,15 @@ "Ethernet32|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, + "Ethernet33|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet34|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet35|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, "Ethernet36|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, @@ -213,9 +234,33 @@ "Ethernet42|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, + "Ethernet43|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet44|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet45|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet46|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet47|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, "Ethernet48|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, + "Ethernet49|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet50|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet51|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, "Ethernet52|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, @@ -236,6 +281,21 @@ }, "Ethernet58|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet59|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet60|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet61|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet62|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet63|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" } }, @@ -246,6 +306,12 @@ "Ethernet1|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, + "Ethernet2|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet3|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, "Ethernet4|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, @@ -288,6 +354,12 @@ "Ethernet17|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, + "Ethernet18|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet19|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, "Ethernet20|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, @@ -327,6 +399,15 @@ "Ethernet32|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, + "Ethernet33|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet34|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet35|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, "Ethernet36|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, @@ -348,9 +429,33 @@ "Ethernet42|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, + "Ethernet43|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet44|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet45|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet46|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet47|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, "Ethernet48|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, + "Ethernet49|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet50|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet51|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, "Ethernet52|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, @@ -372,12 +477,33 @@ "Ethernet58|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, + "Ethernet59|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet60|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet61|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet62|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet63|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, "Ethernet0|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, "Ethernet1|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, + "Ethernet2|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet3|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, "Ethernet4|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -420,6 +546,12 @@ "Ethernet17|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, + "Ethernet18|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet19|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, "Ethernet20|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -459,6 +591,15 @@ "Ethernet32|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, + "Ethernet33|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet34|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet35|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, "Ethernet36|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -480,9 +621,33 @@ "Ethernet42|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, + "Ethernet43|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet44|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet45|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet46|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet47|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, "Ethernet48|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, + "Ethernet49|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet50|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet51|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, "Ethernet52|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -504,12 +669,33 @@ "Ethernet58|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, + "Ethernet59|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet60|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet61|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet62|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet63|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, "Ethernet0|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, "Ethernet1|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, + "Ethernet2|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet3|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, "Ethernet4|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -552,6 +738,12 @@ "Ethernet17|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, + "Ethernet18|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet19|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, "Ethernet20|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -591,6 +783,15 @@ "Ethernet32|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, + "Ethernet33|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet34|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet35|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, "Ethernet36|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -612,9 +813,33 @@ "Ethernet42|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, + "Ethernet43|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet44|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet45|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet46|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet47|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, "Ethernet48|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, + "Ethernet49|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet50|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet51|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, "Ethernet52|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -635,6 +860,21 @@ }, "Ethernet58|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet59|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet60|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet61|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet62|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet63|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" } } } From c16f12b082090fe1316e5ad79700818e3e926503 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Fri, 4 Oct 2019 12:47:56 -0700 Subject: [PATCH 043/278] Update sonic-utilities (#3563) --- src/sonic-utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-utilities b/src/sonic-utilities index cbf19f643a1a..02375e195394 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit cbf19f643a1aa708eee6306814c0d52fd7535ec4 +Subproject commit 02375e195394cd84fb2e7639f953a72b894ed000 From d316bcb53761172cc657f7a17e4da11e60445589 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Mon, 7 Oct 2019 22:13:47 +0800 Subject: [PATCH 044/278] [Mellanox]Upload the SDK makefile modification (#3555) Adjust the SDK makefiles so that it reflects the dependencies among libraries in SDK 4.3.2104. This is a supplement of PR [Mellanox]Update SDK(4.3.2104), SAI-Implementation(1.15) and firmware 2162. It doesn't impact the sonic-mellanox.bin image but makes the future SDK-integration easier. --- .../mellanox/sdk-src/sx-acl-helper/Makefile | 29 ++++++++++++++++ platform/mellanox/sdk.mk | 33 ++++++++++++------- 2 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 platform/mellanox/sdk-src/sx-acl-helper/Makefile diff --git a/platform/mellanox/sdk-src/sx-acl-helper/Makefile b/platform/mellanox/sdk-src/sx-acl-helper/Makefile new file mode 100644 index 000000000000..d9d0aef8775b --- /dev/null +++ b/platform/mellanox/sdk-src/sx-acl-helper/Makefile @@ -0,0 +1,29 @@ +.ONESHELL: +SHELL = /bin/bash + +MAIN_TARGET = sx-acl-helper_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +DERIVED_TARGETS = sx-acl-helper-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb \ + sx-acl-helper-dev-static_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb \ + sx-acl-helper-dbgsym_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +PACKAGE_NAME = sx_acl_helper + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # get sources + rm -rf $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + wget -c $(MLNX_SDK_SOURCE_BASE_URL)/$(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION).tar.gz -O - | tar -xz + + # build + pushd $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + if [ -f autogen.sh ]; then + ./autogen.sh + fi + + debuild -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + + popd + + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/platform/mellanox/sdk.mk b/platform/mellanox/sdk.mk index 7a832b2502d1..3cf3ee3ff976 100644 --- a/platform/mellanox/sdk.mk +++ b/platform/mellanox/sdk.mk @@ -15,17 +15,17 @@ endif export MLNX_SDK_SOURCE_BASE_URL MLNX_SDK_VERSION MLNX_SDK_ISSU_VERSION MLNX_SDK_DEB_VERSION -MLNX_SDK_RDEBS += $(APPLIBS) $(IPROUTE2_MLNX) $(SX_COMPLIB) \ - $(SX_EXAMPLES) $(SX_GEN_UTILS) $(SX_SCEW) $(SXD_LIBS) $(WJH_LIBS) +MLNX_SDK_RDEBS += $(APPLIBS) $(IPROUTE2_MLNX) $(SX_COMPLIB) $(SX_EXAMPLES) \ + $(SX_GEN_UTILS) $(SX_SCEW) $(SXD_LIBS) $(WJH_LIBS) $(SX_ACL_HELPER) -MLNX_SDK_DEBS += $(APPLIBS_DEV) $(IPROUTE2_MLNX_DEV) \ - $(SX_COMPLIB_DEV) $(SX_COMPLIB_DEV_STATIC) $(SX_EXAMPLES_DEV) \ - $(SX_GEN_UTILS_DEV) $(SX_SCEW_DEV) $(SX_SCEW_DEV_STATIC) \ - $(SXD_LIBS_DEV) $(SXD_LIBS_DEV_STATIC) $(WJH_LIBS_DEV) +MLNX_SDK_DEBS += $(APPLIBS_DEV) $(IPROUTE2_MLNX_DEV) $(SX_COMPLIB_DEV) \ + $(SX_COMPLIB_DEV_STATIC) $(SX_EXAMPLES_DEV) $(SX_GEN_UTILS_DEV) \ + $(SX_SCEW_DEV) $(SX_SCEW_DEV_STATIC) $(SXD_LIBS_DEV)\ + $(SXD_LIBS_DEV_STATIC) $(WJH_LIBS_DEV) $(SX_ACL_HELPER_DEV) MLNX_SDK_DBG_DEBS += $(APPLIBS_DBGSYM) $(IPROUTE2_MLNX_DBGSYM) $(SX_COMPLIB_DBGSYM) \ $(SX_EXAMPLES_DBGSYM) $(SX_GEN_UTILS_DBGSYM) $(SX_SCEW_DBGSYM) \ - $(SXD_LIBS_DBGSYM) $(WJH_LIBS_DBGSYM) + $(SXD_LIBS_DBGSYM) $(WJH_LIBS_DBGSYM) $(SX_ACL_HELPER_DBGSYM) APPLIBS = applibs_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(APPLIBS)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/applibs @@ -69,7 +69,7 @@ endif SX_GEN_UTILS = sx-gen-utils_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(SX_GEN_UTILS)_SRC_PATH += $(PLATFORM_PATH)/sdk-src/sx-gen-utils -$(SX_GEN_UTILS)_DEPENDS += $(SX_COMPLIB_DEV) $(SXD_LIBS_DEV) +$(SX_GEN_UTILS)_DEPENDS += $(SX_COMPLIB_DEV) $(SX_GEN_UTILS)_RDEPENDS += $(SX_COMPLIB) SX_GEN_UTILS_DEV = sx-gen-utils-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(eval $(call add_derived_package,$(SX_GEN_UTILS),$(SX_GEN_UTILS_DEV))) @@ -89,7 +89,7 @@ endif SXD_LIBS = sxd-libs_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(SXD_LIBS)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/sxd-libs -$(SXD_LIBS)_DEPENDS += $(SX_COMPLIB_DEV) +$(SXD_LIBS)_DEPENDS += $(SX_COMPLIB_DEV) $(SX_GEN_UTILS_DEV) SXD_LIBS_DEV = sxd-libs-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(eval $(call add_derived_package,$(SXD_LIBS),$(SXD_LIBS_DEV))) SXD_LIBS_DBGSYM = sxd-libs-dbgsym_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb @@ -107,10 +107,21 @@ ifeq ($(SDK_FROM_SRC),y) $(eval $(call add_derived_package,$(PYTHON_SDK_API),$(PYTHON_SDK_API_DBGSYM))) endif +SX_ACL_HELPER = sx-acl-helper_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +$(SX_ACL_HELPER)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/sx-acl-helper +$(SX_ACL_HELPER)_DEPENDS += $(SX_COMPLIB_DEV) $(SXD_LIBS_DEV) $(APPLIBS_DEV) +$(SX_ACL_HELPER)_RDEPENDS += $(SX_COMPLIB) $(PYTHON_SDK_API) +SX_ACL_HELPER_DEV = sx-acl-helper-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +$(eval $(call add_derived_package,$(SX_ACL_HELPER),$(SX_ACL_HELPER_DEV))) +SX_ACL_HELPER_DBGSYM = sx-acl-helper-dbgsym_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +ifeq ($(SDK_FROM_SRC),y) +$(eval $(call add_derived_package,$(SX_ACL_HELPER),$(SX_ACL_HELPER_DBGSYM))) +endif + WJH_LIBS = wjh-libs_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(WJH_LIBS)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/wjh-libs -$(WJH_LIBS)_DEPENDS += $(SX_COMPLIB_DEV) $(SXD_LIBS_DEV) $(APPLIBS_DEV) -$(WJH_LIBS)_RDEPENDS += $(SX_COMPLIB) $(PYTHON_SDK_API) +$(WJH_LIBS)_DEPENDS += $(SX_COMPLIB_DEV) $(SXD_LIBS_DEV) $(APPLIBS_DEV) $(SX_ACL_HELPER_DEV) $(SX_SCEW_DEV) +$(WJH_LIBS)_RDEPENDS += $(SX_COMPLIB) $(PYTHON_SDK_API) $(SX_ACL_HELPER) WJH_LIBS_DEV = wjh-libs-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(eval $(call add_derived_package,$(WJH_LIBS),$(WJH_LIBS_DEV))) WJH_LIBS_DBGSYM = wjh-libs-dbgsym_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb From e9a0c5771465ec31d5ee83a9be3a2f86ad9cb374 Mon Sep 17 00:00:00 2001 From: Mike Lazar Date: Mon, 7 Oct 2019 10:16:11 -0400 Subject: [PATCH 045/278] [vsimage]: Support for the creation of a GNS3 appliance file (#3553) The script sonic-gns3a.sh creates a GNS3 appliance flle, that points to a sonin-vs.img (SONiC Virtual Switch). The appliance file (and sonic-vs.img file) can subsequently be imported into a GNS3 simulation environment. --- platform/vs/README.gns3.md | 17 ++++++++ platform/vs/sonic-gns3a.sh | 81 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 platform/vs/README.gns3.md create mode 100644 platform/vs/sonic-gns3a.sh diff --git a/platform/vs/README.gns3.md b/platform/vs/README.gns3.md new file mode 100644 index 000000000000..c434d5e9b405 --- /dev/null +++ b/platform/vs/README.gns3.md @@ -0,0 +1,17 @@ +HOWTO Create a GNS3 Appliance File (.gns3a) + + +Execute the command sonic-gns3.sh + + +For instance: + +./sonic-gns3a.sh -h + +sonic-gns3a.sh [ -r ] -b +e.g.: sonic-gns3a.sh -r 1.1 -b /sonic-vs.img + +For more information about GNS3, please refer to: + +https://gns3.com/ + diff --git a/platform/vs/sonic-gns3a.sh b/platform/vs/sonic-gns3a.sh new file mode 100644 index 000000000000..57c63fb75f32 --- /dev/null +++ b/platform/vs/sonic-gns3a.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +# This script creates a .gns3a SONiC appliance file +IMGFILE="sonic-vs.image" +RELEASE="latest" + +usage() { + echo "`basename $0` [ -r ] -b " + echo "e.g.: `basename $0` -r 1.1 -b /sonic-vs.image" + exit 0 +} + +while getopts "r:b:h" arg; do + case $arg in + h) + usage + ;; + r) + RELEASE=$OPTARG + ;; + b) + IMGFILE=$OPTARG + ;; + esac +done + +if [ ! -e ${IMGFILE} ]; then + echo "ERROR: ${IMGFILE} not found" + exit 2 +fi + + +MD5SUMIMGFILE=`md5sum ${IMGFILE} | cut -f 1 -d " "` +LENIMGFILE=`stat -c %s ${IMGFILE}` +GNS3APPNAME="SONiC-${RELEASE}.gns3a" +NAMEIMGFILE=`basename $IMGFILE` + +echo " +{ + \"name\": \"SONiC\", + \"category\": \"router\", + \"description\": \"SONiC Virtual Switch/Router\n\", + \"vendor_name\": \"SONiC\", + \"vendor_url\": \"https://azure.github.io/SONiC/\", + \"product_name\": \"SONiC\", + \"product_url\": \"https://azure.github.io/SONiC/\", + \"registry_version\": 3, + \"status\": \"experimental\", + \"maintainer\": \"SONiC\", + \"maintainer_email\": \"sonicproject@googlegroups.com\", + \"usage\": \"Supports SONiC release: ${RELEASE}\", + \"qemu\": { + \"adapter_type\": \"e1000\", + \"adapters\": 10, + \"ram\": 2048, + \"hda_disk_interface\": \"virtio\", + \"arch\": \"x86_64\", + \"console_type\": \"telnet\", + \"boot_priority\": \"d\", + \"kvm\": \"require\" + }, + \"images\": [ + { + \"filename\": \"${NAMEIMGFILE}\", + \"version\": \"${RELEASE}\", + \"md5sum\": \"${MD5SUMIMGFILE}\", + \"filesize\": ${LENIMGFILE} + } + ], + \"versions\": [ + { + \"name\": \"${RELEASE}\", + \"images\": { + \"hda_disk_image\": \"${NAMEIMGFILE}\" + } + } + ] +} + +" > ${GNS3APPNAME} + From 50cfa7724327cc9e3446bdf17dd01717bff3a507 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Mon, 7 Oct 2019 21:17:46 +0700 Subject: [PATCH 046/278] [device/celestica]: update psuutil follow new platform api (#3537) Fixes #3518 Update psuutil API to detect PSU GPIO base from label --- .../x86_64-cel_seastone-r0/plugins/psuutil.py | 77 ++++++++----------- 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/device/celestica/x86_64-cel_seastone-r0/plugins/psuutil.py b/device/celestica/x86_64-cel_seastone-r0/plugins/psuutil.py index 510c03a43ff1..b2764b5b6ae0 100644 --- a/device/celestica/x86_64-cel_seastone-r0/plugins/psuutil.py +++ b/device/celestica/x86_64-cel_seastone-r0/plugins/psuutil.py @@ -12,49 +12,51 @@ raise ImportError(str(e) + "- required module not found") +GPIO_DIR = "/sys/class/gpio" +GPIO_LABEL = "pca9505" +DX010_MAX_PSUS = 2 + + class PsuUtil(PsuBase): """Platform-specific PSUutil class""" def __init__(self): PsuBase.__init__(self) # DX010 PSU pin mapping - self.psu = [ - {'base': self.get_gpio_base()}, - {'abs':27, 'power':22}, - {'abs':28, 'power':25} + self.dx010_psu_gpio = [ + {'base': self.__get_gpio_base()}, + {'prs': 27, 'status': 22}, + {'prs': 28, 'status': 25} ] - def get_gpio_base(self): - sys_gpio_dir = "/sys/class/gpio" - for r in os.listdir(sys_gpio_dir): - if "gpiochip" in r: - return int(r[8:],10) - return 216 #Reserve - - - # Get a psu status and presence - def read_psu_statuses(self, pinnum): - sys_gpio_dir = "/sys/class/gpio" - gpio_base = self.psu[0]['base'] - - gpio_dir = sys_gpio_dir + '/gpio' + str(gpio_base+pinnum) - gpio_file = gpio_dir + "/value" - + def __read_txt_file(self, file_path): try: - with open(gpio_file, 'r') as fd: - retval = fd.read() + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() except IOError: - raise IOError("Unable to open " + gpio_file + "file !") - - retval = retval.rstrip('\r\n') - return retval + pass + return "" + + def __get_gpio_base(self): + for r in os.listdir(GPIO_DIR): + label_path = os.path.join(GPIO_DIR, r, "label") + if "gpiochip" in r and GPIO_LABEL in self.__read_txt_file(label_path): + return int(r[8:], 10) + return 216 # Reserve + + def __get_gpio_value(self, pinnum): + gpio_base = self.dx010_psu_gpio[0]['base'] + gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base+pinnum) + gpio_file = gpio_dir + "/value" + retval = self.__read_txt_file(gpio_file) + return retval.rstrip('\r\n') 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 """ - DX010_MAX_PSUS = 2 return DX010_MAX_PSUS def get_psu_status(self, index): @@ -65,14 +67,9 @@ def get_psu_status(self, index): :return: Boolean, True if PSU is operating properly, False if PSU is\ faulty """ - status = 0 - psu_status = self.read_psu_statuses(self.psu[index]['power']) - psu_status = int(psu_status, 10) - # Check for PSU status - if (psu_status == 1): - status = 1 - - return status + raw = self.__get_gpio_value( + self.dx010_psu_gpio[index]['status']) + return int(raw, 10) == 1 def get_psu_presence(self, index): """ @@ -81,11 +78,5 @@ def get_psu_presence(self, index): :param index: An integer, index of the PSU of which to query status :return: Boolean, True if PSU is plugged, False if not """ - status = 0 - psu_absence = self.read_psu_statuses(self.psu[index]['abs']) - psu_absence = (int(psu_absence, 10)) - # Check for PSU presence - if (psu_absence == 0): - status = 1 - - return status + raw = self.__get_gpio_value(self.dx010_psu_gpio[index]['prs']) + return int(raw, 10) == 0 From 9b8f5c9c9ad757f7504dc5e1afa95a4556655684 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Mon, 7 Oct 2019 07:49:25 -0700 Subject: [PATCH 047/278] [ntp]: Use loopback address when we don't have MGMT interface (#3566) Added configuration to use Loopback ip if a switch doesn't have MGMT_PORT. --- files/image_config/ntp/ntp.conf.j2 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/files/image_config/ntp/ntp.conf.j2 b/files/image_config/ntp/ntp.conf.j2 index 1255369773f0..cef6527fc28f 100644 --- a/files/image_config/ntp/ntp.conf.j2 +++ b/files/image_config/ntp/ntp.conf.j2 @@ -27,12 +27,19 @@ filegen clockstats file clockstats type day enable server {{ ntp_server }} iburst {% endfor %} -#only listen on localhost and eth0 ips (default is to listen on all ip addresses) +#only listen on MGMT_INTERFACE, LOOPBACK_INTERFACE ip when MGMT_INTERFACE is not defined, or eth0 +# if we don't have both of them (default is to listen on all ip addresses) interface ignore wildcard {% if MGMT_INTERFACE %} {% for (mgmt_intf, mgmt_prefix) in MGMT_INTERFACE|pfx_filter %} interface listen {{ mgmt_prefix | ip }} {% endfor %} +{% elif LOOPBACK_INTERFACE %} +{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %} +{% if prefix | ipv4 and name == 'Loopback0' %} +interface listen {{ prefix | ip }} +{% endif %} +{% endfor %} {% else %} interface listen eth0 {% endif %} From e69cb73fc77132c93d4df6e67d3a1791ac6a80a8 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Mon, 7 Oct 2019 16:05:07 -0700 Subject: [PATCH 048/278] [frr]: Implement BGP_MONITORS support (#3545) Implement support of BGP Monitors Add changes into minigraph to extract BGP Monitors information. Add new templates for FRR. --- dockers/docker-fpm-frr/bgpd.conf.default.j2 | 26 +++++++++++++++++++ src/sonic-config-engine/minigraph.py | 9 +++++-- .../tests/sample_output/bgpd_frr.conf | 14 ++++++++++ .../tests/simple-sample-graph.xml | 24 +++++++++++++++++ .../tests/t0-sample-graph.xml | 24 +++++++++++++++++ src/sonic-config-engine/tests/test_cfggen.py | 6 +++++ .../tests/test_minigraph_case.py | 6 +++++ 7 files changed, 107 insertions(+), 2 deletions(-) diff --git a/dockers/docker-fpm-frr/bgpd.conf.default.j2 b/dockers/docker-fpm-frr/bgpd.conf.default.j2 index 371f1fe3dd36..72779ac53d52 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.default.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.default.j2 @@ -22,6 +22,12 @@ route-map TO_BGP_PEER_V4 permit 100 ! route-map TO_BGP_PEER_V6 permit 100 ! +{% if BGP_MONITORS is defined and BGP_MONITORS|length > 0 %} +route-map FROM_BGPMON_V4 deny 10 +! +route-map TO_BGPMON_V4 permit 10 +! +{% endif %} router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} bgp log-neighbor-changes bgp bestpath as-path multipath-relax @@ -153,4 +159,24 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% endfor %} {% endif %} {% endblock bgp_peers_with_range %} +{% block bgp_monitors %} +{% if BGP_MONITORS is defined and BGP_MONITORS|length > 0 %} + neighbor BGPMON_V4 peer-group +{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %} +{% if prefix | ipv4 and name == 'Loopback0' %} + neighbor BGPMON_V4 update-source {{ prefix | ip }} +{% endif %} +{% endfor %} + neighbor BGPMON_V4 route-map FROM_BGPMON_V4 in + neighbor BGPMON_V4 route-map TO_BGPMON_V4 out + neighbor BGPMON_V4 send-community + neighbor BGPMON_V4 maximum-prefix 1 +{% for neighbor_addr, bgp_session in BGP_MONITORS.items() %} + neighbor {{ neighbor_addr }} remote-as {{ DEVICE_METADATA['localhost']['bgp_asn'] }} + neighbor {{ neighbor_addr }} peer-group BGPMON_V4 + neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} + neighbor {{ neighbor_addr }} activate +{% endfor %} +{% endif %} +{% endblock bgp_monitors %} ! diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index bea5f31eeaa3..f64cbefafbd5 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -383,8 +383,11 @@ def parse_cpg(cpg, hname): bgp_session = bgp_sessions[peer] if hostname.lower() == bgp_session['name'].lower(): bgp_session['asn'] = asn + + bgp_monitors = { key: bgp_sessions[key] for key in bgp_sessions if bgp_sessions[key].has_key('asn') and bgp_sessions[key]['name'] == 'BGPMonitor' } bgp_sessions = { key: bgp_sessions[key] for key in bgp_sessions if bgp_sessions[key].has_key('asn') and int(bgp_sessions[key]['asn']) != 0 } - return bgp_sessions, myasn, bgp_peers_with_range + + return bgp_sessions, myasn, bgp_peers_with_range, bgp_monitors def parse_meta(meta, hname): @@ -516,6 +519,7 @@ def parse_xml(filename, platform=None, port_config_file=None): u_devices = None hwsku = None bgp_sessions = None + bgp_monitors = [] bgp_asn = None intfs = None vlan_intfs = None @@ -559,7 +563,7 @@ def parse_xml(filename, platform=None, port_config_file=None): if child.tag == str(QName(ns, "DpgDec")): (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls, vni) = parse_dpg(child, hostname) elif child.tag == str(QName(ns, "CpgDec")): - (bgp_sessions, bgp_asn, bgp_peers_with_range) = parse_cpg(child, hostname) + (bgp_sessions, bgp_asn, bgp_peers_with_range, bgp_monitors) = parse_cpg(child, hostname) elif child.tag == str(QName(ns, "PngDec")): (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port, port_speed_png, console_ports) = parse_png(child, hostname) elif child.tag == str(QName(ns, "UngDec")): @@ -580,6 +584,7 @@ def parse_xml(filename, platform=None, port_config_file=None): 'type': current_device['type'] }} results['BGP_NEIGHBOR'] = bgp_sessions + results['BGP_MONITORS'] = bgp_monitors results['BGP_PEER_RANGE'] = bgp_peers_with_range if mgmt_routes: # TODO: differentiate v4 and v6 diff --git a/src/sonic-config-engine/tests/sample_output/bgpd_frr.conf b/src/sonic-config-engine/tests/sample_output/bgpd_frr.conf index b65cad324d27..c796ef8c164b 100644 --- a/src/sonic-config-engine/tests/sample_output/bgpd_frr.conf +++ b/src/sonic-config-engine/tests/sample_output/bgpd_frr.conf @@ -25,6 +25,10 @@ route-map TO_BGP_PEER_V4 permit 100 ! route-map TO_BGP_PEER_V6 permit 100 ! +route-map FROM_BGPMON_V4 deny 10 +! +route-map TO_BGPMON_V4 permit 10 +! router bgp 65100 bgp log-neighbor-changes bgp bestpath as-path multipath-relax @@ -114,6 +118,16 @@ router bgp 65100 neighbor fc00::76 route-map TO_BGP_PEER_V6 out maximum-paths 64 exit-address-family + neighbor BGPMON_V4 peer-group + neighbor BGPMON_V4 update-source 10.1.0.32 + neighbor BGPMON_V4 route-map FROM_BGPMON_V4 in + neighbor BGPMON_V4 route-map TO_BGPMON_V4 out + neighbor BGPMON_V4 send-community + neighbor BGPMON_V4 maximum-prefix 1 + neighbor 10.20.30.40 remote-as 65100 + neighbor 10.20.30.40 peer-group BGPMON_V4 + neighbor 10.20.30.40 description BGPMonitor + neighbor 10.20.30.40 activate !! maximum-paths 64 ! diff --git a/src/sonic-config-engine/tests/simple-sample-graph.xml b/src/sonic-config-engine/tests/simple-sample-graph.xml index e04f692729f0..5ebbaafd9671 100644 --- a/src/sonic-config-engine/tests/simple-sample-graph.xml +++ b/src/sonic-config-engine/tests/simple-sample-graph.xml @@ -2,6 +2,15 @@ + + switch-t0 + 10.1.0.32 + BGPMonitor + 10.20.30.40 + 30 + 10 + 3 + false switch-t0 @@ -42,6 +51,21 @@ + + 0 + + BGPMonitor + + + BGPPeer +

10.1.0.32
+ + + + + + + 65100 switch-t0 diff --git a/src/sonic-config-engine/tests/t0-sample-graph.xml b/src/sonic-config-engine/tests/t0-sample-graph.xml index bb1a4a4a22f6..180895928fbd 100644 --- a/src/sonic-config-engine/tests/t0-sample-graph.xml +++ b/src/sonic-config-engine/tests/t0-sample-graph.xml @@ -2,6 +2,15 @@ + + switch-t0 + 10.1.0.32 + BGPMonitor + 10.20.30.40 + 30 + 10 + 3 + false switch-t0 @@ -80,6 +89,21 @@ + + 0 + + BGPMonitor + + + BGPPeer +
10.1.0.32
+ + + +
+
+ +
65100 switch-t0 diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index d6544dc063e4..fb85c54cfc90 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -260,3 +260,9 @@ def test_minigraph_vxlan(self): argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "VXLAN_TUNNEL"' output = self.run_script(argument) self.assertEqual(output.strip(), "") + + def test_minigraph_bgp_mon(self): + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "BGP_MONITORS"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{'10.20.30.40': {'rrclient': 0, 'name': 'BGPMonitor', 'local_addr': '10.1.0.32', 'nhopself': 0, 'holdtime': '10', 'asn': '0', 'keepalive': '3'}}") + diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index 71d0c3d7db57..b77f0859584a 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -135,3 +135,9 @@ def test_minigraph_vxlan(self): argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "VXLAN_TUNNEL"' output = self.run_script(argument) self.assertEqual(output.strip(), "") + + def test_minigraph_bgp_mon(self): + argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "BGP_MONITORS"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{}") + From 9726f6c00312dd6d3ab4f5960a95a5017f1f139b Mon Sep 17 00:00:00 2001 From: "Sudharsan D.G" Date: Mon, 7 Oct 2019 16:35:22 -0700 Subject: [PATCH 049/278] [devices]: Adding pre-emphasis for s6000 (#3571) --- .../media_settings.json | 1348 +++++++++++++++++ 1 file changed, 1348 insertions(+) create mode 100644 device/dell/x86_64-dell_s6000_s1220-r0/media_settings.json diff --git a/device/dell/x86_64-dell_s6000_s1220-r0/media_settings.json b/device/dell/x86_64-dell_s6000_s1220-r0/media_settings.json new file mode 100644 index 000000000000..9032a2e53b26 --- /dev/null +++ b/device/dell/x86_64-dell_s6000_s1220-r0/media_settings.json @@ -0,0 +1,1348 @@ +{ + "PORT_MEDIA_SETTINGS": { + "0": { + "Default": { + "preemphasis": { + "lane0":"0xcad0", + "lane1":"0xc6e0", + "lane2":"0xc6e0", + "lane3":"0xd2b0" + }, + "idriver": { + "lane0":"0x5", + "lane1":"0x5", + "lane2":"0x5", + "lane3":"0x5" + }, + "ipredriver": { + "lane0":"0x5", + "lane1":"0x5", + "lane2":"0x5", + "lane3":"0x5" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x5", + "lane1":"0x5", + "lane2":"0x5", + "lane3":"0x5" + }, + "ipredriver": { + "lane0":"0x5", + "lane1":"0x5", + "lane2":"0x5", + "lane3":"0x5" + } + } + }, + "1": { + "Default": { + "preemphasis": { + "lane0":"0xc2f0", + "lane1":"0xd2b0", + "lane2":"0xc6e0", + "lane3":"0xc2f0" + }, + "idriver": { + "lane0":"0x6", + "lane1":"0x7", + "lane2":"0x6", + "lane3":"0x6" + }, + "ipredriver": { + "lane0":"0x6", + "lane1":"0x7", + "lane2":"0x6", + "lane3":"0x6" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x6", + "lane1":"0x7", + "lane2":"0x6", + "lane3":"0x6" + }, + "ipredriver": { + "lane0":"0x6", + "lane1":"0x7", + "lane2":"0x6", + "lane3":"0x6" + } + } + }, + "2": { + "Default": { + "preemphasis": { + "lane0":"0xc6e0", + "lane1":"0xc6e0", + "lane2":"0xc6e0", + "lane3":"0xc6e0" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + } + }, + "3": { + "Default": { + "preemphasis": { + "lane0":"0xcad0", + "lane1":"0xcad0", + "lane2":"0xc2f0", + "lane3":"0xc2f0" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + } + }, + "4": { + "Default": { + "preemphasis": { + "lane0":"0xc2f0", + "lane1":"0xc2f0", + "lane2":"0xc2f0", + "lane3":"0xc2f0" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + } + }, + "5": { + "Default": { + "preemphasis": { + "lane0":"0xc6e0", + "lane1":"0xc2f0", + "lane2":"0xc2f0", + "lane3":"0xcad0" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + } + }, + "6": { + "Default": { + "preemphasis": { + "lane0":"0xc6e0", + "lane1":"0xcad0", + "lane2":"0xc6e0", + "lane3":"0xcad0" + }, + "idriver": { + "lane0":"0x5", + "lane1":"0x5", + "lane2":"0x5", + "lane3":"0x5" + }, + "ipredriver": { + "lane0":"0x5", + "lane1":"0x5", + "lane2":"0x5", + "lane3":"0x5" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x5", + "lane1":"0x5", + "lane2":"0x5", + "lane3":"0x5" + }, + "ipredriver": { + "lane0":"0x5", + "lane1":"0x5", + "lane2":"0x5", + "lane3":"0x5" + } + } + }, + "7": { + "Default": { + "preemphasis": { + "lane0":"0xc6e0", + "lane1":"0xc6e0", + "lane2":"0xc6e0", + "lane3":"0xc6e0" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + } + }, + "8": { + "Default": { + "preemphasis": { + "lane0":"0xb270", + "lane1":"0xbb10", + "lane2":"0xb720", + "lane3":"0xb720" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x3", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x3", + "lane2":"0x2", + "lane3":"0x2" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xea05", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x3", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x3", + "lane2":"0x2", + "lane3":"0x2" + } + } + }, + "9": { + "Default": { + "preemphasis": { + "lane0":"0xc2f0", + "lane1":"0xc6e0", + "lane2":"0xbf00", + "lane3":"0xc2f0" + }, + "idriver": { + "lane0":"0x3", + "lane1":"0x3", + "lane2":"0x3", + "lane3":"0x3" + }, + "ipredriver": { + "lane0":"0x3", + "lane1":"0x3", + "lane2":"0x3", + "lane3":"0x3" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x3", + "lane1":"0x3", + "lane2":"0x3", + "lane3":"0x3" + }, + "ipredriver": { + "lane0":"0x3", + "lane1":"0x3", + "lane2":"0x3", + "lane3":"0x3" + } + } + }, + "10": { + "Default": { + "preemphasis": { + "lane0":"0xb330", + "lane1":"0xbb10", + "lane2":"0xbb10", + "lane3":"0xbb10" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + } + }, + "11": { + "Default": { + "preemphasis": { + "lane0":"0xb330", + "lane1":"0xb330", + "lane2":"0xb330", + "lane3":"0xb330" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + } + }, + "12": { + "Default": { + "preemphasis": { + "lane0":"0xaf40", + "lane1":"0xaf40", + "lane2":"0xaf40", + "lane3":"0xaf40" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + } + }, + "13": { + "Default": { + "preemphasis": { + "lane0":"0xa760", + "lane1":"0xa760", + "lane2":"0xa760", + "lane3":"0xa760" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + } + }, + "14": { + "Default": { + "preemphasis": { + "lane0":"0xa760", + "lane1":"0xa760", + "lane2":"0xa760", + "lane3":"0xa760" + }, + "idriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + }, + "ipredriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + }, + "ipredriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + } + } + }, + "15": { + "Default": { + "preemphasis": { + "lane0":"0xa760", + "lane1":"0xa760", + "lane2":"0xa760", + "lane3":"0xa760" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + } + }, + "16": { + "Default": { + "preemphasis": { + "lane0":"0xa760", + "lane1":"0xa760", + "lane2":"0xa760", + "lane3":"0xa760" + }, + "idriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + }, + "ipredriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + }, + "ipredriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + } + } + }, + "17": { + "Default": { + "preemphasis": { + "lane0":"0xa370", + "lane1":"0xa370", + "lane2":"0xa370", + "lane3":"0xa370" + }, + "idriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + }, + "ipredriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + }, + "ipredriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + } + } + }, + "18": { + "Default": { + "preemphasis": { + "lane0":"0xa760", + "lane1":"0xa760", + "lane2":"0xa760", + "lane3":"0xa760" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + } + }, + "19": { + "Default": { + "preemphasis": { + "lane0":"0xaf40", + "lane1":"0xaf40", + "lane2":"0xaf40", + "lane3":"0xaf40" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + } + }, + "20": { + "Default": { + "preemphasis": { + "lane0":"0xb330", + "lane1":"0xb330", + "lane2":"0xb330", + "lane3":"0xbff0" + }, + "idriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x2" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x2" + } + } + }, + "21": { + "Default": { + "preemphasis": { + "lane0":"0xb330", + "lane1":"0xb330", + "lane2":"0xb330", + "lane3":"0xb330" + }, + "idriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + }, + "ipredriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + }, + "ipredriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + } + } + }, + "22": { + "Default": { + "preemphasis": { + "lane0":"0xbb10", + "lane1":"0xbb10", + "lane2":"0xbb10", + "lane3":"0xc2f0" + }, + "idriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + }, + "ipredriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + }, + "ipredriver": { + "lane0":"0x1", + "lane1":"0x1", + "lane2":"0x1", + "lane3":"0x1" + } + } + }, + "23": { + "Default": { + "preemphasis": { + "lane0":"0xc6e0", + "lane1":"0xc6e0", + "lane2":"0xc6e0", + "lane3":"0xc6e0" + }, + "idriver": { + "lane0":"0x3", + "lane1":"0x5", + "lane2":"0x3", + "lane3":"0x3" + }, + "ipredriver": { + "lane0":"0x3", + "lane1":"0x5", + "lane2":"0x3", + "lane3":"0x3" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x3", + "lane1":"0x5", + "lane2":"0x3", + "lane3":"0x3" + }, + "ipredriver": { + "lane0":"0x3", + "lane1":"0x5", + "lane2":"0x3", + "lane3":"0x3" + } + } + }, + "24": { + "Default": { + "preemphasis": { + "lane0":"0xc6e0", + "lane1":"0xc6e0", + "lane2":"0xc6e0", + "lane3":"0xcec0" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + } + }, + "25": { + "Default": { + "preemphasis": { + "lane0":"0xc6e0", + "lane1":"0xc6e0", + "lane2":"0xc6e0", + "lane3":"0xc6c0" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + } + }, + "26": { + "Default": { + "preemphasis": { + "lane0":"0xbb10", + "lane1":"0xbb10", + "lane2":"0xbf00", + "lane3":"0xbb10" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + }, + "ipredriver": { + "lane0":"0x2", + "lane1":"0x2", + "lane2":"0x2", + "lane3":"0x2" + } + } + }, + "27": { + "Default": { + "preemphasis": { + "lane0":"0xc2f0", + "lane1":"0xc6e0", + "lane2":"0xc6e0", + "lane3":"0xc6e0" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x5", + "lane2":"0x4", + "lane3":"0x5" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x5", + "lane2":"0x4", + "lane3":"0x5" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x5", + "lane2":"0x4", + "lane3":"0x5" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x5", + "lane2":"0x4", + "lane3":"0x5" + } + } + }, + "28": { + "Default": { + "preemphasis": { + "lane0":"0xc2f0", + "lane1":"0xc2f0", + "lane2":"0xc2f0", + "lane3":"0xc2f0" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xe225", + "lane1":"0xe225", + "lane2":"0xe225", + "lane3":"0xe225" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + } + }, + "29": { + "Default": { + "preemphasis": { + "lane0":"0xcad0", + "lane1":"0xc6e0", + "lane2":"0xc6e0", + "lane3":"0xc6e0" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + }, + "ipredriver": { + "lane0":"0x4", + "lane1":"0x4", + "lane2":"0x4", + "lane3":"0x4" + } + } + }, + "30": { + "Default": { + "preemphasis": { + "lane0":"0xcec0", + "lane1":"0xcec0", + "lane2":"0xcad0", + "lane3":"0xc6e0" + }, + "idriver": { + "lane0":"0x6", + "lane1":"0x6", + "lane2":"0x6", + "lane3":"0x7" + }, + "ipredriver": { + "lane0":"0x6", + "lane1":"0x6", + "lane2":"0x6", + "lane3":"0x7" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x6", + "lane1":"0x6", + "lane2":"0x6", + "lane3":"0x7" + }, + "ipredriver": { + "lane0":"0x6", + "lane1":"0x6", + "lane2":"0x6", + "lane3":"0x7" + } + } + }, + "31": { + "Default": { + "preemphasis": { + "lane0":"0xcad0", + "lane1":"0xcad0", + "lane2":"0xcad0", + "lane3":"0xcad0" + }, + "idriver": { + "lane0":"0x5", + "lane1":"0x5", + "lane2":"0x5", + "lane3":"0x5" + }, + "ipredriver": { + "lane0":"0x5", + "lane1":"0x5", + "lane2":"0x5", + "lane3":"0x5" + } + }, + "QSFP+-40GBASE-CR4-3M": { + "preemphasis": { + "lane0":"0xea05", + "lane1":"0xea05", + "lane2":"0xea05", + "lane3":"0xea05" + }, + "idriver": { + "lane0":"0x5", + "lane1":"0x5", + "lane2":"0x5", + "lane3":"0x5" + }, + "ipredriver": { + "lane0":"0x5", + "lane1":"0x5", + "lane2":"0x5", + "lane3":"0x5" + } + } + } + } +} From ce2ecf26805d7b7314393cd59823fb131df3e059 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Tue, 8 Oct 2019 07:30:27 -0700 Subject: [PATCH 050/278] [frr]: Update frr version to 7.1 (#3575) * Build 7.1 without patches * Port patches --- .gitmodules | 2 +- rules/frr.mk | 2 +- src/sonic-frr/Makefile | 4 +- src/sonic-frr/frr | 2 +- ...01-Add-support-of-bgp-tcp-DSCP-value.patch | 28 ++-- ...verity-of-Vty-connected-from-message.patch | 10 +- ...xthop-attribute-when-NLRI-is-present.patch | 156 ------------------ ...EXT_HOP-to-be-0.0.0.0-due-to-allevia.patch | 12 +- src/sonic-frr/patch/0005-Support-VRF.patch | 12 +- src/sonic-frr/patch/series | 1 - 10 files changed, 36 insertions(+), 193 deletions(-) delete mode 100644 src/sonic-frr/patch/0003-ignore-nexthop-attribute-when-NLRI-is-present.patch diff --git a/.gitmodules b/.gitmodules index 3d2a8e3f7a1d..d02ee6fb942b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -47,7 +47,7 @@ [submodule "src/sonic-frr/frr"] path = src/sonic-frr/frr url = https://github.com/Azure/sonic-frr.git - branch = frr/7.0 + branch = frr/7.1 [submodule "platform/p4/p4-hlir/p4-hlir-v1.1"] path = platform/p4/p4-hlir/p4-hlir-v1.1 url = https://github.com/p4lang/p4-hlir.git diff --git a/rules/frr.mk b/rules/frr.mk index a14d398f89a1..83c359992ac3 100644 --- a/rules/frr.mk +++ b/rules/frr.mk @@ -1,6 +1,6 @@ # FRRouting (frr) package -FRR_VERSION = 7.0.1 +FRR_VERSION = 7.1 FRR_SUBVERSION = 0 export FRR_VERSION FRR_SUBVERSION diff --git a/src/sonic-frr/Makefile b/src/sonic-frr/Makefile index e7c13a1f8b6f..4a31f23436ec 100644 --- a/src/sonic-frr/Makefile +++ b/src/sonic-frr/Makefile @@ -9,14 +9,14 @@ BRANCH = $(shell date +%Y%m%d\.%H%M%S) $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : # Build the package pushd ./frr - git checkout -b $(BRANCH) origin/frr/7.0 + git checkout -b $(BRANCH) origin/frr/7.1 stg init stg import -s ../patch/series tools/tarsource.sh -V -e '-sonic' dpkg-buildpackage -rfakeroot -b -us -uc -Ppkg.frr.nortrlib -j$(SONIC_CONFIG_MAKE_JOBS) stg undo git clean -xfdf - git checkout frr/7.0 + git checkout frr/7.1 git branch -D $(BRANCH) popd mv $(DERIVED_TARGET) $* $(DEST)/ diff --git a/src/sonic-frr/frr b/src/sonic-frr/frr index cd305c0973be..8c5e037c4960 160000 --- a/src/sonic-frr/frr +++ b/src/sonic-frr/frr @@ -1 +1 @@ -Subproject commit cd305c0973be0baa1173e09f9d72e096c03e7e7e +Subproject commit 8c5e037c496025597406f496010d6ef6b1d2e73d diff --git a/src/sonic-frr/patch/0001-Add-support-of-bgp-tcp-DSCP-value.patch b/src/sonic-frr/patch/0001-Add-support-of-bgp-tcp-DSCP-value.patch index e9f496d7af62..c7676fd65cb4 100644 --- a/src/sonic-frr/patch/0001-Add-support-of-bgp-tcp-DSCP-value.patch +++ b/src/sonic-frr/patch/0001-Add-support-of-bgp-tcp-DSCP-value.patch @@ -1,7 +1,7 @@ -From ef017a613691a40f32cdaa5396bbd4889b1cb647 Mon Sep 17 00:00:00 2001 +From ab8ae984def8ee5cea22f802b2a60a05214c11d2 Mon Sep 17 00:00:00 2001 From: Pavel Shirshov -Date: Fri, 14 Jun 2019 17:45:31 -0700 -Subject: [PATCH] Add support of bgp tcp DSCP value +Date: Mon, 7 Oct 2019 17:00:15 -0700 +Subject: [PATCH 1/1] Add support of bgp tcp DSCP value --- bgpd/bgp_network.c | 11 ++++------- @@ -11,10 +11,10 @@ Subject: [PATCH] Add support of bgp tcp DSCP value 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c -index 4153da5a6..fed133eb7 100644 +index 6a5c2c4b3..9ec162aa4 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c -@@ -569,11 +569,9 @@ int bgp_connect(struct peer *peer) +@@ -627,11 +627,9 @@ int bgp_connect(struct peer *peer) #ifdef IPTOS_PREC_INTERNETCONTROL frr_elevate_privs(&bgpd_privs) { if (sockunion_family(&peer->su) == AF_INET) @@ -28,7 +28,7 @@ index 4153da5a6..fed133eb7 100644 } #endif -@@ -643,10 +641,9 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen, +@@ -707,10 +705,9 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen, #ifdef IPTOS_PREC_INTERNETCONTROL if (sa->sa_family == AF_INET) @@ -42,10 +42,10 @@ index 4153da5a6..fed133eb7 100644 sockopt_v6only(sa->sa_family, sock); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c -index 7445df883..f91b908a4 100644 +index d05432327..a15a0f526 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c -@@ -1113,6 +1113,42 @@ DEFUN (no_router_bgp, +@@ -1139,6 +1139,42 @@ DEFUN (no_router_bgp, return CMD_SUCCESS; } @@ -88,7 +88,7 @@ index 7445df883..f91b908a4 100644 /* BGP router-id. */ -@@ -12798,6 +12834,10 @@ void bgp_vty_init(void) +@@ -12929,6 +12965,10 @@ void bgp_vty_init(void) /* "no router bgp" commands. */ install_element(CONFIG_NODE, &no_router_bgp_cmd); @@ -100,10 +100,10 @@ index 7445df883..f91b908a4 100644 install_element(BGP_NODE, &bgp_router_id_cmd); install_element(BGP_NODE, &no_bgp_router_id_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c -index 6fb3a70c7..503e6b4ed 100644 +index 8c0b5336e..55aeb2dd8 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c -@@ -2995,7 +2995,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, +@@ -3040,7 +3040,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->evpn_info = XCALLOC(MTYPE_BGP_EVPN_INFO, sizeof(struct bgp_evpn_info)); @@ -112,7 +112,7 @@ index 6fb3a70c7..503e6b4ed 100644 bgp_evpn_init(bgp); bgp_pbr_init(bgp); return bgp; -@@ -7516,6 +7516,9 @@ int bgp_config_write(struct vty *vty) +@@ -7629,6 +7629,9 @@ int bgp_config_write(struct vty *vty) if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) vty_out(vty, " no bgp fast-external-failover\n"); @@ -123,10 +123,10 @@ index 6fb3a70c7..503e6b4ed 100644 if (bgp->router_id_static.s_addr != 0) vty_out(vty, " bgp router-id %s\n", diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h -index df3fde840..a6546457c 100644 +index b0f656753..32983a0a9 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h -@@ -553,6 +553,9 @@ struct bgp { +@@ -569,6 +569,9 @@ struct bgp { /* Count of peers in established state */ uint32_t established_peers; diff --git a/src/sonic-frr/patch/0002-Reduce-severity-of-Vty-connected-from-message.patch b/src/sonic-frr/patch/0002-Reduce-severity-of-Vty-connected-from-message.patch index ae2b3ba91223..9ec7b980ae84 100644 --- a/src/sonic-frr/patch/0002-Reduce-severity-of-Vty-connected-from-message.patch +++ b/src/sonic-frr/patch/0002-Reduce-severity-of-Vty-connected-from-message.patch @@ -1,17 +1,17 @@ -From 87760a6a04d6ffbcc7a1093549bfb76656002b61 Mon Sep 17 00:00:00 2001 +From 5a30a4e91a91f8e19c69ef219cd6d8b19e9b6fae Mon Sep 17 00:00:00 2001 From: Pavel Shirshov -Date: Fri, 14 Jun 2019 17:48:50 -0700 -Subject: [PATCH] Reduce severity of 'Vty connected from' message +Date: Mon, 7 Oct 2019 17:06:27 -0700 +Subject: [PATCH 1/1] Reduce severity of 'Vty connected from' message --- lib/vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vty.c b/lib/vty.c -index 8450922c2..f159d1b4b 100644 +index b1ed3d63c..5aa4b56cb 100644 --- a/lib/vty.c +++ b/lib/vty.c -@@ -1875,7 +1875,7 @@ static int vty_accept(struct thread *thread) +@@ -1870,7 +1870,7 @@ static int vty_accept(struct thread *thread) zlog_info("can't set sockopt to vty_sock : %s", safe_strerror(errno)); diff --git a/src/sonic-frr/patch/0003-ignore-nexthop-attribute-when-NLRI-is-present.patch b/src/sonic-frr/patch/0003-ignore-nexthop-attribute-when-NLRI-is-present.patch deleted file mode 100644 index 5d55ce547fd1..000000000000 --- a/src/sonic-frr/patch/0003-ignore-nexthop-attribute-when-NLRI-is-present.patch +++ /dev/null @@ -1,156 +0,0 @@ -From 7c31178d8f1b8cc3a9627dc7c7bd1d2a51fe54ce Mon Sep 17 00:00:00 2001 -From: Pavel Shirshov -Date: Tue, 18 Jun 2019 15:27:19 -0700 -Subject: [PATCH] ignore nexthop attribute when NLRI is present - -Backport of https://github.com/FRRouting/frr/pull/4258 ---- - bgpd/bgp_attr.c | 73 ++++++++++++++++++++++++++++++----------------- - bgpd/bgp_attr.h | 3 ++ - bgpd/bgp_packet.c | 11 +++++++ - 3 files changed, 61 insertions(+), 26 deletions(-) - -diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c -index 05e103142..ea7f761ab 100644 ---- a/bgpd/bgp_attr.c -+++ b/bgpd/bgp_attr.c -@@ -1257,6 +1257,32 @@ static int bgp_attr_as4_path(struct bgp_attr_parser_args *args, - return BGP_ATTR_PARSE_PROCEED; - } - -+/* -+ * Check that the nexthop attribute is valid. -+ */ -+bgp_attr_parse_ret_t -+bgp_attr_nexthop_valid(struct peer *peer, struct attr *attr) -+{ -+ in_addr_t nexthop_h; -+ -+ nexthop_h = ntohl(attr->nexthop.s_addr); -+ if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h) -+ || IPV4_CLASS_DE(nexthop_h)) -+ && !BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) { -+ char buf[INET_ADDRSTRLEN]; -+ -+ inet_ntop(AF_INET, &attr->nexthop.s_addr, buf, -+ INET_ADDRSTRLEN); -+ flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s", -+ buf); -+ bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, -+ BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP); -+ return BGP_ATTR_PARSE_ERROR; -+ } -+ -+ return BGP_ATTR_PARSE_PROCEED; -+} -+ - /* Nexthop attribute. */ - static bgp_attr_parse_ret_t bgp_attr_nexthop(struct bgp_attr_parser_args *args) - { -@@ -1264,8 +1290,6 @@ static bgp_attr_parse_ret_t bgp_attr_nexthop(struct bgp_attr_parser_args *args) - struct attr *const attr = args->attr; - const bgp_size_t length = args->length; - -- in_addr_t nexthop_h, nexthop_n; -- - /* Check nexthop attribute length. */ - if (length != 4) { - flog_err(EC_BGP_ATTR_LEN, -@@ -1275,30 +1299,7 @@ static bgp_attr_parse_ret_t bgp_attr_nexthop(struct bgp_attr_parser_args *args) - args->total); - } - -- /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP -- attribute must result in a NOTIFICATION message (this is implemented -- below). -- At the same time, semantically incorrect NEXT_HOP is more likely to -- be just -- logged locally (this is implemented somewhere else). The UPDATE -- message -- gets ignored in any of these cases. */ -- nexthop_n = stream_get_ipv4(peer->curr); -- nexthop_h = ntohl(nexthop_n); -- if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h) -- || IPV4_CLASS_DE(nexthop_h)) -- && !BGP_DEBUG( -- allow_martians, -- ALLOW_MARTIANS)) /* loopbacks may be used in testing */ -- { -- char buf[INET_ADDRSTRLEN]; -- inet_ntop(AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN); -- flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s", buf); -- return bgp_attr_malformed( -- args, BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, args->total); -- } -- -- attr->nexthop.s_addr = nexthop_n; -+ attr->nexthop.s_addr = stream_get_ipv4(peer->curr); - attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); - - return BGP_ATTR_PARSE_PROCEED; -@@ -2669,6 +2670,26 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr, - return BGP_ATTR_PARSE_ERROR; - } - -+ /* -+ * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect, -+ * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute. -+ * This is implemented below and will result in a NOTIFICATION. If the -+ * NEXT_HOP attribute is semantically incorrect, the error SHOULD be -+ * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION -+ * message SHOULD NOT be sent. This is implemented elsewhere. -+ * -+ * RFC4760: An UPDATE message that carries no NLRI, other than the one -+ * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP -+ * attribute. If such a message contains the NEXT_HOP attribute, the BGP -+ * speaker that receives the message SHOULD ignore this attribute. -+ */ -+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) -+ && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI))) { -+ if (bgp_attr_nexthop_valid(peer, attr) < 0) { -+ return BGP_ATTR_PARSE_ERROR; -+ } -+ } -+ - /* Check all mandatory well-known attributes are present */ - if ((ret = bgp_attr_check(peer, attr)) < 0) { - if (as4_path) -diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h -index 47a4182fe..a86684583 100644 ---- a/bgpd/bgp_attr.h -+++ b/bgpd/bgp_attr.h -@@ -350,6 +350,9 @@ extern void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, - uint32_t, int, uint32_t, struct attr *); - extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt); - -+extern bgp_attr_parse_ret_t bgp_attr_nexthop_valid(struct peer *peer, -+ struct attr *attr); -+ - static inline int bgp_rmap_nhop_changed(uint32_t out_rmap_flags, - uint32_t in_rmap_flags) - { -diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c -index fe8a1a256..13f4cf436 100644 ---- a/bgpd/bgp_packet.c -+++ b/bgpd/bgp_packet.c -@@ -1533,6 +1533,17 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) - nlris[NLRI_UPDATE].nlri = stream_pnt(s); - nlris[NLRI_UPDATE].length = update_len; - stream_forward_getp(s, update_len); -+ -+ if (CHECK_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI))) { -+ /* -+ * We skipped nexthop attribute validation earlier so -+ * validate the nexthop now. -+ */ -+ if (bgp_attr_nexthop_valid(peer, &attr) < 0) { -+ bgp_attr_unintern_sub(&attr); -+ return BGP_Stop; -+ } -+ } - } - - if (BGP_DEBUG(update, UPDATE_IN)) --- -2.17.1.windows.2 - diff --git a/src/sonic-frr/patch/0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch b/src/sonic-frr/patch/0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch index 22cf08b82cd4..cb3c30c781d2 100644 --- a/src/sonic-frr/patch/0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch +++ b/src/sonic-frr/patch/0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch @@ -1,18 +1,18 @@ -From 4cd83e56e4f67fdc06325d92a82534fb4cb69952 Mon Sep 17 00:00:00 2001 +From 9fa0ffcc8f9ec987af527e911cd748014aeacffe Mon Sep 17 00:00:00 2001 From: Pavel Shirshov -Date: Thu, 20 Jun 2019 15:35:50 -0700 -Subject: [PATCH] Allow BGP attr NEXT_HOP to be 0.0.0.0 due to alleviate the - vendor bug +Date: Mon, 7 Oct 2019 17:15:15 -0700 +Subject: [PATCH 1/1] Allow BGP attr NEXT_HOP to be 0.0.0.0 due to alleviate + the vendor bug --- bgpd/bgp_route.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c -index 38f3cad5a..55240eab8 100644 +index f8eae135e..732115756 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c -@@ -2873,8 +2873,7 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, +@@ -2904,8 +2904,7 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, /* If NEXT_HOP is present, validate it. */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { diff --git a/src/sonic-frr/patch/0005-Support-VRF.patch b/src/sonic-frr/patch/0005-Support-VRF.patch index c6de0e5ecf0e..8d6689e5240a 100644 --- a/src/sonic-frr/patch/0005-Support-VRF.patch +++ b/src/sonic-frr/patch/0005-Support-VRF.patch @@ -1,14 +1,14 @@ -From 81990d9aafdfd459c0caa6cf07501fa628ada454 Mon Sep 17 00:00:00 2001 -From: Tyler Li -Date: Mon, 3 Jun 2019 01:48:11 -0700 -Subject: [PATCH] Support VRF +From b7ae4e11c2dc14f9208b62ea060bb5ecbf4cddb2 Mon Sep 17 00:00:00 2001 +From: Pavel Shirshov +Date: Mon, 7 Oct 2019 17:17:54 -0700 +Subject: [PATCH 1/1] Support VRF --- zebra/zebra_fpm_netlink.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c -index 207cbc099..b98c6886b 100644 +index 88f0c3250..29f07f801 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -327,7 +327,12 @@ static int netlink_route_info_encode(netlink_route_info_t *ri, char *in_buf, @@ -26,5 +26,5 @@ index 207cbc099..b98c6886b 100644 req->r.rtm_protocol = ri->rtm_protocol; req->r.rtm_scope = RT_SCOPE_UNIVERSE; -- -2.11.0 +2.17.1.windows.2 diff --git a/src/sonic-frr/patch/series b/src/sonic-frr/patch/series index 4033e555fe7f..dc5eaa2fcd36 100644 --- a/src/sonic-frr/patch/series +++ b/src/sonic-frr/patch/series @@ -1,5 +1,4 @@ 0001-Add-support-of-bgp-tcp-DSCP-value.patch 0002-Reduce-severity-of-Vty-connected-from-message.patch -0003-ignore-nexthop-attribute-when-NLRI-is-present.patch 0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch 0005-Support-VRF.patch From aec24770602477102e737ea5fa8192e00a7d6961 Mon Sep 17 00:00:00 2001 From: Stepan Blyshchak <38952541+stepanblyschak@users.noreply.github.com> Date: Tue, 8 Oct 2019 17:57:13 +0300 Subject: [PATCH 051/278] [mellanox] build SDK driver from open source (#3580) * build SDK driver package sx-kernel from open sourced repository Mellanox/Switch-SDK-driver * copy SDK packages and FW binaries from Mellanox/Switch-SDK-driver Signed-off-by: Stepan Blyschak --- .gitmodules | 3 +++ platform/mellanox/.gitignore | 1 + platform/mellanox/fw.mk | 22 ++++++++++++++++--- platform/mellanox/sdk-src/sx-kernel/Makefile | 12 +++++++--- .../sdk-src/sx-kernel/Switch-SDK-drivers | 1 + platform/mellanox/sdk.mk | 18 ++++++++------- 6 files changed, 43 insertions(+), 14 deletions(-) create mode 160000 platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers diff --git a/.gitmodules b/.gitmodules index d02ee6fb942b..08546d46073a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -66,3 +66,6 @@ [submodule "platform/mellanox/mlnx-sai/SAI-Implementation"] path = platform/mellanox/mlnx-sai/SAI-Implementation url = https://github.com/Mellanox/SAI-Implementation +[submodule "Switch-SDK-drivers"] + path = platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers + url = https://github.com/Mellanox/Switch-SDK-drivers diff --git a/platform/mellanox/.gitignore b/platform/mellanox/.gitignore index 74751518db24..1f3d15d640d4 100644 --- a/platform/mellanox/.gitignore +++ b/platform/mellanox/.gitignore @@ -8,6 +8,7 @@ mft/* !mft/Makefile sdk-src/*/* !sdk-src/*/Makefile +!sdk-src/sx-kernel/Switch-SDK-drivers/ !sdk-src/*/*.patch */build */deb_dist diff --git a/platform/mellanox/fw.mk b/platform/mellanox/fw.mk index 6e9a285cc1ce..0ad1b05137ae 100644 --- a/platform/mellanox/fw.mk +++ b/platform/mellanox/fw.mk @@ -1,16 +1,32 @@ # mellanox firmware -MLNX_FW_BASE_URL = $(MLNX_SDK_BASE_URL) +MLNX_FW_BASE_PATH = $(MLNX_SDK_BASE_PATH) + +# Place an URL here to FW if you want to download FW instead +MLNX_FW_BASE_URL = + +ifneq ($(MLNX_FW_BASE_URL), ) +FW_FROM_URL = y +else +FW_FROM_URL = n +endif + MLNX_SPC_FW_VERSION = 13.2000.2162 MLNX_SPC_FW_FILE = fw-SPC-rel-$(subst .,_,$(MLNX_SPC_FW_VERSION))-EVB.mfa +$(MLNX_SPC_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC_FW_FILE) -SONIC_ONLINE_FILES += $(MLNX_SPC_FW_FILE) MLNX_SPC2_FW_VERSION = 29.2000.2162 MLNX_SPC2_FW_FILE = fw-SPC2-rel-$(subst .,_,$(MLNX_SPC2_FW_VERSION))-EVB.mfa +$(MLNX_SPC2_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC2_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC2_FW_FILE) -SONIC_ONLINE_FILES += $(MLNX_SPC2_FW_FILE) + +ifeq ($(FW_FROM_URL),n) +SONIC_COPY_FILES += $(MLNX_SPC_FW_FILE) $(MLNX_SPC2_FW_FILE) +else +SONIC_ONLINE_FILES += $(MLNX_SPC_FW_FILE) $(MLNX_SPC2_FW_FILE) +endif export MLNX_SPC_FW_VERSION export MLNX_SPC_FW_FILE diff --git a/platform/mellanox/sdk-src/sx-kernel/Makefile b/platform/mellanox/sdk-src/sx-kernel/Makefile index 35ce9432a37c..9e979879fef8 100644 --- a/platform/mellanox/sdk-src/sx-kernel/Makefile +++ b/platform/mellanox/sdk-src/sx-kernel/Makefile @@ -7,12 +7,18 @@ PACKAGE_NAME = sx_kernel $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : # get sources - rm -rf sx_kernel-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) - wget -c $(MLNX_SDK_SOURCE_BASE_URL)/$(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION).tar.gz -O - | tar -xz + if [ ! -z "$(MLNX_SDK_SOURCE_BASE_URL)" ]; then + rm -rf sx_kernel-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + wget -c $(MLNX_SDK_SOURCE_BASE_URL)/$(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION).tar.gz -O - | tar -xz + pushd sx_kernel-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + else + pushd Switch-SDK-drivers + git reset --hard + git clean -xfd + fi # build - pushd sx_kernel-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) patch -p1 < ../sx_kernel_makefile_sonic_build.patch debuild -e KVERSION=$(KVERSION) -e KSRC_EXT=/lib/modules/$(KVERSION)/source/ -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) diff --git a/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers b/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers new file mode 160000 index 000000000000..3acd88b3e04e --- /dev/null +++ b/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers @@ -0,0 +1 @@ +Subproject commit 3acd88b3e04ec09e5fb7e2b74ed94540a9fea21e diff --git a/platform/mellanox/sdk.mk b/platform/mellanox/sdk.mk index 3cf3ee3ff976..779e072e3613 100644 --- a/platform/mellanox/sdk.mk +++ b/platform/mellanox/sdk.mk @@ -1,4 +1,4 @@ -MLNX_SDK_BASE_URL = https://github.com/Mellanox/SAI-Implementation/raw/350187a41e408daaf03380401a0a2351b6cb0f9e/sdk +MLNX_SDK_BASE_PATH = $(PLATFORM_PATH)/sdk-src/sx-kernel/Switch-SDK-drivers/bin/ MLNX_SDK_VERSION = 4.3.2104 MLNX_SDK_ISSU_VERSION = 101 @@ -135,19 +135,21 @@ $(SX_KERNEL)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/sx-kernel SX_KERNEL_DEV = sx-kernel-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(eval $(call add_derived_package,$(SX_KERNEL),$(SX_KERNEL_DEV))) -define make_url - $(1)_URL = $(MLNX_SDK_BASE_URL)/$(1) +define make_path + $(1)_PATH = $(MLNX_SDK_BASE_PATH) endef -$(eval $(foreach deb,$(MLNX_SDK_DEBS),$(call make_url,$(deb)))) -$(eval $(foreach deb,$(MLNX_SDK_RDEBS),$(call make_url,$(deb)))) -$(eval $(foreach deb,$(PYTHON_SDK_API) $(SX_KERNEL) $(SX_KERNEL_DEV),$(call make_url,$(deb)))) +$(eval $(foreach deb,$(MLNX_SDK_DEBS),$(call make_path,$(deb)))) +$(eval $(foreach deb,$(MLNX_SDK_RDEBS),$(call make_path,$(deb)))) +$(eval $(foreach deb,$(PYTHON_SDK_API) $(SX_KERNEL) $(SX_KERNEL_DEV),$(call make_path,$(deb)))) + +SONIC_MAKE_DEBS += $(SX_KERNEL) ifeq ($(SDK_FROM_SRC), y) -SONIC_MAKE_DEBS += $(MLNX_SDK_RDEBS) $(PYTHON_SDK_API) $(SX_KERNEL) +SONIC_MAKE_DEBS += $(MLNX_SDK_RDEBS) $(PYTHON_SDK_API) else -SONIC_ONLINE_DEBS += $(MLNX_SDK_RDEBS) $(PYTHON_SDK_API) $(SX_KERNEL) +SONIC_COPY_DEBS += $(MLNX_SDK_RDEBS) $(PYTHON_SDK_API) endif SONIC_STRETCH_DEBS += $(SX_KERNEL) From 350d2c5d2b5171e61ba1c1f96d3dfe7c0039a496 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Wed, 9 Oct 2019 00:26:35 +0800 Subject: [PATCH 052/278] [chassis.py] Fix issue in get_change_event: the returned dictionary doesn't contain 'sfp' key. (#3568) --- platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index 814c7aca8178..02d898822817 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -523,4 +523,4 @@ def get_change_event(self, timeout=0): i = i + 1 return True, {'sfp':port_dict} else: - return True, {} + return True, {'sfp':{}} From 28c358b4915177dbd6de4bc21e8e9757d08be0a3 Mon Sep 17 00:00:00 2001 From: byu343 Date: Tue, 8 Oct 2019 12:05:24 -0700 Subject: [PATCH 053/278] Add hwSku Arista-7280CR3-C28S8 (#3574) --- ...jr2-a7280cr3-32p4-28x100G-8x10G.config.bcm | 737 ++++++++++++++++++ .../Arista-7280CR3-C28S8/port_config.ini | 37 + .../Arista-7280CR3-C28S8/sai.profile | 1 + 3 files changed, 775 insertions(+) create mode 100644 device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/jr2-a7280cr3-32p4-28x100G-8x10G.config.bcm create mode 100644 device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/port_config.ini create mode 100644 device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/sai.profile diff --git a/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/jr2-a7280cr3-32p4-28x100G-8x10G.config.bcm b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/jr2-a7280cr3-32p4-28x100G-8x10G.config.bcm new file mode 100644 index 000000000000..3c0a0ee443a4 --- /dev/null +++ b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/jr2-a7280cr3-32p4-28x100G-8x10G.config.bcm @@ -0,0 +1,737 @@ +soc_family.BCM8869X=BCM8869X + +custom_feature_ucode_path=u_code_db2pem.txt +system_headers_mode=1 +suppress_unknown_prop_warnings=1 +l4_protocols_load_balancing_enable=1 +fabric_logical_port_base=512 +trunk_group_max_members=128 +num_olp_tm_ports.BCM8869X=1 + +ucode_port_0.BCM8869X=CPU.0:core_0.0 +ucode_port_200.BCM8869X=CPU.8:core_1.200 +ucode_port_201.BCM8869X=CPU.16:core_0.201 +ucode_port_202.BCM8869X=CPU.24:core_1.202 +ucode_port_203.BCM8869X=CPU.32:core_0.203 + +port_init_speed_xe.BCM8869X=10000 +port_init_speed_xl.BCM8869X=40000 +port_init_speed_le.BCM8869X=50000 +port_init_speed_ce.BCM8869X=100000 +port_init_speed_cc.BCM8869X=200000 +port_init_speed_cd.BCM8869X=400000 +port_init_speed_il.BCM8869X=10312 + +port_init_cl72=0 + +serdes_tx_taps_1=pam4:-16:64:0:3:0:0 +serdes_tx_taps_2=pam4:-16:64:0:3:0:0 +serdes_tx_taps_3=pam4:-16:64:0:3:0:0 +serdes_tx_taps_4=pam4:-16:64:0:3:0:0 +serdes_tx_taps_5=pam4:-16:64:0:3:0:0 +serdes_tx_taps_6=pam4:-16:64:0:3:0:0 +serdes_tx_taps_7=pam4:-16:64:0:3:0:0 +serdes_tx_taps_8=pam4:-16:64:0:3:0:0 +serdes_tx_taps_9=pam4:-8:60:0:0:0:0 +serdes_tx_taps_10=pam4:-8:60:0:0:0:0 +serdes_tx_taps_11=pam4:-8:60:0:0:0:0 +serdes_tx_taps_12=pam4:-8:60:0:0:0:0 +serdes_tx_taps_13=pam4:-8:60:0:0:0:0 +serdes_tx_taps_14=pam4:-8:60:0:0:0:0 +serdes_tx_taps_15=pam4:-8:60:0:0:0:0 +serdes_tx_taps_16=pam4:-8:60:0:0:0:0 +serdes_tx_taps_17=pam4:-8:60:0:0:0:0 +serdes_tx_taps_18=pam4:-8:60:0:0:0:0 +serdes_tx_taps_19=pam4:-8:60:0:0:0:0 +serdes_tx_taps_20=pam4:-8:60:0:0:0:0 +serdes_tx_taps_21=pam4:-8:60:0:0:0:0 +serdes_tx_taps_22=pam4:-8:60:0:0:0:0 +serdes_tx_taps_23=pam4:-8:60:0:0:0:0 +serdes_tx_taps_24=pam4:-8:60:0:0:0:0 +serdes_tx_taps_25=pam4:-8:60:0:0:0:0 +serdes_tx_taps_26=pam4:-8:60:0:0:0:0 +serdes_tx_taps_27=pam4:-8:60:0:0:0:0 +serdes_tx_taps_28=pam4:-8:60:0:0:0:0 +serdes_tx_taps_29=nrz:0:127:0:0:0:0 +serdes_tx_taps_30=nrz:0:127:0:0:0:0 +serdes_tx_taps_31=nrz:0:127:0:0:0:0 +serdes_tx_taps_32=nrz:0:127:0:0:0:0 +serdes_tx_taps_33=nrz:0:127:0:0:0:0 +serdes_tx_taps_34=nrz:0:127:0:0:0:0 +serdes_tx_taps_35=nrz:0:127:0:0:0:0 +serdes_tx_taps_36=nrz:0:127:0:0:0:0 + +ucode_port_100.BCM8869X=RCY_MIRROR.0:core_0.100 +ucode_port_101.BCM8869X=RCY_MIRROR.1:core_0.101 +ucode_port_102.BCM8869X=RCY_MIRROR.2:core_0.102 +ucode_port_103.BCM8869X=RCY_MIRROR.3:core_0.103 +ucode_port_104.BCM8869X=RCY_MIRROR.4:core_0.104 +ucode_port_105.BCM8869X=RCY_MIRROR.5:core_0.105 +ucode_port_106.BCM8869X=RCY_MIRROR.6:core_0.106 +ucode_port_107.BCM8869X=RCY_MIRROR.7:core_0.107 +ucode_port_108.BCM8869X=RCY_MIRROR.8:core_0.108 +ucode_port_109.BCM8869X=RCY_MIRROR.9:core_0.109 +ucode_port_110.BCM8869X=RCY_MIRROR.10:core_0.110 +ucode_port_111.BCM8869X=RCY_MIRROR.11:core_0.111 +ucode_port_112.BCM8869X=RCY_MIRROR.12:core_0.112 +ucode_port_113.BCM8869X=RCY_MIRROR.13:core_0.113 +ucode_port_114.BCM8869X=RCY_MIRROR.14:core_0.114 +ucode_port_115.BCM8869X=RCY_MIRROR.15:core_0.115 +ucode_port_116.BCM8869X=RCY_MIRROR.16:core_0.116 +ucode_port_117.BCM8869X=RCY_MIRROR.17:core_0.117 +ucode_port_118.BCM8869X=RCY_MIRROR.18:core_0.118 +ucode_port_119.BCM8869X=RCY_MIRROR.19:core_0.119 +ucode_port_120.BCM8869X=RCY_MIRROR.0:core_1.120 +ucode_port_121.BCM8869X=RCY_MIRROR.1:core_1.121 +ucode_port_122.BCM8869X=RCY_MIRROR.2:core_1.122 +ucode_port_123.BCM8869X=RCY_MIRROR.3:core_1.123 +ucode_port_124.BCM8869X=RCY_MIRROR.4:core_1.124 +ucode_port_125.BCM8869X=RCY_MIRROR.5:core_1.125 +ucode_port_126.BCM8869X=RCY_MIRROR.6:core_1.126 +ucode_port_127.BCM8869X=RCY_MIRROR.7:core_1.127 +ucode_port_128.BCM8869X=RCY_MIRROR.8:core_1.128 +ucode_port_129.BCM8869X=RCY_MIRROR.9:core_1.129 +ucode_port_130.BCM8869X=RCY_MIRROR.10:core_1.130 +ucode_port_131.BCM8869X=RCY_MIRROR.11:core_1.131 +ucode_port_132.BCM8869X=RCY_MIRROR.12:core_1.132 +ucode_port_133.BCM8869X=RCY_MIRROR.13:core_1.133 +ucode_port_134.BCM8869X=RCY_MIRROR.14:core_1.134 +ucode_port_135.BCM8869X=RCY_MIRROR.15:core_1.135 +ucode_port_136.BCM8869X=RCY_MIRROR.16:core_1.136 +ucode_port_137.BCM8869X=RCY_MIRROR.17:core_1.137 +ucode_port_138.BCM8869X=RCY_MIRROR.18:core_1.138 +ucode_port_139.BCM8869X=RCY_MIRROR.19:core_1.139 + +port_priorities.BCM8869X=8 + +ucode_port_240.BCM8869X=OLP:core_0.240 + +sw_state_max_size.BCM8869X=750000000 + +stable_location.BCM8869X=4 +stable_location.BCM8869X_ADAPTER=3 + +stable_filename.BCM8869X_ADAPTER=warmboot_data_0 +stable_filename=/dev/shm/warmboot_data_0 +stable_filename.1=/dev/shm/warmboot_data_1 +stable_filename.2=/dev/shm/warmboot_data_2 + +stable_size.BCM8869X=800000000 + +tm_port_header_type_in_0.BCM8869X=INJECTED_2 +tm_port_header_type_out_0.BCM8869X=CPU + +tm_port_header_type_in_200.BCM8869X=INJECTED_2_PP +tm_port_header_type_out_200.BCM8869X=ETH +tm_port_header_type_in_201.BCM8869X=INJECTED_2_PP +tm_port_header_type_out_201.BCM8869X=ETH +tm_port_header_type_in_202.BCM8869X=INJECTED_2_PP +tm_port_header_type_out_202.BCM8869X=ETH +tm_port_header_type_in_203.BCM8869X=INJECTED_2_PP +tm_port_header_type_out_203.BCM8869X=ETH + +sat_enable.BCM8869X=1 +tm_port_header_type_out_218.BCM8869X=CPU +tm_port_header_type_in_218.BCM8869X=INJECTED_2 + +tm_port_header_type_in_232.BCM8869X=INJECTED_2 +tm_port_header_type_out_232.BCM8869X=CPU +tm_port_header_type_in_233.BCM8869X=INJECTED_2 +tm_port_header_type_out_233.BCM8869X=CPU + +tm_port_header_type_in_240.BCM8869X=INJECTED_2 +tm_port_header_type_out_240.BCM8869X=RAW + +dtm_flow_mapping_mode_region_64.BCM8869X=3 +dtm_flow_mapping_mode_region_65.BCM8869X=3 +dtm_flow_mapping_mode_region_66.BCM8869X=3 +dtm_flow_mapping_mode_region_67.BCM8869X=3 +dtm_flow_mapping_mode_region_68.BCM8869X=3 +dtm_flow_mapping_mode_region_69.BCM8869X=3 +dtm_flow_mapping_mode_region_70.BCM8869X=3 +dtm_flow_mapping_mode_region_71.BCM8869X=3 +dtm_flow_mapping_mode_region_72.BCM8869X=3 +dtm_flow_mapping_mode_region_73.BCM8869X=3 +dtm_flow_mapping_mode_region_74.BCM8869X=3 +dtm_flow_mapping_mode_region_75.BCM8869X=3 +dtm_flow_mapping_mode_region_76.BCM8869X=3 +dtm_flow_mapping_mode_region_77.BCM8869X=3 +dtm_flow_mapping_mode_region_78.BCM8869X=3 +dtm_flow_mapping_mode_region_79.BCM8869X=7 +dtm_flow_mapping_mode_region_80.BCM8869X=3 +dtm_flow_mapping_mode_region_81.BCM8869X=1 +dtm_flow_mapping_mode_region_82.BCM8869X=3 +dtm_flow_mapping_mode_region_83.BCM8869X=3 +dtm_flow_mapping_mode_region_84.BCM8869X=3 +dtm_flow_mapping_mode_region_85.BCM8869X=3 +dtm_flow_mapping_mode_region_86.BCM8869X=3 +dtm_flow_mapping_mode_region_87.BCM8869X=3 +dtm_flow_mapping_mode_region_88.BCM8869X=3 +dtm_flow_mapping_mode_region_89.BCM8869X=3 +dtm_flow_mapping_mode_region_90.BCM8869X=3 +dtm_flow_mapping_mode_region_91.BCM8869X=3 +dtm_flow_mapping_mode_region_92.BCM8869X=3 +dtm_flow_mapping_mode_region_93.BCM8869X=3 +dtm_flow_mapping_mode_region_94.BCM8869X=3 + +dtm_flow_nof_remote_cores_region_1.BCM8869X=2 +dtm_flow_nof_remote_cores_region_2.BCM8869X=2 +dtm_flow_nof_remote_cores_region_3.BCM8869X=2 +dtm_flow_nof_remote_cores_region_4.BCM8869X=2 +dtm_flow_nof_remote_cores_region_5.BCM8869X=2 +dtm_flow_nof_remote_cores_region_6.BCM8869X=2 +dtm_flow_nof_remote_cores_region_7.BCM8869X=2 +dtm_flow_nof_remote_cores_region_8.BCM8869X=2 +dtm_flow_nof_remote_cores_region_9.BCM8869X=2 +dtm_flow_nof_remote_cores_region_10.BCM8869X=2 +dtm_flow_nof_remote_cores_region_11.BCM8869X=2 +dtm_flow_nof_remote_cores_region_12.BCM8869X=2 +dtm_flow_nof_remote_cores_region_13.BCM8869X=2 +dtm_flow_nof_remote_cores_region_14.BCM8869X=2 +dtm_flow_nof_remote_cores_region_15.BCM8869X=2 +dtm_flow_nof_remote_cores_region_16.BCM8869X=2 +dtm_flow_nof_remote_cores_region_17.BCM8869X=2 +dtm_flow_nof_remote_cores_region_18.BCM8869X=2 +dtm_flow_nof_remote_cores_region_19.BCM8869X=2 +dtm_flow_nof_remote_cores_region_20.BCM8869X=2 +dtm_flow_nof_remote_cores_region_21.BCM8869X=2 +dtm_flow_nof_remote_cores_region_22.BCM8869X=2 +dtm_flow_nof_remote_cores_region_23.BCM8869X=2 +dtm_flow_nof_remote_cores_region_24.BCM8869X=2 +dtm_flow_nof_remote_cores_region_25.BCM8869X=2 +dtm_flow_nof_remote_cores_region_26.BCM8869X=2 +dtm_flow_nof_remote_cores_region_27.BCM8869X=2 +dtm_flow_nof_remote_cores_region_28.BCM8869X=2 +dtm_flow_nof_remote_cores_region_29.BCM8869X=2 +dtm_flow_nof_remote_cores_region_30.BCM8869X=2 +dtm_flow_nof_remote_cores_region_31.BCM8869X=2 +dtm_flow_nof_remote_cores_region_32.BCM8869X=2 +dtm_flow_nof_remote_cores_region_33.BCM8869X=2 +dtm_flow_nof_remote_cores_region_34.BCM8869X=2 +dtm_flow_nof_remote_cores_region_35.BCM8869X=2 +dtm_flow_nof_remote_cores_region_36.BCM8869X=2 +dtm_flow_nof_remote_cores_region_37.BCM8869X=2 +dtm_flow_nof_remote_cores_region_38.BCM8869X=2 +dtm_flow_nof_remote_cores_region_39.BCM8869X=2 +dtm_flow_nof_remote_cores_region_40.BCM8869X=2 +dtm_flow_nof_remote_cores_region_41.BCM8869X=2 +dtm_flow_nof_remote_cores_region_42.BCM8869X=2 +dtm_flow_nof_remote_cores_region_43.BCM8869X=2 +dtm_flow_nof_remote_cores_region_44.BCM8869X=2 +dtm_flow_nof_remote_cores_region_45.BCM8869X=2 +dtm_flow_nof_remote_cores_region_46.BCM8869X=2 +dtm_flow_nof_remote_cores_region_47.BCM8869X=2 +dtm_flow_nof_remote_cores_region_48.BCM8869X=2 +dtm_flow_nof_remote_cores_region_49.BCM8869X=2 +dtm_flow_nof_remote_cores_region_50.BCM8869X=2 +dtm_flow_nof_remote_cores_region_51.BCM8869X=2 +dtm_flow_nof_remote_cores_region_52.BCM8869X=2 +dtm_flow_nof_remote_cores_region_53.BCM8869X=2 +dtm_flow_nof_remote_cores_region_54.BCM8869X=2 +dtm_flow_nof_remote_cores_region_55.BCM8869X=2 +dtm_flow_nof_remote_cores_region_56.BCM8869X=2 +dtm_flow_nof_remote_cores_region_57.BCM8869X=2 +dtm_flow_nof_remote_cores_region_58.BCM8869X=2 +dtm_flow_nof_remote_cores_region_59.BCM8869X=2 +dtm_flow_nof_remote_cores_region_60.BCM8869X=2 + +mdb_profile.BCM8869X=l3-xl + +outlif_logical_to_physical_phase_map_1=S1 +outlif_logical_to_physical_phase_map_2=L1 +outlif_logical_to_physical_phase_map_3=XL +outlif_logical_to_physical_phase_map_4=L2 +outlif_logical_to_physical_phase_map_5=M1 +outlif_logical_to_physical_phase_map_6=M2 +outlif_logical_to_physical_phase_map_7=M3 +outlif_logical_to_physical_phase_map_8=S2 + +outlif_physical_phase_data_granularity_S1=60 +outlif_physical_phase_data_granularity_S2=60 +outlif_physical_phase_data_granularity_M1=60 +outlif_physical_phase_data_granularity_M2=60 +outlif_physical_phase_data_granularity_M3=60 +outlif_physical_phase_data_granularity_L1=60 +outlif_physical_phase_data_granularity_L2=60 +outlif_physical_phase_data_granularity_XL=60 + +port_init_speed_fabric.BCM8869X=53125 + +fabric_connect_mode.BCM8869X=SINGLE_FAP +protocol_traps_mode.BCM8869X=IN_LIF + +schan_intr_enable.BCM8869X=0 +tdma_intr_enable.BCM8869X=0 +tslam_intr_enable.BCM8869X=0 +miim_intr_enable.BCM8869X=0 +schan_timeout_usec.BCM8869X=300000 +tdma_timeout_usec.BCM8869X=1000000 +tslam_timeout_usec.BCM8869X=1000000 + +appl_enable_intr_init.BCM8869X=1 +polled_irq_mode.BCM8869X=1 +polled_irq_delay.BCM8869X=1000 + +bcm_stat_interval.BCM8869X=1000 + +mem_cache_enable_ecc.BCM8869X=1 +mem_cache_enable_parity.BCM8869X=1 + +serdes_nif_clk_freq_in.BCM8869X=2 +serdes_nif_clk_freq_out.BCM8869X=1 + +serdes_fabric_clk_freq_in.BCM8869X=2 +serdes_fabric_clk_freq_out.BCM8869X=1 + +dram_phy_tune_mode_on_init.BCM8869X=RUN_TUNE + +dport_map_direct.BCM8869X=1 + +pmf_sexem3_stage.BCM8869X=IPMF3 + +lane_to_serdes_map_fabric_lane0.0=rx0:tx0 +lane_to_serdes_map_fabric_lane1.0=rx1:tx1 +lane_to_serdes_map_fabric_lane2.0=rx2:tx2 +lane_to_serdes_map_fabric_lane3.0=rx3:tx3 +lane_to_serdes_map_fabric_lane4.0=rx4:tx4 +lane_to_serdes_map_fabric_lane5.0=rx5:tx5 +lane_to_serdes_map_fabric_lane6.0=rx6:tx6 +lane_to_serdes_map_fabric_lane7.0=rx7:tx7 +lane_to_serdes_map_fabric_lane8.0=rx8:tx8 +lane_to_serdes_map_fabric_lane9.0=rx9:tx9 +lane_to_serdes_map_fabric_lane10.0=rx10:tx10 +lane_to_serdes_map_fabric_lane11.0=rx11:tx11 +lane_to_serdes_map_fabric_lane12.0=rx12:tx12 +lane_to_serdes_map_fabric_lane13.0=rx13:tx13 +lane_to_serdes_map_fabric_lane14.0=rx14:tx14 +lane_to_serdes_map_fabric_lane15.0=rx15:tx15 +lane_to_serdes_map_fabric_lane16.0=rx16:tx16 +lane_to_serdes_map_fabric_lane17.0=rx17:tx17 +lane_to_serdes_map_fabric_lane18.0=rx18:tx18 +lane_to_serdes_map_fabric_lane19.0=rx19:tx19 +lane_to_serdes_map_fabric_lane20.0=rx20:tx20 +lane_to_serdes_map_fabric_lane21.0=rx21:tx21 +lane_to_serdes_map_fabric_lane22.0=rx22:tx22 +lane_to_serdes_map_fabric_lane23.0=rx23:tx23 +lane_to_serdes_map_fabric_lane24.0=rx24:tx24 +lane_to_serdes_map_fabric_lane25.0=rx25:tx25 +lane_to_serdes_map_fabric_lane26.0=rx26:tx26 +lane_to_serdes_map_fabric_lane27.0=rx27:tx27 +lane_to_serdes_map_fabric_lane28.0=rx28:tx28 +lane_to_serdes_map_fabric_lane29.0=rx29:tx29 +lane_to_serdes_map_fabric_lane30.0=rx30:tx30 +lane_to_serdes_map_fabric_lane31.0=rx31:tx31 +lane_to_serdes_map_fabric_lane32.0=rx32:tx32 +lane_to_serdes_map_fabric_lane33.0=rx33:tx33 +lane_to_serdes_map_fabric_lane34.0=rx34:tx34 +lane_to_serdes_map_fabric_lane35.0=rx35:tx35 +lane_to_serdes_map_fabric_lane36.0=rx36:tx36 +lane_to_serdes_map_fabric_lane37.0=rx37:tx37 +lane_to_serdes_map_fabric_lane38.0=rx38:tx38 +lane_to_serdes_map_fabric_lane39.0=rx39:tx39 +lane_to_serdes_map_fabric_lane40.0=rx40:tx40 +lane_to_serdes_map_fabric_lane41.0=rx41:tx41 +lane_to_serdes_map_fabric_lane42.0=rx42:tx42 +lane_to_serdes_map_fabric_lane43.0=rx43:tx43 +lane_to_serdes_map_fabric_lane44.0=rx44:tx44 +lane_to_serdes_map_fabric_lane45.0=rx45:tx45 +lane_to_serdes_map_fabric_lane46.0=rx46:tx46 +lane_to_serdes_map_fabric_lane47.0=rx47:tx47 +lane_to_serdes_map_fabric_lane48.0=rx48:tx48 +lane_to_serdes_map_fabric_lane49.0=rx49:tx49 +lane_to_serdes_map_fabric_lane50.0=rx50:tx50 +lane_to_serdes_map_fabric_lane51.0=rx51:tx51 +lane_to_serdes_map_fabric_lane52.0=rx52:tx52 +lane_to_serdes_map_fabric_lane53.0=rx53:tx53 +lane_to_serdes_map_fabric_lane54.0=rx54:tx54 +lane_to_serdes_map_fabric_lane55.0=rx55:tx55 +lane_to_serdes_map_fabric_lane56.0=rx56:tx56 +lane_to_serdes_map_fabric_lane57.0=rx57:tx57 +lane_to_serdes_map_fabric_lane58.0=rx58:tx58 +lane_to_serdes_map_fabric_lane59.0=rx59:tx59 +lane_to_serdes_map_fabric_lane60.0=rx60:tx60 +lane_to_serdes_map_fabric_lane61.0=rx61:tx61 +lane_to_serdes_map_fabric_lane62.0=rx62:tx62 +lane_to_serdes_map_fabric_lane63.0=rx63:tx63 +lane_to_serdes_map_fabric_lane64.0=rx64:tx64 +lane_to_serdes_map_fabric_lane65.0=rx65:tx65 +lane_to_serdes_map_fabric_lane66.0=rx66:tx66 +lane_to_serdes_map_fabric_lane67.0=rx67:tx67 +lane_to_serdes_map_fabric_lane68.0=rx68:tx68 +lane_to_serdes_map_fabric_lane69.0=rx69:tx69 +lane_to_serdes_map_fabric_lane70.0=rx70:tx70 +lane_to_serdes_map_fabric_lane71.0=rx71:tx71 +lane_to_serdes_map_fabric_lane72.0=rx72:tx72 +lane_to_serdes_map_fabric_lane73.0=rx73:tx73 +lane_to_serdes_map_fabric_lane74.0=rx74:tx74 +lane_to_serdes_map_fabric_lane75.0=rx75:tx75 +lane_to_serdes_map_fabric_lane76.0=rx76:tx76 +lane_to_serdes_map_fabric_lane77.0=rx77:tx77 +lane_to_serdes_map_fabric_lane78.0=rx78:tx78 +lane_to_serdes_map_fabric_lane79.0=rx79:tx79 +lane_to_serdes_map_fabric_lane80.0=rx80:tx80 +lane_to_serdes_map_fabric_lane81.0=rx81:tx81 +lane_to_serdes_map_fabric_lane82.0=rx82:tx82 +lane_to_serdes_map_fabric_lane83.0=rx83:tx83 +lane_to_serdes_map_fabric_lane84.0=rx84:tx84 +lane_to_serdes_map_fabric_lane85.0=rx85:tx85 +lane_to_serdes_map_fabric_lane86.0=rx86:tx86 +lane_to_serdes_map_fabric_lane87.0=rx87:tx87 +lane_to_serdes_map_fabric_lane88.0=rx88:tx88 +lane_to_serdes_map_fabric_lane89.0=rx89:tx89 +lane_to_serdes_map_fabric_lane90.0=rx90:tx90 +lane_to_serdes_map_fabric_lane91.0=rx91:tx91 +lane_to_serdes_map_fabric_lane92.0=rx92:tx92 +lane_to_serdes_map_fabric_lane93.0=rx93:tx93 +lane_to_serdes_map_fabric_lane94.0=rx94:tx94 +lane_to_serdes_map_fabric_lane95.0=rx95:tx95 +lane_to_serdes_map_fabric_lane96.0=rx96:tx96 +lane_to_serdes_map_fabric_lane97.0=rx97:tx97 +lane_to_serdes_map_fabric_lane98.0=rx98:tx98 +lane_to_serdes_map_fabric_lane99.0=rx99:tx99 +lane_to_serdes_map_fabric_lane100.0=rx100:tx100 +lane_to_serdes_map_fabric_lane101.0=rx101:tx101 +lane_to_serdes_map_fabric_lane102.0=rx102:tx102 +lane_to_serdes_map_fabric_lane103.0=rx103:tx103 +lane_to_serdes_map_fabric_lane104.0=rx104:tx104 +lane_to_serdes_map_fabric_lane105.0=rx105:tx105 +lane_to_serdes_map_fabric_lane106.0=rx106:tx106 +lane_to_serdes_map_fabric_lane107.0=rx107:tx107 +lane_to_serdes_map_fabric_lane108.0=rx108:tx108 +lane_to_serdes_map_fabric_lane109.0=rx109:tx109 +lane_to_serdes_map_fabric_lane110.0=rx110:tx110 +lane_to_serdes_map_fabric_lane111.0=rx111:tx111 + +lane_to_serdes_map_nif_lane0.0=rx5:tx7 +lane_to_serdes_map_nif_lane1.0=rx7:tx6 +lane_to_serdes_map_nif_lane2.0=rx4:tx5 +lane_to_serdes_map_nif_lane3.0=rx6:tx4 +lane_to_serdes_map_nif_lane4.0=rx0:tx0 +lane_to_serdes_map_nif_lane5.0=rx1:tx1 +lane_to_serdes_map_nif_lane6.0=rx2:tx3 +lane_to_serdes_map_nif_lane7.0=rx3:tx2 +lane_to_serdes_map_nif_lane8.0=rx13:tx15 +lane_to_serdes_map_nif_lane9.0=rx12:tx14 +lane_to_serdes_map_nif_lane10.0=rx15:tx13 +lane_to_serdes_map_nif_lane11.0=rx14:tx12 +lane_to_serdes_map_nif_lane12.0=rx10:tx10 +lane_to_serdes_map_nif_lane13.0=rx8:tx9 +lane_to_serdes_map_nif_lane14.0=rx9:tx11 +lane_to_serdes_map_nif_lane15.0=rx11:tx8 +lane_to_serdes_map_nif_lane16.0=rx23:tx23 +lane_to_serdes_map_nif_lane17.0=rx21:tx22 +lane_to_serdes_map_nif_lane18.0=rx22:tx21 +lane_to_serdes_map_nif_lane19.0=rx20:tx20 +lane_to_serdes_map_nif_lane20.0=rx16:tx18 +lane_to_serdes_map_nif_lane21.0=rx17:tx17 +lane_to_serdes_map_nif_lane22.0=rx18:tx16 +lane_to_serdes_map_nif_lane23.0=rx19:tx19 +lane_to_serdes_map_nif_lane24.0=rx31:tx31 +lane_to_serdes_map_nif_lane25.0=rx30:tx30 +lane_to_serdes_map_nif_lane26.0=rx29:tx29 +lane_to_serdes_map_nif_lane27.0=rx28:tx28 +lane_to_serdes_map_nif_lane28.0=rx24:tx26 +lane_to_serdes_map_nif_lane29.0=rx26:tx25 +lane_to_serdes_map_nif_lane30.0=rx25:tx24 +lane_to_serdes_map_nif_lane31.0=rx27:tx27 +lane_to_serdes_map_nif_lane32.0=rx39:tx35 +lane_to_serdes_map_nif_lane33.0=rx38:tx36 +lane_to_serdes_map_nif_lane34.0=rx32:tx32 +lane_to_serdes_map_nif_lane35.0=rx37:tx37 +lane_to_serdes_map_nif_lane36.0=rx33:tx34 +lane_to_serdes_map_nif_lane37.0=rx34:tx38 +lane_to_serdes_map_nif_lane38.0=rx35:tx33 +lane_to_serdes_map_nif_lane39.0=rx36:tx39 +lane_to_serdes_map_nif_lane40.0=rx44:tx47 +lane_to_serdes_map_nif_lane41.0=rx43:tx41 +lane_to_serdes_map_nif_lane42.0=rx47:tx46 +lane_to_serdes_map_nif_lane43.0=rx42:tx42 +lane_to_serdes_map_nif_lane44.0=rx45:tx45 +lane_to_serdes_map_nif_lane45.0=rx41:tx40 +lane_to_serdes_map_nif_lane46.0=rx46:tx44 +lane_to_serdes_map_nif_lane47.0=rx40:tx43 +lane_to_serdes_map_nif_lane48.0=rx55:tx55 +lane_to_serdes_map_nif_lane49.0=rx54:tx54 +lane_to_serdes_map_nif_lane50.0=rx53:tx53 +lane_to_serdes_map_nif_lane51.0=rx52:tx52 +lane_to_serdes_map_nif_lane52.0=rx48:tx48 +lane_to_serdes_map_nif_lane53.0=rx49:tx49 +lane_to_serdes_map_nif_lane54.0=rx50:tx50 +lane_to_serdes_map_nif_lane55.0=rx51:tx51 +lane_to_serdes_map_nif_lane56.0=rx60:tx60 +lane_to_serdes_map_nif_lane57.0=rx61:tx61 +lane_to_serdes_map_nif_lane58.0=rx62:tx63 +lane_to_serdes_map_nif_lane59.0=rx63:tx62 +lane_to_serdes_map_nif_lane60.0=rx58:tx59 +lane_to_serdes_map_nif_lane61.0=rx59:tx56 +lane_to_serdes_map_nif_lane62.0=rx57:tx58 +lane_to_serdes_map_nif_lane63.0=rx56:tx57 +lane_to_serdes_map_nif_lane64.0=rx68:tx69 +lane_to_serdes_map_nif_lane65.0=rx69:tx68 +lane_to_serdes_map_nif_lane66.0=rx70:tx71 +lane_to_serdes_map_nif_lane67.0=rx71:tx70 +lane_to_serdes_map_nif_lane68.0=rx67:tx64 +lane_to_serdes_map_nif_lane69.0=rx66:tx67 +lane_to_serdes_map_nif_lane70.0=rx65:tx65 +lane_to_serdes_map_nif_lane71.0=rx64:tx66 +lane_to_serdes_map_nif_lane72.0=rx78:tx76 +lane_to_serdes_map_nif_lane73.0=rx76:tx77 +lane_to_serdes_map_nif_lane74.0=rx79:tx78 +lane_to_serdes_map_nif_lane75.0=rx77:tx79 +lane_to_serdes_map_nif_lane76.0=rx75:tx72 +lane_to_serdes_map_nif_lane77.0=rx74:tx75 +lane_to_serdes_map_nif_lane78.0=rx73:tx73 +lane_to_serdes_map_nif_lane79.0=rx72:tx74 +lane_to_serdes_map_nif_lane80.0=rx81:tx83 +lane_to_serdes_map_nif_lane81.0=rx85:tx84 +lane_to_serdes_map_nif_lane82.0=rx80:tx80 +lane_to_serdes_map_nif_lane83.0=rx86:tx85 +lane_to_serdes_map_nif_lane84.0=rx82:tx82 +lane_to_serdes_map_nif_lane85.0=rx87:tx86 +lane_to_serdes_map_nif_lane86.0=rx83:tx81 +lane_to_serdes_map_nif_lane87.0=rx84:tx87 +lane_to_serdes_map_nif_lane88.0=rx91:tx95 +lane_to_serdes_map_nif_lane89.0=rx90:tx89 +lane_to_serdes_map_nif_lane90.0=rx95:tx94 +lane_to_serdes_map_nif_lane91.0=rx89:tx90 +lane_to_serdes_map_nif_lane92.0=rx93:tx93 +lane_to_serdes_map_nif_lane93.0=rx94:tx88 +lane_to_serdes_map_nif_lane94.0=rx92:tx92 +lane_to_serdes_map_nif_lane95.0=rx88:tx91 +phy_rx_polarity_flip_phy0=0 +phy_rx_polarity_flip_phy1=1 +phy_rx_polarity_flip_phy2=0 +phy_rx_polarity_flip_phy3=0 +phy_rx_polarity_flip_phy4=0 +phy_rx_polarity_flip_phy5=0 +phy_rx_polarity_flip_phy6=0 +phy_rx_polarity_flip_phy7=0 +phy_rx_polarity_flip_phy8=1 +phy_rx_polarity_flip_phy9=1 +phy_rx_polarity_flip_phy10=1 +phy_rx_polarity_flip_phy11=1 +phy_rx_polarity_flip_phy12=0 +phy_rx_polarity_flip_phy13=1 +phy_rx_polarity_flip_phy14=1 +phy_rx_polarity_flip_phy15=1 +phy_rx_polarity_flip_phy16=0 +phy_rx_polarity_flip_phy17=1 +phy_rx_polarity_flip_phy18=1 +phy_rx_polarity_flip_phy19=0 +phy_rx_polarity_flip_phy20=0 +phy_rx_polarity_flip_phy21=0 +phy_rx_polarity_flip_phy22=0 +phy_rx_polarity_flip_phy23=0 +phy_rx_polarity_flip_phy24=1 +phy_rx_polarity_flip_phy25=1 +phy_rx_polarity_flip_phy26=1 +phy_rx_polarity_flip_phy27=0 +phy_rx_polarity_flip_phy28=0 +phy_rx_polarity_flip_phy29=1 +phy_rx_polarity_flip_phy30=1 +phy_rx_polarity_flip_phy31=0 +phy_rx_polarity_flip_phy32=0 +phy_rx_polarity_flip_phy33=1 +phy_rx_polarity_flip_phy34=1 +phy_rx_polarity_flip_phy35=0 +phy_rx_polarity_flip_phy36=0 +phy_rx_polarity_flip_phy37=0 +phy_rx_polarity_flip_phy38=1 +phy_rx_polarity_flip_phy39=0 +phy_rx_polarity_flip_phy40=1 +phy_rx_polarity_flip_phy41=1 +phy_rx_polarity_flip_phy42=0 +phy_rx_polarity_flip_phy43=0 +phy_rx_polarity_flip_phy44=1 +phy_rx_polarity_flip_phy45=1 +phy_rx_polarity_flip_phy46=0 +phy_rx_polarity_flip_phy47=0 +phy_rx_polarity_flip_phy48=1 +phy_rx_polarity_flip_phy49=1 +phy_rx_polarity_flip_phy50=1 +phy_rx_polarity_flip_phy51=1 +phy_rx_polarity_flip_phy52=0 +phy_rx_polarity_flip_phy53=0 +phy_rx_polarity_flip_phy54=0 +phy_rx_polarity_flip_phy55=0 +phy_rx_polarity_flip_phy56=0 +phy_rx_polarity_flip_phy57=0 +phy_rx_polarity_flip_phy58=0 +phy_rx_polarity_flip_phy59=0 +phy_rx_polarity_flip_phy60=1 +phy_rx_polarity_flip_phy61=1 +phy_rx_polarity_flip_phy62=1 +phy_rx_polarity_flip_phy63=1 +phy_rx_polarity_flip_phy64=1 +phy_rx_polarity_flip_phy65=1 +phy_rx_polarity_flip_phy66=1 +phy_rx_polarity_flip_phy67=1 +phy_rx_polarity_flip_phy68=1 +phy_rx_polarity_flip_phy69=1 +phy_rx_polarity_flip_phy70=1 +phy_rx_polarity_flip_phy71=1 +phy_rx_polarity_flip_phy72=1 +phy_rx_polarity_flip_phy73=0 +phy_rx_polarity_flip_phy74=0 +phy_rx_polarity_flip_phy75=1 +phy_rx_polarity_flip_phy76=1 +phy_rx_polarity_flip_phy77=1 +phy_rx_polarity_flip_phy78=1 +phy_rx_polarity_flip_phy79=1 +phy_rx_polarity_flip_phy80=0 +phy_rx_polarity_flip_phy81=0 +phy_rx_polarity_flip_phy82=1 +phy_rx_polarity_flip_phy83=1 +phy_rx_polarity_flip_phy84=1 +phy_rx_polarity_flip_phy85=0 +phy_rx_polarity_flip_phy86=1 +phy_rx_polarity_flip_phy87=1 +phy_rx_polarity_flip_phy88=0 +phy_rx_polarity_flip_phy89=0 +phy_rx_polarity_flip_phy90=1 +phy_rx_polarity_flip_phy91=1 +phy_rx_polarity_flip_phy92=0 +phy_rx_polarity_flip_phy93=1 +phy_rx_polarity_flip_phy94=0 +phy_rx_polarity_flip_phy95=0 +phy_tx_polarity_flip_phy0=1 +phy_tx_polarity_flip_phy1=1 +phy_tx_polarity_flip_phy2=1 +phy_tx_polarity_flip_phy3=1 +phy_tx_polarity_flip_phy4=1 +phy_tx_polarity_flip_phy5=1 +phy_tx_polarity_flip_phy6=0 +phy_tx_polarity_flip_phy7=0 +phy_tx_polarity_flip_phy8=1 +phy_tx_polarity_flip_phy9=1 +phy_tx_polarity_flip_phy10=1 +phy_tx_polarity_flip_phy11=1 +phy_tx_polarity_flip_phy12=1 +phy_tx_polarity_flip_phy13=1 +phy_tx_polarity_flip_phy14=0 +phy_tx_polarity_flip_phy15=0 +phy_tx_polarity_flip_phy16=0 +phy_tx_polarity_flip_phy17=0 +phy_tx_polarity_flip_phy18=0 +phy_tx_polarity_flip_phy19=0 +phy_tx_polarity_flip_phy20=0 +phy_tx_polarity_flip_phy21=0 +phy_tx_polarity_flip_phy22=0 +phy_tx_polarity_flip_phy23=0 +phy_tx_polarity_flip_phy24=0 +phy_tx_polarity_flip_phy25=0 +phy_tx_polarity_flip_phy26=0 +phy_tx_polarity_flip_phy27=0 +phy_tx_polarity_flip_phy28=0 +phy_tx_polarity_flip_phy29=0 +phy_tx_polarity_flip_phy30=0 +phy_tx_polarity_flip_phy31=0 +phy_tx_polarity_flip_phy32=0 +phy_tx_polarity_flip_phy33=0 +phy_tx_polarity_flip_phy34=1 +phy_tx_polarity_flip_phy35=1 +phy_tx_polarity_flip_phy36=1 +phy_tx_polarity_flip_phy37=0 +phy_tx_polarity_flip_phy38=0 +phy_tx_polarity_flip_phy39=1 +phy_tx_polarity_flip_phy40=1 +phy_tx_polarity_flip_phy41=1 +phy_tx_polarity_flip_phy42=0 +phy_tx_polarity_flip_phy43=1 +phy_tx_polarity_flip_phy44=1 +phy_tx_polarity_flip_phy45=1 +phy_tx_polarity_flip_phy46=0 +phy_tx_polarity_flip_phy47=0 +phy_tx_polarity_flip_phy48=0 +phy_tx_polarity_flip_phy49=0 +phy_tx_polarity_flip_phy50=0 +phy_tx_polarity_flip_phy51=0 +phy_tx_polarity_flip_phy52=0 +phy_tx_polarity_flip_phy53=0 +phy_tx_polarity_flip_phy54=0 +phy_tx_polarity_flip_phy55=0 +phy_tx_polarity_flip_phy56=1 +phy_tx_polarity_flip_phy57=1 +phy_tx_polarity_flip_phy58=0 +phy_tx_polarity_flip_phy59=0 +phy_tx_polarity_flip_phy60=1 +phy_tx_polarity_flip_phy61=1 +phy_tx_polarity_flip_phy62=0 +phy_tx_polarity_flip_phy63=0 +phy_tx_polarity_flip_phy64=0 +phy_tx_polarity_flip_phy65=0 +phy_tx_polarity_flip_phy66=0 +phy_tx_polarity_flip_phy67=0 +phy_tx_polarity_flip_phy68=0 +phy_tx_polarity_flip_phy69=0 +phy_tx_polarity_flip_phy70=1 +phy_tx_polarity_flip_phy71=1 +phy_tx_polarity_flip_phy72=1 +phy_tx_polarity_flip_phy73=1 +phy_tx_polarity_flip_phy74=1 +phy_tx_polarity_flip_phy75=1 +phy_tx_polarity_flip_phy76=0 +phy_tx_polarity_flip_phy77=0 +phy_tx_polarity_flip_phy78=1 +phy_tx_polarity_flip_phy79=1 +phy_tx_polarity_flip_phy80=0 +phy_tx_polarity_flip_phy81=1 +phy_tx_polarity_flip_phy82=1 +phy_tx_polarity_flip_phy83=1 +phy_tx_polarity_flip_phy84=1 +phy_tx_polarity_flip_phy85=0 +phy_tx_polarity_flip_phy86=0 +phy_tx_polarity_flip_phy87=1 +phy_tx_polarity_flip_phy88=1 +phy_tx_polarity_flip_phy89=0 +phy_tx_polarity_flip_phy90=0 +phy_tx_polarity_flip_phy91=1 +phy_tx_polarity_flip_phy92=1 +phy_tx_polarity_flip_phy93=1 +phy_tx_polarity_flip_phy94=0 +phy_tx_polarity_flip_phy95=0 + +ucode_port_1=CGE2_0:core_0.1 +ucode_port_2=CGE2_1:core_0.2 +ucode_port_3=CGE2_2:core_0.3 +ucode_port_4=CGE2_3:core_0.4 +ucode_port_5=CGE2_4:core_0.5 +ucode_port_6=CGE2_5:core_0.6 +ucode_port_7=CGE2_6:core_0.7 +ucode_port_8=CGE2_7:core_0.8 +ucode_port_9=CGE2_8:core_0.9 +ucode_port_10=CGE2_9:core_0.10 +ucode_port_11=CGE2_10:core_0.11 +ucode_port_12=CGE2_11:core_0.12 +ucode_port_13=CGE2_12:core_0.13 +ucode_port_14=CGE2_13:core_0.14 +ucode_port_15=CGE2_14:core_0.15 +ucode_port_16=CGE2_15:core_0.16 +ucode_port_17=CGE2_36:core_1.17 +ucode_port_18=CGE2_37:core_1.18 +ucode_port_19=CGE2_38:core_1.19 +ucode_port_20=CGE2_39:core_1.20 +ucode_port_21=CGE2_32:core_1.21 +ucode_port_22=CGE2_33:core_1.22 +ucode_port_23=CGE2_34:core_1.23 +ucode_port_24=CGE2_35:core_1.24 +ucode_port_25=CGE2_28:core_1.25 +ucode_port_26=CGE2_29:core_1.26 +ucode_port_27=CGE2_30:core_1.27 +ucode_port_28=CGE2_31:core_1.28 +ucode_port_29=XE48:core_1.29 +ucode_port_30=XE49:core_1.30 +ucode_port_31=XE50:core_1.31 +ucode_port_32=XE51:core_1.32 +ucode_port_33=XE52:core_1.33 +ucode_port_34=XE53:core_1.34 +ucode_port_35=XE54:core_1.35 +ucode_port_36=XE55:core_1.36 + +rif_id_max=0x4000 + +dma_desc_aggregator_chain_length_max.BCM8869X=1000 +dma_desc_aggregator_buff_size_kb.BCM8869X=100 +dma_desc_aggregator_timeout_usec.BCM8869X=1000 +dma_desc_aggregator_enable_specific_MDB_LPM.BCM8869X=1 +dma_desc_aggregator_enable_specific_MDB_FEC.BCM8869X=1 diff --git a/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/port_config.ini b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/port_config.ini new file mode 100644 index 000000000000..cb1c2a4663e8 --- /dev/null +++ b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/port_config.ini @@ -0,0 +1,37 @@ +# name lanes alias index speed +Ethernet0 0,1 Ethernet1/1 1 100000 +Ethernet4 2,3 Ethernet2/1 2 100000 +Ethernet8 4,5 Ethernet3/1 3 100000 +Ethernet12 6,7 Ethernet4/1 4 100000 +Ethernet16 8,9 Ethernet5/1 5 100000 +Ethernet20 10,11 Ethernet6/1 6 100000 +Ethernet24 12,13 Ethernet7/1 7 100000 +Ethernet28 14,15 Ethernet8/1 8 100000 +Ethernet32 16,17 Ethernet9/1 9 100000 +Ethernet36 18,19 Ethernet10/1 10 100000 +Ethernet40 20,21 Ethernet11/1 11 100000 +Ethernet44 22,23 Ethernet12/1 12 100000 +Ethernet48 24,25 Ethernet13/1 13 100000 +Ethernet52 26,27 Ethernet14/1 14 100000 +Ethernet56 28,29 Ethernet15/1 15 100000 +Ethernet60 30,31 Ethernet16/1 16 100000 +Ethernet64 72,73 Ethernet17/1 17 100000 +Ethernet68 74,75 Ethernet18/1 18 100000 +Ethernet72 76,77 Ethernet19/1 19 100000 +Ethernet76 78,79 Ethernet20/1 20 100000 +Ethernet80 64,65 Ethernet21/1 21 100000 +Ethernet84 66,67 Ethernet22/1 22 100000 +Ethernet88 68,69 Ethernet23/1 23 100000 +Ethernet92 70,71 Ethernet24/1 24 100000 +Ethernet96 56,57 Ethernet25/1 25 100000 +Ethernet100 58,59 Ethernet26/1 26 100000 +Ethernet104 60,61 Ethernet27/1 27 100000 +Ethernet108 62,63 Ethernet28/1 28 100000 +Ethernet112 48 Ethernet29/1 29 10000 +Ethernet113 49 Ethernet29/2 29 10000 +Ethernet114 50 Ethernet29/3 29 10000 +Ethernet115 51 Ethernet29/4 29 10000 +Ethernet120 52 Ethernet31/1 31 10000 +Ethernet121 53 Ethernet31/2 31 10000 +Ethernet122 54 Ethernet31/3 31 10000 +Ethernet123 55 Ethernet31/4 31 10000 diff --git a/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/sai.profile b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/sai.profile new file mode 100644 index 000000000000..7e699b10430e --- /dev/null +++ b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/jr2-a7280cr3-32p4-28x100G-8x10G.config.bcm From 1e7c458454bae653627b796d1723eb317878ff63 Mon Sep 17 00:00:00 2001 From: Dong Zhang <41927498+dzhangalibaba@users.noreply.github.com> Date: Tue, 8 Oct 2019 18:10:38 -0700 Subject: [PATCH 054/278] Add separator field to database_config.json (#3581) --- dockers/docker-database/database_config.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dockers/docker-database/database_config.json b/dockers/docker-database/database_config.json index d5d951bead5d..b86ae11bba98 100644 --- a/dockers/docker-database/database_config.json +++ b/dockers/docker-database/database_config.json @@ -9,38 +9,47 @@ "DATABASES" : { "APPL_DB" : { "id" : 0, + "separator": ":", "instance" : "redis" }, "ASIC_DB" : { "id" : 1, + "separator": ":", "instance" : "redis" }, "COUNTERS_DB" : { "id" : 2, + "separator": ":", "instance" : "redis" }, "LOGLEVEL_DB" : { "id" : 3, + "separator": ":", "instance" : "redis" }, "CONFIG_DB" : { "id" : 4, + "separator": "|", "instance" : "redis" }, "PFC_WD_DB" : { "id" : 5, + "separator": ":", "instance" : "redis" }, "FLEX_COUNTER_DB" : { "id" : 5, + "separator": ":", "instance" : "redis" }, "STATE_DB" : { "id" : 6, + "separator": "|", "instance" : "redis" }, "SNMP_OVERLAY_DB" : { "id" : 7, + "separator": "|", "instance" : "redis" } }, From 0d8895b35494b9d7a7780e3b96f8890000d20280 Mon Sep 17 00:00:00 2001 From: Guohan Lu Date: Wed, 9 Oct 2019 04:57:00 +0000 Subject: [PATCH 055/278] [submodule]: update sonic-sairedis * 1f4a1d7 2019-09-24 | Add warm boot support with removed/created port (#515) (HEAD, origin/master, origin/HEAD) [Kamil Cudnik] * 59e530a 2019-09-20 | Add support for debug counters (#517) [Danny Allen] * 1ed09e0 2019-09-20 | fully support bulk_remove in sairedis (#516) [Dong Zhang] * 6cb1b31 2019-09-17 | Add support for port remove and port create (no warm boot) (#500) [Kamil Cudnik] * 83d86ed 2019-09-17 | Fix c_str() in printf for string (#514) [Kamil Cudnik] * 11b44b5 2019-09-16 | Advance SAI reference pointer to v1.5.0 (#509) [Wenda Ni] * 38c6945 2019-09-14 | support sflow on virtual switch (#498) [Rakesh Datta] * e7d766e 2019-09-09 | Add acl counter match logic based on acl entry field (#511) [Kamil Cudnik] * 58845ce 2019-09-06 | Add extra check for warm boot discovered RIDs (#502) [Kamil Cudnik] * b4893ef 2019-09-05 | [flex counter]: Lower the severity of log during rif counter support check (#504) [shikenghua] * b859344 2019-09-03 | fix found typo in new added syncMode related codes (#506) [Dong Zhang] Signed-off-by: Guohan Lu --- src/sonic-sairedis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 5fc89b569c98..1f4a1d76bd9c 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 5fc89b569c98ca1be51f0069c59465abd5873b19 +Subproject commit 1f4a1d76bd9cd3e8865911840ab8e47c0ba221f1 From 8d2f67ef00ec079364936a0fb4ddaefb79dce00d Mon Sep 17 00:00:00 2001 From: lguohan Date: Wed, 9 Oct 2019 07:40:01 -0700 Subject: [PATCH 056/278] [baseimage]: incrase docker ramfs from 800MB to 900MB (#3582) --- onie-image.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onie-image.conf b/onie-image.conf index db99c867de04..2ca0a68484e2 100644 --- a/onie-image.conf +++ b/onie-image.conf @@ -25,7 +25,7 @@ FILESYSTEM_DOCKERFS=dockerfs.tar.gz DOCKERFS_DIR=docker ## docker ramfs disk space -DOCKER_RAMFS_SIZE=800M +DOCKER_RAMFS_SIZE=900M ## Output file name for onie installer OUTPUT_ONIE_IMAGE=target/sonic-$TARGET_MACHINE.bin From 576f0982d2551c6c56a075b87b7bf046dabfec75 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Thu, 10 Oct 2019 02:07:30 +0800 Subject: [PATCH 057/278] [Mellanox]Resolve chassis broken due to inconsistent with latest sonic_platform_common (#3569) *Currently get_firmware_version implementated by using chassis.get_firmware_version and chassis._component_name_list which are not supported in the latest sonic_platform_common, causing chassis broken. Update this part so that it aligns to the latest sonic_platform_common *Support component API --- .../sonic_platform/chassis.py | 143 ++++------------- .../sonic_platform/component.py | 148 ++++++++++++++++++ .../sonic_platform/platform.py | 2 +- 3 files changed, 176 insertions(+), 117 deletions(-) create mode 100644 platform/mellanox/mlnx-platform-api/sonic_platform/component.py diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index 02d898822817..f5c7c04a4204 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -10,6 +10,7 @@ try: from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform_base.component_base import ComponentBase from sonic_daemon_base.daemon_base import Logger from os import listdir from os.path import isfile, join @@ -37,22 +38,6 @@ REBOOT_CAUSE_FILE_LENGTH = 1 -#version retrieving related definitions -CPLD_VERSION_ROOT = HWMGMT_SYSTEM_ROOT - -CPLD1_VERSION_FILE = 'cpld1_version' -CPLD2_VERSION_FILE = 'cpld2_version' -CPLD_VERSION_MAX_LENGTH = 4 - -FW_QUERY_VERSION_COMMAND = 'mlxfwmanager --query' -BIOS_QUERY_VERSION_COMMAND = 'dmidecode -t 11' - -#components definitions -COMPONENT_BIOS = "BIOS" -COMPONENT_FIRMWARE = "ASIC-FIRMWARE" -COMPONENT_CPLD1 = "CPLD1" -COMPONENT_CPLD2 = "CPLD2" - # Global logger class instance SYSLOG_IDENTIFIER = "mlnx-chassis-api" logger = Logger(SYSLOG_IDENTIFIER) @@ -78,10 +63,12 @@ def __init__(self): self.reboot_cause_initialized = False logger.log_info("Chassis loaded successfully") + def __del__(self): if self.sfp_event_initialized: self.sfp_event.deinitialize() + def initialize_psu(self): from sonic_platform.psu import Psu # Initialize PSU list @@ -90,6 +77,7 @@ def initialize_psu(self): psu = Psu(index, self.sku_name) self._psu_list.append(psu) + def initialize_fan(self): from sonic_platform.fan import Fan from sonic_platform.fan import FAN_PATH @@ -107,6 +95,7 @@ def initialize_fan(self): fan = Fan(index, index) self._fan_list.append(fan) + def initialize_sfp(self): from sonic_platform.sfp import SFP @@ -128,22 +117,25 @@ def initialize_sfp(self): self.sfp_module_initialized = True + def initialize_thermals(self): from sonic_platform.thermal import initialize_thermals # Initialize thermals initialize_thermals(self.sku_name, self._thermal_list, self._psu_list) + def initialize_eeprom(self): from eeprom import Eeprom # Initialize EEPROM self._eeprom = Eeprom() - def initialize_components_list(self): + + def initialize_components(self): # Initialize component list - self._component_name_list.append(COMPONENT_BIOS) - self._component_name_list.append(COMPONENT_FIRMWARE) - self._component_name_list.append(COMPONENT_CPLD1) - self._component_name_list.append(COMPONENT_CPLD2) + from sonic_platform.component import ComponentBIOS, ComponentCPLD + self._component_list.append(ComponentBIOS()) + self._component_list.append(ComponentCPLD()) + ############################################## # SFP methods @@ -159,6 +151,7 @@ def get_num_sfps(self): self.initialize_sfp() return len(self._sfp_list) + def get_all_sfps(self): """ Retrieves all sfps available on this chassis @@ -171,6 +164,7 @@ def get_all_sfps(self): self.initialize_sfp() return self._sfp_list + def get_sfp(self, index): """ Retrieves sfp represented by (0-based) index @@ -197,6 +191,7 @@ def get_sfp(self, index): return sfp + def _extract_num_of_fans_and_fan_drawers(self): num_of_fan = 0 num_of_drawer = 0 @@ -213,15 +208,18 @@ def _extract_num_of_fans_and_fan_drawers(self): return num_of_fan, num_of_drawer + def _get_sku_name(self): p = subprocess.Popen(GET_HWSKU_CMD, shell=True, stdout=subprocess.PIPE) out, err = p.communicate() return out.rstrip('\n') + def _get_port_position_tuple_by_sku_name(self): position_tuple = port_position_tuple_list[hwsku_dict_port[self.sku_name]] return position_tuple + def get_watchdog(self): """ Retrieves hardware watchdog device on this chassis @@ -246,6 +244,7 @@ def get_watchdog(self): return self._watchdog + def get_base_mac(self): """ Retrieves the base MAC address for the chassis @@ -256,6 +255,7 @@ def get_base_mac(self): """ return self._eeprom.get_base_mac() + def get_serial_number(self): """ Retrieves the hardware serial number for the chassis @@ -265,6 +265,7 @@ def get_serial_number(self): """ return self._eeprom.get_serial_number() + def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis @@ -276,6 +277,7 @@ def get_system_eeprom_info(self): """ return self._eeprom.get_system_eeprom_info() + def _read_generic_file(self, filename, len): """ Read a generic file, returns the contents of the file @@ -290,6 +292,7 @@ def _read_generic_file(self, filename, len): logger.log_info("Fail to read file {} due to {}".format(filename, repr(e))) return '0' + def _verify_reboot_cause(self, filename): ''' Open and read the reboot cause file in @@ -298,6 +301,7 @@ def _verify_reboot_cause(self, filename): ''' return bool(int(self._read_generic_file(join(REBOOT_CAUSE_ROOT, filename), REBOOT_CAUSE_FILE_LENGTH).rstrip('\n'))) + def initialize_reboot_cause(self): self.reboot_major_cause_dict = { 'reset_main_pwr_fail' : self.REBOOT_CAUSE_POWER_LOSS, @@ -323,6 +327,7 @@ def initialize_reboot_cause(self): } self.reboot_cause_initialized = True + def get_reboot_cause(self): """ Retrieves the cause of the previous reboot @@ -348,101 +353,6 @@ def get_reboot_cause(self): return self.REBOOT_CAUSE_NON_HARDWARE, '' - def _get_cpld_version(self, version_file): - cpld_version = self._read_generic_file(join(CPLD_VERSION_ROOT, version_file), CPLD_VERSION_MAX_LENGTH) - return cpld_version.rstrip('\n') - - def _get_command_result(self, cmdline): - try: - proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT) - stdout = proc.communicate()[0] - proc.wait() - result = stdout.rstrip('\n') - - except OSError, e: - result = '' - - return result - - def _get_firmware_version(self): - """ - firmware version is retrieved via command 'mlxfwmanager --query' - which should return result in the following convention - admin@mtbc-sonic-01-2410:~$ sudo mlxfwmanager --query - Querying Mellanox devices firmware ... - - Device #1: - ---------- - - Device Type: Spectrum - Part Number: MSN2410-CxxxO_Ax_Bx - Description: Spectrum based 25GbE/100GbE 1U Open Ethernet switch with ONIE; 48 SFP28 ports; 8 QSFP28 ports; x86 dual core; RoHS6 - PSID: MT_2860111033 - PCI Device Name: /dev/mst/mt52100_pci_cr0 - Base MAC: 98039bf3f500 - Versions: Current Available - FW ***13.2000.1140***N/A - - Status: No matching image found - - By using regular expression '(Versions:.*\n[\s]+FW[\s]+)([\S]+)', - we can extrace the version which is marked with *** in the above context - """ - fw_ver_str = self._get_command_result(FW_QUERY_VERSION_COMMAND) - try: - m = re.search('(Versions:.*\n[\s]+FW[\s]+)([\S]+)', fw_ver_str) - result = m.group(2) - except : - result = '' - - return result - - def _get_bios_version(self): - """ - BIOS version is retrieved via command 'dmidecode -t 11' - which should return result in the following convention - # dmidecode 3.0 - Getting SMBIOS data from sysfs. - SMBIOS 2.7 present. - - Handle 0x0022, DMI type 11, 5 bytes - OEM Strings - String 1:*0ABZS017_02.02.002* - String 2: To Be Filled By O.E.M. - - By using regular expression 'OEM[\s]*Strings\n[\s]*String[\s]*1:[\s]*([0-9a-zA-Z_\.]*)' - we can extrace the version string which is marked with * in the above context - """ - bios_ver_str = self._get_command_result(BIOS_QUERY_VERSION_COMMAND) - try: - m = re.search('OEM[\s]*Strings\n[\s]*String[\s]*1:[\s]*([0-9a-zA-Z_\.]*)', bios_ver_str) - result = m.group(1) - except: - result = '' - - return result - - def get_firmware_version(self, component_name): - """ - Retrieves platform-specific hardware/firmware versions for chassis - componenets such as BIOS, CPLD, FPGA, etc. - Args: - component_name: A string, the component name. - - Returns: - A string containing platform-specific component versions - """ - if component_name in self._component_name_list : - if component_name == COMPONENT_BIOS: - return self._get_bios_version() - elif component_name == COMPONENT_CPLD1: - return self._get_cpld_version(CPLD1_VERSION_FILE) - elif component_name == COMPONENT_CPLD2: - return self._get_cpld_version(CPLD2_VERSION_FILE) - elif component_name == COMPONENT_FIRMWARE: - return self._get_firmware_version() - - return None def _show_capabilities(self): """ @@ -465,6 +375,7 @@ def _show_capabilities(self): except: print "fail to retrieve capabilities for module index {}".format(s.index) + def get_change_event(self, timeout=0): """ Returns a nested dictionary containing all devices which have diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/component.py b/platform/mellanox/mlnx-platform-api/sonic_platform/component.py new file mode 100644 index 000000000000..fd593f7bbe45 --- /dev/null +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/component.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python + +############################################################################# +# Mellanox +# +# implementation of new platform api +############################################################################# + +try: + from sonic_platform_base.component_base import ComponentBase + from glob import glob + import subprocess + import io + import re +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +#components definitions +COMPONENT_BIOS = "BIOS" +COMPONENT_CPLD = "CPLD" + +BIOS_QUERY_VERSION_COMMAND = 'dmidecode -t 11' +CPLD_VERSION_FILE_PATTERN = '/var/run/hw-management/system/cpld[0-9]_version' +CPLD_VERSION_MAX_LENGTH = 4 + +class Component(ComponentBase): + def get_name(self): + """ + Retrieves the name of the component + + Returns: + A string containing the name of the component + """ + return self.name + + + def _read_generic_file(self, filename, len): + """ + Read a generic file, returns the contents of the file + """ + result = '' + try: + with io.open(filename, 'r') as fileobj: + result = fileobj.read(len) + return result + except IOError as e: + raise RuntimeError("Failed to read file {} due to {}".format(filename, repr(e))) + + + def _get_command_result(self, cmdline): + try: + proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + result = stdout.rstrip('\n') + + except OSError as e: + raise RuntimeError("Failed to execute command {} due to {}".format(cmdline, repr(e))) + + return result + + +class ComponentBIOS(Component): + BIOS_VERSION_PARSE_PATTERN = 'OEM[\s]*Strings\n[\s]*String[\s]*1:[\s]*([0-9a-zA-Z_\.]*)' + + + def __init__(self): + self.name = COMPONENT_BIOS + + + def get_description(self): + """ + Retrieves the description of the component + + Returns: + A string containing the description of the component + """ + return "BIOS - Basic Input/Output System" + + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + + Returns: + A string containing the firmware version of the component + + BIOS version is retrieved via command 'dmidecode -t 11' + which should return result in the following convention + # dmidecode 3.0 + Getting SMBIOS data from sysfs. + SMBIOS 2.7 present. + + Handle 0x0022, DMI type 11, 5 bytes + OEM Strings + String 1:*0ABZS017_02.02.002* + String 2: To Be Filled By O.E.M. + + By using regular expression 'OEM[\s]*Strings\n[\s]*String[\s]*1:[\s]*([0-9a-zA-Z_\.]*)' + we can extrace the version string which is marked with * in the above context + """ + bios_ver_str = self._get_command_result(BIOS_QUERY_VERSION_COMMAND) + try: + m = re.search(self.BIOS_VERSION_PARSE_PATTERN, bios_ver_str) + result = m.group(1) + except AttributeError as e: + raise RuntimeError("Failed to parse BIOS version by {} from {} due to {}".format( + self.BIOS_VERSION_PARSE_PATTERN, bios_ver_str, repr(e))) + + return result + + +class ComponentCPLD(Component): + def __init__(self): + self.name = COMPONENT_CPLD + + + def get_description(self): + """ + Retrieves the description of the component + + Returns: + A string containing the description of the component + """ + return "CPLD - includes all CPLDs in the switch" + + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + + Returns: + A string containing the firmware version of the component + """ + cpld_version_file_list = glob(CPLD_VERSION_FILE_PATTERN) + cpld_version = '' + if cpld_version_file_list is not None and cpld_version_file_list: + cpld_version_file_list.sort() + for version_file in cpld_version_file_list: + version = self._read_generic_file(version_file, CPLD_VERSION_MAX_LENGTH) + if not cpld_version == '': + cpld_version += '.' + cpld_version += version.rstrip('\n') + else: + raise RuntimeError("Failed to get CPLD version files by matching {}".format(CPLD_VERSION_FILE_PATTERN)) + + return cpld_version + diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py b/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py index fc555bc479a3..25461986f37a 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py @@ -18,12 +18,12 @@ def __init__(self): PlatformBase.__init__(self) if self._is_host(): self._chassis = Chassis() + self._chassis.initialize_components() else: self._chassis = Chassis() self._chassis.initialize_psu() self._chassis.initialize_fan() self._chassis.initialize_eeprom() - self._chassis.initialize_components_list() def _is_host(self): """ From 41e855c2112326949f68ff4098282bdbb2a24587 Mon Sep 17 00:00:00 2001 From: JohnsonYJLu <31528297+JohnsonYJLu@users.noreply.github.com> Date: Thu, 10 Oct 2019 04:53:07 +0800 Subject: [PATCH 058/278] [devices]: fixed sfputil error on ag9032 (#3579) Signed-off-by: johnson --- .../Delta-ag9032v2a/port_config.ini | 66 ++++---- .../plugins/sfputil.py | 8 +- .../modules/delta_ag9032v2a_platform.c | 151 +++++++++++------- 3 files changed, 134 insertions(+), 91 deletions(-) diff --git a/device/delta/x86_64-delta_ag9032v2a-r0/Delta-ag9032v2a/port_config.ini b/device/delta/x86_64-delta_ag9032v2a-r0/Delta-ag9032v2a/port_config.ini index d7b858054ff9..9eb4ac0c8a0c 100644 --- a/device/delta/x86_64-delta_ag9032v2a-r0/Delta-ag9032v2a/port_config.ini +++ b/device/delta/x86_64-delta_ag9032v2a-r0/Delta-ag9032v2a/port_config.ini @@ -1,34 +1,34 @@ # name lanes alias index speed -Ethernet0 1,2,3,4 hundredGigE1/1 1 100000 -Ethernet4 5,6,7,8 hundredGigE1/2 2 100000 -Ethernet8 9,10,11,12 hundredGigE1/3 3 100000 -Ethernet12 13,14,15,16 hundredGigE1/4 4 100000 -Ethernet16 17,18,19,20 hundredGigE1/5 5 100000 -Ethernet20 21,22,23,24 hundredGigE1/6 6 100000 -Ethernet24 25,26,27,28 hundredGigE1/7 7 100000 -Ethernet28 29,30,31,32 hundredGigE1/8 8 100000 -Ethernet32 33,34,35,36 hundredGigE1/9 9 100000 -Ethernet36 37,38,39,40 hundredGigE1/10 10 100000 -Ethernet40 41,42,43,44 hundredGigE1/11 11 100000 -Ethernet44 45,46,47,48 hundredGigE1/12 12 100000 -Ethernet48 49,50,51,52 hundredGigE1/13 13 100000 -Ethernet52 53,54,55,56 hundredGigE1/14 14 100000 -Ethernet56 57,58,59,60 hundredGigE1/15 15 100000 -Ethernet60 61,62,63,64 hundredGigE1/16 16 100000 -Ethernet64 65,66,67,68 hundredGigE1/17 17 100000 -Ethernet68 69,70,71,72 hundredGigE1/18 18 100000 -Ethernet72 73,74,75,76 hundredGigE1/19 19 100000 -Ethernet76 77,78,79,80 hundredGigE1/20 20 100000 -Ethernet80 81,82,83,84 hundredGigE1/21 21 100000 -Ethernet84 85,86,87,88 hundredGigE1/22 22 100000 -Ethernet88 89,90,91,92 hundredGigE1/23 23 100000 -Ethernet92 93,94,95,96 hundredGigE1/24 24 100000 -Ethernet96 97,98,99,100 hundredGigE1/25 25 100000 -Ethernet100 101,102,103,104 hundredGigE1/26 26 100000 -Ethernet104 105,106,107,108 hundredGigE1/27 27 100000 -Ethernet108 109,110,111,112 hundredGigE1/28 28 100000 -Ethernet112 113,114,115,116 hundredGigE1/29 29 100000 -Ethernet116 117,118,119,120 hundredGigE1/30 30 100000 -Ethernet120 121,122,123,124 hundredGigE1/31 31 100000 -Ethernet124 125,126,127,128 hundredGigE1/32 32 100000 -Ethernet128 129 tenGigE1/33 33 10000 +Ethernet0 1,2,3,4 hundredGigE1/1 0 100000 +Ethernet4 5,6,7,8 hundredGigE1/2 1 100000 +Ethernet8 9,10,11,12 hundredGigE1/3 2 100000 +Ethernet12 13,14,15,16 hundredGigE1/4 3 100000 +Ethernet16 17,18,19,20 hundredGigE1/5 4 100000 +Ethernet20 21,22,23,24 hundredGigE1/6 5 100000 +Ethernet24 25,26,27,28 hundredGigE1/7 6 100000 +Ethernet28 29,30,31,32 hundredGigE1/8 7 100000 +Ethernet32 33,34,35,36 hundredGigE1/9 8 100000 +Ethernet36 37,38,39,40 hundredGigE1/10 9 100000 +Ethernet40 41,42,43,44 hundredGigE1/11 10 100000 +Ethernet44 45,46,47,48 hundredGigE1/12 11 100000 +Ethernet48 49,50,51,52 hundredGigE1/13 12 100000 +Ethernet52 53,54,55,56 hundredGigE1/14 13 100000 +Ethernet56 57,58,59,60 hundredGigE1/15 14 100000 +Ethernet60 61,62,63,64 hundredGigE1/16 15 100000 +Ethernet64 65,66,67,68 hundredGigE1/17 16 100000 +Ethernet68 69,70,71,72 hundredGigE1/18 17 100000 +Ethernet72 73,74,75,76 hundredGigE1/19 18 100000 +Ethernet76 77,78,79,80 hundredGigE1/20 19 100000 +Ethernet80 81,82,83,84 hundredGigE1/21 20 100000 +Ethernet84 85,86,87,88 hundredGigE1/22 21 100000 +Ethernet88 89,90,91,92 hundredGigE1/23 22 100000 +Ethernet92 93,94,95,96 hundredGigE1/24 23 100000 +Ethernet96 97,98,99,100 hundredGigE1/25 24 100000 +Ethernet100 101,102,103,104 hundredGigE1/26 25 100000 +Ethernet104 105,106,107,108 hundredGigE1/27 26 100000 +Ethernet108 109,110,111,112 hundredGigE1/28 27 100000 +Ethernet112 113,114,115,116 hundredGigE1/29 28 100000 +Ethernet116 117,118,119,120 hundredGigE1/30 29 100000 +Ethernet120 121,122,123,124 hundredGigE1/31 30 100000 +Ethernet124 125,126,127,128 hundredGigE1/32 31 100000 +Ethernet128 129 tenGigE1/33 32 10000 diff --git a/device/delta/x86_64-delta_ag9032v2a-r0/plugins/sfputil.py b/device/delta/x86_64-delta_ag9032v2a-r0/plugins/sfputil.py index 2cffa8807c0a..9abaa8cf01c1 100644 --- a/device/delta/x86_64-delta_ag9032v2a-r0/plugins/sfputil.py +++ b/device/delta/x86_64-delta_ag9032v2a-r0/plugins/sfputil.py @@ -62,7 +62,7 @@ def get_presence(self, port_num): reg_value = int(content, 16) # Mask off the bit corresponding to our port - mask = (1 << port_num) + mask = (1 << (self.port_end - port_num + 7)) # ModPrsL is active low if reg_value & mask == 0: @@ -86,7 +86,7 @@ def get_low_power_mode(self, port_num): reg_value = int(content, 16) # Mask off the bit corresponding to our port - mask = (1 << port_num) + mask = (1 << (self.port_end - port_num) - 1) # LPMode is active high if reg_value & mask == 0: @@ -111,7 +111,7 @@ def set_low_power_mode(self, port_num, lpmode): reg_value = int(content, 16) # Mask off the bit corresponding to our port - mask = (1 << port_num) + mask = (1 << (self.port_end - port_num) - 1) # LPMode is active high; set or clear the bit accordingly if lpmode is True: @@ -147,7 +147,7 @@ def reset(self, port_num): reg_value = int(content, 16) # Mask off the bit corresponding to our port - mask = (1 << port_num) + mask = (1 << (self.port_end - port_num) - 1) # ResetL is active low reg_value = reg_value & ~mask diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9032v2a/modules/delta_ag9032v2a_platform.c b/platform/broadcom/sonic-platform-modules-delta/ag9032v2a/modules/delta_ag9032v2a_platform.c index e9baeb928faf..85719af7ea94 100644 --- a/platform/broadcom/sonic-platform-modules-delta/ag9032v2a/modules/delta_ag9032v2a_platform.c +++ b/platform/broadcom/sonic-platform-modules-delta/ag9032v2a/modules/delta_ag9032v2a_platform.c @@ -566,53 +566,53 @@ static ssize_t for_status(struct device *dev, struct device_attribute *dev_attr, mutex_lock(&dni_lock); switch (attr->index) { case SFP_IS_PRESENT: - /*QSFP1~8*/ - ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_PRESENCE_1); - data = (u32)(reverse_8bits(ret) & 0xff); - /*QSFP9~16*/ - ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_PRESENCE_2); - data |= (u32)(reverse_8bits(ret) & 0xff) << 8; - /*QSFP17~24*/ - ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_PRESENCE_3); - data |= (u32)(reverse_8bits(ret) & 0xff) << 16; /*QSFP25~32*/ ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_PRESENCE_4); - data |= (u32)(reverse_8bits(ret) & 0xff) << 24; + data = (u32)ret & 0xff; + /*QSFP17~24*/ + ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_PRESENCE_3); + data |= ((u32)ret & 0xff) << 8; + /*QSFP9~16*/ + ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_PRESENCE_2); + data |= (u32)(ret & 0xff) << 16; + /*QSFP1~8*/ + ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_PRESENCE_1); + data |= (u32)(ret & 0xff) << 24; ret = i2c_smbus_read_byte_data(pdata2[swpld2].client, SFP_PRESENCE_5); - ret_sfp = (ret & (0x80)) >> 7; + ret_sfp = (ret & (0x80)); mutex_unlock(&dni_lock); - return sprintf(buf, "0x%x%x\n", ret_sfp, data); + return sprintf(buf, "0x%x%02x\n", data, ret_sfp); case QSFP_LPMODE: - /*QSFP1~8*/ - ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_LPMODE_1); - data = (u32)(reverse_8bits(ret) & 0xff); - /*QSFP9~16*/ - ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_LPMODE_2); - data |= (u32)(reverse_8bits(ret) & 0xff) << 8; - /*QSFP17~24*/ - ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_LPMODE_3); - data |= (u32)(reverse_8bits(ret) & 0xff) << 16; /*QSFP25~32*/ ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_LPMODE_4); - data |= (u32)(reverse_8bits(ret) & 0xff) << 24; + data = (u32)(ret & 0xff); + /*QSFP17~24*/ + ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_LPMODE_3); + data |= (u32)(ret & 0xff) << 8; + /*QSFP9~16*/ + ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_LPMODE_2); + data |= (u32)(ret & 0xff) << 16; + /*QSFP1~8*/ + ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_LPMODE_1); + data |= (u32)(ret & 0xff) << 24; mutex_unlock(&dni_lock); return sprintf(buf, "0x%x\n", data); case QSFP_RESET: - /*QSFP1~8*/ - ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_RESET_1); - data = (u32)(reverse_8bits(ret) & 0xff); - /*QSFP9~16*/ - ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_RESET_2); - data |= (u32)(reverse_8bits(ret) & 0xff) << 8; - /*QSFP17~24*/ - ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_RESET_3); - data |= (u32)(reverse_8bits(ret) & 0xff) << 16; /*QSFP25~32*/ ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_RESET_4); - data |= (u32)(reverse_8bits(ret) & 0xff) << 24; + data = (u32)(ret & 0xff); + /*QSFP17~24*/ + ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_RESET_3); + data |= (u32)(ret & 0xff) << 8; + /*QSFP9~16*/ + ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_RESET_2); + data |= (u32)(ret & 0xff) << 16; + /*QSFP1~8*/ + ret = i2c_smbus_read_byte_data(pdata1[swpld1].client, QSFP_RESET_1); + data |= (u32)(ret & 0xff) << 24; mutex_unlock(&dni_lock); return sprintf(buf, "0x%x\n", data); @@ -628,6 +628,7 @@ static ssize_t set_lpmode_data(struct device *dev, struct device_attribute *dev_ struct cpld_platform_data *pdata = i2cdev->platform_data; unsigned long long set_data; int err; + int status = 0; unsigned char set_bytes; @@ -636,24 +637,45 @@ static ssize_t set_lpmode_data(struct device *dev, struct device_attribute *dev_ return err; } mutex_lock(&dni_lock); - /*QSFP1~8*/ - set_bytes = reverse_8bits(set_data & 0xff); - i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_LPMODE_1, set_bytes); + /*QSFP25~32*/ + set_bytes = set_data & 0xff; + status = i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_LPMODE_4, set_bytes); + if(status < 0) + { + goto ERROR; + } + + /*QSFP17~24*/ + set_bytes = (set_data >> 8 ) & 0xff; + status = i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_LPMODE_3, set_bytes); + if(status < 0) + { + goto ERROR; + } /*QSFP9~16*/ - set_bytes = reverse_8bits((set_data >> 8 ) & 0xff); - i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_LPMODE_2, set_bytes); + set_bytes = (set_data >> 16 ) & 0xff; + status = i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_LPMODE_2, set_bytes); + if(status < 0) + { + goto ERROR; + } - /*QSFP17~24*/ - set_bytes = reverse_8bits((set_data >> 16 ) & 0xff); - i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_LPMODE_3, set_bytes); + /*QSFP1~8*/ + set_bytes = (set_data >> 24 ) & 0xff; + status = i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_LPMODE_1, set_bytes); + if(status < 0) + { + goto ERROR; + } - /*QSFP25~32*/ - set_bytes = reverse_8bits((set_data >> 24 ) & 0xff); - i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_LPMODE_4, set_bytes); mutex_unlock(&dni_lock); return count; +ERROR: + mutex_unlock(&dni_lock); + return status; + } static ssize_t set_reset_data(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count) @@ -662,6 +684,7 @@ static ssize_t set_reset_data(struct device *dev, struct device_attribute *dev_a struct cpld_platform_data *pdata = i2cdev->platform_data; unsigned long long set_data; int err; + int status = 0; unsigned char set_bytes; err = kstrtoull(buf, 16, &set_data); @@ -670,23 +693,43 @@ static ssize_t set_reset_data(struct device *dev, struct device_attribute *dev_a } mutex_lock(&dni_lock); - /*QSFP1~8*/ - set_bytes = reverse_8bits(set_data & 0xff); - i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_RESET_1, set_bytes); + /*QSFP25~32*/ + set_bytes = set_data & 0xff; + status = i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_RESET_4, set_bytes); + if(status < 0) + { + goto ERROR; + } + + /*QSFP17~24*/ + set_bytes = (set_data >> 8 ) & 0xff; + status = i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_RESET_3, set_bytes); + if(status < 0) + { + goto ERROR; + } /*QSFP9~16*/ - set_bytes = reverse_8bits((set_data >> 8 ) & 0xff); - i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_RESET_2, set_bytes); + set_bytes = (set_data >> 16 ) & 0xff; + status = i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_RESET_2, set_bytes); + if(status < 0) + { + goto ERROR; + } - /*QSFP17~24*/ - set_bytes = reverse_8bits((set_data >> 16 ) & 0xff); - i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_RESET_3, set_bytes); + /*QSFP1~8*/ + set_bytes = (set_data >> 24 ) & 0xff; + status = i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_RESET_1, set_bytes); + if(status < 0) + { + goto ERROR; + } - /*QSFP25~32*/ - set_bytes = reverse_8bits((set_data >> 24 ) & 0xff); - i2c_smbus_write_byte_data(pdata[swpld1].client, QSFP_RESET_4, set_bytes); mutex_unlock(&dni_lock); return count; +ERROR: + mutex_unlock(&dni_lock); + return status; } From 110bff9b47f5bcfa76638ac52f862dd83ba113b7 Mon Sep 17 00:00:00 2001 From: David Xiao <53024022+david-xk@users.noreply.github.com> Date: Wed, 9 Oct 2019 16:16:05 -0700 Subject: [PATCH 059/278] [Inventec][D6356] Update driver and Add new platform API implementation (#3521) * Update driver and Add new platform API implementation for Inventec D6356 * Update Platform API (SFP) * Update Platform API (QSFP) * Update Platform API (FAN, THERMAL) Signed-off-by: David Xiao --- .../INVENTEC-D6356/buffers.json.j2 | 2 + .../INVENTEC-D6356/buffers_defaults_t0.j2 | 50 + .../INVENTEC-D6356/buffers_defaults_t1.j2 | 50 + .../INVENTEC-D6356/pg_profile_lookup.ini | 17 + .../INVENTEC-D6356/port_config.ini | 114 +- .../INVENTEC-D6356/qos.json.j2 | 155 +++ .../td3-d6356-48x25G-8x100G.config.bcm | 248 ++-- .../x86_64-inventec_d6356-r0/custom_led.bin | Bin 0 -> 552 bytes .../led_proc_init.soc | 4 +- .../linkscan_led_fw.bin | Bin 0 -> 4744 bytes .../plugins/psuutil.py | 12 +- .../plugins/sfputil.py | 170 ++- .../x86_64-inventec_d6356-r0/sensors.conf | 7 +- .../d6356/modules/Makefile | 4 + .../d6356/modules/gpio-ich.c | 513 ++++++++ .../d6356/modules/i2c-mux-pca9541.c | 573 +++++++++ .../d6356/modules/inv_cpld.c | 165 ++- .../d6356/modules/inv_mux.c | 364 +++++- .../d6356/modules/inv_mux.h | 46 +- .../d6356/modules/inv_platform.c | 92 +- .../d6356/modules/inv_swps.c | 331 ++++- .../d6356/modules/inv_swps.h | 621 +++++++-- .../d6356/modules/io_expander.c | 630 ++++++++- .../d6356/modules/io_expander.h | 52 +- .../d6356/modules/lpc_ich.c | 1131 +++++++++++++++++ .../d6356/modules/pmbus.h | 425 +++++++ .../d6356/modules/transceiver.c | 35 +- .../d6356/modules/transceiver.h | 8 +- .../d6356/modules/ucd9000.c | 247 ++++ .../d6356/setup.py | 15 + .../d6356/sonic_platform/__init__.py | 3 + .../d6356/sonic_platform/chassis.py | 149 +++ .../d6356/sonic_platform/eeprom.py | 110 ++ .../d6356/sonic_platform/fan.py | 204 +++ .../d6356/sonic_platform/platform.py | 20 + .../d6356/sonic_platform/psu.py | 202 +++ .../d6356/sonic_platform/qsfp.py | 925 ++++++++++++++ .../d6356/sonic_platform/sfp.py | 739 +++++++++++ .../d6356/sonic_platform/thermal.py | 170 +++ .../d6356/utils/inventec_d6356_util.py | 33 +- .../debian/control | 2 +- .../debian/platform-modules-d6356.install | 4 +- .../debian/rules | 18 +- .../systemd/platform-modules-d6356.service | 13 + 44 files changed, 8074 insertions(+), 599 deletions(-) create mode 100644 device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/buffers.json.j2 create mode 100644 device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/buffers_defaults_t0.j2 create mode 100644 device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/buffers_defaults_t1.j2 create mode 100644 device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/pg_profile_lookup.ini create mode 100644 device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/qos.json.j2 create mode 100644 device/inventec/x86_64-inventec_d6356-r0/custom_led.bin create mode 100644 device/inventec/x86_64-inventec_d6356-r0/linkscan_led_fw.bin create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/modules/gpio-ich.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/modules/i2c-mux-pca9541.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/modules/lpc_ich.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/modules/pmbus.h create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/modules/ucd9000.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/setup.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/__init__.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/chassis.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/eeprom.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/fan.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/platform.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/psu.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/qsfp.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/sfp.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/thermal.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/systemd/platform-modules-d6356.service diff --git a/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/buffers.json.j2 b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/buffers.json.j2 new file mode 100644 index 000000000000..0b1cb2c541b6 --- /dev/null +++ b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/buffers.json.j2 @@ -0,0 +1,2 @@ +{%- set default_topo = 't1' %} +{%- include 'buffers_config.j2' %} diff --git a/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/buffers_defaults_t0.j2 b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/buffers_defaults_t0.j2 new file mode 100644 index 000000000000..1587625a294e --- /dev/null +++ b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/buffers_defaults_t0.j2 @@ -0,0 +1,50 @@ +{%- set default_cable = '40m' %} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {% for port_idx in range(0,47) %} + {% if PORT.append("Ethernet%d" % (port_idx)) %}{% endif %} + {% endfor %} + {% for port_idx in range(12,19) %} + {% if PORT.append("Ethernet%d" % (port_idx*4)) %}{% endif %} + {% endfor %} +{%- endmacro %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "10443264", + "type": "ingress", + "mode": "dynamic", + "xoff": "7335744" + }, + "egress_lossy_pool": { + "size": "8877440", + "type": "egress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "15982720", + "type": "egress", + "mode": "static" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "dynamic_th":"3" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "static_th":"3995680" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} + diff --git a/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/buffers_defaults_t1.j2 b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/buffers_defaults_t1.j2 new file mode 100644 index 000000000000..1587625a294e --- /dev/null +++ b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/buffers_defaults_t1.j2 @@ -0,0 +1,50 @@ +{%- set default_cable = '40m' %} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {% for port_idx in range(0,47) %} + {% if PORT.append("Ethernet%d" % (port_idx)) %}{% endif %} + {% endfor %} + {% for port_idx in range(12,19) %} + {% if PORT.append("Ethernet%d" % (port_idx*4)) %}{% endif %} + {% endfor %} +{%- endmacro %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "10443264", + "type": "ingress", + "mode": "dynamic", + "xoff": "7335744" + }, + "egress_lossy_pool": { + "size": "8877440", + "type": "egress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "15982720", + "type": "egress", + "mode": "static" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "dynamic_th":"3" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "static_th":"3995680" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} + diff --git a/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/pg_profile_lookup.ini b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/pg_profile_lookup.ini new file mode 100644 index 000000000000..7222f8014925 --- /dev/null +++ b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/pg_profile_lookup.ini @@ -0,0 +1,17 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold xon_offset + 10000 5m 1248 2288 35776 -4 2288 + 25000 5m 1248 2288 53248 -4 2288 + 40000 5m 1248 2288 66560 -4 2288 + 50000 5m 1248 2288 79872 -4 2288 + 100000 5m 1248 2288 165568 -4 2288 + 10000 40m 1248 2288 37024 -4 2288 + 25000 40m 1248 2288 56160 -4 2288 + 40000 40m 1248 2288 71552 -4 2288 + 50000 40m 1248 2288 85696 -4 2288 + 100000 40m 1248 2288 177632 -4 2288 + 10000 300m 1248 2288 46176 -4 2288 + 25000 300m 1248 2288 79040 -4 2288 + 40000 300m 1248 2288 108160 -4 2288 + 50000 300m 1248 2288 131456 -4 2288 + 100000 300m 1248 2288 268736 -4 2288 diff --git a/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/port_config.ini b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/port_config.ini index ba13dd5743bc..aaac478ab8fd 100755 --- a/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/port_config.ini +++ b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/port_config.ini @@ -1,57 +1,57 @@ -# name lanes alias index -Ethernet0 1 Ethernet0 0 -Ethernet1 2 Ethernet1 1 -Ethernet2 3 Ethernet2 2 -Ethernet3 4 Ethernet3 3 -Ethernet4 5 Ethernet4 4 -Ethernet5 6 Ethernet5 5 -Ethernet6 7 Ethernet6 6 -Ethernet7 8 Ethernet7 7 -Ethernet8 13 Ethernet8 8 -Ethernet9 14 Ethernet9 9 -Ethernet10 15 Ethernet10 10 -Ethernet11 16 Ethernet11 11 -Ethernet12 21 Ethernet12 12 -Ethernet13 22 Ethernet13 13 -Ethernet14 23 Ethernet14 14 -Ethernet15 24 Ethernet15 15 -Ethernet16 29 Ethernet16 16 -Ethernet17 30 Ethernet17 17 -Ethernet18 31 Ethernet18 18 -Ethernet19 32 Ethernet19 19 -Ethernet20 33 Ethernet20 20 -Ethernet21 34 Ethernet21 21 -Ethernet22 35 Ethernet22 22 -Ethernet23 36 Ethernet23 23 -Ethernet24 41 Ethernet24 24 -Ethernet25 42 Ethernet25 25 -Ethernet26 43 Ethernet26 26 -Ethernet27 44 Ethernet27 27 -Ethernet28 49 Ethernet28 28 -Ethernet29 50 Ethernet29 29 -Ethernet30 51 Ethernet30 30 -Ethernet31 52 Ethernet31 31 -Ethernet32 57 Ethernet32 32 -Ethernet33 58 Ethernet33 33 -Ethernet34 59 Ethernet34 34 -Ethernet35 60 Ethernet35 35 -Ethernet36 61 Ethernet36 36 -Ethernet37 62 Ethernet37 37 -Ethernet38 63 Ethernet38 38 -Ethernet39 64 Ethernet39 39 -Ethernet40 65 Ethernet40 40 -Ethernet41 66 Ethernet41 41 -Ethernet42 67 Ethernet42 42 -Ethernet43 68 Ethernet43 43 -Ethernet44 69 Ethernet44 44 -Ethernet45 70 Ethernet45 45 -Ethernet46 71 Ethernet46 46 -Ethernet47 72 Ethernet47 47 -Ethernet48 85,86,87,88 Ethernet48 48 -Ethernet52 77,78,79,80 Ethernet52 49 -Ethernet56 93,94,95,96 Ethernet56 50 -Ethernet60 97,98,99,100 Ethernet60 51 -Ethernet64 113,114,115,116 Ethernet64 52 -Ethernet68 105,106,107,108 Ethernet68 53 -Ethernet72 121,122,123,124 Ethernet72 54 -Ethernet76 125,126,127,128 Ethernet76 55 +# name lanes alias index speed +Ethernet0 1 Ethernet0 0 25000 +Ethernet1 2 Ethernet1 1 25000 +Ethernet2 3 Ethernet2 2 25000 +Ethernet3 4 Ethernet3 3 25000 +Ethernet4 5 Ethernet4 4 25000 +Ethernet5 6 Ethernet5 5 25000 +Ethernet6 7 Ethernet6 6 25000 +Ethernet7 8 Ethernet7 7 25000 +Ethernet8 13 Ethernet8 8 25000 +Ethernet9 14 Ethernet9 9 25000 +Ethernet10 15 Ethernet10 10 25000 +Ethernet11 16 Ethernet11 11 25000 +Ethernet12 21 Ethernet12 12 25000 +Ethernet13 22 Ethernet13 13 25000 +Ethernet14 23 Ethernet14 14 25000 +Ethernet15 24 Ethernet15 15 25000 +Ethernet16 29 Ethernet16 16 25000 +Ethernet17 30 Ethernet17 17 25000 +Ethernet18 31 Ethernet18 18 25000 +Ethernet19 32 Ethernet19 19 25000 +Ethernet20 33 Ethernet20 20 25000 +Ethernet21 34 Ethernet21 21 25000 +Ethernet22 35 Ethernet22 22 25000 +Ethernet23 36 Ethernet23 23 25000 +Ethernet24 41 Ethernet24 24 25000 +Ethernet25 42 Ethernet25 25 25000 +Ethernet26 43 Ethernet26 26 25000 +Ethernet27 44 Ethernet27 27 25000 +Ethernet28 49 Ethernet28 28 25000 +Ethernet29 50 Ethernet29 29 25000 +Ethernet30 51 Ethernet30 30 25000 +Ethernet31 52 Ethernet31 31 25000 +Ethernet32 57 Ethernet32 32 25000 +Ethernet33 58 Ethernet33 33 25000 +Ethernet34 59 Ethernet34 34 25000 +Ethernet35 60 Ethernet35 35 25000 +Ethernet36 61 Ethernet36 36 25000 +Ethernet37 62 Ethernet37 37 25000 +Ethernet38 63 Ethernet38 38 25000 +Ethernet39 64 Ethernet39 39 25000 +Ethernet40 65 Ethernet40 40 25000 +Ethernet41 66 Ethernet41 41 25000 +Ethernet42 67 Ethernet42 42 25000 +Ethernet43 68 Ethernet43 43 25000 +Ethernet44 69 Ethernet44 44 25000 +Ethernet45 70 Ethernet45 45 25000 +Ethernet46 71 Ethernet46 46 25000 +Ethernet47 72 Ethernet47 47 25000 +Ethernet48 85,86,87,88 Ethernet48 48 100000 +Ethernet52 77,78,79,80 Ethernet52 49 100000 +Ethernet56 93,94,95,96 Ethernet56 50 100000 +Ethernet60 97,98,99,100 Ethernet60 51 100000 +Ethernet64 113,114,115,116 Ethernet64 52 100000 +Ethernet68 105,106,107,108 Ethernet68 53 100000 +Ethernet72 121,122,123,124 Ethernet72 54 100000 +Ethernet76 125,126,127,128 Ethernet76 55 100000 diff --git a/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/qos.json.j2 b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/qos.json.j2 new file mode 100644 index 000000000000..d3cac04f662a --- /dev/null +++ b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/qos.json.j2 @@ -0,0 +1,155 @@ +{ + "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":"0", + "1":"0", + "2":"0", + "3":"3", + "4":"4", + "5":"0", + "6":"0", + "7":"0", + "8":"1", + "9":"0", + "10":"0", + "11":"0", + "12":"0", + "13":"0", + "14":"0", + "15":"0", + "16":"0", + "17":"0", + "18":"0", + "19":"0", + "20":"0", + "21":"0", + "22":"0", + "23":"0", + "24":"0", + "25":"0", + "26":"0", + "27":"0", + "28":"0", + "29":"0", + "30":"0", + "31":"0", + "32":"0", + "33":"0", + "34":"0", + "35":"0", + "36":"0", + "37":"0", + "38":"0", + "39":"0", + "40":"0", + "41":"0", + "42":"0", + "43":"0", + "44":"0", + "45":"0", + "46":"0", + "47":"0", + "48":"0", + "49":"0", + "50":"0", + "51":"0", + "52":"0", + "53":"0", + "54":"0", + "55":"0", + "56":"0", + "57":"0", + "58":"0", + "59":"0", + "60":"0", + "61":"0", + "62":"0", + "63":"0" + } + }, + "SCHEDULER": { + "scheduler.0" : { + "type":"DWRR", + "weight": "25" + }, + "scheduler.1" : { + "type":"DWRR", + "weight": "30" + }, + "scheduler.2" : { + "type":"DWRR", + "weight": "20" + } + }, + "PORT_QOS_MAP": { + "Ethernet0,Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet52,Ethernet56,Ethernet60,Ethernet64,Ethernet68,Ethernet72,Ethernet76": { + "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" + } + }, + "WRED_PROFILE": { + "AZURE_LOSSLESS" : { + "wred_green_enable":"true", + "wred_yellow_enable":"true", + "wred_red_enable":"true", + "ecn":"ecn_all", + "red_max_threshold":"312000", + "red_min_threshold":"104000", + "yellow_max_threshold":"312000", + "yellow_min_threshold":"104000", + "green_max_threshold": "312000", + "green_min_threshold": "104000" + } + }, + "QUEUE": { + "Ethernet0,Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet52,Ethernet56,Ethernet60,Ethernet64,Ethernet68,Ethernet72,Ethernet76|3-4" : { + "scheduler" : "[SCHEDULER|scheduler.0]", + "wred_profile" : "[WRED_PROFILE|AZURE_LOSSLESS]" + }, + "Ethernet0,Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet52,Ethernet56,Ethernet60,Ethernet64,Ethernet68,Ethernet72,Ethernet76|0" : { + "scheduler" : "[SCHEDULER|scheduler.1]" + }, + "Ethernet0,Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet52,Ethernet56,Ethernet60,Ethernet64,Ethernet68,Ethernet72,Ethernet76|1" : { + "scheduler" : "[SCHEDULER|scheduler.2]" + } + } +} diff --git a/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/td3-d6356-48x25G-8x100G.config.bcm b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/td3-d6356-48x25G-8x100G.config.bcm index f6fc4f02f1ef..57fd5cd57164 100644 --- a/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/td3-d6356-48x25G-8x100G.config.bcm +++ b/device/inventec/x86_64-inventec_d6356-r0/INVENTEC-D6356/td3-d6356-48x25G-8x100G.config.bcm @@ -2,8 +2,10 @@ ptp_ts_pll_fref=50000000 ptp_bs_fref_0=50000000 ptp_bs_fref_1=50000000 +ifp_inports_support_enable=1 ### end fix +stable_size=0x5500000 core_clock_frequency=1525 dpp_clock_ratio=2:3 @@ -12,7 +14,7 @@ oversubscribe_mode=1 pbmp_xport_xe=0x488787878808787fdfe1e1e1fe1e1e1fe -portmap_65=130:10 +#portmap_65=130:10 ### Pipeline0, halfpipe 0 (12x25G + 2x100G) portmap_1=1:25 @@ -60,11 +62,11 @@ portmap_64=64:25 ### Pipeline 1 ### First management port -portmap_66=129:10:m +#portmap_66=129:10:m ### Second management port -portmap_130=128:10:m +#portmap_130=128:10:m ### Loopback port -portmap_131=131:10 +#portmap_131=131:10 ### Pipeline 1, halfpipe 0 (12x25G + 2x100G) portmap_67=65:25 @@ -92,6 +94,11 @@ fpem_mem_entries=16384 l2xmsg_mode=1 + +pdma_descriptor_prefetch_enable=1 + +port_flex_enable=1 + #dport part dport_map_port_79=87 dport_map_port_87=79 @@ -281,118 +288,125 @@ phy_chain_tx_polarity_flip_physical{132.0}=0x0 phy_chain_rx_polarity_flip_physical{132.0}=0x0 # EQ/IDriver -serdes_preemphasis_1=0x13460B -serdes_preemphasis_2=0x13460B -serdes_preemphasis_3=0x14450B -serdes_preemphasis_4=0x13460B -serdes_preemphasis_5=0x11480B -serdes_preemphasis_6=0x13470A -serdes_preemphasis_7=0x14460A -serdes_preemphasis_8=0x11490A -serdes_preemphasis_13=0x10490B -serdes_preemphasis_14=0x104A0A -serdes_preemphasis_15=0x0F4B0A -serdes_preemphasis_16=0x0F4B0A -serdes_preemphasis_21=0x0D4D0A -serdes_preemphasis_22=0x0D4D0A -serdes_preemphasis_23=0x0D4D0A -serdes_preemphasis_24=0x0D4D0A -serdes_preemphasis_29=0x0B4F0A -serdes_preemphasis_30=0x0D4E09 -serdes_preemphasis_31=0x0B4F0A -serdes_preemphasis_32=0x0C4F09 -serdes_preemphasis_33=0x0B4F0A -serdes_preemphasis_34=0x0A5109 -serdes_preemphasis_35=0x09510A -serdes_preemphasis_36=0x0B5009 -serdes_preemphasis_41=0x09510A -serdes_preemphasis_42=0x0B5009 -serdes_preemphasis_43=0x09510A -serdes_preemphasis_44=0x0A5109 -serdes_preemphasis_49=0x0A500A -serdes_preemphasis_50=0x0B4F0A -serdes_preemphasis_51=0x09510A -serdes_preemphasis_52=0x0E4C0A -serdes_preemphasis_57=0x0D4D0A -serdes_preemphasis_58=0x0E4D09 -serdes_preemphasis_59=0x0C4E0A -serdes_preemphasis_60=0x0E4D09 -serdes_preemphasis_61=0x0B4F0A -serdes_preemphasis_62=0x0D4E09 -serdes_preemphasis_63=0x0D4D0A -serdes_preemphasis_64=0x0D4D0A -serdes_preemphasis_67=0x0B4F0A -serdes_preemphasis_68=0x0C4E0A -serdes_preemphasis_69=0x0B4F0A -serdes_preemphasis_70=0x0B4F0A -serdes_preemphasis_71=0x0B4F0A -serdes_preemphasis_72=0x0F4B0A -serdes_preemphasis_73=0x0E4C0A -serdes_preemphasis_74=0x0F4B0A -serdes_preemphasis_87=0x0E4C0A -serdes_preemphasis_79=0x0F4B0A -serdes_preemphasis_95=0x0F4B0A -serdes_preemphasis_99=0x0F4B0A -serdes_preemphasis_115=0x13470A -serdes_preemphasis_107=0x12480A -serdes_preemphasis_123=0x154609 -serdes_preemphasis_127=0x13470A +# 25G +serdes_preemphasis_1=0x0F4B0A +serdes_preemphasis_2=0x104A0A +serdes_preemphasis_3=0x0E4C0A +serdes_preemphasis_4=0x0E4C0A +serdes_preemphasis_5=0x0D4D0A +serdes_preemphasis_6=0x0D4D0A +serdes_preemphasis_7=0x0D4D0A +serdes_preemphasis_8=0x0D4D0A +serdes_preemphasis_13=0x0C4E0A +serdes_preemphasis_14=0x0D4D0A +serdes_preemphasis_15=0x0B4F0A +serdes_preemphasis_16=0x0C4E0A +serdes_preemphasis_21=0x0A500A +serdes_preemphasis_22=0x0A500A +serdes_preemphasis_23=0x09510A +serdes_preemphasis_24=0x09510A +serdes_preemphasis_29=0x08520A +serdes_preemphasis_30=0x08520A +serdes_preemphasis_31=0x07530A +serdes_preemphasis_32=0x07530A +serdes_preemphasis_33=0x06540A +serdes_preemphasis_34=0x07530A +serdes_preemphasis_35=0x05550A +serdes_preemphasis_36=0x06540A +serdes_preemphasis_41=0x05550A +serdes_preemphasis_42=0x06540A +serdes_preemphasis_43=0x05550A +serdes_preemphasis_44=0x05550A +serdes_preemphasis_49=0x04560A +serdes_preemphasis_50=0x05550A +serdes_preemphasis_51=0x05550A +serdes_preemphasis_52=0x06540A +serdes_preemphasis_57=0x06540A +serdes_preemphasis_58=0x07530A +serdes_preemphasis_59=0x06540A +serdes_preemphasis_60=0x07530A +serdes_preemphasis_61=0x06540A +serdes_preemphasis_62=0x08520A +serdes_preemphasis_63=0x08520A +serdes_preemphasis_64=0x09510A +serdes_preemphasis_67=0x06540A +serdes_preemphasis_68=0x06540A +serdes_preemphasis_69=0x06540A +serdes_preemphasis_70=0x08520A +serdes_preemphasis_71=0x09510A +serdes_preemphasis_72=0x09510A +serdes_preemphasis_73=0x09510A +serdes_preemphasis_74=0x0A500A +serdes_preemphasis_lane0_87=0x07530A +serdes_preemphasis_lane1_87=0x05550A +serdes_preemphasis_lane2_87=0x07530A +serdes_preemphasis_lane3_87=0x05550A +serdes_preemphasis_79=0x05550A +serdes_preemphasis_95=0x07530A +serdes_preemphasis_lane0_99=0x085309 +serdes_preemphasis_lane1_99=0x0B4F0A +serdes_preemphasis_lane2_99=0x085309 +serdes_preemphasis_lane3_99=0x0B4F0A +serdes_preemphasis_115=0x0B4F0A +serdes_preemphasis_107=0x0B4F0A +serdes_preemphasis_123=0x0B4F0A +serdes_preemphasis_127=0x0D4E09 +# 10G # interface type -serdes_if_type_1=13 -serdes_if_type_2=13 -serdes_if_type_3=13 -serdes_if_type_4=13 -serdes_if_type_5=13 -serdes_if_type_6=13 -serdes_if_type_7=13 -serdes_if_type_8=13 -serdes_if_type_13=13 -serdes_if_type_14=13 -serdes_if_type_15=13 -serdes_if_type_16=13 -serdes_if_type_21=13 -serdes_if_type_22=13 -serdes_if_type_23=13 -serdes_if_type_24=13 -serdes_if_type_29=13 -serdes_if_type_30=13 -serdes_if_type_31=13 -serdes_if_type_32=13 -serdes_if_type_33=13 -serdes_if_type_34=13 -serdes_if_type_35=13 -serdes_if_type_36=13 -serdes_if_type_41=13 -serdes_if_type_42=13 -serdes_if_type_43=13 -serdes_if_type_44=13 -serdes_if_type_49=13 -serdes_if_type_50=13 -serdes_if_type_51=13 -serdes_if_type_52=13 -serdes_if_type_57=13 -serdes_if_type_58=13 -serdes_if_type_59=13 -serdes_if_type_60=13 -serdes_if_type_61=13 -serdes_if_type_62=13 -serdes_if_type_63=13 -serdes_if_type_64=13 -serdes_if_type_67=13 -serdes_if_type_68=13 -serdes_if_type_69=13 -serdes_if_type_70=13 -serdes_if_type_71=13 -serdes_if_type_72=13 -serdes_if_type_73=13 -serdes_if_type_74=13 -serdes_if_type_87=14 -serdes_if_type_79=14 -serdes_if_type_95=14 -serdes_if_type_99=14 -serdes_if_type_115=14 -serdes_if_type_107=14 -serdes_if_type_123=14 -serdes_if_type_127=14 - +serdes_if_type_1=16 +serdes_if_type_2=16 +serdes_if_type_3=16 +serdes_if_type_4=16 +serdes_if_type_5=16 +serdes_if_type_6=16 +serdes_if_type_7=16 +serdes_if_type_8=16 +serdes_if_type_13=16 +serdes_if_type_14=16 +serdes_if_type_15=16 +serdes_if_type_16=16 +serdes_if_type_21=16 +serdes_if_type_22=16 +serdes_if_type_23=16 +serdes_if_type_24=16 +serdes_if_type_29=16 +serdes_if_type_30=16 +serdes_if_type_31=16 +serdes_if_type_32=16 +serdes_if_type_33=16 +serdes_if_type_34=16 +serdes_if_type_35=16 +serdes_if_type_36=16 +serdes_if_type_41=16 +serdes_if_type_42=16 +serdes_if_type_43=16 +serdes_if_type_44=16 +serdes_if_type_49=16 +serdes_if_type_50=16 +serdes_if_type_51=16 +serdes_if_type_52=16 +serdes_if_type_57=16 +serdes_if_type_58=16 +serdes_if_type_59=16 +serdes_if_type_60=16 +serdes_if_type_61=16 +serdes_if_type_62=16 +serdes_if_type_63=16 +serdes_if_type_64=16 +serdes_if_type_67=16 +serdes_if_type_68=16 +serdes_if_type_69=16 +serdes_if_type_70=16 +serdes_if_type_71=16 +serdes_if_type_72=16 +serdes_if_type_73=16 +serdes_if_type_74=16 +serdes_if_type_87=28 +serdes_if_type_79=28 +serdes_if_type_95=28 +serdes_if_type_99=28 +serdes_if_type_115=28 +serdes_if_type_107=28 +serdes_if_type_123=28 +serdes_if_type_127=28 diff --git a/device/inventec/x86_64-inventec_d6356-r0/custom_led.bin b/device/inventec/x86_64-inventec_d6356-r0/custom_led.bin new file mode 100644 index 0000000000000000000000000000000000000000..237c2a1a4c32e9774997a42e36661528a0b42a79 GIT binary patch literal 552 zcmeycHQp`E&DYJv?ZXxZWp*XUj8j1@#uD1UF5Ut1TrwU3d0&9MS|0|*T7O0*X4RE$ zY-$_an3QL^F{-X{>vm&*z^=o1gUNcK zaUjbC%o4iU%fObgKDt5G)`{Ul_k&oswv6%^R(+<6>29{pYd5hPO=57%m>N7wX3{2i z&4m|z6dP2T)pxkDDbI0ZQd#K6sK%ha%dLA;6i{A9#>ZyKCT1O`8&WdjK=;VVgn;>s zH&np97$6VicL*;7MXmtKGXSfsfU1P>0>E+_H)UiZz$|4TD+SDw1F~|!EXkWC*0VP; zYm46OW?;{_6Rql`b1~ShJ)y|**U2xi9z{r(&6O8DLfBc-Td6_fFYFsJk%}sd9s_k jo4V8ai{5T$pWE!2;5O53k=tsw4|@-|{ru0s@B@eeGVH;d literal 0 HcmV?d00001 diff --git a/device/inventec/x86_64-inventec_d6356-r0/led_proc_init.soc b/device/inventec/x86_64-inventec_d6356-r0/led_proc_init.soc index d4c2fde64f9c..01b49772c0ba 100644 --- a/device/inventec/x86_64-inventec_d6356-r0/led_proc_init.soc +++ b/device/inventec/x86_64-inventec_d6356-r0/led_proc_init.soc @@ -1,5 +1,5 @@ -led auto off -led stop +#led auto off +#led stop m0 load 0 0x0 /usr/share/sonic/platform/linkscan_led_fw.bin m0 load 0 0x3800 /usr/share/sonic/platform/custom_led.bin led auto on diff --git a/device/inventec/x86_64-inventec_d6356-r0/linkscan_led_fw.bin b/device/inventec/x86_64-inventec_d6356-r0/linkscan_led_fw.bin new file mode 100644 index 0000000000000000000000000000000000000000..e9d763ad98b22a06834cb2d6874287d36b122931 GIT binary patch literal 4744 zcmaJ_4|o&Dm4CY{$t(Yrjg!bmHY?fKD~BX9arv7jYb}f=V>`m-%PD`jZ)KdYGLR~5 z;?nCMY)HWlNn;W&C)1>DDBp!ENzQOlueqW_CRdKoTyJeRUjyph>8`zqYf@Nhf`lw< z@2%vJw3n;=&CJ`G`Mr5F@6Wt3gaEn$Ab@2HmOu4-_)~*hksihp{8V8)-y)RiOM?eG zHd8o&ymQHq{{U8cz&(jTquhB6|nr< z4uAwCJV#aUc5_#+7HeJT{?ZvWJe#&i7hPQ*0QexXjI{IyvWgo_`dWK{zwNuk2xDvV2 zy?cU}fu|JUa#5q*On=}3Rn|WA0w?&p9nTpqN*f16I4_JAjaCFDi<3HUu?M9XRQsXM z;)esEIy7joCx+RliLr?uk9V)29}~N4e0Ff$FFtCmBz*H%#m9Zk*2k>(O7u(5NI#Pv zCS?Iw`b?m#ueGvhzS*0Fr;B7Az0Q-8W zJ)os(wWZQ4Nt&?45}EXRQUCOe0kvSs%ik&f#M^82+1tf0Snm&llU9uRF>p|gynUm1 zzqQxa6`)(vaZA(^Io{bTANT~{*hov_u`X~xjju5vE+T?e$Fw76LmmU1jsj;z{BT#l z{Ia`b+L*_Dx2u27(Bm$=;9?q{(I&ExNO#8*>H-IB%^)=it3fA5Ir~54= z)S=G}br>C0v`^gMIb`)YHsa{VJ^OC-@UBqDY{Ue6CiZ%$u?pp*pdoyRyj^BpFm}>i zISuMx<)B8W`?1?NLvezg?>{e&~CkbIt z|0363X9%~DCkb%Hi9N8D%=uq|nT>Y_`)z{l2X2_68%Nx~pOIz3+8Wf)9Mq+`5t}Sg zVag6ND^laE1l*bAY-Hbr5m@C?uuTrhPr6N06s~MWIdpk4Nn>*m*DxJC3@7}1;GC}| zDA@XKhx04^*gZQ#hlilr1?snR>^SOQGAq>%M5u-w8>SCYvXT2`O=*HgUcX5Ge>_~W zGZ?EWNI5+}VslBRa5R~Y6hSpHD{zn{WrTI*f}rN++v|WU&7V~|x+cHdf-Jk?hyEYH z?|maE6NH`e5VZP$OGi_Y=APZS!z$%+kQx8Fyh>(Usj(;BaDXMc4&I%I8fsjq8*v*@ z3rwE#+N7?7vb+vHhdOv`o*EC->RRCQTDZKRg}R^lsug>d%I#`_84O_?|ltVu! zT@wY_;Lw=+%FI{glEfyA8>LvX_W(SDF?8&fMrLFYz=+kkpru~i|4!7B;m{B;iPe5@ z5%Y_|dbs`ilpz7P(+b$BaN#^JzP|_N{7=K8jkgB9xYizBCmeid9Q6*|`S;a`fs9V9 zLjR1-8)1z?)ftiAI`1SFY`0*`wz5e5`8;qGd6eu1!FJro@|id%-$^Db1fU!+HU`c9 zUfV9H5SREk|6~Q*^3e=5ejnOvs#{%tQ16-Vx3SBv#sACWB!IDMZ_Yq?)c-^C9MP>v z_vcK~5{YjB&PHg$wGG1qKEc+9D_uvgo{hXb!8F>#zY&2qC{PD#={&{L3P&0cZ4aZj zsLVXa)8}=2yo#FHK}=*AWqmX+D}#LQ;m{&2M?w9E zEPD*S{q82|AuFI$6lGYkVbqafp}J;1%%&8--Q zVxld7V)+mKTX1ZV@MT>8Y8)EEaHP{fz^=7D(RP#n2zj}yj~wxTuk#MVEwA!73pbP7 zg@44@eyC@Yz^yneF86tD%bg#@U+`LA<66!B2W?Itduu#SaRHnpV}sDq#kKYOZDND)xKH%4EtlfZ_%hDH*+=zx#Q!3>XM;rQ z{4x>!F0zEI6nJ5un^86kUnIxGulagy%UgaImxTQjNGg z&f(=jJHBM4|a|h2bj|17EEy>eA!< zn}|wB?ZkzMfm~UlK$$gmfojp11!_IYHl_RqbB#ufFPqi_2A5WfLz>5u)iiAxwxLL) z7n(wT{iX)H&UJa#P;a=Pdub?2**{8B`L)Kfi@WWFm-HFWXBi?(*3QD(f0i}Y8!r^- z6G=uXw49cDbxupYgR)djaTr_n%$dEwk4VLe*=xpJjm>8U?E%K#E@`P! z+?^$=$3k7^17-jlwrjBsMe@}$>I^oW*TK$auc zinISZqvJq5j2wnftkG9jr_zYQ_V5B~6j32uui90Hkqy+RaRpG%rVCO%n{lEHT53?! zcWEL;MBgDa>O1^OhO&>+57)!kh#O{>5q*z4GD2s&cTeq@`wpe#SH=7irJv`NZ#br5 zsFqXKVs=tGwIs2oGi-GzL)Hf6bDh2JA*5I0h(lRMTJt;Jv~U)fy+-jC2vZ3N(+>Bh z%Si^mGD!p0siYC>t4R~qSCU0oUrMrAe~>g|eGwxP*x^7BW&f8sLw!Y@X@ZxoiEx`) z;Ze?-30qc@H4G}GM zNgFkoON9p@s(&T(U+!Lr+B~o`)KTkYLwX%6GRx=WUbYuv6|{Ix3U%Cs9v+ipMX`!d zN0m2bGRsc|d(FL6teh5~!dFn4ryp}J*rw0G?0w2xKQ|TXD9ZN=f7FZb3JqZ0!amf< zOPx!Wo{`5l9O`<_ctD2RYn1zTQq6aZ_l1grBzSG{pzRIv^WZ6Cy|An7ZgDHwWo!~o z72hrXJg_hLx~Q3UnRWV1uz;is$N@4?K$Z{uUu1dTzJZUC<$Y%c3P?i%xs7ZqAbUOo z+0(ag+sDYBzBAhjNH&k`*lyZ>YVj`HN%HK#kBm!%!LpU&BV^FnEc~c=rTA>$-tB)Y zUNa4vb^6Tq0@6}ga|hXRl3ZK-uLFa&wZc|%%DAg+tseJ{M~WN7pY;vxI3~tSf|)_O zccgd2S@}7mRj4Ynh-W1=n!~8n)dOSHn1Q%LS}L3C?B*p3BULIVOCHZr$O3a@~M&6X~#)I&_^Qx#)!4+&L+)7Au7>jXY

u_quO?Wpl+sVg~YruZ;-_w%+>d)1i*(6I6o6FZ2xj z0>?GX7!CMltkg3`^#045E*;b{cA=ixSw+{1-umnB>aQ_|Fb+24wLx)jedb*&_L%T3 zYU(j2IPz<`=5}MhUq%8W%GmZYpd&| zwF6^E1o#G}Y6C0*M~%!RhTY72#l$Ov^ZFFD6f2A5Cu?7H8>T?ES}l@=&jCPo@b_3Exh>EsHxNBu}G%Qs@iFG8rH=qZk6=Qq!0P) zYZ!cx|DOz0Gf9BxVKePAKo&O7828b;H literal 0 HcmV?d00001 diff --git a/device/inventec/x86_64-inventec_d6356-r0/plugins/psuutil.py b/device/inventec/x86_64-inventec_d6356-r0/plugins/psuutil.py index 8ed0bce72979..732650ffe638 100755 --- a/device/inventec/x86_64-inventec_d6356-r0/plugins/psuutil.py +++ b/device/inventec/x86_64-inventec_d6356-r0/plugins/psuutil.py @@ -15,7 +15,7 @@ class PsuUtil(PsuBase): """Platform-specific PSUutil class""" - PSU_DIR = "/sys/class/hwmon/hwmon1" + PSU_DIR = "/sys/class/hwmon/hwmon2/device/" def __init__(self): PsuBase.__init__(self) @@ -53,9 +53,12 @@ def get_psu_status(self, index): faulty """ status = 0 - attr_file = 'psoc_psu'+ str(index) + '_iout' - attr_path = self.PSU_DIR +'/' + attr_file + if index == 1 : + attr_path = "/sys/class/hwmon/hwmon7/in1_input" + else : + attr_path = "/sys/class/hwmon/hwmon8/in1_input" + attr_value = self.get_attr_value(attr_path) if (attr_value != 'ERR'): # Check for PSU status @@ -75,10 +78,11 @@ def get_psu_presence(self, index): ind = index attr_file ='psu'+ str(ind) attr_path = self.PSU_DIR +'/' + attr_file - normal_attr_value = '0 : normal' + normal_attr_value = '1:normal' attr_value = self.get_attr_value(attr_path) if (attr_value != 'ERR'): # Check for PSU presence if (attr_value == normal_attr_value): status = 1 return status + diff --git a/device/inventec/x86_64-inventec_d6356-r0/plugins/sfputil.py b/device/inventec/x86_64-inventec_d6356-r0/plugins/sfputil.py index 5ea81ffcfc16..116a3d9acbc9 100755 --- a/device/inventec/x86_64-inventec_d6356-r0/plugins/sfputil.py +++ b/device/inventec/x86_64-inventec_d6356-r0/plugins/sfputil.py @@ -3,12 +3,78 @@ # Platform-specific SFP transceiver interface for SONiC # +# +# INV_FIX-4037 +# (1) Support get_transceiver_change_event. +# Create the SWPSEventMonitor class to handle any kobject event from the SWPS driver. +# (2) Integrated with the optoe driver +# Due to installing the optoe driver to create the i2c topology, +# it needs to overwrite the followings functions which are declared in the sfputilbase.py. +# First, it needs to impore some SFP-related class object +# try: import time + import socket, re,os + from collections import OrderedDict from sonic_sfp.sfputilbase import SfpUtilBase + from sonic_sfp.sff8472 import sff8472Dom except ImportError as e: raise ImportError("%s - required module not found" % str(e)) +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VLOT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 + +NETLINK_KOBJECT_UEVENT = 15 +monitor = None + +class SWPSEventMonitor(object): + + def __init__(self): + self.recieved_events = OrderedDict() + self.socket = socket.socket( + socket.AF_NETLINK, socket.SOCK_DGRAM, NETLINK_KOBJECT_UEVENT) + + def start(self): + self.socket.bind((os.getpid(), -1)) + + def stop(self): + self.socket.close() + + def __enter__(self): + self.start() + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.stop() + + def __iter__(self): + global monitor + while True: + for item in monitor.next_events(): + yield item + + def next_events(self): + data = self.socket.recv(16384) + event = {} + for item in data.split(b'\x00'): + if not item: + # check if we have an event and if we already received it + if event and event['SEQNUM'] not in self.recieved_events: + self.recieved_events[event['SEQNUM']] = None + if (len(self.recieved_events) > 100): + self.recieved_events.popitem(last=False) + yield event + event = {} + else: + try: + k, v = item.split(b'=', 1) + event[k.decode('ascii')] = v.decode('ascii') + except ValueError: + pass class SfpUtil(SfpUtilBase): """Platform-specific SfpUtil class""" @@ -210,8 +276,104 @@ def reset(self, port_num): return True +# +# INV_FIX-4037 +# (1) Support get_transceiver_change_event. +# Modify get_transceiver_change_event() to listen the SWPS kobject event. +# (2) Integrated with the optoe driver +# Due to installing the optoe driver to create the i2c topology, +# it needs to overwrite the followings functions which are declared in the sfputilbase.py. +# It modified the get_eeprom_dom_raw() and get_transceiver_dom_info_dict(). +# def get_transceiver_change_event(self): - """ - TODO: This function need to be implemented - """ - raise NotImplementedError + global monitor + port_dict = {} + with SWPSEventMonitor() as monitor: + for event in monitor: + if event['SUBSYSTEM'] == 'swps': + #print('SWPS event. From %s, ACTION %s, IF_TYPE %s, IF_LANE %s' % (event['DEVPATH'], event['ACTION'], event['IF_TYPE'], event['IF_LANE'])) + portname = event['DEVPATH'].split("/")[-1] + rc = re.match(r"port(?P\d+)",portname) + if rc is not None: + if event['ACTION'] == "remove": + remove_num = int(rc.group("num")) + port_dict[remove_num] = "0" + #port_dict[rc.group("num")] = "0" + if event['ACTION'] == "add": + add_num = int(rc.group("num")) + port_dict[add_num] = "1" + #port_dict[rc.group("num")] = "1" + return True, port_dict + return False, {} + + def get_eeprom_dom_raw(self, port_num): + if port_num in self.qsfp_ports: + # QSFP DOM EEPROM is also at addr 0x50 and thus also stored in eeprom_ifraw + return None + else: + # Read dom eeprom at addr 0x51 + return self._read_eeprom_devid(port_num, self.DOM_EEPROM_ADDR, 256) + + def get_transceiver_dom_info_dict(self, port_num): + if port_num in self.qsfp_ports: + return SfpUtilBase.get_transceiver_dom_info_dict(self, port_num) + else: + transceiver_dom_info_dict = {} + + 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, "rb") + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8472Dom(None, 1) + 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_VLOT_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 + + diff --git a/device/inventec/x86_64-inventec_d6356-r0/sensors.conf b/device/inventec/x86_64-inventec_d6356-r0/sensors.conf index 6f7318168ee6..3a056f7ca99f 100644 --- a/device/inventec/x86_64-inventec_d6356-r0/sensors.conf +++ b/device/inventec/x86_64-inventec_d6356-r0/sensors.conf @@ -2,6 +2,9 @@ chip "ucd90160-*" ignore temp1 +chip "pch_haswell-*" + label temp1 "PCH Temperature" + chip "tmp75-i2c-*-0048" label temp1 "CPU Board Temperature" @@ -31,7 +34,7 @@ chip "inv_cpld-i2c-*-77" label pwm4 "FanModule4 PWM (0-255)" label pwm5 "FanModule5 PWM (0-255)" -chip "pmbus-i2c-*-005a" +chip "pmbus-i2c-*-005b" ignore power3 ignore curr3 label fan1 "PSU1 Fan RPM" @@ -46,7 +49,7 @@ chip "pmbus-i2c-*-005a" label power2 "PSU1 Output Power" label pwm1 "PSU1 PWM (0-100)" -chip "pmbus-i2c-*-005b" +chip "pmbus-i2c-*-005a" ignore power3 ignore curr3 label fan1 "PSU2 Fan RPM" diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/Makefile b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/Makefile index 23e8295b9026..6c1acbc88a71 100755 --- a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/Makefile @@ -1,3 +1,7 @@ +obj-m += ucd9000.o +obj-m += i2c-mux-pca9541.o +obj-m += gpio-ich.o +obj-m += lpc_ich.o obj-m += inv_cpld.o obj-m += inv_platform.o obj-m += inv_eeprom.o diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/gpio-ich.c b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/gpio-ich.c new file mode 100644 index 000000000000..4f6d643516b7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/gpio-ich.c @@ -0,0 +1,513 @@ +/* + * Intel ICH6-10, Series 5 and 6, Atom C2000 (Avoton/Rangeley) GPIO driver + * + * Copyright (C) 2010 Extreme Engineering Solutions. + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "gpio_ich" + +/* + * GPIO register offsets in GPIO I/O space. + * Each chunk of 32 GPIOs is manipulated via its own USE_SELx, IO_SELx, and + * LVLx registers. Logic in the read/write functions takes a register and + * an absolute bit number and determines the proper register offset and bit + * number in that register. For example, to read the value of GPIO bit 50 + * the code would access offset ichx_regs[2(=GPIO_LVL)][1(=50/32)], + * bit 18 (50%32). + */ +enum GPIO_REG { + GPIO_USE_SEL = 0, + GPIO_IO_SEL, + GPIO_LVL, + GPO_BLINK +}; + +static const u8 ichx_regs[4][3] = { + {0x00, 0x30, 0x40}, /* USE_SEL[1-3] offsets */ + {0x04, 0x34, 0x44}, /* IO_SEL[1-3] offsets */ + {0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */ + {0x18, 0x18, 0x18}, /* BLINK offset */ +}; + +static const u8 ichx_reglen[3] = { + 0x30, 0x10, 0x10, +}; + +static const u8 avoton_regs[4][3] = { + {0x00, 0x80, 0x00}, + {0x04, 0x84, 0x00}, + {0x08, 0x88, 0x00}, +}; + +static const u8 avoton_reglen[3] = { + 0x10, 0x10, 0x00, +}; + +#define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start) +#define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start) + +struct ichx_desc { + /* Max GPIO pins the chipset can have */ + uint ngpio; + + /* chipset registers */ + const u8 (*regs)[3]; + const u8 *reglen; + + /* GPO_BLINK is available on this chipset */ + bool have_blink; + + /* Whether the chipset has GPIO in GPE0_STS in the PM IO region */ + bool uses_gpe0; + + /* USE_SEL is bogus on some chipsets, eg 3100 */ + u32 use_sel_ignore[3]; + + /* Some chipsets have quirks, let these use their own request/get */ + int (*request)(struct gpio_chip *chip, unsigned offset); + int (*get)(struct gpio_chip *chip, unsigned offset); + + /* + * Some chipsets don't let reading output values on GPIO_LVL register + * this option allows driver caching written output values + */ + bool use_outlvl_cache; +}; + +static struct { + spinlock_t lock; + struct platform_device *dev; + struct gpio_chip chip; + struct resource *gpio_base; /* GPIO IO base */ + struct resource *pm_base; /* Power Mangagment IO base */ + struct ichx_desc *desc; /* Pointer to chipset-specific description */ + u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */ + u8 use_gpio; /* Which GPIO groups are usable */ + int outlvl_cache[3]; /* cached output values */ +} ichx_priv; + +static int modparam_gpiobase = -1; /* dynamic */ +module_param_named(gpiobase, modparam_gpiobase, int, 0444); +MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, " + "which is the default."); + +static int ichx_write_bit(int reg, unsigned nr, int val, int verify) +{ + unsigned long flags; + u32 data, tmp; + int reg_nr = nr / 32; + int bit = nr & 0x1f; + int ret = 0; + + spin_lock_irqsave(&ichx_priv.lock, flags); + + if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) + data = ichx_priv.outlvl_cache[reg_nr]; + else + data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); + + if (val) + data |= 1 << bit; + else + data &= ~(1 << bit); + ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); + if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) + ichx_priv.outlvl_cache[reg_nr] = data; + + tmp = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); + if (verify && data != tmp) + ret = -EPERM; + + spin_unlock_irqrestore(&ichx_priv.lock, flags); + + return ret; +} + +static int ichx_read_bit(int reg, unsigned nr) +{ + unsigned long flags; + u32 data; + int reg_nr = nr / 32; + int bit = nr & 0x1f; + + spin_lock_irqsave(&ichx_priv.lock, flags); + + data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); + + if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) + data = ichx_priv.outlvl_cache[reg_nr] | data; + + spin_unlock_irqrestore(&ichx_priv.lock, flags); + + return data & (1 << bit) ? 1 : 0; +} + +static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr) +{ + return !!(ichx_priv.use_gpio & (1 << (nr / 32))); +} + +static int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned nr) +{ + return ichx_read_bit(GPIO_IO_SEL, nr) ? GPIOF_DIR_IN : GPIOF_DIR_OUT; +} + +static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) +{ + /* + * Try setting pin as an input and verify it worked since many pins + * are output-only. + */ + if (ichx_write_bit(GPIO_IO_SEL, nr, 1, 1)) + return -EINVAL; + + return 0; +} + +static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, + int val) +{ + /* Disable blink hardware which is available for GPIOs from 0 to 31. */ + if (nr < 32 && ichx_priv.desc->have_blink) + ichx_write_bit(GPO_BLINK, nr, 0, 0); + + /* Set GPIO output value. */ + ichx_write_bit(GPIO_LVL, nr, val, 0); + + /* + * Try setting pin as an output and verify it worked since many pins + * are input-only. + */ + if (ichx_write_bit(GPIO_IO_SEL, nr, 0, 1)) + return -EINVAL; + + return 0; +} + +static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr) +{ + return ichx_read_bit(GPIO_LVL, nr); +} + +static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr) +{ + unsigned long flags; + u32 data; + + /* + * GPI 0 - 15 need to be read from the power management registers on + * a ICH6/3100 bridge. + */ + if (nr < 16) { + if (!ichx_priv.pm_base) + return -ENXIO; + + spin_lock_irqsave(&ichx_priv.lock, flags); + + /* GPI 0 - 15 are latched, write 1 to clear*/ + ICHX_WRITE(1 << (16 + nr), 0, ichx_priv.pm_base); + data = ICHX_READ(0, ichx_priv.pm_base); + + spin_unlock_irqrestore(&ichx_priv.lock, flags); + + return (data >> 16) & (1 << nr) ? 1 : 0; + } else { + return ichx_gpio_get(chip, nr); + } +} + +static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr) +{ + if (!ichx_gpio_check_available(chip, nr)) + return -ENXIO; + + /* + * Note we assume the BIOS properly set a bridge's USE value. Some + * chips (eg Intel 3100) have bogus USE values though, so first see if + * the chipset's USE value can be trusted for this specific bit. + * If it can't be trusted, assume that the pin can be used as a GPIO. + */ + if (ichx_priv.desc->use_sel_ignore[nr / 32] & (1 << (nr & 0x1f))) + return 0; + + return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV; +} + +static int ich6_gpio_request(struct gpio_chip *chip, unsigned nr) +{ + /* + * Fixups for bits 16 and 17 are necessary on the Intel ICH6/3100 + * bridge as they are controlled by USE register bits 0 and 1. See + * "Table 704 GPIO_USE_SEL1 register" in the i3100 datasheet for + * additional info. + */ + if (nr == 16 || nr == 17) + nr -= 16; + + return ichx_gpio_request(chip, nr); +} + +static void ichx_gpio_set(struct gpio_chip *chip, unsigned nr, int val) +{ + ichx_write_bit(GPIO_LVL, nr, val, 0); +} + +static void ichx_gpiolib_setup(struct gpio_chip *chip) +{ + chip->owner = THIS_MODULE; + chip->label = DRV_NAME; + chip->parent = &ichx_priv.dev->dev; + + /* Allow chip-specific overrides of request()/get() */ + chip->request = ichx_priv.desc->request ? + ichx_priv.desc->request : ichx_gpio_request; + chip->get = ichx_priv.desc->get ? + ichx_priv.desc->get : ichx_gpio_get; + + chip->set = ichx_gpio_set; + chip->get_direction = ichx_gpio_get_direction; + chip->direction_input = ichx_gpio_direction_input; + chip->direction_output = ichx_gpio_direction_output; + chip->base = modparam_gpiobase; + chip->ngpio = ichx_priv.desc->ngpio; + chip->can_sleep = false; + chip->dbg_show = NULL; +} + +/* ICH6-based, 631xesb-based */ +static struct ichx_desc ich6_desc = { + /* Bridges using the ICH6 controller need fixups for GPIO 0 - 17 */ + .request = ich6_gpio_request, + .get = ich6_gpio_get, + + /* GPIO 0-15 are read in the GPE0_STS PM register */ + .uses_gpe0 = true, + + .ngpio = 50, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, +}; + +/* Intel 3100 */ +static struct ichx_desc i3100_desc = { + /* + * Bits 16,17, 20 of USE_SEL and bit 16 of USE_SEL2 always read 0 on + * the Intel 3100. See "Table 712. GPIO Summary Table" of 3100 + * Datasheet for more info. + */ + .use_sel_ignore = {0x00130000, 0x00010000, 0x0}, + + /* The 3100 needs fixups for GPIO 0 - 17 */ + .request = ich6_gpio_request, + .get = ich6_gpio_get, + + /* GPIO 0-15 are read in the GPE0_STS PM register */ + .uses_gpe0 = true, + + .ngpio = 50, + .regs = ichx_regs, + .reglen = ichx_reglen, +}; + +/* ICH7 and ICH8-based */ +static struct ichx_desc ich7_desc = { + .ngpio = 50, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, +}; + +/* ICH9-based */ +static struct ichx_desc ich9_desc = { + .ngpio = 61, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, +}; + +/* ICH10-based - Consumer/corporate versions have different amount of GPIO */ +static struct ichx_desc ich10_cons_desc = { + .ngpio = 61, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, +}; +static struct ichx_desc ich10_corp_desc = { + .ngpio = 72, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, +}; + +/* Intel 5 series, 6 series, 3400 series, and C200 series */ +static struct ichx_desc intel5_desc = { + .ngpio = 76, + .regs = ichx_regs, + .reglen = ichx_reglen, +}; + +/* Avoton */ +static struct ichx_desc avoton_desc = { + /* Avoton has only 59 GPIOs, but we assume the first set of register + * (Core) has 32 instead of 31 to keep gpio-ich compliance + */ + .ngpio = 60, + .regs = avoton_regs, + .reglen = avoton_reglen, + .use_outlvl_cache = true, +}; + +static int ichx_gpio_request_regions(struct device *dev, + struct resource *res_base, const char *name, u8 use_gpio) +{ + int i; + + if (!res_base || !res_base->start || !res_base->end) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) { + if (!(use_gpio & (1 << i))) + continue; + if (!devm_request_region(dev, + res_base->start + ichx_priv.desc->regs[0][i], + ichx_priv.desc->reglen[i], name)) + return -EBUSY; + } + return 0; +} + +static int ichx_gpio_probe(struct platform_device *pdev) +{ + struct resource *res_base, *res_pm; + int err; + struct lpc_ich_info *ich_info = dev_get_platdata(&pdev->dev); + + if (!ich_info) + return -ENODEV; + + ichx_priv.dev = pdev; + + switch (ich_info->gpio_version) { + case ICH_I3100_GPIO: + ichx_priv.desc = &i3100_desc; + break; + case ICH_V5_GPIO: + ichx_priv.desc = &intel5_desc; + break; + case ICH_V6_GPIO: + ichx_priv.desc = &ich6_desc; + break; + case ICH_V7_GPIO: + ichx_priv.desc = &ich7_desc; + break; + case ICH_V9_GPIO: + ichx_priv.desc = &ich9_desc; + break; + case ICH_V10CORP_GPIO: + ichx_priv.desc = &ich10_corp_desc; + break; + case ICH_V10CONS_GPIO: + ichx_priv.desc = &ich10_cons_desc; + break; + case AVOTON_GPIO: + ichx_priv.desc = &avoton_desc; + break; + default: + return -ENODEV; + } + + spin_lock_init(&ichx_priv.lock); + res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO); + ichx_priv.use_gpio = ich_info->use_gpio; + err = ichx_gpio_request_regions(&pdev->dev, res_base, pdev->name, + ichx_priv.use_gpio); + if (err) + return err; + + ichx_priv.gpio_base = res_base; + + /* + * If necessary, determine the I/O address of ACPI/power management + * registers which are needed to read the the GPE0 register for GPI pins + * 0 - 15 on some chipsets. + */ + if (!ichx_priv.desc->uses_gpe0) + goto init; + + res_pm = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPE0); + if (!res_pm) { + pr_warn("ACPI BAR is unavailable, GPI 0 - 15 unavailable\n"); + goto init; + } + + if (!devm_request_region(&pdev->dev, res_pm->start, + resource_size(res_pm), pdev->name)) { + pr_warn("ACPI BAR is busy, GPI 0 - 15 unavailable\n"); + goto init; + } + + ichx_priv.pm_base = res_pm; + +init: + ichx_gpiolib_setup(&ichx_priv.chip); + err = gpiochip_add_data(&ichx_priv.chip, NULL); + if (err) { + pr_err("Failed to register GPIOs\n"); + return err; + } + + pr_info("GPIO from %d to %d on %s\n", ichx_priv.chip.base, + ichx_priv.chip.base + ichx_priv.chip.ngpio - 1, DRV_NAME); + + return 0; +} + +static int ichx_gpio_remove(struct platform_device *pdev) +{ + gpiochip_remove(&ichx_priv.chip); + + return 0; +} + +static struct platform_driver ichx_gpio_driver = { + .driver = { + .name = DRV_NAME, + }, + .probe = ichx_gpio_probe, + .remove = ichx_gpio_remove, +}; + +module_platform_driver(ichx_gpio_driver); + +MODULE_AUTHOR("Peter Tyser "); +MODULE_DESCRIPTION("GPIO interface for Intel ICH series"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:"DRV_NAME); diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/i2c-mux-pca9541.c b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/i2c-mux-pca9541.c new file mode 100644 index 000000000000..68c44dbc533f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/i2c-mux-pca9541.c @@ -0,0 +1,573 @@ +/* + * I2C multiplexer driver for PCA9541 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 + +/* + * The PCA9541 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 PCA9541_CONTROL 0x01 +#define PCA9541_ISTAT 0x02 + +#define PCA9541_CTL_MYBUS (1 << 0) +#define PCA9541_CTL_NMYBUS (1 << 1) +#define PCA9541_CTL_BUSON (1 << 2) +#define PCA9541_CTL_NBUSON (1 << 3) +#define PCA9541_CTL_BUSINIT (1 << 4) +#define PCA9541_CTL_TESTON (1 << 6) +#define PCA9541_CTL_NTESTON (1 << 7) + +#define PCA9541_ISTAT_INTIN (1 << 0) +#define PCA9541_ISTAT_BUSINIT (1 << 1) +#define PCA9541_ISTAT_BUSOK (1 << 2) +#define PCA9541_ISTAT_BUSLOST (1 << 3) +#define PCA9541_ISTAT_MYTEST (1 << 6) +#define PCA9541_ISTAT_NMYTEST (1 << 7) + +#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) + +#define PCA9641_RES_TIME 0x03 + + +#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON) +#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS) +#define mybus(x) (!((x) & MYBUS) || ((x) & MYBUS) == MYBUS) +#define busoff(x) (!((x) & BUSON) || ((x) & BUSON) == BUSON) + +#define BUSOFF(x, y) (!((x) & PCA9641_CTL_LOCK_GRANT) && \ + !((y) & PCA9641_STS_OTHER_LOCK)) +#define other_lock(x) ((x) & PCA9641_STS_OTHER_LOCK) +#define lock_grant(x) ((x) & PCA9641_CTL_LOCK_GRANT) + +/* 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 + +struct pca9541 { + struct i2c_client *client; + unsigned long select_timeout; + unsigned long arb_timeout; +}; + +static const struct i2c_device_id pca9541_id[] = { + {"pca9541", 0}, + {"pca9641", 1}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, pca9541_id); + +#ifdef CONFIG_OF +static const struct of_device_id pca9541_of_match[] = { + { .compatible = "nxp,pca9541" }, + { .compatible = "nxp,pca9641" }, + {} +}; +#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 pca9541_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 = __i2c_transfer(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 pca9541_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 = __i2c_transfer(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 + */ + +/* Release bus. Also reset NTESTON and BUSINIT if it was set. */ +static void pca9541_release_bus(struct i2c_client *client) +{ + int reg; + + reg = pca9541_reg_read(client, PCA9541_CONTROL); + if (reg >= 0 && !busoff(reg) && mybus(reg)) + pca9541_reg_write(client, PCA9541_CONTROL, + (reg & PCA9541_CTL_NBUSON) >> 1); +} + +/* + * 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. + */ + +/* Control commands per PCA9541 datasheet */ +static const u8 pca9541_control[16] = { + 4, 0, 1, 5, 4, 4, 5, 5, 0, 0, 1, 1, 0, 4, 5, 1 +}; + +/* + * Channel arbitration + * + * Return values: + * <0: error + * 0 : bus not acquired + * 1 : bus acquired + */ +static int pca9541_arbitrate(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct pca9541 *data = i2c_mux_priv(muxc); + int reg; + + reg = pca9541_reg_read(client, PCA9541_CONTROL); + if (reg < 0) + return reg; + + if (busoff(reg)) { + int istat; + /* + * Bus is off. Request ownership or turn it on unless + * other master requested ownership. + */ + istat = pca9541_reg_read(client, PCA9541_ISTAT); + if (!(istat & PCA9541_ISTAT_NMYTEST) + || time_is_before_eq_jiffies(data->arb_timeout)) { + /* + * Other master did not request ownership, + * or arbitration timeout expired. Take the bus. + */ + pca9541_reg_write(client, + PCA9541_CONTROL, + pca9541_control[reg & 0x0f] + | PCA9541_CTL_NTESTON); + data->select_timeout = SELECT_DELAY_SHORT; + } 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 (mybus(reg)) { + /* + * Bus is on, and we own it. We are done with acquisition. + * Reset NTESTON and BUSINIT, then return success. + */ + if (reg & (PCA9541_CTL_NTESTON | PCA9541_CTL_BUSINIT)) + pca9541_reg_write(client, + PCA9541_CONTROL, + reg & ~(PCA9541_CTL_NTESTON + | PCA9541_CTL_BUSINIT)); + return 1; + } else { + /* + * Other master owns the bus. + * If arbitration timeout has expired, force ownership. + * Otherwise request it. + */ + data->select_timeout = SELECT_DELAY_LONG; + if (time_is_before_eq_jiffies(data->arb_timeout)) { + /* Time is up, take the bus and reset it. */ + pca9541_reg_write(client, + PCA9541_CONTROL, + pca9541_control[reg & 0x0f] + | PCA9541_CTL_BUSINIT + | PCA9541_CTL_NTESTON); + } else { + /* Request bus ownership if needed */ + if (!(reg & PCA9541_CTL_NTESTON)) + pca9541_reg_write(client, + PCA9541_CONTROL, + reg | PCA9541_CTL_NTESTON); + } + } + return 0; +} + +static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9541 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int ret; + unsigned long timeout = jiffies + ARB2_TIMEOUT; + /* give up after this time */ + + data->arb_timeout = jiffies + ARB_TIMEOUT; + /* force bus ownership after this time */ + + do { + ret = pca9541_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)); + + return -ETIMEDOUT; +} + +static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9541 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + + pca9541_release_bus(client); + return 0; +} + +/* + * Arbitration management functions + */ +static void pca9641_release_bus(struct i2c_client *client) +{ + pca9541_reg_write(client, PCA9641_CONTROL, 0); +} + +/* + * 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 pca9541 *data = i2c_mux_priv(muxc); + int reg_ctl, reg_sts; + + reg_ctl = pca9541_reg_read(client, PCA9641_CONTROL); + if (reg_ctl < 0) + return reg_ctl; + reg_sts = pca9541_reg_read(client, PCA9641_STATUS); + + if (BUSOFF(reg_ctl, reg_sts)) { + /* + * Bus is off. Request ownership or turn it on unless + * other master requested ownership. + */ + reg_ctl |= PCA9641_CTL_LOCK_REQ; + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); + reg_ctl = pca9541_reg_read(client, PCA9641_CONTROL); + + if (lock_grant(reg_ctl)) { + /* + * Other master did not request ownership, + * or arbitration timeout expired. Take the bus. + */ + reg_ctl |= PCA9641_CTL_BUS_CONNECT + | PCA9641_CTL_LOCK_REQ; + pca9541_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 (lock_grant(reg_ctl)) { + /* + * Bus is on, and we own it. We are done with acquisition. + */ + reg_ctl |= PCA9641_CTL_BUS_CONNECT | PCA9641_CTL_LOCK_REQ; + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); + + return 1; + } else if (other_lock(reg_sts)) { + /* + * Other master owns the bus. + * If arbitration timeout has expired, force ownership. + * Otherwise request it. + */ + data->select_timeout = SELECT_DELAY_LONG; + reg_ctl |= PCA9641_CTL_LOCK_REQ; + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); + } + return 0; +} + +static int pca9641_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9541 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int ret; + unsigned long timeout = jiffies + ARB2_TIMEOUT; + /* give up after this time */ + + 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)); + + return -ETIMEDOUT; +} + +static int pca9641_release_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9541 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + + pca9641_release_bus(client); + return 0; +} + +static int pca9641_detect_id(struct i2c_client *client) +{ + int reg; + + reg = pca9541_reg_read(client, PCA9641_ID); + if (reg == PCA9641_ID_MAGIC) + return 1; + else + return 0; +} + +/* + * I2C init/probing/exit functions + */ +static int pca9541_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = client->adapter; + struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev); + struct i2c_mux_core *muxc; + struct pca9541 *data; + int force; + int ret; + int detect_id; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + detect_id = pca9641_detect_id(client); + /* + * I2C accesses are unprotected here. + * We have to lock the adapter before releasing the bus. + */ + if (detect_id == 0) { + i2c_lock_adapter(adap); + pca9541_release_bus(client); + i2c_unlock_adapter(adap); + } else { + i2c_lock_adapter(adap); + pca9641_release_bus(client); + i2c_unlock_adapter(adap); + } + + /* Create mux adapter */ + + force = 0; + if (pdata) + force = pdata->modes[0].adap_id; + if (detect_id == 0) { + muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), + I2C_MUX_ARBITRATOR, + pca9541_select_chan, pca9541_release_chan); + } else { + 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 pca9541_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 pca9541_driver = { + .driver = { + .name = "pca9541", + .of_match_table = of_match_ptr(pca9541_of_match), + }, + .probe = pca9541_probe, + .remove = pca9541_remove, + .id_table = pca9541_id, +}; + +module_i2c_driver(pca9541_driver); + +MODULE_AUTHOR("Guenter Roeck "); +MODULE_DESCRIPTION("PCA9541 I2C master selector driver"); +MODULE_LICENSE("GPL v2"); diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_cpld.c b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_cpld.c index 8ccaf617b3c4..8e2693d2e251 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_cpld.c +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_cpld.c @@ -30,6 +30,7 @@ #define CPLD_INFO_OFFSET 0x00 #define CPLD_BIOSCS_OFFSET 0x04 #define CPLD_CTL_OFFSET 0x0C +#define CPLD_SYSLED_OFFSET 0x0E #define CPLD_LED_OFFSET 0x2E #define CPLD_INT_OFFSET 0x30 #define CPLD_INTMASK_OFFSET 0x31 @@ -58,6 +59,7 @@ struct cpld_data { struct device *hwmon_dev; struct mutex update_lock; u8 diag; + struct task_struct *tsk; }; /*-----------------------------------------------------------------------*/ @@ -97,6 +99,7 @@ static ssize_t cpld_i2c_write(struct i2c_client *client, char *buf, unsigned off #define CMD_GETDATA 0x31 #define CMD_SETDATA 0x32 #define IPMI_DIAGFLAG_OFFSET 0x00 +#define IPMI_SWITCHTEMP_OFFSET 0x02 struct ipmi_result{ char result[MAX_IPMI_RECV_LENGTH]; @@ -203,6 +206,30 @@ int start_ipmi_command(char NetFn, char cmd,char *data,int data_length, char* re } EXPORT_SYMBOL(start_ipmi_command); +static int cpld_thread(void *p) +{ +#ifndef XORP + struct i2c_client *client = p; + + u8 byte[9]; + uint8_t result[MAX_IPMI_RECV_LENGTH]; + int result_len=0; + + //Handle LED control by the driver + byte[0]=0x01; + cpld_i2c_write(client, byte, CPLD_CTL_OFFSET, 1); + + //Disable BMC Watchdog + byte[0]=0x04; + byte[1]=0x00; + byte[2]=0x00; + byte[3]=0x00; + byte[4]=0x2C; + byte[5]=0x01; + start_ipmi_command(0x06, 0x24, byte, 6, result, &result_len); +#endif + return 0; +} /*-----------------------------------------------------------------------*/ /* sysfs attributes for hwmon */ static ssize_t show_info(struct device *dev, struct device_attribute *da, @@ -231,7 +258,7 @@ static ssize_t show_info(struct device *dev, struct device_attribute *da, sprintf (buf, "%s\nThe CPLD2 release date is %02d/%02d/%d.\n", buf, byte[2] & 0xf, (byte[3] & 0x1f), 2014+(byte[2] >> 4)); /* mm/dd/yyyy*/ - sprintf (buf, "%sThe CPLD version is %d.%d\n", buf, byte[1]>>4, byte[1]&0xf); + sprintf (buf, "%sThe CPLD2 version is %d.%d\n", buf, byte[1]>>4, byte[1]&0xf); } return strlen(buf); @@ -251,7 +278,7 @@ static ssize_t show_powerstatus(struct device *dev, struct device_attribute *da, u8 byte[2] = {0,0}; mutex_lock(&data->update_lock); - len = cpld_i2c_read(client, byte, CPLD_POWERSTATUS_OFFSET, 2); + len = cpld_i2c_read(client2, byte, CPLD_POWERSTATUS_OFFSET, 2); mutex_unlock(&data->update_lock); if (len==0) return 0; @@ -265,8 +292,7 @@ static ssize_t show_powerstatus(struct device *dev, struct device_attribute *da, sprintf (buf, "%sPGD_P0V8_A: %s\n", buf,powerstatus_str[(byte[1]>>7) & 0x01]); sprintf (buf, "%sPGD_P0V89_ROV: %s\n", buf, powerstatus_str[(byte[1]>>6) & 0x01]); sprintf (buf, "%sSW_PWR_READY: %s\n", buf, powerstatus_str[(byte[1]>>3) & 0x01]); - sprintf (buf, "%sCORE_PWRGD_TO_CPLD: %s\n", buf, powerstatus_str[(byte[1]>>2) & 0x01]); - sprintf (buf, "%sCPU_STBY_PWROK: %s\n", buf, powerstatus_str[(byte[1]>>1) & 0x01]); + sprintf (buf, "%sCPU_STBY_PWROK: %s\n", buf, powerstatus_str[(byte[1]>>0) & 0x01]); return strlen(buf); } @@ -302,44 +328,27 @@ static ssize_t set_diag(struct device *dev, return count; } -static char* resetbutton_str[] = { - "No press", //0 - "Reserved", //1 - "Press and hold <5s", //2 - "Press and hold >5s", //3 -}; - -static ssize_t show_resetbuttonstatus(struct device *dev, struct device_attribute *da, +static ssize_t show_thermal(struct device *dev, struct device_attribute *da, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct cpld_data *data = i2c_get_clientdata(client); - ssize_t len = 0; - u8 byte = 0; - - mutex_lock(&data->update_lock); - len = cpld_i2c_read(client, &byte, CPLD_RESETBUTTONSTATUS_OFFSET, 1); - mutex_unlock(&data->update_lock); - if (len==0) return 0; - - byte &=0x03; - - return sprintf (buf, "0x%02X:%s\n", byte,resetbutton_str[byte]); + uint8_t ipmisend[]= { IPMI_SWITCHTEMP_OFFSET, 1}; + uint8_t result[MAX_IPMI_RECV_LENGTH]; + int result_len=0; + start_ipmi_command(NETFN_OEM, CMD_GETDATA,ipmisend, 2, result, &result_len); + return sprintf(buf, "%d\n", result[0] * 1000 ); } static char* interrupt_str[] = { "CPU_SEN_ALERT_N", //0 "EXT_USB_OC_N", //1 - "PS2_ALERT_N", //2 - "PS1_ALERT_N", //3 + "", //2 + "", //3 "PLD_SEN5_ALERT_N", //4 "PLD_SEN4_ALERT_N", //5 "PLD_SEN3_ALERT_N", //6 "UCD90160_TEMP_INT_N", //7 "RSTBTN_INT_N", //8 - "WDT_IRQ_N", //9 - "RSTBTN_5s_INT_N", //10 - "Reserved" //11 + "WDT_IRQ_N", //9 }; static ssize_t show_interrupt(struct device *dev, struct device_attribute *da, @@ -359,15 +368,12 @@ static ssize_t show_interrupt(struct device *dev, struct device_attribute *da, if(byte[0]==0xff && byte[2]==0x07) sprintf (buf, "%sNone",buf); if(!(byte[0]&0x01)) sprintf (buf, "%s%s ",buf,interrupt_str[0]); if(!(byte[0]&0x02)) sprintf (buf, "%s%s ",buf,interrupt_str[1]); - if(!(byte[0]&0x04)) sprintf (buf, "%s%s ",buf,interrupt_str[2]); - if(!(byte[0]&0x08)) sprintf (buf, "%s%s ",buf,interrupt_str[3]); if(!(byte[0]&0x10)) sprintf (buf, "%s%s ",buf,interrupt_str[4]); if(!(byte[0]&0x20)) sprintf (buf, "%s%s ",buf,interrupt_str[5]); if(!(byte[0]&0x40)) sprintf (buf, "%s%s ",buf,interrupt_str[6]); if(!(byte[0]&0x80)) sprintf (buf, "%s%s ",buf,interrupt_str[7]); if(!(byte[2]&0x01)) sprintf (buf, "%s%s%s ",buf,interrupt_str[8] ,(byte[3]&0x01)?"(Blocked)":""); if(!(byte[2]&0x02)) sprintf (buf, "%s%s%s ",buf,interrupt_str[9] ,(byte[3]&0x02)?"(Blocked)":""); - if(!(byte[2]&0x04)) sprintf (buf, "%s%s%s ",buf,interrupt_str[10],(byte[3]&0x04)?"(Blocked)":""); return sprintf (buf, "%s\n", buf); } @@ -414,10 +420,10 @@ static ssize_t set_bios_cs(struct device *dev, } static char* led_str[] = { - "OFF", //000 - "ON", //001 - "1 Hz", //010 - "2 Hz", //011 + "OFF", //00 + "Green/Blue", //01 + "Yellow/Orange", //10 + "Red", //11 }; static ssize_t show_led(struct device *dev, struct device_attribute *da, @@ -437,7 +443,7 @@ static ssize_t show_led(struct device *dev, struct device_attribute *da, byte = (byte >> shift) & 0x3; - return sprintf (buf, "%d: %s\n", byte, led_str[byte]); + return sprintf (buf, "%d:%s\n", byte, led_str[byte]); } static ssize_t set_led(struct device *dev, struct device_attribute *da, @@ -462,6 +468,61 @@ static ssize_t set_led(struct device *dev, struct device_attribute *da, return count; } +static char* sysled_str[] = { + "OFF", //000 + "0.5 Hz", //001 + "1 Hz", //010 + "2 Hz", //011 + "4 Hz", //100 + "NA", //101 + "NA", //110 + "ON", //111 +}; + +static ssize_t show_sysled(struct device *dev, struct device_attribute *da, + char *buf) +{ + u32 status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + u8 byte; + int shift = (attr->index == 0)?3:0; + + mutex_lock(&data->update_lock); + status = cpld_i2c_read(client, &byte, CPLD_SYSLED_OFFSET, 1); + mutex_unlock(&data->update_lock); + + byte = (byte >> shift) & 0x7; + status = sprintf (buf, "%d:%s\n", byte, sysled_str[byte]); + + return strlen(buf); +} + +static ssize_t set_sysled(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + + u8 temp = simple_strtol(buf, NULL, 16); + u8 byte; + int shift = (attr->index == 0)?3:0; + + temp &= 0x7; + + mutex_lock(&data->update_lock); + cpld_i2c_read(client, &byte, CPLD_SYSLED_OFFSET, 1); + byte &= ~(0x7<update_lock); + + return count; +} + static char* psu_str[] = { "unpowered", //00 "normal", //01 @@ -714,12 +775,15 @@ static ssize_t show_watchdog_counter(struct device *dev, struct device_attribute static SENSOR_DEVICE_ATTR(info, S_IRUGO, show_info, 0, 0); static SENSOR_DEVICE_ATTR(diag, S_IWUSR|S_IRUGO, show_diag, set_diag, 0); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_thermal, 0, 0); static SENSOR_DEVICE_ATTR(interrupt, S_IRUGO, show_interrupt, 0, 0); -static SENSOR_DEVICE_ATTR(stacking_led, S_IWUSR|S_IRUGO, show_led, set_led, 0); -static SENSOR_DEVICE_ATTR(fan_led, S_IWUSR|S_IRUGO, show_led, set_led, 2); -static SENSOR_DEVICE_ATTR(power_led, S_IWUSR|S_IRUGO, show_led, set_led, 4); -static SENSOR_DEVICE_ATTR(service_led, S_IWUSR|S_IRUGO, show_led, set_led, 6); +static SENSOR_DEVICE_ATTR(fan_led, S_IWUSR|S_IRUGO, show_led, set_led, 2); +static SENSOR_DEVICE_ATTR(power_led, S_IWUSR|S_IRUGO, show_led, set_led, 4); +static SENSOR_DEVICE_ATTR(location_led, S_IWUSR|S_IRUGO, show_led, set_led, 6); + +static SENSOR_DEVICE_ATTR(grn_led, S_IWUSR|S_IRUGO, show_sysled, set_sysled, 0); +static SENSOR_DEVICE_ATTR(red_led, S_IWUSR|S_IRUGO, show_sysled, set_sysled, 1); static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 0); static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 1); @@ -761,7 +825,6 @@ static SENSOR_DEVICE_ATTR(fan10_input,S_IRUGO, show_rpm, 0, 9); static SENSOR_DEVICE_ATTR(psu1, S_IRUGO, show_psu, 0, 0); static SENSOR_DEVICE_ATTR(psu2, S_IRUGO, show_psu, 0, 1); static SENSOR_DEVICE_ATTR(power_status, S_IRUGO, show_powerstatus, 0, 0); -static SENSOR_DEVICE_ATTR(resetbutton_status, S_IRUGO, show_resetbuttonstatus, 0, 0); static SENSOR_DEVICE_ATTR(watchdog_feed, S_IWUSR, 0, set_watchdog_feed, 0); static SENSOR_DEVICE_ATTR(watchdog_enable, S_IWUSR|S_IRUGO, show_watchdog_enable, set_watchdog_enable, 0); @@ -773,18 +836,20 @@ static SENSOR_DEVICE_ATTR(bios_cs, S_IWUSR|S_IRUGO, show_bios_cs, set_b static struct attribute *cpld_attributes[] = { &sensor_dev_attr_info.dev_attr.attr, &sensor_dev_attr_diag.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_stacking_led.dev_attr.attr, &sensor_dev_attr_fan_led.dev_attr.attr, &sensor_dev_attr_power_led.dev_attr.attr, - &sensor_dev_attr_service_led.dev_attr.attr, + &sensor_dev_attr_location_led.dev_attr.attr, + + &sensor_dev_attr_grn_led.dev_attr.attr, + &sensor_dev_attr_red_led.dev_attr.attr, &sensor_dev_attr_interrupt.dev_attr.attr, &sensor_dev_attr_psu1.dev_attr.attr, &sensor_dev_attr_psu2.dev_attr.attr, &sensor_dev_attr_power_status.dev_attr.attr, - &sensor_dev_attr_resetbutton_status.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr, @@ -839,7 +904,6 @@ cpld_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct cpld_data *data; int status; - u8 byte[5]; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) @@ -879,11 +943,7 @@ cpld_probe(struct i2c_client *client, const struct i2c_device_id *id) } } - //Handle LED control by the driver - byte[0]=0x01; - cpld_i2c_write(client, byte, CPLD_CTL_OFFSET, 1); - cpld_i2c_write(client2, byte, CPLD_CTL_OFFSET, 1); - + data->tsk = kthread_run(cpld_thread,client,"%s",dev_name(data->hwmon_dev)); dev_info(&client->dev, "%s: sensor '%s'\n", dev_name(data->hwmon_dev), client->name); @@ -908,6 +968,7 @@ static int cpld_remove(struct i2c_client *client) i2c_unregister_device(client2); i2c_set_clientdata(client2, NULL); } + kfree(data); return 0; } diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_mux.c b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_mux.c index a303527bec46..143aee309dba 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_mux.c +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_mux.c @@ -1,22 +1,55 @@ -/* - * 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. - */ #include #include #include #include #include +#include #include "io_expander.h" #include "inv_mux.h" -static struct mux_obj_s *mux_head_p = NULL; +/* For build single module using (Ex: ONL platform) */ +#include +//#include +//#include +static struct mux_obj_s *mux_head_p = NULL; + /* ========== MUX object functions ========== */ +static int +_setup_i2c_value(struct mux_obj_s *self, int offset, int value){ + + return i2c_smbus_write_byte_data(self->i2c_client_p, offset, value); +} + + +static int +_setup_i2c_client(struct mux_obj_s *self, int chan_id, int addr){ + + struct i2c_adapter *adap = NULL; + char *emsg = "ERR"; + + adap = i2c_get_adapter(chan_id); + if (!adap){ + emsg = "can't get adapter"; + goto err_setup_i2c_client; + } + self->i2c_client_p = kzalloc(sizeof(*self->i2c_client_p), GFP_KERNEL); + if (!self->i2c_client_p){ + emsg = "can't kzalloc client"; + goto err_setup_i2c_client; + } + self->i2c_client_p->adapter = adap; + self->i2c_client_p->addr = addr; + return 0; + +err_setup_i2c_client: + SWPS_ERR("%s: %s\n", __func__, emsg); + return ERR_MUX_UNEXCPT; +} + + int _common_force_pull_gpio(int mem_addr, int input, @@ -93,6 +126,78 @@ normal_gpio_pull_low(struct mux_obj_s *self){ } +int +cpld_rst_all_4_pull_low(struct mux_obj_s *self){ + + char *emsg = "ERR"; + int err = ERR_MUX_UNEXCPT; + + switch(self->gpio_num) { + case MUX_RST_CPLD_C0_A77_70_74_RST_ALL: + goto setlow_cpld_rst_all_4_c0_a77_70_74_rst_all; + + default: + break; + } + emsg = "Undefined case"; + goto err_cpld_rst_all_4_pull_low; + +setlow_cpld_rst_all_4_c0_a77_70_74_rst_all: + err = _setup_i2c_value(self, 0x70, 0x0); + if (err < 0) { + emsg = "setup 0x70 fail"; + goto err_cpld_rst_all_4_pull_low; + } + err = _setup_i2c_value(self, 0x74, 0x01); + if (err < 0) { + emsg = "setup 0x74 fail"; + goto err_cpld_rst_all_4_pull_low; + } + return 0; + +err_cpld_rst_all_4_pull_low: + SWPS_INFO("%s: %s :%d :%d\n", + __func__, emsg, self->gpio_num, err); + return ERR_MUX_UNEXCPT; +} + + +int +cpld_rst_all_4_pull_high(struct mux_obj_s *self){ + + char *emsg = "ERR"; + int err = ERR_MUX_UNEXCPT; + + switch(self->gpio_num) { + case MUX_RST_CPLD_C0_A77_70_74_RST_ALL: + goto sethigh_cpld_rst_all_4_c0_a77_70_74_rst_all; + + default: + break; + } + emsg = "Undefined case"; + goto err_cpld_rst_all_4_pull_high; + +sethigh_cpld_rst_all_4_c0_a77_70_74_rst_all: + err = _setup_i2c_value(self, 0x70, 0xfe); + if (err < 0) { + emsg = "setup 0x70 fail"; + goto err_cpld_rst_all_4_pull_high; + } + err = _setup_i2c_value(self, 0x74, 0x03); + if (err < 0) { + emsg = "setup 0x74 fail"; + goto err_cpld_rst_all_4_pull_high; + } + return 0; + +err_cpld_rst_all_4_pull_high: + SWPS_INFO("%s: %s :%d :%d\n", + __func__, emsg, self->gpio_num, err); + return ERR_MUX_UNEXCPT; +} + + int pca9548_reset_mux_all(struct mux_obj_s *self){ /* [Note] Power-on reset (PCA9548A-NXP) @@ -108,13 +213,44 @@ pca9548_reset_mux_all(struct mux_obj_s *self){ SWPS_ERR("%s: _pull_low fail!\n", __func__); return -1; } - mdelay(MUX_RST_WAIT_MS); + mdelay(MUX_RST_WAIT_MS_PCA9548); if (self->_pull_high(self) < 0) { SWPS_ERR("%s: _pull_high fail!\n", __func__); return -1; } - mdelay(MUX_RST_WAIT_MS); + mdelay(MUX_RST_WAIT_MS_PCA9548); + return 0; +} + + +int +cpld_reset_mux_all(struct mux_obj_s *self){ + + char *emsg = "ERR"; + int err = ERR_MUX_UNEXCPT; + + switch(self->gpio_num) { + case MUX_RST_CPLD_C0_A77_70_74_RST_ALL: + goto reset_cpld_rst_all_4_c0_a77_70_74_rst_all; + + default: + break; + } + emsg = "Undefined case"; + goto err_cpld_reset_mux_all; + +reset_cpld_rst_all_4_c0_a77_70_74_rst_all: + if (self->_pull_low(self) < 0) { + emsg = "_pull_low fail"; + goto err_cpld_reset_mux_all; + } + mdelay(MUX_RST_WAIT_MS_CPLD); return 0; + +err_cpld_reset_mux_all: + SWPS_INFO("%s: %s :%d :%d\n", + __func__, emsg, self->gpio_num, err); + return ERR_MUX_UNEXCPT; } @@ -127,6 +263,11 @@ common_reset_mux_all(struct mux_obj_s *self){ int init_gpio_4_force(struct mux_obj_s *self){ + + if (self->_pull_high(self) < 0) { + SWPS_ERR("%s: setup default fail!\n", __func__); + return -1; + } return 0; } @@ -134,20 +275,95 @@ init_gpio_4_force(struct mux_obj_s *self){ int init_gpio_4_normal(struct mux_obj_s *self){ - int err = 0; + int err = 0; + char *emsg = "ERR"; if (!gpio_is_valid(self->gpio_num)) { - SWPS_ERR("%s: GIPO:%d isn't valid\n", __func__, self->gpio_num); - return -1; + emsg = "GPIO invalid"; + goto err_init_gpio_4_normal; } err = gpio_request(self->gpio_num, MUX_GPIO_LABEL); if (err < 0) { - SWPS_ERR("%s: gpio_request fail :%d :%d\n", - __func__, err, self->gpio_num); - return -1; + emsg = "gpio_request fail"; + goto err_init_gpio_4_normal; + } + err = self->_pull_high(self); + if (err < 0) { + emsg = "setup default fail"; + goto err_init_gpio_4_normal; } SWPS_DEBUG("%s: gpio_request:%d ok.\n", __func__, self->gpio_num); return 0; + +err_init_gpio_4_normal: + SWPS_ERR("%s: %s :%d :%d\n", + __func__, emsg, self->gpio_num, err); + return -1; +} + + +int +init_cpld_4_rst_all(struct mux_obj_s *self){ + + char *emsg = "ERR"; + int err = ERR_MUX_UNEXCPT; + int chan = ERR_MUX_UNEXCPT; + int addr = ERR_MUX_UNEXCPT; + + switch(self->gpio_num) { + case MUX_RST_CPLD_C0_A77_70_74_RST_ALL: + goto init_cpld_i2c_c0_a77_70_74_rst_all; + + default: + break; + } + emsg = "Undefined case"; + goto err_init_cpld_4_rst_all; + +init_cpld_i2c_c0_a77_70_74_rst_all: + chan = 0; + addr = 0x77; + err = _setup_i2c_client(self, chan, addr); + if (err < 0) { + emsg = "_setup_i2c_client fail"; + goto err_init_cpld_4_rst_all; + } + err = self->_pull_high(self); + if (err < 0) { + emsg = "setup default value fail"; + goto err_init_cpld_4_rst_all; + } + SWPS_DEBUG("%s: init_cpld_i2c_c0_a77_70_74_rst_all ok", __func__); + return 0; + +err_init_cpld_4_rst_all: + SWPS_INFO("%s: %s :%d :%d\n", + __func__, emsg, self->gpio_num, err); + return ERR_MUX_UNEXCPT; +} + + +int +clean_gpio_4_common(struct mux_obj_s *self){ + + if (!self) return 0; + if (!gpio_is_valid(self->gpio_num)) return 0; + self->_pull_high(self); + gpio_free(mux_head_p->gpio_num); + return 0; +} + + +int +clean_cpld_4_rst_all(struct mux_obj_s *self){ + + if (!self) return 0; + self->_pull_high(self); + if (self->i2c_client_p) { + i2c_put_adapter(self->i2c_client_p->adapter); + kfree(self->i2c_client_p); + } + return 0; } @@ -163,6 +379,7 @@ _setup_muxctl_cb(struct mux_obj_s *self, self->_pull_low = rangeley_force_pull_low; self->_pull_high = rangeley_force_pull_high; self->_init = init_gpio_4_force; + self->_clean = clean_gpio_4_common; self->reset = pca9548_reset_mux_all; memset(mod_dsc, 0, 32); snprintf(mod_dsc, 31, "Rangeley force mode"); @@ -173,25 +390,38 @@ _setup_muxctl_cb(struct mux_obj_s *self, self->_pull_low = hedera_force_pull_low; self->_pull_high = hedera_force_pull_high; self->_init = init_gpio_4_force; + self->_clean = clean_gpio_4_common; self->reset = pca9548_reset_mux_all; memset(mod_dsc, 0, 32); snprintf(mod_dsc, 31, "Hedera force mode"); goto ok_setup_muxctl_cb; - case MUX_RST_GPIO_48_PAC9548: - case MUX_RST_GPIO_69_PAC9548: + case MUX_RST_GPIO_48_PCA9548: + case MUX_RST_GPIO_69_PCA9548: case MUX_RST_GPIO_249_PCA9548: - case MUX_RST_GPIO_500_PAC9548: + case MUX_RST_GPIO_500_PCA9548: case MUX_RST_GPIO_505_PCA9548: self->gpio_num = gpio; self->_pull_low = normal_gpio_pull_low; self->_pull_high = normal_gpio_pull_high; self->_init = init_gpio_4_normal; + self->_clean = clean_gpio_4_common; self->reset = pca9548_reset_mux_all; memset(mod_dsc, 0, 32); snprintf(mod_dsc, 31, "Normal mode :%d", (int)gpio); goto ok_setup_muxctl_cb; + case MUX_RST_CPLD_C0_A77_70_74_RST_ALL: + self->gpio_num = gpio; + self->_pull_low = cpld_rst_all_4_pull_low; + self->_pull_high = cpld_rst_all_4_pull_high; + self->_init = init_cpld_4_rst_all; + self->_clean = clean_cpld_4_rst_all; + self->reset = cpld_reset_mux_all; + memset(mod_dsc, 0, 32); + snprintf(mod_dsc, 31, "CPLD mode :%d", (int)gpio); + goto ok_setup_muxctl_cb; + default: break; } @@ -207,23 +437,28 @@ _setup_muxctl_cb(struct mux_obj_s *self, /* ========== MUX public functions ========== */ void -clean_mux_gpio(void){ +clean_mux_objs(void){ - if (!mux_head_p) { + struct mux_obj_s *curr_p = mux_head_p; + struct mux_obj_s *next_p = NULL; + + if (!curr_p) { SWPS_DEBUG("%s: mux_head_p is NULL\n", __func__); return; } - if (gpio_is_valid(mux_head_p->gpio_num)) { - gpio_free(mux_head_p->gpio_num); + while (curr_p) { + next_p = curr_p->next; + curr_p->_clean(curr_p); + kfree(curr_p); + curr_p = next_p; } - kfree(mux_head_p); - mux_head_p = NULL; SWPS_DEBUG("%s: done.\n", __func__); } +EXPORT_SYMBOL(clean_mux_objs); int -reset_mux_gpio(void){ +reset_mux_objs(void){ if (!mux_head_p) { SWPS_ERR("%s: MUX ctl object doesn't exist!\n", __func__); @@ -235,47 +470,78 @@ reset_mux_gpio(void){ } return 0; } +EXPORT_SYMBOL(reset_mux_objs); + + +struct mux_obj_s * +_create_mux_obj(unsigned gpio){ + + char *emsg = "ERR"; + struct mux_obj_s *obj_p = NULL; + + obj_p = kzalloc(sizeof(struct mux_obj_s), GFP_KERNEL); + if (!obj_p) { + emsg = "kzalloc fail!"; + goto err_create_mux_obj_1; + } + if (_setup_muxctl_cb(obj_p, gpio) < 0){ + emsg = "_setup_muxctl_cb fail!"; + goto err_create_mux_obj_2; + } + if (obj_p->_init(obj_p) < 0) { + emsg = "_init() fail!"; + goto err_create_mux_obj_2; + } + SWPS_DEBUG("%s: created MUX object :%d\n", __func__, gpio); + return obj_p; + +err_create_mux_obj_2: + kfree(obj_p); +err_create_mux_obj_1: + SWPS_ERR("%s: %s :%d\n", __func__, emsg, gpio); + return NULL; +} int -init_mux_gpio(unsigned gpio){ +init_mux_objs(unsigned gpio){ + + struct mux_obj_s *curr_p = NULL; + char *emsg = "ERR"; /* Create MUX control object */ if (mux_head_p) { SWPS_DEBUG("%s: mux_head_p is not NULL!\n", __func__); - clean_mux_gpio(); + clean_mux_objs(); } /* Currently, it is using single muxctl architecture. - * In the future, it may use the multi-muxctl if HW add new features. - * (Ex: Port power-status control) + * In the future, it may use the multi-muxctl. + * (Ex: Gulmohar's advance I2C control / Peony's reset single mux) */ - mux_head_p = kzalloc(sizeof(struct mux_obj_s), GFP_KERNEL); - if (!mux_head_p) { - SWPS_ERR("%s: kzalloc fail!\n", __func__); - return -1; - } - /* Initial MUX controller */ - if (_setup_muxctl_cb(mux_head_p, gpio) < 0){ - SWPS_ERR("%s: _setup_muxctl_cb fail!\n", __func__); - return -1; - } - if (mux_head_p->_init(mux_head_p) < 0) { - SWPS_ERR("%s: init() fail\n", __func__); - goto err_init_mux_gpio; - } - /* Setup default value */ - if (mux_head_p->_pull_high(mux_head_p) < 0) { - SWPS_ERR("%s: setup default fail!\n", __func__); - goto err_init_mux_gpio; + curr_p = _create_mux_obj(gpio); + if (!curr_p) { + emsg = "_create_mux_obj fail"; + goto err_init_mux_objs; } + curr_p->next = NULL; + mux_head_p = curr_p; + SWPS_DEBUG("%s: all done. :%d\n", __func__, gpio); return 0; -err_init_mux_gpio: - clean_mux_gpio(); +err_init_mux_objs: + clean_mux_objs(); + SWPS_ERR("%s: %s\n", __func__, emsg); return -1; } +EXPORT_SYMBOL(init_mux_objs); +/* For single ko module + * => You need to declare MODULE_LICENSE If you want to build single module along. + * => Ex: For ONL platform + */ +MODULE_LICENSE("GPL"); + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_mux.h b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_mux.h index f981a304644a..a913b24c6053 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_mux.h +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_mux.h @@ -1,47 +1,51 @@ -/* - * 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. - */ - #ifndef INV_MUX_H #define INV_MUX_H +#include /* MUX basic information */ #define MUX_GPIO_LABEL "SWPS_RST_MUX" /* MUX reset GPIO define */ -#define MUX_RST_GPIO_FORCE (30100) -#define MUX_RST_GPIO_FORCE_RANGELEY (30101) -#define MUX_RST_GPIO_FORCE_HEDERA (30102) -#define MUX_RST_GPIO_48_PAC9548 (48) -#define MUX_RST_GPIO_69_PAC9548 (69) -#define MUX_RST_GPIO_249_PCA9548 (249) -#define MUX_RST_GPIO_500_PAC9548 (500) -#define MUX_RST_GPIO_505_PCA9548 (505) +#define MUX_RST_GPIO_FORCE (30100) +#define MUX_RST_GPIO_FORCE_RANGELEY (30101) +#define MUX_RST_GPIO_FORCE_HEDERA (30102) +#define MUX_RST_GPIO_48_PCA9548 (48) +#define MUX_RST_GPIO_69_PCA9548 (69) +#define MUX_RST_GPIO_249_PCA9548 (249) +#define MUX_RST_GPIO_500_PCA9548 (500) +#define MUX_RST_GPIO_505_PCA9548 (505) +#define MUX_RST_CPLD_C0_A77_70_74_RST_ALL (30201) /* MUX relate value define */ -#define MUX_RST_WAIT_MS (1) -#define MUX_RST_MEM_ADDR_RANGELEY (0) // TBD -#define MUX_RST_MEM_ADDR_HEDERA (0x548) +#define MUX_RST_WAIT_MS_PCA9548 (1) +#define MUX_RST_WAIT_MS_CPLD (10) +#define MUX_RST_MEM_ADDR_RANGELEY (0) // TBD +#define MUX_RST_MEM_ADDR_HEDERA (0x548) + +/* MUX error code define */ +#define ERR_MUX_UNEXCPT (-399) struct mux_obj_s { + struct i2c_client *i2c_client_p; + struct mux_obj_s *next; unsigned gpio_num; int (*_pull_high)(struct mux_obj_s *self); int (*_pull_low)(struct mux_obj_s *self); int (*_init)(struct mux_obj_s *self); + int (*_clean)(struct mux_obj_s *self); int (*reset)(struct mux_obj_s *self); }; -void clean_mux_gpio(void); -int reset_mux_gpio(void); -int init_mux_gpio(unsigned gpio); +void clean_mux_objs(void); +int reset_mux_objs(void); +int init_mux_objs(unsigned gpio); #endif /* INV_MUX_H */ + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_platform.c b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_platform.c index 42900232dca8..212388c8e98d 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_platform.c +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_platform.c @@ -137,49 +137,49 @@ static struct pca954x_platform_data mux_data_0_6 = { }; static struct i2c_board_info i2c_device_info0[] __initdata = { - {"pca9641", 0, 0x76, &pca9641_data_1, 0, 0}, //PCA9641-1 - {"pca9641", 0, 0x73, &pca9641_data_3, 0, 0}, //PCA9641-3 - {"pca9641", 0, 0x09, &pca9641_data_4, 0, 0}, //PCA9641-4 + {"pca9641", 0, 0x76, &pca9641_data_1, 0, 0}, //PCA9641-1 + {"pca9641", 0, 0x73, &pca9641_data_3, 0, 0}, //PCA9641-3 + {"pca9641", 0, 0x09, &pca9641_data_4, 0, 0}, //PCA9641-4 }; static struct i2c_board_info i2c_device_info1[] __initdata = { - {"pca9641", 0, 0x0A, &pca9641_data_2, 0, 0}, //PCA9641-2 + {"pca9641", 0, 0x0A, &pca9641_data_2, 0, 0}, //PCA9641-2 }; static struct i2c_board_info i2c_device_info2[] __initdata = { - {"inv_cpld", 0, 0x77, 0, 0, 0}, //CPLD + {"inv_cpld", 0, 0x77, 0, 0, 0}, //CPLD }; static struct i2c_board_info i2c_device_info3[] __initdata = { - {"tmp75", 0, 0x48, 0, 0, 0}, //CPU Board Temp - {"tmp75", 0, 0x4A, 0, 0, 0}, //Temp - {"tmp75", 0, 0x4D, 0, 0, 0}, //Temp - {"tmp75", 0, 0x4E, 0, 0, 0}, //Temp + {"tmp75", 0, 0x48, 0, 0, 0}, //CPU Board Temp + {"tmp75", 0, 0x4A, 0, 0, 0}, //Temp + {"tmp75", 0, 0x4D, 0, 0, 0}, //Temp + {"tmp75", 0, 0x4E, 0, 0, 0}, //Temp }; static struct i2c_board_info i2c_device_info4[] __initdata = { - {"pmbus", 0, 0x5A, 0, 0, 0}, //PSU1 - {"pmbus", 0, 0x5B, 0, 0, 0}, //PSU2 + {"pmbus", 0, 0x5B, 0, 0, 0}, //PSU1 + {"pmbus", 0, 0x5A, 0, 0, 0}, //PSU2 }; static struct i2c_board_info i2c_device_info5[] __initdata = { - {"pca9548", 0, 0x70, &mux_data_0, 0, 0}, //mux root + {"pca9548", 0, 0x70, &mux_data_0, 0, 0}, //mux root }; static struct i2c_board_info i2c_device_info6[] __initdata = { - {"pca9548", 0, 0x72, &mux_data_0_0, 0, 0}, + {"pca9548", 0, 0x72, &mux_data_0_0, 0, 0}, }; static struct i2c_board_info i2c_device_info7[] __initdata = { - {"pca9548", 0, 0x72, &mux_data_0_1, 0, 0}, + {"pca9548", 0, 0x72, &mux_data_0_1, 0, 0}, }; static struct i2c_board_info i2c_device_info8[] __initdata = { - {"pca9548", 0, 0x72, &mux_data_0_2, 0, 0}, + {"pca9548", 0, 0x72, &mux_data_0_2, 0, 0}, }; static struct i2c_board_info i2c_device_info9[] __initdata = { - {"pca9548", 0, 0x72, &mux_data_0_3, 0, 0}, + {"pca9548", 0, 0x72, &mux_data_0_3, 0, 0}, }; static struct i2c_board_info i2c_device_info10[] __initdata = { - {"pca9548", 0, 0x72, &mux_data_0_4, 0, 0}, + {"pca9548", 0, 0x72, &mux_data_0_4, 0, 0}, }; static struct i2c_board_info i2c_device_info11[] __initdata = { - {"pca9548", 0, 0x72, &mux_data_0_5, 0, 0}, + {"pca9548", 0, 0x72, &mux_data_0_5, 0, 0}, }; static struct i2c_board_info i2c_device_info12[] __initdata = { - {"pca9548", 0, 0x72, &mux_data_0_6, 0, 0}, + {"pca9548", 0, 0x72, &mux_data_0_6, 0, 0}, }; @@ -196,19 +196,23 @@ static struct inv_i2c_board_info i2cdev_list[] = { {bus_id(9), ARRAY_SIZE(i2c_device_info9), i2c_device_info9 }, //mux CH3 {bus_id(10),ARRAY_SIZE(i2c_device_info10), i2c_device_info10}, //mux CH4 {bus_id(11),ARRAY_SIZE(i2c_device_info11), i2c_device_info11}, //mux CH5 - {bus_id(12),ARRAY_SIZE(i2c_device_info12), i2c_device_info12}, //mux CH6 + {bus_id(12),ARRAY_SIZE(i2c_device_info12), i2c_device_info12}, //mux CH6 }; +#define INV_PLATFORM_CLIENT_MAX_NUM 50 /*A big enough number for sum of i2cdev_list[i].size */ +static int client_list_index = 0; +static struct i2c_client *client_list[INV_PLATFORM_CLIENT_MAX_NUM] = {0}; + ///////////////////////////////////////////////////////////////////////////////////////// static struct platform_device *device_i2c_gpio0; -static struct i2c_gpio_platform_data i2c_gpio_platdata0 = { - .scl_pin = 58, //494, - .sda_pin = 75, //511, - - .udelay = 5, //5:100kHz - .sda_is_open_drain = 0, - .scl_is_open_drain = 0, - .scl_is_output_only = 0 +static struct i2c_gpio_platform_data i2c_gpio_platdata0 = { + .scl_pin = 58, //494, + .sda_pin = 75, //511, + + .udelay = 5, //5:100kHz + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 0 }; static int __init inv_platform_init(void) @@ -220,7 +224,7 @@ static int __init inv_platform_init(void) //printk("%s \n", __func__); - //use i2c-gpio + //use i2c-gpio //register i2c gpio //config gpio58,75 to gpio function 58=32+3*8+2 75=32*2+8*1+3 gpio69=32*2+8*0+5 outl( inl(0x533) | (1<<2), 0x533); //i2c-gpio sdl (GPIO58) @@ -229,7 +233,7 @@ static int __init inv_platform_init(void) outl( inl(0x500) | (1<<7), 0x500); //SYS_RDY_N (GPIO7) outl( inl(0x501) | (1<<7), 0x501); //BMC_HEART_BEAT (GPIO15) outl( inl(0x503) | (1<<2)|(1<<3), 0x503); //PSOC_HEART_BEAT(26),CPLD_HEART_BEAT(27) - + device_i2c_gpio0 = platform_device_alloc("i2c-gpio", 1); if (!device_i2c_gpio0) { printk(KERN_ERR "i2c-gpio: platform_device_alloc fail\n"); @@ -243,7 +247,8 @@ static int __init inv_platform_init(void) if (ret) { printk(KERN_ERR "i2c-gpio: platform_device_add fail %d\n", ret); } - msleep(10); + msleep(10); + for(i=0; idev.platform_data = NULL; - platform_device_unregister(device_i2c_gpio0); + int i; + + for(i=client_list_index-1; i>=0; i--) { + i2c_unregister_device(client_list[i]); + } + device_i2c_gpio0->dev.platform_data = NULL; + platform_device_unregister(device_i2c_gpio0); + printk("inv_platform_exit done\n"); } module_init(inv_platform_init); @@ -273,3 +294,4 @@ module_exit(inv_platform_exit); MODULE_AUTHOR("Inventec"); MODULE_DESCRIPTION("Platform devices"); MODULE_LICENSE("GPL"); + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_swps.c b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_swps.c index cbb22fba2979..11b60f78ae90 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_swps.c +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_swps.c @@ -1,9 +1,3 @@ -/* - * 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. - */ #include #include #include @@ -15,12 +9,14 @@ #include #include #include +#include #include "inv_swps.h" static int ctl_major; static int port_major; static int ioexp_total; static int port_total; +static int block_polling; static int auto_config; static int flag_i2c_reset; static int flag_mod_state; @@ -29,7 +25,8 @@ static struct class *swp_class_p = NULL; static struct inv_platform_s *platform_p = NULL; static struct inv_ioexp_layout_s *ioexp_layout = NULL; static struct inv_port_layout_s *port_layout = NULL; - +int io_no_init = 0; +module_param(io_no_init, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); static void swp_polling_worker(struct work_struct *work); static DECLARE_DELAYED_WORK(swp_polling, swp_polling_worker); @@ -140,6 +137,47 @@ _get_transvr_obj(char *dev_name) { } +static int +_is_i2c_target_exist(int chan, int addr) { + /* retval: Exist = 1 / Not exist = 0 / Error < 0 + */ + struct i2c_adapter *adap = NULL; + struct i2c_client *client = NULL; + int retval = -1; + int err = -1; + int d_offs = 0; + + adap = i2c_get_adapter(chan); + if (!adap) { + SWPS_DEBUG("%s: can't get adapter\n", __func__); + retval = 0; + goto out_is_i2c_target_exist_1; + } + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) { + SWPS_ERR("%s: kzalloc fail\n", __func__); + retval = -1; + goto out_is_i2c_target_exist_2; + } + client->adapter = adap; + client->addr = addr; + err = i2c_smbus_read_byte_data(client, d_offs); + if (err < 0) { + retval = 0; + } else { + retval = 1; + } + i2c_put_adapter(adap); + kfree(client); + return retval; + +out_is_i2c_target_exist_2: + i2c_put_adapter(adap); +out_is_i2c_target_exist_1: + return retval; +} + + static void unlock_tobj_all(void) { @@ -254,6 +292,22 @@ show_attr_auto_config(struct device *dev_p, } +static ssize_t +show_attr_block_poll(struct device *dev_p, + struct device_attribute *attr_p, + char *buf_p){ + + return snprintf(buf_p, 8, "%d\n", block_polling); +} +static ssize_t +show_attr_io_no_init(struct device *dev_p, + struct device_attribute *attr_p, + char *buf_p){ + + return snprintf(buf_p, 8, "%d\n", io_no_init); +} + + static int _check_reset_pwd(const char *buf_p, size_t count) { @@ -360,6 +414,53 @@ store_attr_auto_config(struct device *dev_p, } +static ssize_t +store_attr_block_poll( struct device *dev_p, + struct device_attribute *attr_p, + const char *buf_p, + size_t count){ + + int input_val = sscanf_2_int(buf_p); + + if (input_val < 0){ + return -EBFONT; + } + if ((input_val != 0) && (input_val != 1)) { + return -EBFONT; + } + + if(input_val != block_polling){ + block_polling = input_val; + if(block_polling){ + cancel_delayed_work_sync(&swp_polling); + } + else{ + schedule_delayed_work(&swp_polling, _get_polling_period()); + } + } + + return count; +} + +static ssize_t +store_attr_io_no_init( struct device *dev_p, + struct device_attribute *attr_p, + const char *buf_p, + size_t count){ + + int input_val = sscanf_2_int(buf_p); + + if ((input_val != 0) && (input_val != 1)) { + return -EBFONT; + } + + if(input_val != io_no_init){ + io_no_init = input_val; + } + + return count; +} + /* ========== Show functions: For transceiver attribute ========== */ static ssize_t @@ -1604,6 +1705,9 @@ static DEVICE_ATTR(status, S_IRUGO, show_attr_status, static DEVICE_ATTR(reset_i2c, S_IWUSR, NULL, store_attr_reset_i2c); static DEVICE_ATTR(reset_swps, S_IWUSR, NULL, store_attr_reset_swps); static DEVICE_ATTR(auto_config, S_IRUGO|S_IWUSR, show_attr_auto_config, store_attr_auto_config); +static DEVICE_ATTR(block_poll, S_IRUGO|S_IWUSR, show_attr_block_poll, store_attr_block_poll); +static DEVICE_ATTR(io_no_init, S_IRUGO|S_IWUSR, show_attr_io_no_init, store_attr_io_no_init); + /* ========== Transceiver attribute: from eeprom ========== */ @@ -1666,12 +1770,12 @@ static DEVICE_ATTR(hard_rs1, S_IRUGO|S_IWUSR, show_attr_hard_rs1, /* ========== Functions for module handling ========== */ static void -clean_port_obj(void){ +clean_port_objs(void){ dev_t dev_num; char dev_name[32]; struct device *device_p; - struct transvr_obj_s *transvr_obj_p; + struct transvr_obj_s *tobj_p; int minor_curr, port_id; for (minor_curr=0; minor_curri2c_client_p); - kfree(transvr_obj_p->vendor_name); - kfree(transvr_obj_p->vendor_pn); - kfree(transvr_obj_p->vendor_rev); - kfree(transvr_obj_p->vendor_sn); - kfree(transvr_obj_p->worker_p); - kfree(transvr_obj_p); + tobj_p = dev_get_drvdata(device_p); + if (tobj_p){ + if (tobj_p->i2c_client_p) { + i2c_put_adapter(tobj_p->i2c_client_p->adapter); + kfree(tobj_p->i2c_client_p); + } + kfree(tobj_p->vendor_name); + kfree(tobj_p->vendor_pn); + kfree(tobj_p->vendor_rev); + kfree(tobj_p->vendor_sn); + kfree(tobj_p->worker_p); + kfree(tobj_p); } dev_num = MKDEV(port_major, minor_curr); device_unregister(device_p); @@ -1713,6 +1820,9 @@ clean_swps_common(void){ device_destroy(swp_class_p, dev_num); } cancel_delayed_work_sync(&swp_polling); + if (platform_p) { + kfree(platform_p); + } SWPS_DEBUG("%s: done.\n", __func__); } @@ -1720,8 +1830,10 @@ clean_swps_common(void){ static int get_platform_type(void){ - int i; - int pf_total = ARRAY_SIZE(platform_map); + int i, tmp; + int auto_chan = -1; + int auto_addr = -1; + int pf_total = ARRAY_SIZE(platform_map); char log_msg[64] = "ERROR"; platform_p = kzalloc(sizeof(struct inv_platform_s), GFP_KERNEL); @@ -1749,6 +1861,30 @@ get_platform_type(void){ platform_p->name); goto err_get_platform_type_2; + case PLATFORM_TYPE_PEONY_AUTO: +#ifdef SWPS_PEONY_SFP + auto_chan = peony_sfp_ioexp_layout[0].addr[0].chan_id; + auto_addr = peony_sfp_ioexp_layout[0].addr[0].chip_addr; +#endif + tmp = _is_i2c_target_exist(auto_chan, auto_addr); + switch (tmp) { + case 0: /* Copper SKU */ + SWPS_INFO("Auto-detected :Peony :Copper\n"); + platform_p->id = PLATFORM_TYPE_PEONY_COPPER_GA; + goto map_platform_name; + + case 1: /* SFP SKU */ + SWPS_INFO("Auto-detected :Peony :SFP\n"); + platform_p->id = PLATFORM_TYPE_PEONY_SFP_GA; + goto map_platform_name; + + default: + break; + } + snprintf(log_msg, sizeof(log_msg), + "Auto detect Peony SKU fail! :%d", tmp); + goto err_get_platform_type_2; + case PLATFORM_TYPE_MAGNOLIA: case PLATFORM_TYPE_MAGNOLIA_FNC: case PLATFORM_TYPE_REDWOOD: @@ -1763,22 +1899,14 @@ get_platform_type(void){ case PLATFORM_TYPE_LAVENDER_GA: case PLATFORM_TYPE_LAVENDER_ONL: case PLATFORM_TYPE_COTTONWOOD_RANGELEY: - case PLATFORM_TYPE_MAPLE: + case PLATFORM_TYPE_MAPLE_GA: + case PLATFORM_TYPE_MAPLE_B: + case PLATFORM_TYPE_GULMOHAR_GA: + case PLATFORM_TYPE_GULMOHAR_2T_EVT1_GA: + case PLATFORM_TYPE_PEONY_SFP_GA: + case PLATFORM_TYPE_PEONY_COPPER_GA: platform_p->id = PLATFORM_SETTINGS; - for (i=0; iname, (sizeof(platform_p->name) - 1), - "%s", platform_map[i].name); - snprintf(log_msg, sizeof(log_msg), - "User setup platform: %d (%s)", - platform_p->id, platform_p->name); - goto ok_get_platform_type_1; - } - } - snprintf(log_msg, sizeof(log_msg), - "Internal error, can not map id:%d", - PLATFORM_SETTINGS); - goto err_get_platform_type_2; + goto map_platform_name; default: break; @@ -1787,6 +1915,22 @@ get_platform_type(void){ "PLATFORM_SETTINGS:%d undefined", PLATFORM_SETTINGS); goto err_get_platform_type_2; +map_platform_name: + for (i=0; iid == platform_map[i].id) { + snprintf(platform_p->name, (sizeof(platform_p->name) - 1), + "%s", platform_map[i].name); + snprintf(log_msg, sizeof(log_msg), + "User setup platform: %d (%s)", + platform_p->id, platform_p->name); + goto ok_get_platform_type_1; + } + } + snprintf(log_msg, sizeof(log_msg), + "Internal error, can not map id:%d", + platform_p->id ); + goto err_get_platform_type_2; + ok_get_platform_type_1: SWPS_DEBUG("%s: %s, :%d\n", __func__, log_msg, PLATFORM_SETTINGS); return 0; @@ -1913,15 +2057,61 @@ get_layout_info(void){ port_total = ARRAY_SIZE(cottonwood_rangeley_port_layout); break; #endif -#ifdef SWPS_MAPLE - case PLATFORM_TYPE_MAPLE: - gpio_rest_mux = maple_gpio_rest_mux; - ioexp_layout = maple_ioexp_layout; - port_layout = maple_port_layout; - ioexp_total = ARRAY_SIZE(maple_ioexp_layout); - port_total = ARRAY_SIZE(maple_port_layout); +#ifdef SWPS_MAPLE_GA + case PLATFORM_TYPE_MAPLE_GA: + gpio_rest_mux = maple_ga_gpio_rest_mux; + ioexp_layout = maple_ga_ioexp_layout; + port_layout = maple_ga_port_layout; + ioexp_total = ARRAY_SIZE(maple_ga_ioexp_layout); + port_total = ARRAY_SIZE(maple_ga_port_layout); + break; +#endif +#ifdef SWPS_MAPLE_B + case PLATFORM_TYPE_MAPLE_B: + gpio_rest_mux = maple_b_gpio_rest_mux; + ioexp_layout = maple_b_ioexp_layout; + port_layout = maple_b_port_layout; + ioexp_total = ARRAY_SIZE(maple_b_ioexp_layout); + port_total = ARRAY_SIZE(maple_b_port_layout); + break; +#endif +#ifdef SWPS_GULMOHAR + case PLATFORM_TYPE_GULMOHAR_GA: + gpio_rest_mux = gulmohar_gpio_rest_mux; + ioexp_layout = gulmohar_ioexp_layout; + port_layout = gulmohar_port_layout; + ioexp_total = ARRAY_SIZE(gulmohar_ioexp_layout); + port_total = ARRAY_SIZE(gulmohar_port_layout); + break; +#endif +#ifdef SWPS_GULMOHAR_2T_EVT1 + case PLATFORM_TYPE_GULMOHAR_2T_EVT1_GA: + gpio_rest_mux = gulmohar_2t_evt1_gpio_rest_mux; + ioexp_layout = gulmohar_2t_evt1_ioexp_layout; + port_layout = gulmohar_2t_evt1_port_layout; + ioexp_total = ARRAY_SIZE(gulmohar_2t_evt1_ioexp_layout); + port_total = ARRAY_SIZE(gulmohar_2t_evt1_port_layout); + break; +#endif +#ifdef SWPS_PEONY_SFP + case PLATFORM_TYPE_PEONY_SFP_GA: + gpio_rest_mux = peony_sfp_gpio_rest_mux; + ioexp_layout = peony_sfp_ioexp_layout; + port_layout = peony_sfp_port_layout; + ioexp_total = ARRAY_SIZE(peony_sfp_ioexp_layout); + port_total = ARRAY_SIZE(peony_sfp_port_layout); + break; +#endif +#ifdef SWPS_PEONY_COPPER + case PLATFORM_TYPE_PEONY_COPPER_GA: + gpio_rest_mux = peony_copper_gpio_rest_mux; + ioexp_layout = peony_copper_ioexp_layout; + port_layout = peony_copper_port_layout; + ioexp_total = ARRAY_SIZE(peony_copper_ioexp_layout); + port_total = ARRAY_SIZE(peony_copper_port_layout); break; #endif + default: SWPS_ERR(" Invalid platform: %d (%s)\n", platform_p->id, platform_p->name); @@ -1952,11 +2142,18 @@ __detect_issues_port(int minor_num) { } if (resync_channel_tier_2(tobj_p) < 0) { if (check_channel_tier_1() < 0) { - alarm_msg_2_user(tobj_p, i2c_emsg); - return -2;; + goto get_target_issues_port; } } + /* Re-check again for i2c-gpio special case */ + if (check_channel_tier_1() < 0) { + goto get_target_issues_port; + } return 0; + +get_target_issues_port: + alarm_msg_2_user(tobj_p, i2c_emsg); + return -2; } @@ -2015,11 +2212,11 @@ _isolate_issues_port(int minor_num) { static int _reset_i2c_topology_tier_1(void) { - if (reset_mux_gpio() < 0) { + if (reset_mux_objs() < 0) { SWPS_ERR("%s: reset MUX GPIO fail!\n", __func__); return -1; } - SWPS_DEBUG("%s: reset_mux_gpio OK.\n", __func__); + SWPS_DEBUG("%s: reset_mux_objs OK.\n", __func__); if (resync_channel_tier_1() < 0) { SWPS_ERR("%s: resync tier-1 channel fail!\n", __func__); return -1; @@ -2596,6 +2793,15 @@ register_modctl_attr(struct device *device_p){ err_msg = "dev_attr_auto_config"; goto err_reg_modctl_attr; } + if (device_create_file(device_p, &dev_attr_block_poll) < 0) { + err_msg = "dev_attr_block_poll"; + goto err_reg_modctl_attr; + } + if (device_create_file(device_p, &dev_attr_io_no_init) < 0) { + err_msg = "dev_attr_io_no_init"; + goto err_reg_modctl_attr; + } + return 0; err_reg_modctl_attr: @@ -2619,13 +2825,19 @@ register_ioexp_attr(struct device *device_p, goto err_reg_ioexp_attr; } break; - case IOEXP_TYPE_CYPRESS_NABC: + case IOEXP_TYPE_MAPLE_NABC: + case IOEXP_TYPE_GULMOHAR_NABC: + case IOEXP_TYPE_GULMOHAR_2T_EVT1_NABC: + case IOEXP_TYPE_GULMOHAR_2T_EVT1_1ABC: + case IOEXP_TYPE_GULMOHAR_2T_EVT1_3ABC: + case IOEXP_TYPE_SFP_8P_LAYOUT_1: if (register_ioexp_attr_sfp_2(device_p) < 0){ err_msg = "register_ioexp_attr_sfp_2 fail"; goto err_reg_ioexp_attr; } break; + case IOEXP_TYPE_MAGINOLIA_7AB: case IOEXP_TYPE_SPRUCE_7AB: case IOEXP_TYPE_CYPRESS_7ABC: @@ -2638,6 +2850,9 @@ register_ioexp_attr(struct device *device_p, case IOEXP_TYPE_SEQUOIA_NABC: case IOEXP_TYPE_LAVENDER_P65: case IOEXP_TYPE_MAPLE_0ABC: + case IOEXP_TYPE_GULMOHAR_7ABC: + case IOEXP_TYPE_GULMOHAR_2T_EVT1_7ABC: + case IOEXP_TYPE_QSFP_6P_LAYOUT_1: if (register_ioexp_attr_qsfp_1(device_p) < 0){ err_msg = "register_ioexp_attr_qsfp_1 fail"; goto err_reg_ioexp_attr; @@ -2732,7 +2947,7 @@ register_swp_module(void){ SWPS_WARN("Allocate CTL MAJOR failure! \n"); goto err_register_swp_module_1; } - if (alloc_chrdev_region(&port_devt, 0, dev_total, SWP_CLS_NAME) < 0){ + if (alloc_chrdev_region(&port_devt, 0, port_total, SWP_CLS_NAME) < 0){ SWPS_WARN("Allocate PORT MAJOR failure! \n"); goto err_register_swp_module_2; } @@ -2863,13 +3078,13 @@ create_port_objs(void) { /* Success */ ok_count++; } - SWPS_INFO("%s: initialed %d port-dev",__func__, ok_count); + SWPS_INFO("%s: initialed %d port-dev\n",__func__, ok_count); return 0; err_initport_reg_device: kfree(transvr_obj_p); err_initport_create_tranobj: - clean_port_obj(); + clean_port_objs(); SWPS_ERR("%s: %s", __func__, err_msg); SWPS_ERR("Dump: :%d :%d :%d :%d :%d :%d\n", port_id, chan_id, ioexp_id, ioexp_virt_offset, transvr_type, run_mod); @@ -2942,6 +3157,7 @@ init_swps_common(void){ char *err_msg = "ERR"; + block_polling = 0; auto_config = 0; if ((SWP_AUTOCONFIG_ENABLE) && (SWP_POLLING_ENABLE)){ auto_config = 1; @@ -2985,7 +3201,7 @@ swp_module_init(void){ if (create_port_objs() < 0){ goto err_init_portobj; } - if (init_mux_gpio(gpio_rest_mux) < 0){ + if (init_mux_objs(gpio_rest_mux) < 0){ goto err_init_mux; } if (init_dev_topology() < 0){ @@ -2999,13 +3215,12 @@ swp_module_init(void){ err_init_topology: - clean_mux_gpio(); + clean_mux_objs(); err_init_mux: - clean_port_obj(); + clean_port_objs(); err_init_portobj: clean_ioexp_objs(); err_init_ioexp: - class_unregister(swp_class_p); class_destroy(swp_class_p); unregister_chrdev_region(MKDEV(ctl_major, 0), 1); unregister_chrdev_region(MKDEV(port_major, 0), port_total); @@ -3019,10 +3234,9 @@ static void __exit swp_module_exit(void){ clean_swps_common(); - clean_port_obj(); + clean_port_objs(); clean_ioexp_objs(); - clean_mux_gpio(); - class_unregister(swp_class_p); + clean_mux_objs(); class_destroy(swp_class_p); unregister_chrdev_region(MKDEV(ctl_major, 0), 1); unregister_chrdev_region(MKDEV(port_major, 0), port_total); @@ -3035,6 +3249,7 @@ MODULE_AUTHOR(SWP_AUTHOR); MODULE_DESCRIPTION(SWP_DESC); MODULE_VERSION(SWP_VERSION); MODULE_LICENSE(SWP_LICENSE); +MODULE_SOFTDEP("pre: inv_platform"); module_init(swp_module_init); module_exit(swp_module_exit); @@ -3047,3 +3262,5 @@ module_exit(swp_module_exit); + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_swps.h b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_swps.h index d28a0a3c968e..ad1f337b0c06 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_swps.h +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/inv_swps.h @@ -1,10 +1,3 @@ -/* - * 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. - */ - #ifndef INV_SWPS_H #define INV_SWPS_H @@ -24,7 +17,7 @@ /* Module information */ #define SWP_AUTHOR "Neil " #define SWP_DESC "Inventec port and transceiver driver" -#define SWP_VERSION "4.2.9" +#define SWP_VERSION "C1-4.3.5" #define SWP_LICENSE "GPL" /* Module status define */ @@ -52,9 +45,15 @@ #define PLATFORM_TYPE_LAVENDER_GA (181) #define PLATFORM_TYPE_LAVENDER_ONL (182) #define PLATFORM_TYPE_COTTONWOOD_RANGELEY (191) -#define PLATFORM_TYPE_MAPLE (201) +#define PLATFORM_TYPE_MAPLE_GA (201) +#define PLATFORM_TYPE_GULMOHAR_GA (202) +#define PLATFORM_TYPE_GULMOHAR_2T_EVT1_GA (203) +#define PLATFORM_TYPE_PEONY_SFP_GA (204) +#define PLATFORM_TYPE_PEONY_COPPER_GA (205) +#define PLATFORM_TYPE_PEONY_AUTO (206) +#define PLATFORM_TYPE_MAPLE_B (207) /* Current running platfrom */ -#define PLATFORM_SETTINGS PLATFORM_TYPE_MAPLE +#define PLATFORM_SETTINGS PLATFORM_TYPE_MAPLE_B /* Define platform flag and kernel version */ #if (PLATFORM_SETTINGS == PLATFORM_TYPE_MAGNOLIA) @@ -99,12 +98,30 @@ #elif (PLATFORM_SETTINGS == PLATFORM_TYPE_COTTONWOOD_RANGELEY) #define SWPS_COTTONWOOD_RANGELEY (1) #define SWPS_KERN_VER_AF_3_10 (1) -#elif (PLATFORM_SETTINGS == PLATFORM_TYPE_MAPLE) - #define SWPS_MAPLE (1) +#elif (PLATFORM_SETTINGS == PLATFORM_TYPE_MAPLE_GA) + #define SWPS_MAPLE_GA (1) + #define SWPS_KERN_VER_AF_3_10 (1) +#elif (PLATFORM_SETTINGS == PLATFORM_TYPE_MAPLE_B) + #define SWPS_MAPLE_B (1) + #define SWPS_KERN_VER_AF_3_10 (1) +#elif (PLATFORM_SETTINGS == PLATFORM_TYPE_GULMOHAR_GA) + #define SWPS_GULMOHAR (1) + #define SWPS_KERN_VER_AF_3_10 (1) +#elif (PLATFORM_SETTINGS == PLATFORM_TYPE_GULMOHAR_2T_EVT1_GA) + #define SWPS_GULMOHAR_2T_EVT1 (1) + #define SWPS_KERN_VER_AF_3_10 (1) +#elif (PLATFORM_SETTINGS == PLATFORM_TYPE_PEONY_SFP_GA) + #define SWPS_PEONY_SFP (1) + #define SWPS_KERN_VER_AF_3_10 (1) +#elif (PLATFORM_SETTINGS == PLATFORM_TYPE_PEONY_COPPER_GA) + #define SWPS_PEONY_COPPER (1) + #define SWPS_KERN_VER_AF_3_10 (1) +#elif (PLATFORM_SETTINGS == PLATFORM_TYPE_PEONY_AUTO) + #define SWPS_PEONY_SFP (1) + #define SWPS_PEONY_COPPER (1) #define SWPS_KERN_VER_AF_3_10 (1) #endif - struct inv_platform_s { int id; char name[64]; @@ -147,7 +164,13 @@ struct inv_platform_s platform_map[] = { {PLATFORM_TYPE_LAVENDER_GA, "Lavender_GA" }, {PLATFORM_TYPE_LAVENDER_ONL, "Lavender_ONL" }, {PLATFORM_TYPE_COTTONWOOD_RANGELEY, "Cottonwood_RANGELEY" }, - {PLATFORM_TYPE_MAPLE, "Maple" }, + {PLATFORM_TYPE_MAPLE_GA, "Maple_GA" }, + {PLATFORM_TYPE_MAPLE_B, "Maple_B" }, + {PLATFORM_TYPE_GULMOHAR_GA, "Gulmohar_GA" }, + {PLATFORM_TYPE_GULMOHAR_2T_EVT1_GA, "Gulmohar_2T_EVT1_GA" }, + {PLATFORM_TYPE_PEONY_SFP_GA, "Peony_SFP_GA" }, + {PLATFORM_TYPE_PEONY_COPPER_GA, "Peony_Copper_GA" }, + {PLATFORM_TYPE_PEONY_AUTO, "Peony_Auto_Detect" }, }; @@ -156,7 +179,7 @@ struct inv_platform_s platform_map[] = { * ========================================== */ #ifdef SWPS_MAGNOLIA -unsigned magnolia_gpio_rest_mux = MUX_RST_GPIO_48_PAC9548; +unsigned magnolia_gpio_rest_mux = MUX_RST_GPIO_48_PCA9548; struct inv_ioexp_layout_s magnolia_ioexp_layout[] = { /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ @@ -248,7 +271,7 @@ struct inv_port_layout_s magnolia_port_layout[] = { * ========================================== */ #ifdef SWPS_REDWOOD -unsigned redwood_gpio_rest_mux = MUX_RST_GPIO_48_PAC9548; +unsigned redwood_gpio_rest_mux = MUX_RST_GPIO_48_PCA9548; struct inv_ioexp_layout_s redwood_ioexp_layout[] = { /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ @@ -313,7 +336,7 @@ struct inv_port_layout_s redwood_port_layout[] = { * ========================================== */ #ifdef SWPS_HUDSON32I_GA -unsigned hudsin32iga_gpio_rest_mux = MUX_RST_GPIO_48_PAC9548; +unsigned hudsin32iga_gpio_rest_mux = MUX_RST_GPIO_48_PCA9548; struct inv_ioexp_layout_s hudson32iga_ioexp_layout[] = { /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ @@ -378,7 +401,7 @@ struct inv_port_layout_s hudson32iga_port_layout[] = { * ========================================== */ #ifdef SWPS_SPRUCE -unsigned spruce_gpio_rest_mux = MUX_RST_GPIO_48_PAC9548; +unsigned spruce_gpio_rest_mux = MUX_RST_GPIO_48_PCA9548; struct inv_ioexp_layout_s spruce_ioexp_layout[] = { /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ @@ -404,33 +427,33 @@ struct inv_port_layout_s spruce_port_layout[] = { * ========================================== */ #ifdef SWPS_CYPRESS_GA1 -unsigned cypress_ga1_gpio_rest_mux = MUX_RST_GPIO_69_PAC9548; +unsigned cypress_ga1_gpio_rest_mux = MUX_RST_GPIO_69_PCA9548; struct inv_ioexp_layout_s cypress_ga1_ioexp_layout[] = { /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ - {0, IOEXP_TYPE_CYPRESS_NABC, { {2, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {2, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {2, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {0, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {2, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {2, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {2, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {1, IOEXP_TYPE_CYPRESS_NABC, { {3, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {3, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {3, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {1, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {3, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {3, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {3, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {2, IOEXP_TYPE_CYPRESS_NABC, { {4, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {4, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {4, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {2, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {4, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {4, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {4, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {3, IOEXP_TYPE_CYPRESS_NABC, { {5, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {5, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {5, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {3, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {5, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {5, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {5, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {4, IOEXP_TYPE_CYPRESS_NABC, { {6, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {6, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {6, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {4, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {6, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {6, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {6, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {5, IOEXP_TYPE_CYPRESS_NABC, { {7, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {7, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {7, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {5, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {7, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {7, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {7, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, {6, IOEXP_TYPE_CYPRESS_7ABC, { {8, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xc0, 0xc0}, }, /* addr[0] = I/O Expander 7 A */ {8, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xc0, 0xc0}, {0xff, 0xc0}, }, /* addr[1] = I/O Expander 7 B */ @@ -507,29 +530,29 @@ unsigned cypress_ga2_gpio_rest_mux = MUX_RST_GPIO_FORCE_HEDERA; struct inv_ioexp_layout_s cypress_ga2_ioexp_layout[] = { /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ - {0, IOEXP_TYPE_CYPRESS_NABC, { {2, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {2, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {2, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {0, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {2, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {2, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {2, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {1, IOEXP_TYPE_CYPRESS_NABC, { {3, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {3, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {3, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {1, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {3, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {3, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {3, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {2, IOEXP_TYPE_CYPRESS_NABC, { {4, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {4, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {4, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {2, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {4, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {4, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {4, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {3, IOEXP_TYPE_CYPRESS_NABC, { {5, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {5, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {5, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {3, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {5, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {5, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {5, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {4, IOEXP_TYPE_CYPRESS_NABC, { {6, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {6, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {6, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {4, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {6, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {6, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {6, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {5, IOEXP_TYPE_CYPRESS_NABC, { {7, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {7, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {7, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {5, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {7, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {7, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {7, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, {6, IOEXP_TYPE_CYPRESS_7ABC, { {8, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xc0, 0xc0}, }, /* addr[0] = I/O Expander 7 A */ {8, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xc0, 0xc0}, {0xff, 0xc0}, }, /* addr[1] = I/O Expander 7 B */ @@ -606,29 +629,29 @@ unsigned cypress_b_gpio_rest_mux = MUX_RST_GPIO_FORCE_HEDERA; struct inv_ioexp_layout_s cypress_b_ioexp_layout[] = { /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ - {0, IOEXP_TYPE_CYPRESS_NABC, { {2, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {2, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {2, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {0, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {2, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {2, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {2, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {1, IOEXP_TYPE_CYPRESS_NABC, { {3, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {3, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {3, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {1, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {3, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {3, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {3, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {2, IOEXP_TYPE_CYPRESS_NABC, { {4, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {4, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {4, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {2, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {4, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {4, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {4, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {3, IOEXP_TYPE_CYPRESS_NABC, { {5, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {5, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {5, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {3, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {5, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {5, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {5, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {4, IOEXP_TYPE_CYPRESS_NABC, { {6, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {6, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {6, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {4, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {6, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {6, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {6, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, - {5, IOEXP_TYPE_CYPRESS_NABC, { {7, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ - {7, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ - {7, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + {5, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {7, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {7, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {7, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ }, {6, IOEXP_TYPE_CYPRESS_7ABC, { {8, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xc0, 0xc0}, }, /* addr[0] = I/O Expander 7 A */ {8, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xc0, 0xc0}, {0xff, 0xc0}, }, /* addr[1] = I/O Expander 7 B */ @@ -701,7 +724,7 @@ struct inv_port_layout_s cypress_b_port_layout[] = { * ========================================== */ #ifdef SWPS_REDWOOD_FSL -unsigned redwood_fsl_gpio_rest_mux = MUX_RST_GPIO_48_PAC9548; +unsigned redwood_fsl_gpio_rest_mux = MUX_RST_GPIO_48_PCA9548; struct inv_ioexp_layout_s redwood_fsl_ioexp_layout[] = { /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ @@ -801,7 +824,7 @@ struct inv_port_layout_s tahoe_port_layout[] = { * ========================================== */ #ifdef SWPS_SEQUOIA -unsigned sequoia_gpio_rest_mux = MUX_RST_GPIO_69_PAC9548; +unsigned sequoia_gpio_rest_mux = MUX_RST_GPIO_69_PCA9548; struct inv_ioexp_layout_s sequoia_ioexp_layout[] = { /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ @@ -917,7 +940,7 @@ struct inv_port_layout_s sequoia_port_layout[] = { #if (PLATFORM_SETTINGS == PLATFORM_TYPE_LAVENDER_GA) unsigned lavender_gpio_rest_mux = MUX_RST_GPIO_505_PCA9548; #elif (PLATFORM_SETTINGS == PLATFORM_TYPE_LAVENDER_ONL) -unsigned lavender_gpio_rest_mux = MUX_RST_GPIO_69_PAC9548; +unsigned lavender_gpio_rest_mux = MUX_RST_GPIO_69_PCA9548; #endif #ifdef SWPS_LAVENDER @@ -1035,7 +1058,7 @@ struct inv_port_layout_s lavender_port_layout[] = { * =========================================================== */ #ifdef SWPS_COTTONWOOD_RANGELEY -unsigned cottonwood_rangeley_gpio_rest_mux = MUX_RST_GPIO_500_PAC9548; +unsigned cottonwood_rangeley_gpio_rest_mux = MUX_RST_GPIO_500_PCA9548; struct inv_ioexp_layout_s cottonwood_rangeley_ioexp_layout[] = { /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ @@ -1055,13 +1078,13 @@ struct inv_port_layout_s cottonwood_rangeley_port_layout[] = { #endif /* =========================================================== - * Maple Layout configuration + * Maple Layout configuration (Old) * =========================================================== */ -#ifdef SWPS_MAPLE -unsigned maple_gpio_rest_mux = 249; +#ifdef SWPS_MAPLE_GA +unsigned maple_ga_gpio_rest_mux = MUX_RST_GPIO_505_PCA9548; -struct inv_ioexp_layout_s maple_ioexp_layout[] = { +struct inv_ioexp_layout_s maple_ga_ioexp_layout[] = { /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ {0, IOEXP_TYPE_MAPLE_0ABC, { {2, 0x20, {0, 1}, {2, 3}, {6, 7}, {0x00, 0xff}, {0x00, 0x00}, }, /* addr[0] = I/O Expander 0 A */ {2, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0xff}, }, /* addr[1] = I/O Expander 0 B */ @@ -1093,7 +1116,7 @@ struct inv_ioexp_layout_s maple_ioexp_layout[] = { }, }; -struct inv_port_layout_s maple_port_layout[] = { +struct inv_port_layout_s maple_ga_port_layout[] = { /* Port_ID / Chan_ID / IOEXP_ID / IOEXP_VIRT_OFFSET / TRANSCEIVER_TYPE / BCM_CHIP_TYPE / LANE_ID */ { 0, 18, 1, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 1} }, { 1, 19, 1, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 2} }, @@ -1154,6 +1177,438 @@ struct inv_port_layout_s maple_port_layout[] = { }; #endif +/* =========================================================== + * Maple Layout configuration (B version) + * =========================================================== + */ +#ifdef SWPS_MAPLE_B +unsigned maple_b_gpio_rest_mux = MUX_RST_GPIO_69_PCA9548; + +struct inv_ioexp_layout_s maple_b_ioexp_layout[] = { + /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ + {0, IOEXP_TYPE_MAPLE_0ABC, { { 6, 0x20, {0, 1}, {2, 3}, {6, 7}, {0x00, 0xff}, {0x00, 0x00}, }, /* addr[0] = I/O Expander 0 A */ + { 6, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0xff}, }, /* addr[1] = I/O Expander 0 B */ + { 6, 0x22, {0, 1}, {2, 3}, {6, 7}, {0x00, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 0 C */ + }, + {1, IOEXP_TYPE_MAPLE_NABC, { { 7, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + { 7, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + { 7, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {2, IOEXP_TYPE_MAPLE_NABC, { { 8, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + { 8, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + { 8, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {3, IOEXP_TYPE_MAPLE_NABC, { { 9, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + { 9, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + { 9, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {4, IOEXP_TYPE_MAPLE_NABC, { {10, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {10, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {10, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {5, IOEXP_TYPE_MAPLE_NABC, { {11, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {11, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {11, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {6, IOEXP_TYPE_MAPLE_NABC, { {12, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {12, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {12, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, +}; + +struct inv_port_layout_s maple_b_port_layout[] = { + /* Port_ID / Chan_ID / IOEXP_ID / IOEXP_VIRT_OFFSET / TRANSCEIVER_TYPE / BCM_CHIP_TYPE / LANE_ID */ + { 1, 23, 1, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 2} }, + { 0, 22, 1, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 1} }, + { 3, 25, 1, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 4} }, + { 2, 24, 1, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 3} }, + { 5, 27, 1, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 6} }, + { 4, 26, 1, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 5} }, + { 7, 29, 1, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 8} }, + { 6, 28, 1, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 7} }, + { 9, 31, 2, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 14} }, + { 8, 30, 2, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 13} }, + {11, 33, 2, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 16} }, + {10, 32, 2, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 15} }, + {13, 35, 2, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 22} }, + {12, 34, 2, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 21} }, + {15, 37, 2, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 24} }, + {14, 36, 2, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 23} }, + {17, 39, 3, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 30} }, + {16, 38, 3, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 29} }, + {19, 41, 3, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 32} }, + {18, 40, 3, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 31} }, + {21, 43, 3, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 34} }, + {20, 42, 3, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 33} }, + {23, 45, 3, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 36} }, + {22, 44, 3, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 35} }, + {25, 47, 4, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 42} }, + {24, 46, 4, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 41} }, + {27, 49, 4, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 44} }, + {26, 48, 4, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 43} }, + {29, 51, 4, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 50} }, + {28, 50, 4, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 49} }, + {31, 53, 4, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 52} }, + {30, 52, 4, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 51} }, + {33, 55, 5, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 58} }, + {32, 54, 5, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 57} }, + {35, 57, 5, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 60} }, + {34, 56, 5, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 59} }, + {37, 59, 5, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 62} }, + {36, 58, 5, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 61} }, + {39, 61, 5, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 64} }, + {38, 60, 5, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 63} }, + {41, 63, 6, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 66} }, + {40, 62, 6, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 65} }, + {43, 65, 6, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 68} }, + {42, 64, 6, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 67} }, + {45, 67, 6, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 70} }, + {44, 66, 6, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 69} }, + {47, 69, 6, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 72} }, + {46, 68, 6, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 71} }, + {49, 15, 0, 1, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 77, 78, 79, 80} }, + {48, 14, 0, 0, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 85, 86, 87, 88} }, + {51, 17, 0, 3, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 97, 98, 99,100} }, + {50, 16, 0, 2, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 93, 94, 95, 96} }, + {53, 19, 0, 5, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, {105,106,107,108} }, + {52, 18, 0, 4, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, {113,114,115,116} }, + {55, 21, 0, 7, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, {125,126,127,128} }, + {54, 20, 0, 6, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, {121,122,123,124} }, +}; +#endif + + +/* ========================================== + * Gulmohar Layout configuration + * ========================================== + */ +#ifdef SWPS_GULMOHAR +unsigned gulmohar_gpio_rest_mux = MUX_RST_GPIO_505_PCA9548; + +struct inv_ioexp_layout_s gulmohar_ioexp_layout[] = { + /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ + {0, IOEXP_TYPE_GULMOHAR_NABC, { {2, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[0] = I/O Expander N A */ + {2, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[1] = I/O Expander N B */ + {2, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {1, IOEXP_TYPE_GULMOHAR_NABC, { {3, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[0] = I/O Expander N A */ + {3, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[1] = I/O Expander N B */ + {3, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {2, IOEXP_TYPE_GULMOHAR_NABC, { {4, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[0] = I/O Expander N A */ + {4, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[1] = I/O Expander N B */ + {4, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {3, IOEXP_TYPE_GULMOHAR_NABC, { {5, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[0] = I/O Expander N A */ + {5, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[1] = I/O Expander N B */ + {5, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {4, IOEXP_TYPE_GULMOHAR_NABC, { {6, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[0] = I/O Expander N A */ + {6, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[1] = I/O Expander N B */ + {6, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {5, IOEXP_TYPE_GULMOHAR_NABC, { {7, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[0] = I/O Expander N A */ + {7, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[1] = I/O Expander N B */ + {7, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {6, IOEXP_TYPE_GULMOHAR_7ABC, { {8, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xc0, 0xff}, {0xc0, 0xc0}, }, /* addr[0] = I/O Expander 7 A */ + {8, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xc0, 0xff}, }, /* addr[1] = I/O Expander 7 B */ + {8, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xc0, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 7 C */ + }, +}; + + + +struct inv_port_layout_s gulmohar_port_layout[] = { + /* Port_ID / Chan_ID / IOEXP_ID / IOEXP_VIRT_OFFSET / TRANSCEIVER_TYPE / BCM_CHIP_TYPE / LANE_ID */ + { 0, 10, 0, 0, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 1} }, + { 1, 11, 0, 1, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 2} }, + { 2, 12, 0, 2, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 3} }, + { 3, 13, 0, 3, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 4} }, + { 4, 14, 0, 4, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 5} }, + { 5, 15, 0, 5, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 6} }, + { 6, 16, 0, 6, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 7} }, + { 7, 17, 0, 7, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 8} }, + { 8, 18, 1, 0, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 9} }, + { 9, 19, 1, 1, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 10} }, + {10, 20, 1, 2, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 11} }, + {11, 21, 1, 3, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 12} }, + {12, 22, 1, 4, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 21} }, + {13, 23, 1, 5, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 22} }, + {14, 24, 1, 6, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 23} }, + {15, 25, 1, 7, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 24} }, + {16, 26, 2, 0, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 33} }, + {17, 27, 2, 1, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 34} }, + {18, 28, 2, 2, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 35} }, + {19, 29, 2, 3, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 36} }, + {20, 30, 2, 4, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 37} }, + {21, 31, 2, 5, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 38} }, + {22, 32, 2, 6, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 39} }, + {23, 33, 2, 7, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 40} }, + {24, 34, 3, 0, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 41} }, + {25, 35, 3, 1, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 42} }, + {26, 36, 3, 2, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 43} }, + {27, 37, 3, 3, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 44} }, + {28, 38, 3, 4, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 49} }, + {29, 39, 3, 5, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 50} }, + {30, 40, 3, 6, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 51} }, + {31, 41, 3, 7, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 52} }, + {32, 42, 4, 0, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 53} }, + {33, 43, 4, 1, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 54} }, + {34, 44, 4, 2, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 55} }, + {35, 45, 4, 3, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 56} }, + {36, 46, 4, 4, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 65} }, + {37, 47, 4, 5, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 66} }, + {38, 48, 4, 6, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 67} }, + {39, 49, 4, 7, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 68} }, + {40, 50, 5, 0, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 69} }, + {41, 51, 5, 1, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 70} }, + {42, 52, 5, 2, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 71} }, + {43, 53, 5, 3, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 72} }, + {44, 54, 5, 4, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 81} }, + {45, 55, 5, 5, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 82} }, + {46, 56, 5, 6, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 83} }, + {47, 57, 5, 7, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, { 84} }, + {48, 58, 6, 0, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, { 97, 98, 99,100} }, + {49, 59, 6, 1, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, { 85, 86, 87, 88} }, + {50, 60, 6, 2, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, {101,102,103,104} }, + {51, 61, 6, 3, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, {105,106,107,108} }, + {52, 62, 6, 4, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, {109,110,111,112} }, + {53, 63, 6, 5, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, {109,110,111,112} }, +}; +#endif + + +/* ========================================== + * Gulmohar_2T EVT1 Layout configuration + * ========================================== + */ +#ifdef SWPS_GULMOHAR_2T_EVT1 +unsigned gulmohar_2t_evt1_gpio_rest_mux = MUX_RST_GPIO_505_PCA9548; + +struct inv_ioexp_layout_s gulmohar_2t_evt1_ioexp_layout[] = { + /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ + {0, IOEXP_TYPE_GULMOHAR_2T_EVT1_NABC,{ {2, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xdd, 0xdd}, {0xdd, 0xdd}, }, /* addr[0] = I/O Expander N A */ + {2, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xdd, 0xdd}, {0xdd, 0xdd}, }, /* addr[1] = I/O Expander N B */ + {2, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {1, IOEXP_TYPE_GULMOHAR_2T_EVT1_1ABC,{ {3, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xdd, 0xdd}, {0xdd, 0xdd}, }, /* addr[0] = I/O Expander N A */ + {3, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[1] = I/O Expander N B */ + {3, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {2, IOEXP_TYPE_GULMOHAR_2T_EVT1_NABC,{ {4, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xdd, 0xdd}, {0xdd, 0xdd}, }, /* addr[0] = I/O Expander N A */ + {4, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xdd, 0xdd}, {0xdd, 0xdd}, }, /* addr[1] = I/O Expander N B */ + {4, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {3, IOEXP_TYPE_GULMOHAR_2T_EVT1_3ABC,{ {5, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xf3, 0xf3}, {0xf3, 0xf3}, }, /* addr[0] = I/O Expander N A */ + {5, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xdd, 0xdd}, {0xdd, 0xdd}, }, /* addr[1] = I/O Expander N B */ + {5, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {4, IOEXP_TYPE_GULMOHAR_2T_EVT1_NABC,{ {6, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xdd, 0xdd}, {0xdd, 0xdd}, }, /* addr[0] = I/O Expander N A */ + {6, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xdd, 0xdd}, {0xdd, 0xdd}, }, /* addr[1] = I/O Expander N B */ + {6, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {5, IOEXP_TYPE_GULMOHAR_2T_EVT1_NABC,{ {7, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xdd, 0xdd}, {0xdd, 0xdd}, }, /* addr[0] = I/O Expander N A */ + {7, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xdd, 0xdd}, {0xdd, 0xdd}, }, /* addr[1] = I/O Expander N B */ + {7, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {6, IOEXP_TYPE_GULMOHAR_2T_EVT1_7ABC,{ {8, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xd6, 0xda}, {0x18, 0xe3}, }, /* addr[0] = I/O Expander 7 A */ + {8, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xd6, 0xda}, {0x18, 0xe3}, }, /* addr[1] = I/O Expander 7 B */ + {8, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xd6, 0xff}, {0x18, 0xff}, }, }, /* addr[2] = I/O Expander 7 C */ + }, +}; + + + +struct inv_port_layout_s gulmohar_2t_evt1_port_layout[] = { + /* Port_ID / Chan_ID / IOEXP_ID / IOEXP_VIRT_OFFSET / TRANSCEIVER_TYPE / BCM_CHIP_TYPE / LANE_ID */ + { 0, 10, 0, 0, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + { 1, 11, 0, 1, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + { 2, 12, 0, 2, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + { 3, 13, 0, 3, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + { 4, 14, 0, 4, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + { 5, 15, 0, 5, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + { 6, 16, 0, 6, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + { 7, 17, 0, 7, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + { 8, 18, 1, 0, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + { 9, 19, 1, 1, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {10, 20, 1, 2, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {11, 21, 1, 3, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {12, 22, 1, 4, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {13, 23, 1, 5, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {14, 24, 1, 6, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {15, 25, 1, 7, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {16, 26, 2, 0, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {17, 27, 2, 1, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {18, 28, 2, 2, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {19, 29, 2, 3, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {20, 30, 2, 4, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {21, 31, 2, 5, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {22, 32, 2, 6, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {23, 33, 2, 7, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {24, 34, 3, 0, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {25, 35, 3, 1, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {26, 36, 3, 2, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {27, 37, 3, 3, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {28, 38, 3, 4, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {29, 39, 3, 5, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {30, 40, 3, 6, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {31, 41, 3, 7, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {32, 42, 4, 0, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {33, 43, 4, 1, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {34, 44, 4, 2, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {35, 45, 4, 3, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {36, 46, 4, 4, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {37, 47, 4, 5, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {38, 48, 4, 6, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {39, 49, 4, 7, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {40, 50, 5, 0, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {41, 51, 5, 1, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {42, 52, 5, 2, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {43, 53, 5, 3, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {44, 54, 5, 4, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {45, 55, 5, 5, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {46, 56, 5, 6, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {47, 57, 5, 7, TRANSVR_TYPE_SFP, BF_CHIP_TYPE_TOFINO, {-99} }, + {48, 59, 6, 1, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, {-99,-99,-99,-99} }, + {49, 58, 6, 0, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, {-99,-99,-99,-99} }, + {50, 61, 6, 3, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, {-99,-99,-99,-99} }, + {51, 60, 6, 2, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, {-99,-99,-99,-99} }, + {52, 63, 6, 5, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, {-99,-99,-99,-99} }, + {53, 62, 6, 4, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, {-99,-99,-99,-99} }, + {54, 65, 6, 7, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, {-99,-99,-99,-99} }, + {55, 64, 6, 6, TRANSVR_TYPE_QSFP_28, BF_CHIP_TYPE_TOFINO, {-99,-99,-99,-99} }, +}; +#endif + + +/* =========================================================== + * Peony-SFP Layout configuration + * =========================================================== + */ +#ifdef SWPS_PEONY_SFP +unsigned peony_sfp_gpio_rest_mux = MUX_RST_CPLD_C0_A77_70_74_RST_ALL; + +struct inv_ioexp_layout_s peony_sfp_ioexp_layout[] = { + /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ + {0, IOEXP_TYPE_QSFP_6P_LAYOUT_1, { {4, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xc0, 0xff}, {0xc0, 0xc0}, }, /* addr[0] = I/O Expander 0 A */ + {4, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xc0, 0xff}, }, /* addr[1] = I/O Expander 0 B */ + {4, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xc0, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 0 C */ + }, + {1, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {5, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {5, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {5, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {2, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {6, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {6, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {6, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {3, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {7, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {7, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {7, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {4, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {8, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {8, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {8, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {5, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {9, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {9, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {9, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {6, IOEXP_TYPE_SFP_8P_LAYOUT_1, { {10, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {10, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {10, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, +}; + +struct inv_port_layout_s peony_sfp_port_layout[] = { + /* Port_ID / Chan_ID / IOEXP_ID / IOEXP_VIRT_OFFSET / TRANSCEIVER_TYPE / BCM_CHIP_TYPE / LANE_ID */ + { 0, 20, 1, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 1} }, + { 1, 21, 1, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 2} }, + { 2, 22, 1, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 3} }, + { 3, 23, 1, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 4} }, + { 4, 24, 1, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 5} }, + { 5, 25, 1, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 6} }, + { 6, 26, 1, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 7} }, + { 7, 27, 1, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 8} }, + { 8, 28, 2, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 13} }, + { 9, 29, 2, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 14} }, + {10, 30, 2, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 15} }, + {11, 31, 2, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 16} }, + {12, 32, 2, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 21} }, + {13, 33, 2, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 22} }, + {14, 34, 2, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 23} }, + {15, 35, 2, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 24} }, + {16, 36, 3, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 29} }, + {17, 37, 3, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 30} }, + {18, 38, 3, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 31} }, + {19, 39, 3, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 32} }, + {20, 40, 3, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 33} }, + {21, 41, 3, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 34} }, + {22, 42, 3, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 35} }, + {23, 43, 3, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 36} }, + {24, 44, 4, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 65} }, + {25, 45, 4, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 66} }, + {26, 46, 4, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 67} }, + {27, 47, 4, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 68} }, + {28, 48, 4, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 69} }, + {29, 49, 4, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 70} }, + {30, 50, 4, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 71} }, + {31, 51, 4, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 72} }, + {32, 52, 5, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 97} }, + {33, 53, 5, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 98} }, + {34, 54, 5, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, { 99} }, + {35, 55, 5, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, {100} }, + {36, 56, 5, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, {105} }, + {37, 57, 5, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, {106} }, + {38, 58, 5, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, {107} }, + {39, 59, 5, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, {108} }, + {40, 60, 6, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, {113} }, + {41, 61, 6, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, {114} }, + {42, 62, 6, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, {115} }, + {43, 63, 6, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, {116} }, + {44, 64, 6, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, {121} }, + {45, 65, 6, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, {122} }, + {46, 66, 6, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, {123} }, + {47, 67, 6, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TRIDENT_3, {124} }, + {48, 12, 0, 0, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 49, 50, 51, 52} }, + {49, 13, 0, 1, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 57, 58, 59, 60} }, + {50, 14, 0, 2, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 61, 62, 63, 64} }, + {51, 15, 0, 3, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 77, 78, 79, 80} }, + {52, 16, 0, 4, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 85, 86, 87, 88} }, + {53, 17, 0, 5, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 93, 94, 95, 96} }, +}; +#endif + + +/* =========================================================== + * Peony-Copper Layout configuration + * =========================================================== + */ +#ifdef SWPS_PEONY_COPPER +unsigned peony_copper_gpio_rest_mux = MUX_RST_CPLD_C0_A77_70_74_RST_ALL; + +struct inv_ioexp_layout_s peony_copper_ioexp_layout[] = { + /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ + {0, IOEXP_TYPE_QSFP_6P_LAYOUT_1, { {10, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xc0, 0xff}, {0xc0, 0xc0}, }, /* addr[0] = I/O Expander 0 A */ + {10, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xc0, 0xff}, }, /* addr[1] = I/O Expander 0 B */ + {10, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xc0, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 0 C */ + }, +}; + +struct inv_port_layout_s peony_copper_port_layout[] = { + /* Port_ID / Chan_ID / IOEXP_ID / IOEXP_VIRT_OFFSET / TRANSCEIVER_TYPE / BCM_CHIP_TYPE / LANE_ID */ + {48, 4, 0, 0, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 49, 50, 51, 52} }, + {49, 5, 0, 1, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 57, 58, 59, 60} }, + {50, 6, 0, 2, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 61, 62, 63, 64} }, + {51, 7, 0, 3, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 77, 78, 79, 80} }, + {52, 8, 0, 4, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 85, 86, 87, 88} }, + {53, 9, 0, 5, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TRIDENT_3, { 93, 94, 95, 96} }, +}; +#endif + + + #endif /* INV_SWPS_H */ @@ -1162,3 +1617,5 @@ struct inv_port_layout_s maple_port_layout[] = { + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/io_expander.c b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/io_expander.c index 4564b5855fd8..985bfbb45eb8 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/io_expander.c +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/io_expander.c @@ -2,9 +2,14 @@ #include #include "io_expander.h" +/* For build single module using (Ex: ONL platform) */ +#include +//#include + + static struct ioexp_obj_s *ioexp_head_p = NULL; static struct ioexp_obj_s *ioexp_tail_p = NULL; - +extern int io_no_init; /* ========== Register IOEXP layout ========== */ @@ -571,6 +576,7 @@ struct ioexp_map_s cpld_map_cottonwood = { }, }; + struct ioexp_map_s ioexp_map_maple_0abc = { .chip_amount = 3, @@ -614,6 +620,7 @@ struct ioexp_map_s ioexp_map_maple_0abc = { }, }; + struct ioexp_map_s ioexp_map_maple_nabc = { .chip_amount = 3, @@ -675,6 +682,440 @@ struct ioexp_map_s ioexp_map_maple_nabc = { }, }; + +struct ioexp_map_s ioexp_map_gulmohar_nabc = { + + .chip_amount = 3, + .data_width = 2, + + .map_present = { {0, 0, 4}, /* map_present[0] = MOD_ABS_PORT(X) */ + {0, 0, 5}, /* map_present[1] = MOD_ABS_PORT(X+1) */ + {0, 1, 4}, /* map_present[2] = MOD_ABS_PORT(X+2) */ + {0, 1, 5}, /* map_present[3] = MOD_ABS_PORT(X+3) */ + {1, 0, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */ + {1, 0, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */ + {1, 1, 4}, /* map_present[6] = MOD_ABS_PORT(X+6) */ + {1, 1, 5}, /* map_present[7] = MOD_ABS_PORT(X+7) */ + }, + .map_tx_disable = { {0, 0, 2}, /* map_tx_disable[0] = TXDISABLE_SFP+_P(X) */ + {0, 0, 3}, /* map_tx_disable[1] = TXDISABLE_SFP+_P(X+1) */ + {0, 1, 2}, /* map_tx_disable[2] = TXDISABLE_SFP+_P(X+2) */ + {0, 1, 3}, /* map_tx_disable[3] = TXDISABLE_SFP+_P(X+3) */ + {1, 0, 2}, /* map_tx_disable[4] = TXDISABLE_SFP+_P(X+4) */ + {1, 0, 3}, /* map_tx_disable[5] = TXDISABLE_SFP+_P(X+5) */ + {1, 1, 2}, /* map_tx_disable[6] = TXDISABLE_SFP+_P(X+6) */ + {1, 1, 3}, /* map_tx_disable[7] = TXDISABLE_SFP+_P(X+7) */ + }, + .map_tx_fault = { {0, 0, 0}, /* map_tx_fault[0] = TXFAULT_SFP+_P(X) */ + {0, 0, 1}, /* map_tx_fault[1] = TXFAULT_SFP+_P(X+1) */ + {0, 1, 0}, /* map_tx_fault[2] = TXFAULT_SFP+_P(X+2) */ + {0, 1, 1}, /* map_tx_fault[3] = TXFAULT_SFP+_P(X+3) */ + {1, 0, 0}, /* map_tx_fault[4] = TXFAULT_SFP+_P(X+4) */ + {1, 0, 1}, /* map_tx_fault[5] = TXFAULT_SFP+_P(X+5) */ + {1, 1, 0}, /* map_tx_fault[6] = TXFAULT_SFP+_P(X+6) */ + {1, 1, 1}, /* map_tx_fault[7] = TXFAULT_SFP+_P(X+7) */ + }, + .map_rxlos = { {0, 0, 6}, /* map_rxlos[0] = OPRXLOS_PORT(X) */ + {0, 0, 7}, /* map_rxlos[1] = OPRXLOS_PORT(X+1) */ + {0, 1, 6}, /* map_rxlos[2] = OPRXLOS_PORT(X+2) */ + {0, 1, 7}, /* map_rxlos[3] = OPRXLOS_PORT(X+3) */ + {1, 0, 6}, /* map_rxlos[4] = OPRXLOS_PORT(X+4) */ + {1, 0, 7}, /* map_rxlos[5] = OPRXLOS_PORT(X+5) */ + {1, 1, 6}, /* map_rxlos[6] = OPRXLOS_PORT(X+6) */ + {1, 1, 7}, /* map_rxlos[7] = OPRXLOS_PORT(X+7) */ + }, + .map_hard_rs0 = { {2, 0, 0}, /* map_hard_rs0[0] = RS0_SFP28_P(X) */ + {2, 0, 2}, /* map_hard_rs0[1] = RS0_SFP28_P(X+1) */ + {2, 0, 4}, /* map_hard_rs0[2] = RS0_SFP28_P(X+2) */ + {2, 0, 6}, /* map_hard_rs0[3] = RS0_SFP28_P(X+3) */ + {2, 1, 0}, /* map_hard_rs0[4] = RS0_SFP28_P(X+4) */ + {2, 1, 2}, /* map_hard_rs0[5] = RS0_SFP28_P(X+5) */ + {2, 1, 4}, /* map_hard_rs0[6] = RS0_SFP28_P(X+6) */ + {2, 1, 6}, /* map_hard_rs0[7] = RS0_SFP28_P(X+7) */ + }, + .map_hard_rs1 = { {2, 0, 1}, /* map_hard_rs1[0] = RS1_SFP28_P(X) */ + {2, 0, 3}, /* map_hard_rs1[1] = RS1_SFP28_P(X+1) */ + {2, 0, 5}, /* map_hard_rs1[2] = RS1_SFP28_P(X+2) */ + {2, 0, 7}, /* map_hard_rs1[3] = RS1_SFP28_P(X+3) */ + {2, 1, 1}, /* map_hard_rs1[4] = RS1_SFP28_P(X+4) */ + {2, 1, 3}, /* map_hard_rs1[5] = RS1_SFP28_P(X+5) */ + {2, 1, 5}, /* map_hard_rs1[6] = RS1_SFP28_P(X+6) */ + {2, 1, 7}, /* map_hard_rs1[7] = RS1_SFP28_P(X+7) */ + }, +}; + + +struct ioexp_map_s ioexp_map_gulmohar_7abc = { + + .chip_amount = 3, + .data_width = 2, + + .map_present = { {2, 1, 0}, /* map_present[0] = MOD_ABS_PORT(X) */ + {2, 1, 1}, /* map_present[1] = MOD_ABS_PORT(X+1) */ + {2, 1, 2}, /* map_present[2] = MOD_ABS_PORT(X+2) */ + {2, 1, 3}, /* map_present[3] = MOD_ABS_PORT(X+3) */ + {2, 1, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */ + {2, 1, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */ + }, + .map_reset = { {0, 1, 0}, /* map_reset[0] = QRESET_QSFP_N_P(X) */ + {0, 1, 1}, /* map_reset[1] = QRESET_QSFP_N_P(X+1) */ + {0, 1, 2}, /* map_reset[2] = QRESET_QSFP_N_P(X+2) */ + {0, 1, 3}, /* map_reset[3] = QRESET_QSFP_N_P(X+3) */ + {0, 1, 4}, /* map_reset[4] = QRESET_QSFP_N_P(X+4) */ + {0, 1, 5}, /* map_reset[5] = QRESET_QSFP_N_P(X+5) */ + }, + .map_lpmod = { {1, 0, 0}, /* map_lpmod[0] = LPMODE_QSFP_P(X) */ + {1, 0, 1}, /* map_lpmod[1] = LPMODE_QSFP_P(X+1) */ + {1, 0, 2}, /* map_lpmod[2] = LPMODE_QSFP_P(X+2) */ + {1, 0, 3}, /* map_lpmod[3] = LPMODE_QSFP_P(X+3) */ + {1, 0, 4}, /* map_lpmod[4] = LPMODE_QSFP_P(X+4) */ + {1, 0, 5}, /* map_lpmod[5] = LPMODE_QSFP_P(X+5) */ + }, + .map_modsel = { {0, 0, 0}, /* map_modsel[0] = MODSEL_QSFP_N_P(X) */ + {0, 0, 1}, /* map_modsel[1] = MODSEL_QSFP_N_P(X+1) */ + {0, 0, 2}, /* map_modsel[2] = MODSEL_QSFP_N_P(X+2) */ + {0, 0, 3}, /* map_modsel[3] = MODSEL_QSFP_N_P(X+3) */ + {0, 0, 4}, /* map_modsel[4] = MODSEL_QSFP_N_P(X+4) */ + {0, 0, 5}, /* map_modsel[5] = MODSEL_QSFP_N_P(X+5) */ + }, +}; + + +struct ioexp_map_s ioexp_map_gulmohar_2t_evt1_nabc = { + + .chip_amount = 3, + .data_width = 2, + + .map_present = { {0, 0, 2}, /* map_present[0] = MOD_ABS_PORT(X) */ + {0, 0, 6}, /* map_present[1] = MOD_ABS_PORT(X+1) */ + {0, 1, 2}, /* map_present[2] = MOD_ABS_PORT(X+2) */ + {0, 1, 6}, /* map_present[3] = MOD_ABS_PORT(X+3) */ + {1, 0, 2}, /* map_present[4] = MOD_ABS_PORT(X+4) */ + {1, 0, 6}, /* map_present[5] = MOD_ABS_PORT(X+5) */ + {1, 1, 2}, /* map_present[6] = MOD_ABS_PORT(X+6) */ + {1, 1, 6}, /* map_present[7] = MOD_ABS_PORT(X+7) */ + }, + .map_tx_disable = { {0, 0, 1}, /* map_tx_disable[0] = TXDISABLE_SFP+_P(X) */ + {0, 0, 5}, /* map_tx_disable[1] = TXDISABLE_SFP+_P(X+1) */ + {0, 1, 1}, /* map_tx_disable[2] = TXDISABLE_SFP+_P(X+2) */ + {0, 1, 5}, /* map_tx_disable[3] = TXDISABLE_SFP+_P(X+3) */ + {1, 0, 1}, /* map_tx_disable[4] = TXDISABLE_SFP+_P(X+4) */ + {1, 0, 5}, /* map_tx_disable[5] = TXDISABLE_SFP+_P(X+5) */ + {1, 1, 1}, /* map_tx_disable[6] = TXDISABLE_SFP+_P(X+6) */ + {1, 1, 5}, /* map_tx_disable[7] = TXDISABLE_SFP+_P(X+7) */ + }, + .map_tx_fault = { {0, 0, 0}, /* map_tx_fault[0] = TXFAULT_SFP+_P(X) */ + {0, 0, 4}, /* map_tx_fault[1] = TXFAULT_SFP+_P(X+1) */ + {0, 1, 0}, /* map_tx_fault[2] = TXFAULT_SFP+_P(X+2) */ + {0, 1, 4}, /* map_tx_fault[3] = TXFAULT_SFP+_P(X+3) */ + {1, 0, 0}, /* map_tx_fault[4] = TXFAULT_SFP+_P(X+4) */ + {1, 0, 4}, /* map_tx_fault[5] = TXFAULT_SFP+_P(X+5) */ + {1, 1, 0}, /* map_tx_fault[6] = TXFAULT_SFP+_P(X+6) */ + {1, 1, 4}, /* map_tx_fault[7] = TXFAULT_SFP+_P(X+7) */ + }, + .map_rxlos = { {0, 0, 3}, /* map_rxlos[0] = OPRXLOS_PORT(X) */ + {0, 0, 7}, /* map_rxlos[1] = OPRXLOS_PORT(X+1) */ + {0, 1, 3}, /* map_rxlos[2] = OPRXLOS_PORT(X+2) */ + {0, 1, 7}, /* map_rxlos[3] = OPRXLOS_PORT(X+3) */ + {1, 0, 3}, /* map_rxlos[4] = OPRXLOS_PORT(X+4) */ + {1, 0, 7}, /* map_rxlos[5] = OPRXLOS_PORT(X+5) */ + {1, 1, 3}, /* map_rxlos[6] = OPRXLOS_PORT(X+6) */ + {1, 1, 7}, /* map_rxlos[7] = OPRXLOS_PORT(X+7) */ + }, + .map_hard_rs0 = { {2, 0, 0}, /* map_hard_rs0[0] = RS0_SFP28_P(X) */ + {2, 0, 2}, /* map_hard_rs0[1] = RS0_SFP28_P(X+1) */ + {2, 0, 4}, /* map_hard_rs0[2] = RS0_SFP28_P(X+2) */ + {2, 0, 6}, /* map_hard_rs0[3] = RS0_SFP28_P(X+3) */ + {2, 1, 0}, /* map_hard_rs0[4] = RS0_SFP28_P(X+4) */ + {2, 1, 2}, /* map_hard_rs0[5] = RS0_SFP28_P(X+5) */ + {2, 1, 4}, /* map_hard_rs0[6] = RS0_SFP28_P(X+6) */ + {2, 1, 6}, /* map_hard_rs0[7] = RS0_SFP28_P(X+7) */ + }, + .map_hard_rs1 = { {2, 0, 1}, /* map_hard_rs1[0] = RS1_SFP28_P(X) */ + {2, 0, 3}, /* map_hard_rs1[1] = RS1_SFP28_P(X+1) */ + {2, 0, 5}, /* map_hard_rs1[2] = RS1_SFP28_P(X+2) */ + {2, 0, 7}, /* map_hard_rs1[3] = RS1_SFP28_P(X+3) */ + {2, 1, 1}, /* map_hard_rs1[4] = RS1_SFP28_P(X+4) */ + {2, 1, 3}, /* map_hard_rs1[5] = RS1_SFP28_P(X+5) */ + {2, 1, 5}, /* map_hard_rs1[6] = RS1_SFP28_P(X+6) */ + {2, 1, 7}, /* map_hard_rs1[7] = RS1_SFP28_P(X+7) */ + }, +}; + + +struct ioexp_map_s ioexp_map_gulmohar_2t_evt1_1abc = { + + .chip_amount = 3, + .data_width = 2, + + .map_present = { {0, 0, 2}, /* map_present[0] = MOD_ABS_PORT(X) */ + {0, 0, 6}, /* map_present[1] = MOD_ABS_PORT(X+1) */ + {0, 1, 2}, /* map_present[2] = MOD_ABS_PORT(X+2) */ + {0, 1, 6}, /* map_present[3] = MOD_ABS_PORT(X+3) */ + {1, 0, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */ + {1, 0, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */ + {1, 1, 4}, /* map_present[6] = MOD_ABS_PORT(X+6) */ + {1, 1, 5}, /* map_present[7] = MOD_ABS_PORT(X+7) */ + }, + .map_tx_disable = { {0, 0, 1}, /* map_tx_disable[0] = TXDISABLE_SFP+_P(X) */ + {0, 0, 5}, /* map_tx_disable[1] = TXDISABLE_SFP+_P(X+1) */ + {0, 1, 1}, /* map_tx_disable[2] = TXDISABLE_SFP+_P(X+2) */ + {0, 1, 5}, /* map_tx_disable[3] = TXDISABLE_SFP+_P(X+3) */ + {1, 0, 2}, /* map_tx_disable[4] = TXDISABLE_SFP+_P(X+4) */ + {1, 0, 3}, /* map_tx_disable[5] = TXDISABLE_SFP+_P(X+5) */ + {1, 1, 2}, /* map_tx_disable[6] = TXDISABLE_SFP+_P(X+6) */ + {1, 1, 3}, /* map_tx_disable[7] = TXDISABLE_SFP+_P(X+7) */ + }, + .map_tx_fault = { {0, 0, 0}, /* map_tx_fault[0] = TXFAULT_SFP+_P(X) */ + {0, 0, 4}, /* map_tx_fault[1] = TXFAULT_SFP+_P(X+1) */ + {0, 1, 0}, /* map_tx_fault[2] = TXFAULT_SFP+_P(X+2) */ + {0, 1, 4}, /* map_tx_fault[3] = TXFAULT_SFP+_P(X+3) */ + {1, 0, 0}, /* map_tx_fault[4] = TXFAULT_SFP+_P(X+4) */ + {1, 0, 1}, /* map_tx_fault[5] = TXFAULT_SFP+_P(X+5) */ + {1, 1, 0}, /* map_tx_fault[6] = TXFAULT_SFP+_P(X+6) */ + {1, 1, 1}, /* map_tx_fault[7] = TXFAULT_SFP+_P(X+7) */ + }, + .map_rxlos = { {0, 0, 3}, /* map_rxlos[0] = OPRXLOS_PORT(X) */ + {0, 0, 7}, /* map_rxlos[1] = OPRXLOS_PORT(X+1) */ + {0, 1, 3}, /* map_rxlos[2] = OPRXLOS_PORT(X+2) */ + {0, 1, 7}, /* map_rxlos[3] = OPRXLOS_PORT(X+3) */ + {1, 0, 6}, /* map_rxlos[4] = OPRXLOS_PORT(X+4) */ + {1, 0, 7}, /* map_rxlos[5] = OPRXLOS_PORT(X+5) */ + {1, 1, 6}, /* map_rxlos[6] = OPRXLOS_PORT(X+6) */ + {1, 1, 7}, /* map_rxlos[7] = OPRXLOS_PORT(X+7) */ + }, + .map_hard_rs0 = { {2, 0, 0}, /* map_hard_rs0[0] = RS0_SFP28_P(X) */ + {2, 0, 2}, /* map_hard_rs0[1] = RS0_SFP28_P(X+1) */ + {2, 0, 4}, /* map_hard_rs0[2] = RS0_SFP28_P(X+2) */ + {2, 0, 6}, /* map_hard_rs0[3] = RS0_SFP28_P(X+3) */ + {2, 1, 0}, /* map_hard_rs0[4] = RS0_SFP28_P(X+4) */ + {2, 1, 2}, /* map_hard_rs0[5] = RS0_SFP28_P(X+5) */ + {2, 1, 4}, /* map_hard_rs0[6] = RS0_SFP28_P(X+6) */ + {2, 1, 6}, /* map_hard_rs0[7] = RS0_SFP28_P(X+7) */ + }, + .map_hard_rs1 = { {2, 0, 1}, /* map_hard_rs1[0] = RS1_SFP28_P(X) */ + {2, 0, 3}, /* map_hard_rs1[1] = RS1_SFP28_P(X+1) */ + {2, 0, 5}, /* map_hard_rs1[2] = RS1_SFP28_P(X+2) */ + {2, 0, 7}, /* map_hard_rs1[3] = RS1_SFP28_P(X+3) */ + {2, 1, 1}, /* map_hard_rs1[4] = RS1_SFP28_P(X+4) */ + {2, 1, 3}, /* map_hard_rs1[5] = RS1_SFP28_P(X+5) */ + {2, 1, 5}, /* map_hard_rs1[6] = RS1_SFP28_P(X+6) */ + {2, 1, 7}, /* map_hard_rs1[7] = RS1_SFP28_P(X+7) */ + }, +}; + + +struct ioexp_map_s ioexp_map_gulmohar_2t_evt1_3abc = { + + .chip_amount = 3, + .data_width = 2, + + .map_present = { {0, 0, 4}, /* map_present[0] = MOD_ABS_PORT(X) */ + {0, 0, 5}, /* map_present[1] = MOD_ABS_PORT(X+1) */ + {0, 1, 4}, /* map_present[2] = MOD_ABS_PORT(X+2) */ + {0, 1, 5}, /* map_present[3] = MOD_ABS_PORT(X+3) */ + {1, 0, 2}, /* map_present[4] = MOD_ABS_PORT(X+4) */ + {1, 0, 6}, /* map_present[5] = MOD_ABS_PORT(X+5) */ + {1, 1, 2}, /* map_present[6] = MOD_ABS_PORT(X+6) */ + {1, 1, 6}, /* map_present[7] = MOD_ABS_PORT(X+7) */ + }, + .map_tx_disable = { {0, 0, 2}, /* map_tx_disable[0] = TXDISABLE_SFP+_P(X) */ + {0, 0, 3}, /* map_tx_disable[1] = TXDISABLE_SFP+_P(X+1) */ + {0, 1, 2}, /* map_tx_disable[2] = TXDISABLE_SFP+_P(X+2) */ + {0, 1, 3}, /* map_tx_disable[3] = TXDISABLE_SFP+_P(X+3) */ + {1, 0, 1}, /* map_tx_disable[4] = TXDISABLE_SFP+_P(X+4) */ + {1, 0, 5}, /* map_tx_disable[5] = TXDISABLE_SFP+_P(X+5) */ + {1, 1, 1}, /* map_tx_disable[6] = TXDISABLE_SFP+_P(X+6) */ + {1, 1, 5}, /* map_tx_disable[7] = TXDISABLE_SFP+_P(X+7) */ + }, + .map_tx_fault = { {0, 0, 0}, /* map_tx_fault[0] = TXFAULT_SFP+_P(X) */ + {0, 0, 1}, /* map_tx_fault[1] = TXFAULT_SFP+_P(X+1) */ + {0, 1, 0}, /* map_tx_fault[2] = TXFAULT_SFP+_P(X+2) */ + {0, 1, 1}, /* map_tx_fault[3] = TXFAULT_SFP+_P(X+3) */ + {1, 0, 0}, /* map_tx_fault[4] = TXFAULT_SFP+_P(X+4) */ + {1, 0, 4}, /* map_tx_fault[5] = TXFAULT_SFP+_P(X+5) */ + {1, 1, 0}, /* map_tx_fault[6] = TXFAULT_SFP+_P(X+6) */ + {1, 1, 4}, /* map_tx_fault[7] = TXFAULT_SFP+_P(X+7) */ + }, + .map_rxlos = { {0, 0, 6}, /* map_rxlos[0] = OPRXLOS_PORT(X) */ + {0, 0, 7}, /* map_rxlos[1] = OPRXLOS_PORT(X+1) */ + {0, 1, 6}, /* map_rxlos[2] = OPRXLOS_PORT(X+2) */ + {0, 1, 7}, /* map_rxlos[3] = OPRXLOS_PORT(X+3) */ + {1, 0, 3}, /* map_rxlos[4] = OPRXLOS_PORT(X+4) */ + {1, 0, 7}, /* map_rxlos[5] = OPRXLOS_PORT(X+5) */ + {1, 1, 3}, /* map_rxlos[6] = OPRXLOS_PORT(X+6) */ + {1, 1, 7}, /* map_rxlos[7] = OPRXLOS_PORT(X+7) */ + }, + .map_hard_rs0 = { {2, 0, 0}, /* map_hard_rs0[0] = RS0_SFP28_P(X) */ + {2, 0, 2}, /* map_hard_rs0[1] = RS0_SFP28_P(X+1) */ + {2, 0, 4}, /* map_hard_rs0[2] = RS0_SFP28_P(X+2) */ + {2, 0, 6}, /* map_hard_rs0[3] = RS0_SFP28_P(X+3) */ + {2, 1, 0}, /* map_hard_rs0[4] = RS0_SFP28_P(X+4) */ + {2, 1, 2}, /* map_hard_rs0[5] = RS0_SFP28_P(X+5) */ + {2, 1, 4}, /* map_hard_rs0[6] = RS0_SFP28_P(X+6) */ + {2, 1, 6}, /* map_hard_rs0[7] = RS0_SFP28_P(X+7) */ + }, + .map_hard_rs1 = { {2, 0, 1}, /* map_hard_rs1[0] = RS1_SFP28_P(X) */ + {2, 0, 3}, /* map_hard_rs1[1] = RS1_SFP28_P(X+1) */ + {2, 0, 5}, /* map_hard_rs1[2] = RS1_SFP28_P(X+2) */ + {2, 0, 7}, /* map_hard_rs1[3] = RS1_SFP28_P(X+3) */ + {2, 1, 1}, /* map_hard_rs1[4] = RS1_SFP28_P(X+4) */ + {2, 1, 3}, /* map_hard_rs1[5] = RS1_SFP28_P(X+5) */ + {2, 1, 5}, /* map_hard_rs1[6] = RS1_SFP28_P(X+6) */ + {2, 1, 7}, /* map_hard_rs1[7] = RS1_SFP28_P(X+7) */ + }, +}; + + + +struct ioexp_map_s ioexp_map_gulmohar_2t_evt1_7abc = { + + .chip_amount = 3, + .data_width = 2, + + .map_present = { {0, 0, 4}, /* map_present[0] = MOD_ABS_PORT(X) */ + {0, 1, 1}, /* map_present[1] = MOD_ABS_PORT(X+1) */ + {0, 1, 6}, /* map_present[2] = MOD_ABS_PORT(X+2) */ + {1, 0, 4}, /* map_present[3] = MOD_ABS_PORT(X+3) */ + {1, 1, 1}, /* map_present[4] = MOD_ABS_PORT(X+4) */ + {1, 1, 6}, /* map_present[5] = MOD_ABS_PORT(X+5) */ + {2, 0, 4}, /* map_present[6] = MOD_ABS_PORT(X+6) */ + {2, 1, 1}, /* map_present[7] = MOD_ABS_PORT(X+7) */ + }, + .map_reset = { {0, 0, 1}, /* map_reset[0] = QRESET_QSFP_N_P(X) */ + {0, 0, 6}, /* map_reset[1] = QRESET_QSFP_N_P(X+1) */ + {0, 1, 3}, /* map_reset[2] = QRESET_QSFP_N_P(X+2) */ + {1, 0, 1}, /* map_reset[3] = QRESET_QSFP_N_P(X+3) */ + {1, 0, 6}, /* map_reset[4] = QRESET_QSFP_N_P(X+4) */ + {1, 1, 3}, /* map_reset[5] = QRESET_QSFP_N_P(X+5) */ + {2, 0, 1}, /* map_reset[6] = QRESET_QSFP_N_P(X+6) */ + {2, 0, 6}, /* map_reset[7] = QRESET_QSFP_N_P(X+7) */ + }, + .map_lpmod = { {0, 0, 2}, /* map_lpmod[0] = LPMODE_QSFP_P(X) */ + {0, 0, 7}, /* map_lpmod[1] = LPMODE_QSFP_P(X+1) */ + {0, 1, 4}, /* map_lpmod[2] = LPMODE_QSFP_P(X+2) */ + {1, 0, 2}, /* map_lpmod[3] = LPMODE_QSFP_P(X+3) */ + {1, 0, 7}, /* map_lpmod[4] = LPMODE_QSFP_P(X+4) */ + {1, 1, 4}, /* map_lpmod[5] = LPMODE_QSFP_P(X+5) */ + {2, 0, 2}, /* map_lpmod[6] = LPMODE_QSFP_P(X+6) */ + {2, 0, 7}, /* map_lpmod[7] = LPMODE_QSFP_P(X+7) */ + }, + .map_modsel = { {0, 0, 0}, /* map_modsel[0] = MODSEL_QSFP_N_P(X) */ + {0, 0, 5}, /* map_modsel[1] = MODSEL_QSFP_N_P(X+1) */ + {0, 1, 2}, /* map_modsel[2] = MODSEL_QSFP_N_P(X+2) */ + {1, 0, 0}, /* map_modsel[3] = MODSEL_QSFP_N_P(X+3) */ + {1, 0, 5}, /* map_modsel[4] = MODSEL_QSFP_N_P(X+4) */ + {1, 1, 2}, /* map_modsel[5] = MODSEL_QSFP_N_P(X+5) */ + {2, 0, 0}, /* map_modsel[6] = MODSEL_QSFP_N_P(X+6) */ + {2, 0, 5}, /* map_modsel[7] = MODSEL_QSFP_N_P(X+7) */ + }, +}; + + +/* PortType: SFP / 8 port + * Platform: Cypress, Peony_SFP + */ +struct ioexp_map_s ioexp_map_sfp_8p_layout_1 = { + + .chip_amount = 3, + .data_width = 2, + + .map_present = { {0, 0, 4}, /* map_present[0] = MOD_ABS_PORT(X) */ + {0, 0, 5}, /* map_present[1] = MOD_ABS_PORT(X+1) */ + {0, 0, 6}, /* map_present[2] = MOD_ABS_PORT(X+2) */ + {0, 0, 7}, /* map_present[3] = MOD_ABS_PORT(X+3) */ + {1, 0, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */ + {1, 0, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */ + {1, 0, 6}, /* map_present[6] = MOD_ABS_PORT(X+6) */ + {1, 0, 7}, /* map_present[7] = MOD_ABS_PORT(X+7) */ + }, + .map_tx_disable = { {0, 1, 0}, /* map_tx_disable[0] = TXDISABLE_SFP+_P(X) */ + {0, 1, 1}, /* map_tx_disable[1] = TXDISABLE_SFP+_P(X+1) */ + {0, 1, 2}, /* map_tx_disable[2] = TXDISABLE_SFP+_P(X+2) */ + {0, 1, 3}, /* map_tx_disable[3] = TXDISABLE_SFP+_P(X+3) */ + {1, 1, 0}, /* map_tx_disable[4] = TXDISABLE_SFP+_P(X+4) */ + {1, 1, 1}, /* map_tx_disable[5] = TXDISABLE_SFP+_P(X+5) */ + {1, 1, 2}, /* map_tx_disable[6] = TXDISABLE_SFP+_P(X+6) */ + {1, 1, 3}, /* map_tx_disable[7] = TXDISABLE_SFP+_P(X+7) */ + }, + .map_tx_fault = { {0, 0, 0}, /* map_tx_fault[0] = TXFAULT_SFP+_P(X) */ + {0, 0, 1}, /* map_tx_fault[1] = TXFAULT_SFP+_P(X+1) */ + {0, 0, 2}, /* map_tx_fault[2] = TXFAULT_SFP+_P(X+2) */ + {0, 0, 3}, /* map_tx_fault[3] = TXFAULT_SFP+_P(X+3) */ + {1, 0, 0}, /* map_tx_fault[4] = TXFAULT_SFP+_P(X+4) */ + {1, 0, 1}, /* map_tx_fault[5] = TXFAULT_SFP+_P(X+5) */ + {1, 0, 2}, /* map_tx_fault[6] = TXFAULT_SFP+_P(X+6) */ + {1, 0, 3}, /* map_tx_fault[7] = TXFAULT_SFP+_P(X+7) */ + }, + .map_rxlos = { {0, 1, 4}, /* map_rxlos[0] = OPRXLOS_PORT(X) */ + {0, 1, 5}, /* map_rxlos[1] = OPRXLOS_PORT(X+1) */ + {0, 1, 6}, /* map_rxlos[2] = OPRXLOS_PORT(X+2) */ + {0, 1, 7}, /* map_rxlos[3] = OPRXLOS_PORT(X+3) */ + {1, 1, 4}, /* map_rxlos[4] = OPRXLOS_PORT(X+4) */ + {1, 1, 5}, /* map_rxlos[5] = OPRXLOS_PORT(X+5) */ + {1, 1, 6}, /* map_rxlos[6] = OPRXLOS_PORT(X+6) */ + {1, 1, 7}, /* map_rxlos[7] = OPRXLOS_PORT(X+7) */ + }, + .map_hard_rs0 = { {2, 0, 0}, /* map_hard_rs0[0] = RS0_SFP28_P(X) */ + {2, 0, 2}, /* map_hard_rs0[1] = RS0_SFP28_P(X+1) */ + {2, 0, 4}, /* map_hard_rs0[2] = RS0_SFP28_P(X+2) */ + {2, 0, 6}, /* map_hard_rs0[3] = RS0_SFP28_P(X+3) */ + {2, 1, 0}, /* map_hard_rs0[4] = RS0_SFP28_P(X+4) */ + {2, 1, 2}, /* map_hard_rs0[5] = RS0_SFP28_P(X+5) */ + {2, 1, 4}, /* map_hard_rs0[6] = RS0_SFP28_P(X+6) */ + {2, 1, 6}, /* map_hard_rs0[7] = RS0_SFP28_P(X+7) */ + }, + .map_hard_rs1 = { {2, 0, 1}, /* map_hard_rs1[0] = RS1_SFP28_P(X) */ + {2, 0, 3}, /* map_hard_rs1[1] = RS1_SFP28_P(X+1) */ + {2, 0, 5}, /* map_hard_rs1[2] = RS1_SFP28_P(X+2) */ + {2, 0, 7}, /* map_hard_rs1[3] = RS1_SFP28_P(X+3) */ + {2, 1, 1}, /* map_hard_rs1[4] = RS1_SFP28_P(X+4) */ + {2, 1, 3}, /* map_hard_rs1[5] = RS1_SFP28_P(X+5) */ + {2, 1, 5}, /* map_hard_rs1[6] = RS1_SFP28_P(X+6) */ + {2, 1, 7}, /* map_hard_rs1[7] = RS1_SFP28_P(X+7) */ + }, +}; + + +/* PortType: QSFP / 6 port + * Platform: Gulmohar, Peony_SFP, Peony_Copper + */ +struct ioexp_map_s ioexp_map_6p_qsfp_type_1 = { + + .chip_amount = 3, + .data_width = 2, + + .map_present = { {2, 1, 0}, /* map_present[0] = MOD_ABS_PORT(X) */ + {2, 1, 1}, /* map_present[1] = MOD_ABS_PORT(X+1) */ + {2, 1, 2}, /* map_present[2] = MOD_ABS_PORT(X+2) */ + {2, 1, 3}, /* map_present[3] = MOD_ABS_PORT(X+3) */ + {2, 1, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */ + {2, 1, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */ + }, + .map_reset = { {0, 1, 0}, /* map_reset[0] = QRESET_QSFP_N_P(X) */ + {0, 1, 1}, /* map_reset[1] = QRESET_QSFP_N_P(X+1) */ + {0, 1, 2}, /* map_reset[2] = QRESET_QSFP_N_P(X+2) */ + {0, 1, 3}, /* map_reset[3] = QRESET_QSFP_N_P(X+3) */ + {0, 1, 4}, /* map_reset[4] = QRESET_QSFP_N_P(X+4) */ + {0, 1, 5}, /* map_reset[5] = QRESET_QSFP_N_P(X+5) */ + }, + .map_lpmod = { {1, 0, 0}, /* map_lpmod[0] = LPMODE_QSFP_P(X) */ + {1, 0, 1}, /* map_lpmod[1] = LPMODE_QSFP_P(X+1) */ + {1, 0, 2}, /* map_lpmod[2] = LPMODE_QSFP_P(X+2) */ + {1, 0, 3}, /* map_lpmod[3] = LPMODE_QSFP_P(X+3) */ + {1, 0, 4}, /* map_lpmod[4] = LPMODE_QSFP_P(X+4) */ + {1, 0, 5}, /* map_lpmod[5] = LPMODE_QSFP_P(X+5) */ + }, + .map_modsel = { {0, 0, 0}, /* map_modsel[0] = MODSEL_QSFP_N_P(X) */ + {0, 0, 1}, /* map_modsel[1] = MODSEL_QSFP_N_P(X+1) */ + {0, 0, 2}, /* map_modsel[2] = MODSEL_QSFP_N_P(X+2) */ + {0, 0, 3}, /* map_modsel[3] = MODSEL_QSFP_N_P(X+3) */ + {0, 0, 4}, /* map_modsel[4] = MODSEL_QSFP_N_P(X+4) */ + {0, 0, 5}, /* map_modsel[5] = MODSEL_QSFP_N_P(X+5) */ + }, +}; + + /* ========== Private functions ========== */ int check_channel_tier_1(void); @@ -1125,32 +1566,35 @@ common_ioexp_init(struct ioexp_obj_s *self) { if (self->mode == IOEXP_MODE_DIRECT) { goto update_common_ioexp_init; } - /* Setup default value to each physical IO Expander */ - for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){ - /* Get address mapping */ - addr_p = &(self->ioexp_map_p->map_addr[chip_id]); - if (!addr_p){ - SWPS_ERR("%s: IOEXP config incorrect! :%d \n", - __func__, chip_id); - return -1; - } - /* Setup default value */ - for (offset=0; offset<(self->ioexp_map_p->data_width); offset++){ - - /* [Desc] Skip the setup default value behavior - [Note] Setup default value = -1 if you don't want to write the value to IOEXP or CPLD - */ - if(addr_p->write_offset[offset] < 0){ - SWPS_DEBUG("skip a write_offset <%d>\n", addr_p->conf_offset[offset]); - continue; + if (!io_no_init) { /*normal init*/ + + /* Setup default value to each physical IO Expander */ + for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){ + /* Get address mapping */ + addr_p = &(self->ioexp_map_p->map_addr[chip_id]); + if (!addr_p){ + SWPS_ERR("%s: IOEXP config incorrect! :%d \n", + __func__, chip_id); + return -1; } - err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, chip_id), - addr_p->write_offset[offset], - addr_p->data_default[offset]); - if (err_code < 0){ - SWPS_ERR("%s: set default fail! :%d \n", - __func__, err_code); - return ERR_IOEXP_UNEXCPT; + /* Setup default value */ + for (offset=0; offset<(self->ioexp_map_p->data_width); offset++){ + + /* [Desc] Skip the setup default value behavior + [Note] Setup default value = -1 if you don't want to write the value to IOEXP or CPLD + */ + if(addr_p->write_offset[offset] < 0){ + SWPS_DEBUG("skip a write_offset <%d>\n", addr_p->conf_offset[offset]); + continue; + } + err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, chip_id), + addr_p->write_offset[offset], + addr_p->data_default[offset]); + if (err_code < 0){ + SWPS_ERR("%s: set default fail! :%d \n", + __func__, err_code); + return ERR_IOEXP_UNEXCPT; + } } } } @@ -1171,24 +1615,56 @@ common_ioexp_init(struct ioexp_obj_s *self) { int _is_channel_ready(struct ioexp_obj_s *self){ - int buf = 0; - int chip_id = 0; /* Use first chip which be registered */ - int data_id = 0; /* Use first byte which be registered */ - struct ioexp_addr_s *ioexp_addr = NULL; + int chip_id = 0; + int byte_id = 0; + int getval = ERR_IOEXP_UNEXCPT; + int chkval = ERR_IOEXP_UNEXCPT; + char *emsg = "ERR"; + struct ioexp_addr_s *addr_p = NULL; - ioexp_addr = &(self->ioexp_map_p->map_addr[chip_id]); - if (!ioexp_addr){ - SWPS_ERR("%s: config incorrect!\n", __func__); - return ERR_IOEXP_UNEXCPT; + for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++) { + addr_p = &(self->ioexp_map_p->map_addr[chip_id]); + if (!addr_p){ + emsg = "IOEXP config incorrect"; + goto err_is_channel_ready; + } + for (byte_id=0; byte_id<(self->ioexp_map_p->data_width); byte_id++) { + if (addr_p->conf_offset[byte_id] < 0) { + continue; + } + if ((addr_p->conf_default[byte_id]) != 0) { + goto go_is_channel_ready; + } + } + if (chip_id == ((self->ioexp_map_p->chip_amount) - 1)) { + SWPS_DEBUG("%s: no non-zero config", __func__); + break; + } } - buf = i2c_smbus_read_byte_data(_get_i2c_client(self, chip_id), - ioexp_addr->read_offset[data_id]); - if (buf >= 0){ + chip_id = 0; + byte_id = 0; + +go_is_channel_ready: + addr_p = &(self->ioexp_map_p->map_addr[chip_id]); + chkval = addr_p->conf_default[byte_id]; + getval = i2c_smbus_read_byte_data(_get_i2c_client(self, chip_id), + addr_p->conf_offset[byte_id]); + + SWPS_DEBUG("%s: target info :%d :%d :%d :%d :%d\n", + __func__, self->ioexp_id, chip_id, byte_id, chkval, getval); + + if ((getval >= 0) && (getval == chkval)) { return 1; } return 0; + +err_is_channel_ready: + SWPS_ERR("%s: %s :%d :%d :%d :%d :%d\n", + __func__, emsg, self->ioexp_id, chip_id, byte_id, chkval, getval); + return ERR_IOEXP_UNEXCPT; } + int _ioexp_init_handler(struct ioexp_obj_s *self){ @@ -1395,8 +1871,6 @@ get_ioexp_map(int ioexp_type){ return &ioexp_map_hudson32iga_p01p08_p17p24; case IOEXP_TYPE_HUDSON32IGA_P09P16: return &ioexp_map_hudson32iga_p09p16_p25p32; - case IOEXP_TYPE_CYPRESS_NABC: - return &ioexp_map_cypress_nabc; case IOEXP_TYPE_CYPRESS_7ABC: return &ioexp_map_cypress_7abc; case IOEXP_TYPE_TAHOE_5A: @@ -1413,6 +1887,22 @@ get_ioexp_map(int ioexp_type){ return &ioexp_map_maple_0abc; case IOEXP_TYPE_MAPLE_NABC: return &ioexp_map_maple_nabc; + case IOEXP_TYPE_GULMOHAR_NABC: + return &ioexp_map_gulmohar_nabc; + case IOEXP_TYPE_GULMOHAR_7ABC: + return &ioexp_map_gulmohar_7abc; + case IOEXP_TYPE_GULMOHAR_2T_EVT1_NABC: + return &ioexp_map_gulmohar_2t_evt1_nabc; + case IOEXP_TYPE_GULMOHAR_2T_EVT1_1ABC: + return &ioexp_map_gulmohar_2t_evt1_1abc; + case IOEXP_TYPE_GULMOHAR_2T_EVT1_3ABC: + return &ioexp_map_gulmohar_2t_evt1_3abc; + case IOEXP_TYPE_GULMOHAR_2T_EVT1_7ABC: + return &ioexp_map_gulmohar_2t_evt1_7abc; + case IOEXP_TYPE_SFP_8P_LAYOUT_1: + return &ioexp_map_sfp_8p_layout_1; + case IOEXP_TYPE_QSFP_6P_LAYOUT_1: + return &ioexp_map_6p_qsfp_type_1; default: return NULL; } @@ -1497,8 +1987,13 @@ setup_ioexp_public_cb(struct ioexp_obj_s *self, self->set_hard_rs0 = ioexp_set_not_support; self->set_hard_rs1 = ioexp_set_not_support; return 0; - case IOEXP_TYPE_CYPRESS_NABC: + case IOEXP_TYPE_MAPLE_NABC: + case IOEXP_TYPE_GULMOHAR_NABC: + case IOEXP_TYPE_GULMOHAR_2T_EVT1_NABC: + case IOEXP_TYPE_GULMOHAR_2T_EVT1_1ABC: + case IOEXP_TYPE_GULMOHAR_2T_EVT1_3ABC: + case IOEXP_TYPE_SFP_8P_LAYOUT_1: self->get_present = common_get_present; self->get_tx_fault = common_get_tx_fault; self->get_rxlos = common_get_rxlos; @@ -1515,6 +2010,7 @@ setup_ioexp_public_cb(struct ioexp_obj_s *self, self->set_hard_rs0 = common_set_hard_rs0; self->set_hard_rs1 = common_set_hard_rs1; return 0; + case IOEXP_TYPE_MAGINOLIA_7AB: case IOEXP_TYPE_SPRUCE_7AB: case IOEXP_TYPE_REDWOOD_P01P08: @@ -1527,6 +2023,9 @@ setup_ioexp_public_cb(struct ioexp_obj_s *self, case IOEXP_TYPE_SEQUOIA_NABC: case IOEXP_TYPE_LAVENDER_P65: case IOEXP_TYPE_MAPLE_0ABC: + case IOEXP_TYPE_GULMOHAR_7ABC: + case IOEXP_TYPE_GULMOHAR_2T_EVT1_7ABC: + case IOEXP_TYPE_QSFP_6P_LAYOUT_1: self->get_present = common_get_present; self->get_tx_fault = ioexp_get_not_support; self->get_rxlos = ioexp_get_not_support; @@ -1565,7 +2064,6 @@ setup_ioexp_private_cb(struct ioexp_obj_s *self, case IOEXP_TYPE_REDWOOD_P09P16: case IOEXP_TYPE_HUDSON32IGA_P01P08: case IOEXP_TYPE_HUDSON32IGA_P09P16: - case IOEXP_TYPE_CYPRESS_NABC: case IOEXP_TYPE_CYPRESS_7ABC: case IOEXP_TYPE_TAHOE_5A: case IOEXP_TYPE_TAHOE_6ABC: @@ -1574,6 +2072,14 @@ setup_ioexp_private_cb(struct ioexp_obj_s *self, case CPLD_TYPE_COTTONWOOD: case IOEXP_TYPE_MAPLE_NABC: case IOEXP_TYPE_MAPLE_0ABC: + case IOEXP_TYPE_GULMOHAR_NABC: + case IOEXP_TYPE_GULMOHAR_7ABC: + case IOEXP_TYPE_GULMOHAR_2T_EVT1_NABC: + case IOEXP_TYPE_GULMOHAR_2T_EVT1_1ABC: + case IOEXP_TYPE_GULMOHAR_2T_EVT1_3ABC: + case IOEXP_TYPE_GULMOHAR_2T_EVT1_7ABC: + case IOEXP_TYPE_SFP_8P_LAYOUT_1: + case IOEXP_TYPE_QSFP_6P_LAYOUT_1: self->init = common_ioexp_init; self->check = common_ioexp_check; self->update_all = common_ioexp_update_all; @@ -1600,11 +2106,6 @@ setup_i2c_client_one(struct ioexp_obj_s *self, struct ioexp_i2c_s *i2c_curr_p = NULL; int chan_id = self->ioexp_map_p->map_addr[chip_id].chan_id; - adap = i2c_get_adapter(chan_id); - if(!adap){ - err_msg = "Can not get adap!"; - goto err_ioexp_setup_i2c_1; - } client = kzalloc(sizeof(*client), GFP_KERNEL); if (!client){ err_msg = "Can not kzalloc client!"; @@ -1615,6 +2116,11 @@ setup_i2c_client_one(struct ioexp_obj_s *self, err_msg = "Can not kzalloc i2c_obj_p!"; goto err_ioexp_setup_i2c_2; } + adap = i2c_get_adapter(chan_id); + if(!adap){ + err_msg = "Can not get adap!"; + goto err_ioexp_setup_i2c_3; + } client->adapter = adap; client->addr = self->ioexp_map_p->map_addr[chip_id].chip_addr; i2c_obj_p->i2c_client_p = client; @@ -1631,6 +2137,8 @@ setup_i2c_client_one(struct ioexp_obj_s *self, } return 0; +err_ioexp_setup_i2c_3: + kfree(i2c_obj_p); err_ioexp_setup_i2c_2: kfree(client); err_ioexp_setup_i2c_1: @@ -1661,6 +2169,11 @@ setup_ioexp_config(struct ioexp_obj_s *self) { int chip_id, offset, err_code; struct ioexp_addr_s *addr_p; + if (io_no_init) { + + SWPS_INFO("io_no_init:%d \n", io_no_init); + return 0; + } for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){ addr_p = &(self->ioexp_map_p->map_addr[chip_id]); @@ -1743,7 +2256,10 @@ _create_ioexp_obj(int ioexp_id, i2c_next_p = result_p->i2c_head_p; while (i2c_curr_p){ i2c_next_p = i2c_curr_p->next; - kfree(i2c_curr_p->i2c_client_p); + if (i2c_curr_p->i2c_client_p) { + i2c_put_adapter(i2c_curr_p->i2c_client_p->adapter); + kfree(i2c_curr_p->i2c_client_p); + } kfree(i2c_curr_p); i2c_curr_p = i2c_next_p; } @@ -1778,6 +2294,7 @@ create_ioexp_obj(int ioexp_id, ioexp_tail_p = ioexp_p; return 0; } +EXPORT_SYMBOL(create_ioexp_obj); static int @@ -1818,7 +2335,6 @@ init_ioexp_objs(void){ * -1: Detect topology error * -2: SWPS internal error */ - struct ioexp_obj_s *curr_p = ioexp_head_p; if (!curr_p) { @@ -1835,6 +2351,7 @@ init_ioexp_objs(void){ SWPS_DEBUG("%s: done.\n", __func__); return 0; } +EXPORT_SYMBOL(init_ioexp_objs); void @@ -1861,7 +2378,10 @@ clean_ioexp_objs(void){ i2c_curr_p = ioexp_curr_p->i2c_head_p; while (i2c_curr_p) { i2c_next_p = i2c_curr_p->next; - kfree(i2c_curr_p->i2c_client_p); + if (i2c_curr_p->i2c_client_p) { + i2c_put_adapter(i2c_curr_p->i2c_client_p->adapter); + kfree(i2c_curr_p->i2c_client_p); + } kfree(i2c_curr_p); i2c_curr_p = i2c_next_p; } @@ -1871,6 +2391,7 @@ clean_ioexp_objs(void){ ioexp_tail_p = NULL; SWPS_DEBUG("%s: done.\n", __func__); } +EXPORT_SYMBOL(clean_ioexp_objs); int @@ -1888,6 +2409,7 @@ check_ioexp_objs(void){ } return 0; } +EXPORT_SYMBOL(check_ioexp_objs); struct ioexp_obj_s * @@ -1905,6 +2427,7 @@ get_ioexp_obj(int ioexp_id){ } return result_p; } +EXPORT_SYMBOL(get_ioexp_obj); void @@ -1917,7 +2440,7 @@ unlock_ioexp_all(void) { ioexp_curr_p = ioexp_curr_p->next; } } - +EXPORT_SYMBOL(unlock_ioexp_all); int lock_ioexp_all(void) { @@ -1930,6 +2453,7 @@ lock_ioexp_all(void) { } return 0; } +EXPORT_SYMBOL(lock_ioexp_all); int @@ -1941,6 +2465,7 @@ check_channel_tier_1(void) { } return 0; } +EXPORT_SYMBOL(check_channel_tier_1); static int @@ -2037,10 +2562,11 @@ resync_channel_tier_1(void) { SWPS_ERR("%s: %s\n", __func__, emsg); return -1; } +EXPORT_SYMBOL(resync_channel_tier_1); - - +/* For build single module using (Ex: ONL platform) */ +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/io_expander.h b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/io_expander.h index 1af909e2466a..6f9f7b46291e 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/io_expander.h +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/io_expander.h @@ -1,10 +1,3 @@ -/* - * 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. - */ - #ifndef IO_EXPANDER_H #define IO_EXPANDER_H @@ -12,24 +5,31 @@ /* IOEXP type define (SFP series) */ -#define IOEXP_TYPE_MAGINOLIA_NAB (10101) -#define IOEXP_TYPE_MAGINOLIA_4AB (10102) -#define IOEXP_TYPE_CYPRESS_NABC (10103) -#define IOEXP_TYPE_MAPLE_NABC (10104) +#define IOEXP_TYPE_MAGINOLIA_NAB (10101) +#define IOEXP_TYPE_MAGINOLIA_4AB (10102) +#define IOEXP_TYPE_MAPLE_NABC (10104) +#define IOEXP_TYPE_GULMOHAR_NABC (10105) +#define IOEXP_TYPE_GULMOHAR_2T_EVT1_NABC (10106) +#define IOEXP_TYPE_SFP_8P_LAYOUT_1 (10107) +#define IOEXP_TYPE_GULMOHAR_2T_EVT1_1ABC (10108) +#define IOEXP_TYPE_GULMOHAR_2T_EVT1_3ABC (10109) /* IOEXP type define (QSFP series) */ -#define IOEXP_TYPE_MAGINOLIA_7AB (10201) -#define IOEXP_TYPE_REDWOOD_P01P08 (10202) -#define IOEXP_TYPE_REDWOOD_P09P16 (10203) -#define IOEXP_TYPE_HUDSON32IGA_P01P08 (10204) -#define IOEXP_TYPE_HUDSON32IGA_P09P16 (10205) -#define IOEXP_TYPE_SPRUCE_7AB (10206) -#define IOEXP_TYPE_CYPRESS_7ABC (10207) -#define IOEXP_TYPE_TAHOE_5A (10208) -#define IOEXP_TYPE_TAHOE_6ABC (10209) -#define IOEXP_TYPE_SEQUOIA_NABC (10210) -#define IOEXP_TYPE_LAVENDER_P65 (10211) -#define IOEXP_TYPE_MAPLE_0ABC (10212) +#define IOEXP_TYPE_MAGINOLIA_7AB (10201) +#define IOEXP_TYPE_REDWOOD_P01P08 (10202) +#define IOEXP_TYPE_REDWOOD_P09P16 (10203) +#define IOEXP_TYPE_HUDSON32IGA_P01P08 (10204) +#define IOEXP_TYPE_HUDSON32IGA_P09P16 (10205) +#define IOEXP_TYPE_SPRUCE_7AB (10206) +#define IOEXP_TYPE_CYPRESS_7ABC (10207) +#define IOEXP_TYPE_TAHOE_5A (10208) +#define IOEXP_TYPE_TAHOE_6ABC (10209) +#define IOEXP_TYPE_SEQUOIA_NABC (10210) +#define IOEXP_TYPE_LAVENDER_P65 (10211) +#define IOEXP_TYPE_MAPLE_0ABC (10212) +#define IOEXP_TYPE_GULMOHAR_7ABC (10213) +#define IOEXP_TYPE_GULMOHAR_2T_EVT1_7ABC (10214) +#define IOEXP_TYPE_QSFP_6P_LAYOUT_1 (10215) /* CPLD type define */ #define CPLD_TYPE_COTTONWOOD (10301) @@ -87,8 +87,8 @@ struct ioexp_bitmap_s { }; struct ioexp_map_s { - int chip_amount; /* Number of chips that IOEXP object content */ - int data_width; /* Number of (Read/Write/Config) bytes */ + int chip_amount; /* Number of chips that IOEXP object content */ + int data_width; /* Number of (Read/Write/Config) bytes */ struct ioexp_addr_s *map_addr; /* Chip address info */ struct ioexp_bitmap_s map_present[10]; /* IOEXP for SFP / QSFP */ struct ioexp_bitmap_s map_tx_disable[10]; /* IOEXP for SFP */ @@ -185,3 +185,5 @@ int resync_channel_tier_1(void); + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/lpc_ich.c b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/lpc_ich.c new file mode 100644 index 000000000000..66ff6e694d6f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/lpc_ich.c @@ -0,0 +1,1131 @@ +/* + * lpc_ich.c - LPC interface for Intel ICH + * + * LPC bridge function of the Intel ICH contains many other + * functional units, such as Interrupt controllers, Timers, + * Power Management, System Management, GPIO, RTC, and LPC + * Configuration Registers. + * + * This driver is derived from lpc_sch. + + * Copyright (c) 2011 Extreme Engineering Solution, Inc. + * Author: Aaron Sierra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 2 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 + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This driver supports 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 + * document number TBD : Wellsburg + * document number TBD : Avoton SoC + * document number TBD : Coleto Creek + * document number TBD : Wildcat Point-LP + * document number TBD : 9 Series + * document number TBD : Lewisburg + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ACPIBASE 0x40 +#define ACPIBASE_GPE_OFF 0x28 +#define ACPIBASE_GPE_END 0x2f +#define ACPIBASE_SMI_OFF 0x30 +#define ACPIBASE_SMI_END 0x33 +#define ACPIBASE_PMC_OFF 0x08 +#define ACPIBASE_PMC_END 0x0c +#define ACPIBASE_TCO_OFF 0x60 +#define ACPIBASE_TCO_END 0x7f +#define ACPICTRL_PMCBASE 0x44 + +#define ACPIBASE_GCS_OFF 0x3410 +#define ACPIBASE_GCS_END 0x3414 + +#define GPIOBASE_ICH0 0x58 +#define GPIOCTRL_ICH0 0x5C +#define GPIOBASE_ICH6 0x48 +#define GPIOCTRL_ICH6 0x4C + +#define RCBABASE 0xf0 + +#define wdt_io_res(i) wdt_res(0, i) +#define wdt_mem_res(i) wdt_res(ICH_RES_MEM_OFF, i) +#define wdt_res(b, i) (&wdt_ich_res[(b) + (i)]) + +struct lpc_ich_priv { + int chipset; + + int abase; /* ACPI base */ + int actrl_pbase; /* ACPI control or PMC base */ + int gbase; /* GPIO base */ + int gctrl; /* GPIO control */ + + int abase_save; /* Cached ACPI base value */ + int actrl_pbase_save; /* Cached ACPI control or PMC base value */ + int gctrl_save; /* Cached GPIO control value */ +}; + +static struct resource wdt_ich_res[] = { + /* ACPI - TCO */ + { + .flags = IORESOURCE_IO, + }, + /* ACPI - SMI */ + { + .flags = IORESOURCE_IO, + }, + /* GCS or PMC */ + { + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource gpio_ich_res[] = { + /* GPIO */ + { + .flags = IORESOURCE_IO, + }, + /* ACPI - GPE0 */ + { + .flags = IORESOURCE_IO, + }, +}; + +static struct mfd_cell lpc_ich_wdt_cell = { + .name = "iTCO_wdt", + .num_resources = ARRAY_SIZE(wdt_ich_res), + .resources = wdt_ich_res, + .ignore_resource_conflicts = true, +}; + +static struct mfd_cell lpc_ich_gpio_cell = { + .name = "gpio_ich", + .num_resources = ARRAY_SIZE(gpio_ich_res), + .resources = gpio_ich_res, + .ignore_resource_conflicts = true, +}; + +/* chipset related info */ +enum lpc_chipsets { + LPC_ICH = 0, /* ICH */ + LPC_ICH0, /* ICH0 */ + LPC_ICH2, /* ICH2 */ + LPC_ICH2M, /* ICH2-M */ + LPC_ICH3, /* ICH3-S */ + LPC_ICH3M, /* ICH3-M */ + LPC_ICH4, /* ICH4 */ + LPC_ICH4M, /* ICH4-M */ + LPC_CICH, /* C-ICH */ + LPC_ICH5, /* ICH5 & ICH5R */ + LPC_6300ESB, /* 6300ESB */ + LPC_ICH6, /* ICH6 & ICH6R */ + LPC_ICH6M, /* ICH6-M */ + LPC_ICH6W, /* ICH6W & ICH6RW */ + LPC_631XESB, /* 631xESB/632xESB */ + LPC_ICH7, /* ICH7 & ICH7R */ + LPC_ICH7DH, /* ICH7DH */ + LPC_ICH7M, /* ICH7-M & ICH7-U */ + LPC_ICH7MDH, /* ICH7-M DH */ + LPC_NM10, /* NM10 */ + LPC_ICH8, /* ICH8 & ICH8R */ + LPC_ICH8DH, /* ICH8DH */ + LPC_ICH8DO, /* ICH8DO */ + LPC_ICH8M, /* ICH8M */ + LPC_ICH8ME, /* ICH8M-E */ + LPC_ICH9, /* ICH9 */ + LPC_ICH9R, /* ICH9R */ + LPC_ICH9DH, /* ICH9DH */ + LPC_ICH9DO, /* ICH9DO */ + LPC_ICH9M, /* ICH9M */ + LPC_ICH9ME, /* ICH9M-E */ + LPC_ICH10, /* ICH10 */ + LPC_ICH10R, /* ICH10R */ + LPC_ICH10D, /* ICH10D */ + LPC_ICH10DO, /* ICH10DO */ + LPC_PCH, /* PCH Desktop Full Featured */ + LPC_PCHM, /* PCH Mobile Full Featured */ + LPC_P55, /* P55 */ + LPC_PM55, /* PM55 */ + LPC_H55, /* H55 */ + LPC_QM57, /* QM57 */ + LPC_H57, /* H57 */ + LPC_HM55, /* HM55 */ + LPC_Q57, /* Q57 */ + LPC_HM57, /* HM57 */ + LPC_PCHMSFF, /* PCH Mobile SFF Full Featured */ + LPC_QS57, /* QS57 */ + LPC_3400, /* 3400 */ + LPC_3420, /* 3420 */ + LPC_3450, /* 3450 */ + LPC_EP80579, /* EP80579 */ + LPC_CPT, /* Cougar Point */ + LPC_CPTD, /* Cougar Point Desktop */ + LPC_CPTM, /* Cougar Point Mobile */ + LPC_PBG, /* Patsburg */ + LPC_DH89XXCC, /* DH89xxCC */ + LPC_PPT, /* Panther Point */ + LPC_LPT, /* Lynx Point */ + LPC_LPT_LP, /* Lynx Point-LP */ + LPC_WBG, /* Wellsburg */ + LPC_AVN, /* Avoton SoC */ + LPC_BAYTRAIL, /* Bay Trail SoC */ + LPC_COLETO, /* Coleto Creek */ + LPC_WPT_LP, /* Wildcat Point-LP */ + LPC_BRASWELL, /* Braswell SoC */ + LPC_LEWISBURG, /* Lewisburg */ + LPC_9S, /* 9 Series */ +}; + +static struct lpc_ich_info lpc_chipset_info[] = { + [LPC_ICH] = { + .name = "ICH", + .iTCO_version = 1, + }, + [LPC_ICH0] = { + .name = "ICH0", + .iTCO_version = 1, + }, + [LPC_ICH2] = { + .name = "ICH2", + .iTCO_version = 1, + }, + [LPC_ICH2M] = { + .name = "ICH2-M", + .iTCO_version = 1, + }, + [LPC_ICH3] = { + .name = "ICH3-S", + .iTCO_version = 1, + }, + [LPC_ICH3M] = { + .name = "ICH3-M", + .iTCO_version = 1, + }, + [LPC_ICH4] = { + .name = "ICH4", + .iTCO_version = 1, + }, + [LPC_ICH4M] = { + .name = "ICH4-M", + .iTCO_version = 1, + }, + [LPC_CICH] = { + .name = "C-ICH", + .iTCO_version = 1, + }, + [LPC_ICH5] = { + .name = "ICH5 or ICH5R", + .iTCO_version = 1, + }, + [LPC_6300ESB] = { + .name = "6300ESB", + .iTCO_version = 1, + }, + [LPC_ICH6] = { + .name = "ICH6 or ICH6R", + .iTCO_version = 2, + .gpio_version = ICH_V6_GPIO, + }, + [LPC_ICH6M] = { + .name = "ICH6-M", + .iTCO_version = 2, + .gpio_version = ICH_V6_GPIO, + }, + [LPC_ICH6W] = { + .name = "ICH6W or ICH6RW", + .iTCO_version = 2, + .gpio_version = ICH_V6_GPIO, + }, + [LPC_631XESB] = { + .name = "631xESB/632xESB", + .iTCO_version = 2, + .gpio_version = ICH_V6_GPIO, + }, + [LPC_ICH7] = { + .name = "ICH7 or ICH7R", + .iTCO_version = 2, + .gpio_version = ICH_V7_GPIO, + }, + [LPC_ICH7DH] = { + .name = "ICH7DH", + .iTCO_version = 2, + .gpio_version = ICH_V7_GPIO, + }, + [LPC_ICH7M] = { + .name = "ICH7-M or ICH7-U", + .iTCO_version = 2, + .gpio_version = ICH_V7_GPIO, + }, + [LPC_ICH7MDH] = { + .name = "ICH7-M DH", + .iTCO_version = 2, + .gpio_version = ICH_V7_GPIO, + }, + [LPC_NM10] = { + .name = "NM10", + .iTCO_version = 2, + .gpio_version = ICH_V7_GPIO, + }, + [LPC_ICH8] = { + .name = "ICH8 or ICH8R", + .iTCO_version = 2, + .gpio_version = ICH_V7_GPIO, + }, + [LPC_ICH8DH] = { + .name = "ICH8DH", + .iTCO_version = 2, + .gpio_version = ICH_V7_GPIO, + }, + [LPC_ICH8DO] = { + .name = "ICH8DO", + .iTCO_version = 2, + .gpio_version = ICH_V7_GPIO, + }, + [LPC_ICH8M] = { + .name = "ICH8M", + .iTCO_version = 2, + .gpio_version = ICH_V7_GPIO, + }, + [LPC_ICH8ME] = { + .name = "ICH8M-E", + .iTCO_version = 2, + .gpio_version = ICH_V7_GPIO, + }, + [LPC_ICH9] = { + .name = "ICH9", + .iTCO_version = 2, + .gpio_version = ICH_V9_GPIO, + }, + [LPC_ICH9R] = { + .name = "ICH9R", + .iTCO_version = 2, + .gpio_version = ICH_V9_GPIO, + }, + [LPC_ICH9DH] = { + .name = "ICH9DH", + .iTCO_version = 2, + .gpio_version = ICH_V9_GPIO, + }, + [LPC_ICH9DO] = { + .name = "ICH9DO", + .iTCO_version = 2, + .gpio_version = ICH_V9_GPIO, + }, + [LPC_ICH9M] = { + .name = "ICH9M", + .iTCO_version = 2, + .gpio_version = ICH_V9_GPIO, + }, + [LPC_ICH9ME] = { + .name = "ICH9M-E", + .iTCO_version = 2, + .gpio_version = ICH_V9_GPIO, + }, + [LPC_ICH10] = { + .name = "ICH10", + .iTCO_version = 2, + .gpio_version = ICH_V10CONS_GPIO, + }, + [LPC_ICH10R] = { + .name = "ICH10R", + .iTCO_version = 2, + .gpio_version = ICH_V10CONS_GPIO, + }, + [LPC_ICH10D] = { + .name = "ICH10D", + .iTCO_version = 2, + .gpio_version = ICH_V10CORP_GPIO, + }, + [LPC_ICH10DO] = { + .name = "ICH10DO", + .iTCO_version = 2, + .gpio_version = ICH_V10CORP_GPIO, + }, + [LPC_PCH] = { + .name = "PCH Desktop Full Featured", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_PCHM] = { + .name = "PCH Mobile Full Featured", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_P55] = { + .name = "P55", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_PM55] = { + .name = "PM55", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_H55] = { + .name = "H55", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_QM57] = { + .name = "QM57", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_H57] = { + .name = "H57", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_HM55] = { + .name = "HM55", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_Q57] = { + .name = "Q57", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_HM57] = { + .name = "HM57", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_PCHMSFF] = { + .name = "PCH Mobile SFF Full Featured", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_QS57] = { + .name = "QS57", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_3400] = { + .name = "3400", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_3420] = { + .name = "3420", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_3450] = { + .name = "3450", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_EP80579] = { + .name = "EP80579", + .iTCO_version = 2, + }, + [LPC_CPT] = { + .name = "Cougar Point", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_CPTD] = { + .name = "Cougar Point Desktop", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_CPTM] = { + .name = "Cougar Point Mobile", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_PBG] = { + .name = "Patsburg", + .iTCO_version = 2, + }, + [LPC_DH89XXCC] = { + .name = "DH89xxCC", + .iTCO_version = 2, + }, + [LPC_PPT] = { + .name = "Panther Point", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_LPT] = { + .name = "Lynx Point", + .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, + }, + [LPC_LPT_LP] = { + .name = "Lynx Point_LP", + .iTCO_version = 2, + }, + [LPC_WBG] = { + .name = "Wellsburg", + .iTCO_version = 2, + }, + [LPC_AVN] = { + .name = "Avoton SoC", + .iTCO_version = 3, + .gpio_version = AVOTON_GPIO, + }, + [LPC_BAYTRAIL] = { + .name = "Bay Trail SoC", + .iTCO_version = 3, + }, + [LPC_COLETO] = { + .name = "Coleto Creek", + .iTCO_version = 2, + }, + [LPC_WPT_LP] = { + .name = "Wildcat Point_LP", + .iTCO_version = 2, + }, + [LPC_BRASWELL] = { + .name = "Braswell SoC", + .iTCO_version = 3, + }, + [LPC_LEWISBURG] = { + .name = "Lewisburg", + .iTCO_version = 2, + }, + [LPC_9S] = { + .name = "9 Series", + .iTCO_version = 2, + }, +}; + +/* + * This data only exists for exporting the supported PCI ids + * via MODULE_DEVICE_TABLE. We do not actually register a + * pci_driver, because the I/O Controller Hub has also other + * functions that probably will be registered by other drivers. + */ +static const struct pci_device_id lpc_ich_ids[] = { + { PCI_VDEVICE(INTEL, 0x0f1c), LPC_BAYTRAIL}, + { PCI_VDEVICE(INTEL, 0x1c41), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c42), LPC_CPTD}, + { PCI_VDEVICE(INTEL, 0x1c43), LPC_CPTM}, + { PCI_VDEVICE(INTEL, 0x1c44), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c45), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c46), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c47), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c48), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c49), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c4a), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c4b), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c4c), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c4d), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c4e), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c4f), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c50), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c51), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c52), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c53), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c54), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c55), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c56), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c57), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c58), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c59), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c5a), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c5b), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c5c), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c5d), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c5e), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1c5f), LPC_CPT}, + { PCI_VDEVICE(INTEL, 0x1d40), LPC_PBG}, + { PCI_VDEVICE(INTEL, 0x1d41), LPC_PBG}, + { PCI_VDEVICE(INTEL, 0x1e40), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e41), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e42), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e43), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e44), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e45), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e46), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e47), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e48), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e49), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e4a), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e4b), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e4c), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e4d), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e4e), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e4f), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e50), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e51), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e52), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e53), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e54), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e55), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e56), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e57), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e58), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e59), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e5a), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e5b), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e5c), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e5d), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e5e), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1e5f), LPC_PPT}, + { PCI_VDEVICE(INTEL, 0x1f38), LPC_AVN}, + { PCI_VDEVICE(INTEL, 0x1f39), LPC_AVN}, + { PCI_VDEVICE(INTEL, 0x1f3a), LPC_AVN}, + { PCI_VDEVICE(INTEL, 0x1f3b), LPC_AVN}, + { PCI_VDEVICE(INTEL, 0x229c), LPC_BRASWELL}, + { PCI_VDEVICE(INTEL, 0x2310), LPC_DH89XXCC}, + { PCI_VDEVICE(INTEL, 0x2390), LPC_COLETO}, + { PCI_VDEVICE(INTEL, 0x2410), LPC_ICH}, + { PCI_VDEVICE(INTEL, 0x2420), LPC_ICH0}, + { PCI_VDEVICE(INTEL, 0x2440), LPC_ICH2}, + { PCI_VDEVICE(INTEL, 0x244c), LPC_ICH2M}, + { PCI_VDEVICE(INTEL, 0x2450), LPC_CICH}, + { PCI_VDEVICE(INTEL, 0x2480), LPC_ICH3}, + { PCI_VDEVICE(INTEL, 0x248c), LPC_ICH3M}, + { PCI_VDEVICE(INTEL, 0x24c0), LPC_ICH4}, + { PCI_VDEVICE(INTEL, 0x24cc), LPC_ICH4M}, + { PCI_VDEVICE(INTEL, 0x24d0), LPC_ICH5}, + { PCI_VDEVICE(INTEL, 0x25a1), LPC_6300ESB}, + { PCI_VDEVICE(INTEL, 0x2640), LPC_ICH6}, + { PCI_VDEVICE(INTEL, 0x2641), LPC_ICH6M}, + { PCI_VDEVICE(INTEL, 0x2642), LPC_ICH6W}, + { PCI_VDEVICE(INTEL, 0x2670), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x2671), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x2672), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x2673), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x2674), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x2675), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x2676), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x2677), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x2678), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x2679), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x267a), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x267b), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x267c), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x267d), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x267e), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x267f), LPC_631XESB}, + { PCI_VDEVICE(INTEL, 0x27b0), LPC_ICH7DH}, + { PCI_VDEVICE(INTEL, 0x27b8), LPC_ICH7}, + { PCI_VDEVICE(INTEL, 0x27b9), LPC_ICH7M}, + { PCI_VDEVICE(INTEL, 0x27bc), LPC_NM10}, + { PCI_VDEVICE(INTEL, 0x27bd), LPC_ICH7MDH}, + { PCI_VDEVICE(INTEL, 0x2810), LPC_ICH8}, + { PCI_VDEVICE(INTEL, 0x2811), LPC_ICH8ME}, + { PCI_VDEVICE(INTEL, 0x2812), LPC_ICH8DH}, + { PCI_VDEVICE(INTEL, 0x2814), LPC_ICH8DO}, + { PCI_VDEVICE(INTEL, 0x2815), LPC_ICH8M}, + { PCI_VDEVICE(INTEL, 0x2912), LPC_ICH9DH}, + { PCI_VDEVICE(INTEL, 0x2914), LPC_ICH9DO}, + { PCI_VDEVICE(INTEL, 0x2916), LPC_ICH9R}, + { PCI_VDEVICE(INTEL, 0x2917), LPC_ICH9ME}, + { PCI_VDEVICE(INTEL, 0x2918), LPC_ICH9}, + { PCI_VDEVICE(INTEL, 0x2919), LPC_ICH9M}, + { PCI_VDEVICE(INTEL, 0x3a14), LPC_ICH10DO}, + { PCI_VDEVICE(INTEL, 0x3a16), LPC_ICH10R}, + { PCI_VDEVICE(INTEL, 0x3a18), LPC_ICH10}, + { PCI_VDEVICE(INTEL, 0x3a1a), LPC_ICH10D}, + { PCI_VDEVICE(INTEL, 0x3b00), LPC_PCH}, + { PCI_VDEVICE(INTEL, 0x3b01), LPC_PCHM}, + { PCI_VDEVICE(INTEL, 0x3b02), LPC_P55}, + { PCI_VDEVICE(INTEL, 0x3b03), LPC_PM55}, + { PCI_VDEVICE(INTEL, 0x3b06), LPC_H55}, + { PCI_VDEVICE(INTEL, 0x3b07), LPC_QM57}, + { PCI_VDEVICE(INTEL, 0x3b08), LPC_H57}, + { PCI_VDEVICE(INTEL, 0x3b09), LPC_HM55}, + { PCI_VDEVICE(INTEL, 0x3b0a), LPC_Q57}, + { PCI_VDEVICE(INTEL, 0x3b0b), LPC_HM57}, + { PCI_VDEVICE(INTEL, 0x3b0d), LPC_PCHMSFF}, + { PCI_VDEVICE(INTEL, 0x3b0f), LPC_QS57}, + { PCI_VDEVICE(INTEL, 0x3b12), LPC_3400}, + { PCI_VDEVICE(INTEL, 0x3b14), LPC_3420}, + { PCI_VDEVICE(INTEL, 0x3b16), LPC_3450}, + { PCI_VDEVICE(INTEL, 0x5031), LPC_EP80579}, + { PCI_VDEVICE(INTEL, 0x8c40), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c41), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c42), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c43), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c44), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c45), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c46), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c47), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c48), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c49), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c4a), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c4b), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c4c), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c4d), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c4e), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c4f), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c50), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c51), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c52), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c53), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c54), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c55), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c56), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c57), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c58), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c59), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c5a), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c5b), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c5c), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c5d), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c5e), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8c5f), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x8cc1), LPC_9S}, + { PCI_VDEVICE(INTEL, 0x8cc2), LPC_9S}, + { PCI_VDEVICE(INTEL, 0x8cc3), LPC_9S}, + { PCI_VDEVICE(INTEL, 0x8cc4), LPC_9S}, + { PCI_VDEVICE(INTEL, 0x8cc6), LPC_9S}, + { PCI_VDEVICE(INTEL, 0x8d40), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d41), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d42), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d43), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d44), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d45), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d46), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d47), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d48), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d49), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d4a), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d4b), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d4c), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d4d), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d4e), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d4f), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d50), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d51), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d52), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d53), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d54), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d55), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d56), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d57), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d58), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d59), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d5a), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d5b), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d5c), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d5d), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d5e), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d5f), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x9c40), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c41), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c42), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c43), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c44), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c45), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c46), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c47), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9cc1), LPC_WPT_LP}, + { PCI_VDEVICE(INTEL, 0x9cc2), LPC_WPT_LP}, + { PCI_VDEVICE(INTEL, 0x9cc3), LPC_WPT_LP}, + { PCI_VDEVICE(INTEL, 0x9cc5), LPC_WPT_LP}, + { PCI_VDEVICE(INTEL, 0x9cc6), LPC_WPT_LP}, + { PCI_VDEVICE(INTEL, 0x9cc7), LPC_WPT_LP}, + { PCI_VDEVICE(INTEL, 0x9cc9), LPC_WPT_LP}, + { PCI_VDEVICE(INTEL, 0xa1c1), LPC_LEWISBURG}, + { PCI_VDEVICE(INTEL, 0xa1c2), LPC_LEWISBURG}, + { PCI_VDEVICE(INTEL, 0xa1c3), LPC_LEWISBURG}, + { PCI_VDEVICE(INTEL, 0xa1c4), LPC_LEWISBURG}, + { PCI_VDEVICE(INTEL, 0xa1c5), LPC_LEWISBURG}, + { PCI_VDEVICE(INTEL, 0xa1c6), LPC_LEWISBURG}, + { PCI_VDEVICE(INTEL, 0xa1c7), LPC_LEWISBURG}, + { PCI_VDEVICE(INTEL, 0xa242), LPC_LEWISBURG}, + { PCI_VDEVICE(INTEL, 0xa243), LPC_LEWISBURG}, + { 0, }, /* End of list */ +}; +MODULE_DEVICE_TABLE(pci, lpc_ich_ids); + +static void lpc_ich_restore_config_space(struct pci_dev *dev) +{ + struct lpc_ich_priv *priv = pci_get_drvdata(dev); + + if (priv->abase_save >= 0) { + pci_write_config_byte(dev, priv->abase, priv->abase_save); + priv->abase_save = -1; + } + + if (priv->actrl_pbase_save >= 0) { + pci_write_config_byte(dev, priv->actrl_pbase, + priv->actrl_pbase_save); + priv->actrl_pbase_save = -1; + } + + if (priv->gctrl_save >= 0) { + pci_write_config_byte(dev, priv->gctrl, priv->gctrl_save); + priv->gctrl_save = -1; + } +} + +static void lpc_ich_enable_acpi_space(struct pci_dev *dev) +{ + struct lpc_ich_priv *priv = pci_get_drvdata(dev); + u8 reg_save; + + switch (lpc_chipset_info[priv->chipset].iTCO_version) { + case 3: + /* + * Some chipsets (eg Avoton) enable the ACPI space in the + * ACPI BASE register. + */ + pci_read_config_byte(dev, priv->abase, ®_save); + pci_write_config_byte(dev, priv->abase, reg_save | 0x2); + priv->abase_save = reg_save; + break; + default: + /* + * Most chipsets enable the ACPI space in the ACPI control + * register. + */ + pci_read_config_byte(dev, priv->actrl_pbase, ®_save); + pci_write_config_byte(dev, priv->actrl_pbase, reg_save | 0x80); + priv->actrl_pbase_save = reg_save; + break; + } +} + +static void lpc_ich_enable_gpio_space(struct pci_dev *dev) +{ + struct lpc_ich_priv *priv = pci_get_drvdata(dev); + u8 reg_save; + + pci_read_config_byte(dev, priv->gctrl, ®_save); + pci_write_config_byte(dev, priv->gctrl, reg_save | 0x10); + priv->gctrl_save = reg_save; +} + +static void lpc_ich_enable_pmc_space(struct pci_dev *dev) +{ + struct lpc_ich_priv *priv = pci_get_drvdata(dev); + u8 reg_save; + + pci_read_config_byte(dev, priv->actrl_pbase, ®_save); + pci_write_config_byte(dev, priv->actrl_pbase, reg_save | 0x2); + + priv->actrl_pbase_save = reg_save; +} + +static int lpc_ich_finalize_wdt_cell(struct pci_dev *dev) +{ + struct itco_wdt_platform_data *pdata; + struct lpc_ich_priv *priv = pci_get_drvdata(dev); + struct lpc_ich_info *info; + struct mfd_cell *cell = &lpc_ich_wdt_cell; + + pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + info = &lpc_chipset_info[priv->chipset]; + + pdata->version = info->iTCO_version; + strlcpy(pdata->name, info->name, sizeof(pdata->name)); + + cell->platform_data = pdata; + cell->pdata_size = sizeof(*pdata); + return 0; +} + +static void lpc_ich_finalize_gpio_cell(struct pci_dev *dev) +{ + struct lpc_ich_priv *priv = pci_get_drvdata(dev); + struct mfd_cell *cell = &lpc_ich_gpio_cell; + + cell->platform_data = &lpc_chipset_info[priv->chipset]; + cell->pdata_size = sizeof(struct lpc_ich_info); +} + +/* + * We don't check for resource conflict globally. There are 2 or 3 independent + * GPIO groups and it's enough to have access to one of these to instantiate + * the device. + */ +static int lpc_ich_check_conflict_gpio(struct resource *res) +{ + int ret; + u8 use_gpio = 0; + + if (resource_size(res) >= 0x50 && + !acpi_check_region(res->start + 0x40, 0x10, "LPC ICH GPIO3")) + use_gpio |= 1 << 2; + + if (!acpi_check_region(res->start + 0x30, 0x10, "LPC ICH GPIO2")) + use_gpio |= 1 << 1; + + ret = acpi_check_region(res->start + 0x00, 0x30, "LPC ICH GPIO1"); + if (!ret) + use_gpio |= 1 << 0; + + return use_gpio ? use_gpio : ret; +} + +static int lpc_ich_init_gpio(struct pci_dev *dev) +{ + struct lpc_ich_priv *priv = pci_get_drvdata(dev); + u32 base_addr_cfg; + u32 base_addr; + int ret; + bool acpi_conflict = false; + struct resource *res; + + /* Setup power management base register */ + pci_read_config_dword(dev, priv->abase, &base_addr_cfg); + base_addr = base_addr_cfg & 0x0000ff80; + if (!base_addr) { + dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n"); + lpc_ich_gpio_cell.num_resources--; + goto gpe0_done; + } + + res = &gpio_ich_res[ICH_RES_GPE0]; + res->start = base_addr + ACPIBASE_GPE_OFF; + res->end = base_addr + ACPIBASE_GPE_END; + ret = acpi_check_resource_conflict(res); + if (ret) { + /* + * This isn't fatal for the GPIO, but we have to make sure that + * the platform_device subsystem doesn't see this resource + * or it will register an invalid region. + */ + lpc_ich_gpio_cell.num_resources--; + acpi_conflict = true; + } else { + lpc_ich_enable_acpi_space(dev); + } + +gpe0_done: + /* Setup GPIO base register */ + pci_read_config_dword(dev, priv->gbase, &base_addr_cfg); + base_addr = base_addr_cfg & 0x0000ff80; + if (!base_addr) { + dev_notice(&dev->dev, "I/O space for GPIO uninitialized\n"); + ret = -ENODEV; + goto gpio_done; + } + + /* Older devices provide fewer GPIO and have a smaller resource size. */ + res = &gpio_ich_res[ICH_RES_GPIO]; + res->start = base_addr; + switch (lpc_chipset_info[priv->chipset].gpio_version) { + case ICH_V5_GPIO: + case ICH_V10CORP_GPIO: + res->end = res->start + 128 - 1; + break; + default: + res->end = res->start + 64 - 1; + break; + } + + ret = lpc_ich_check_conflict_gpio(res); + if (ret < 0) { + /* this isn't necessarily fatal for the GPIO */ + acpi_conflict = true; + goto gpio_done; + } + lpc_chipset_info[priv->chipset].use_gpio = ret; + lpc_ich_enable_gpio_space(dev); + + lpc_ich_finalize_gpio_cell(dev); + ret = mfd_add_devices(&dev->dev, PLATFORM_DEVID_AUTO, + &lpc_ich_gpio_cell, 1, NULL, 0, NULL); + +gpio_done: + if (acpi_conflict) + pr_warn("Resource conflict(s) found affecting %s\n", + lpc_ich_gpio_cell.name); + return ret; +} + +static int lpc_ich_init_wdt(struct pci_dev *dev) +{ + struct lpc_ich_priv *priv = pci_get_drvdata(dev); + u32 base_addr_cfg; + u32 base_addr; + int ret; + struct resource *res; + + /* If we have ACPI based watchdog use that instead */ + if (acpi_has_watchdog()) + return -ENODEV; + + /* Setup power management base register */ + pci_read_config_dword(dev, priv->abase, &base_addr_cfg); + base_addr = base_addr_cfg & 0x0000ff80; + if (!base_addr) { + dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n"); + ret = -ENODEV; + goto wdt_done; + } + + res = wdt_io_res(ICH_RES_IO_TCO); + res->start = base_addr + ACPIBASE_TCO_OFF; + res->end = base_addr + ACPIBASE_TCO_END; + + res = wdt_io_res(ICH_RES_IO_SMI); + res->start = base_addr + ACPIBASE_SMI_OFF; + res->end = base_addr + ACPIBASE_SMI_END; + + lpc_ich_enable_acpi_space(dev); + + /* + * iTCO v2: + * Get the Memory-Mapped GCS register. To get access to it + * we have to read RCBA from PCI Config space 0xf0 and use + * it as base. GCS = RCBA + ICH6_GCS(0x3410). + * + * iTCO v3: + * Get the Power Management Configuration register. To get access + * to it we have to read the PMC BASE from config space and address + * the register at offset 0x8. + */ + if (lpc_chipset_info[priv->chipset].iTCO_version == 1) { + /* Don't register iomem for TCO ver 1 */ + lpc_ich_wdt_cell.num_resources--; + } else if (lpc_chipset_info[priv->chipset].iTCO_version == 2) { + pci_read_config_dword(dev, RCBABASE, &base_addr_cfg); + base_addr = base_addr_cfg & 0xffffc000; + if (!(base_addr_cfg & 1)) { + dev_notice(&dev->dev, "RCBA is disabled by " + "hardware/BIOS, device disabled\n"); + ret = -ENODEV; + goto wdt_done; + } + res = wdt_mem_res(ICH_RES_MEM_GCS_PMC); + res->start = base_addr + ACPIBASE_GCS_OFF; + res->end = base_addr + ACPIBASE_GCS_END; + } else if (lpc_chipset_info[priv->chipset].iTCO_version == 3) { + lpc_ich_enable_pmc_space(dev); + pci_read_config_dword(dev, ACPICTRL_PMCBASE, &base_addr_cfg); + base_addr = base_addr_cfg & 0xfffffe00; + + res = wdt_mem_res(ICH_RES_MEM_GCS_PMC); + res->start = base_addr + ACPIBASE_PMC_OFF; + res->end = base_addr + ACPIBASE_PMC_END; + } + + ret = lpc_ich_finalize_wdt_cell(dev); + if (ret) + goto wdt_done; + + ret = mfd_add_devices(&dev->dev, PLATFORM_DEVID_AUTO, + &lpc_ich_wdt_cell, 1, NULL, 0, NULL); + +wdt_done: + return ret; +} + +static int lpc_ich_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct lpc_ich_priv *priv; + int ret; + bool cell_added = false; + + priv = devm_kzalloc(&dev->dev, + sizeof(struct lpc_ich_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->chipset = id->driver_data; + + priv->actrl_pbase_save = -1; + priv->abase_save = -1; + + priv->abase = ACPIBASE; + priv->actrl_pbase = ACPICTRL_PMCBASE; + + priv->gctrl_save = -1; + if (priv->chipset <= LPC_ICH5) { + priv->gbase = GPIOBASE_ICH0; + priv->gctrl = GPIOCTRL_ICH0; + } else { + priv->gbase = GPIOBASE_ICH6; + priv->gctrl = GPIOCTRL_ICH6; + } + + pci_set_drvdata(dev, priv); + + if (lpc_chipset_info[priv->chipset].iTCO_version) { + ret = lpc_ich_init_wdt(dev); + if (!ret) + cell_added = true; + } + + if (lpc_chipset_info[priv->chipset].gpio_version) { + ret = lpc_ich_init_gpio(dev); + if (!ret) + cell_added = true; + } + + /* + * We only care if at least one or none of the cells registered + * successfully. + */ + if (!cell_added) { + dev_warn(&dev->dev, "No MFD cells added\n"); + lpc_ich_restore_config_space(dev); + return -ENODEV; + } + + return 0; +} + +static void lpc_ich_remove(struct pci_dev *dev) +{ + mfd_remove_devices(&dev->dev); + lpc_ich_restore_config_space(dev); +} + +static struct pci_driver lpc_ich_driver = { + .name = "lpc_ich", + .id_table = lpc_ich_ids, + .probe = lpc_ich_probe, + .remove = lpc_ich_remove, +}; + +module_pci_driver(lpc_ich_driver); + +MODULE_AUTHOR("Aaron Sierra "); +MODULE_DESCRIPTION("LPC interface for Intel ICH"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/pmbus.h b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/pmbus.h new file mode 100644 index 000000000000..4efa2bd4f6d8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/pmbus.h @@ -0,0 +1,425 @@ +/* + * pmbus.h - Common defines and structures for PMBus devices + * + * Copyright (c) 2010, 2011 Ericsson AB. + * Copyright (c) 2012 Guenter Roeck + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef PMBUS_H +#define PMBUS_H + +#include +#include + +/* + * Registers + */ +enum pmbus_regs { + PMBUS_PAGE = 0x00, + PMBUS_OPERATION = 0x01, + PMBUS_ON_OFF_CONFIG = 0x02, + PMBUS_CLEAR_FAULTS = 0x03, + PMBUS_PHASE = 0x04, + + PMBUS_CAPABILITY = 0x19, + PMBUS_QUERY = 0x1A, + + PMBUS_VOUT_MODE = 0x20, + PMBUS_VOUT_COMMAND = 0x21, + PMBUS_VOUT_TRIM = 0x22, + PMBUS_VOUT_CAL_OFFSET = 0x23, + PMBUS_VOUT_MAX = 0x24, + PMBUS_VOUT_MARGIN_HIGH = 0x25, + PMBUS_VOUT_MARGIN_LOW = 0x26, + PMBUS_VOUT_TRANSITION_RATE = 0x27, + PMBUS_VOUT_DROOP = 0x28, + PMBUS_VOUT_SCALE_LOOP = 0x29, + PMBUS_VOUT_SCALE_MONITOR = 0x2A, + + PMBUS_COEFFICIENTS = 0x30, + PMBUS_POUT_MAX = 0x31, + + PMBUS_FAN_CONFIG_12 = 0x3A, + PMBUS_FAN_COMMAND_1 = 0x3B, + PMBUS_FAN_COMMAND_2 = 0x3C, + PMBUS_FAN_CONFIG_34 = 0x3D, + PMBUS_FAN_COMMAND_3 = 0x3E, + PMBUS_FAN_COMMAND_4 = 0x3F, + + PMBUS_VOUT_OV_FAULT_LIMIT = 0x40, + PMBUS_VOUT_OV_FAULT_RESPONSE = 0x41, + PMBUS_VOUT_OV_WARN_LIMIT = 0x42, + PMBUS_VOUT_UV_WARN_LIMIT = 0x43, + PMBUS_VOUT_UV_FAULT_LIMIT = 0x44, + PMBUS_VOUT_UV_FAULT_RESPONSE = 0x45, + PMBUS_IOUT_OC_FAULT_LIMIT = 0x46, + PMBUS_IOUT_OC_FAULT_RESPONSE = 0x47, + PMBUS_IOUT_OC_LV_FAULT_LIMIT = 0x48, + PMBUS_IOUT_OC_LV_FAULT_RESPONSE = 0x49, + PMBUS_IOUT_OC_WARN_LIMIT = 0x4A, + PMBUS_IOUT_UC_FAULT_LIMIT = 0x4B, + PMBUS_IOUT_UC_FAULT_RESPONSE = 0x4C, + + PMBUS_OT_FAULT_LIMIT = 0x4F, + PMBUS_OT_FAULT_RESPONSE = 0x50, + PMBUS_OT_WARN_LIMIT = 0x51, + PMBUS_UT_WARN_LIMIT = 0x52, + PMBUS_UT_FAULT_LIMIT = 0x53, + PMBUS_UT_FAULT_RESPONSE = 0x54, + PMBUS_VIN_OV_FAULT_LIMIT = 0x55, + PMBUS_VIN_OV_FAULT_RESPONSE = 0x56, + PMBUS_VIN_OV_WARN_LIMIT = 0x57, + PMBUS_VIN_UV_WARN_LIMIT = 0x58, + PMBUS_VIN_UV_FAULT_LIMIT = 0x59, + + PMBUS_IIN_OC_FAULT_LIMIT = 0x5B, + PMBUS_IIN_OC_WARN_LIMIT = 0x5D, + + PMBUS_POUT_OP_FAULT_LIMIT = 0x68, + PMBUS_POUT_OP_WARN_LIMIT = 0x6A, + PMBUS_PIN_OP_WARN_LIMIT = 0x6B, + + PMBUS_STATUS_BYTE = 0x78, + PMBUS_STATUS_WORD = 0x79, + PMBUS_STATUS_VOUT = 0x7A, + PMBUS_STATUS_IOUT = 0x7B, + PMBUS_STATUS_INPUT = 0x7C, + PMBUS_STATUS_TEMPERATURE = 0x7D, + PMBUS_STATUS_CML = 0x7E, + PMBUS_STATUS_OTHER = 0x7F, + PMBUS_STATUS_MFR_SPECIFIC = 0x80, + PMBUS_STATUS_FAN_12 = 0x81, + PMBUS_STATUS_FAN_34 = 0x82, + + PMBUS_READ_VIN = 0x88, + PMBUS_READ_IIN = 0x89, + PMBUS_READ_VCAP = 0x8A, + PMBUS_READ_VOUT = 0x8B, + PMBUS_READ_IOUT = 0x8C, + PMBUS_READ_TEMPERATURE_1 = 0x8D, + PMBUS_READ_TEMPERATURE_2 = 0x8E, + PMBUS_READ_TEMPERATURE_3 = 0x8F, + PMBUS_READ_FAN_SPEED_1 = 0x90, + PMBUS_READ_FAN_SPEED_2 = 0x91, + PMBUS_READ_FAN_SPEED_3 = 0x92, + PMBUS_READ_FAN_SPEED_4 = 0x93, + PMBUS_READ_DUTY_CYCLE = 0x94, + PMBUS_READ_FREQUENCY = 0x95, + PMBUS_READ_POUT = 0x96, + PMBUS_READ_PIN = 0x97, + + PMBUS_REVISION = 0x98, + PMBUS_MFR_ID = 0x99, + PMBUS_MFR_MODEL = 0x9A, + PMBUS_MFR_REVISION = 0x9B, + PMBUS_MFR_LOCATION = 0x9C, + PMBUS_MFR_DATE = 0x9D, + PMBUS_MFR_SERIAL = 0x9E, + +/* + * Virtual registers. + * Useful to support attributes which are not supported by standard PMBus + * registers but exist as manufacturer specific registers on individual chips. + * Must be mapped to real registers in device specific code. + * + * Semantics: + * Virtual registers are all word size. + * READ registers are read-only; writes are either ignored or return an error. + * RESET registers are read/write. Reading reset registers returns zero + * (used for detection), writing any value causes the associated history to be + * reset. + * Virtual registers have to be handled in device specific driver code. Chip + * driver code returns non-negative register values if a virtual register is + * supported, or a negative error code if not. The chip driver may return + * -ENODATA or any other error code in this case, though an error code other + * than -ENODATA is handled more efficiently and thus preferred. Either case, + * the calling PMBus core code will abort if the chip driver returns an error + * code when reading or writing virtual registers. + */ + PMBUS_VIRT_BASE = 0x100, + PMBUS_VIRT_READ_TEMP_AVG, + PMBUS_VIRT_READ_TEMP_MIN, + PMBUS_VIRT_READ_TEMP_MAX, + PMBUS_VIRT_RESET_TEMP_HISTORY, + PMBUS_VIRT_READ_VIN_AVG, + PMBUS_VIRT_READ_VIN_MIN, + PMBUS_VIRT_READ_VIN_MAX, + PMBUS_VIRT_RESET_VIN_HISTORY, + PMBUS_VIRT_READ_IIN_AVG, + PMBUS_VIRT_READ_IIN_MIN, + PMBUS_VIRT_READ_IIN_MAX, + PMBUS_VIRT_RESET_IIN_HISTORY, + PMBUS_VIRT_READ_PIN_AVG, + PMBUS_VIRT_READ_PIN_MIN, + PMBUS_VIRT_READ_PIN_MAX, + PMBUS_VIRT_RESET_PIN_HISTORY, + PMBUS_VIRT_READ_POUT_AVG, + PMBUS_VIRT_READ_POUT_MIN, + PMBUS_VIRT_READ_POUT_MAX, + PMBUS_VIRT_RESET_POUT_HISTORY, + PMBUS_VIRT_READ_VOUT_AVG, + PMBUS_VIRT_READ_VOUT_MIN, + PMBUS_VIRT_READ_VOUT_MAX, + PMBUS_VIRT_RESET_VOUT_HISTORY, + PMBUS_VIRT_READ_IOUT_AVG, + PMBUS_VIRT_READ_IOUT_MIN, + PMBUS_VIRT_READ_IOUT_MAX, + PMBUS_VIRT_RESET_IOUT_HISTORY, + PMBUS_VIRT_READ_TEMP2_AVG, + PMBUS_VIRT_READ_TEMP2_MIN, + PMBUS_VIRT_READ_TEMP2_MAX, + PMBUS_VIRT_RESET_TEMP2_HISTORY, + + PMBUS_VIRT_READ_VMON, + PMBUS_VIRT_VMON_UV_WARN_LIMIT, + PMBUS_VIRT_VMON_OV_WARN_LIMIT, + PMBUS_VIRT_VMON_UV_FAULT_LIMIT, + PMBUS_VIRT_VMON_OV_FAULT_LIMIT, + PMBUS_VIRT_STATUS_VMON, +}; + +/* + * OPERATION + */ +#define PB_OPERATION_CONTROL_ON BIT(7) + +/* + * CAPABILITY + */ +#define PB_CAPABILITY_SMBALERT BIT(4) +#define PB_CAPABILITY_ERROR_CHECK BIT(7) + +/* + * VOUT_MODE + */ +#define PB_VOUT_MODE_MODE_MASK 0xe0 +#define PB_VOUT_MODE_PARAM_MASK 0x1f + +#define PB_VOUT_MODE_LINEAR 0x00 +#define PB_VOUT_MODE_VID 0x20 +#define PB_VOUT_MODE_DIRECT 0x40 + +/* + * Fan configuration + */ +#define PB_FAN_2_PULSE_MASK (BIT(0) | BIT(1)) +#define PB_FAN_2_RPM BIT(2) +#define PB_FAN_2_INSTALLED BIT(3) +#define PB_FAN_1_PULSE_MASK (BIT(4) | BIT(5)) +#define PB_FAN_1_RPM BIT(6) +#define PB_FAN_1_INSTALLED BIT(7) + +/* + * STATUS_BYTE, STATUS_WORD (lower) + */ +#define PB_STATUS_NONE_ABOVE BIT(0) +#define PB_STATUS_CML BIT(1) +#define PB_STATUS_TEMPERATURE BIT(2) +#define PB_STATUS_VIN_UV BIT(3) +#define PB_STATUS_IOUT_OC BIT(4) +#define PB_STATUS_VOUT_OV BIT(5) +#define PB_STATUS_OFF BIT(6) +#define PB_STATUS_BUSY BIT(7) + +/* + * STATUS_WORD (upper) + */ +#define PB_STATUS_UNKNOWN BIT(8) +#define PB_STATUS_OTHER BIT(9) +#define PB_STATUS_FANS BIT(10) +#define PB_STATUS_POWER_GOOD_N BIT(11) +#define PB_STATUS_WORD_MFR BIT(12) +#define PB_STATUS_INPUT BIT(13) +#define PB_STATUS_IOUT_POUT BIT(14) +#define PB_STATUS_VOUT BIT(15) + +/* + * STATUS_IOUT + */ +#define PB_POUT_OP_WARNING BIT(0) +#define PB_POUT_OP_FAULT BIT(1) +#define PB_POWER_LIMITING BIT(2) +#define PB_CURRENT_SHARE_FAULT BIT(3) +#define PB_IOUT_UC_FAULT BIT(4) +#define PB_IOUT_OC_WARNING BIT(5) +#define PB_IOUT_OC_LV_FAULT BIT(6) +#define PB_IOUT_OC_FAULT BIT(7) + +/* + * STATUS_VOUT, STATUS_INPUT + */ +#define PB_VOLTAGE_UV_FAULT BIT(4) +#define PB_VOLTAGE_UV_WARNING BIT(5) +#define PB_VOLTAGE_OV_WARNING BIT(6) +#define PB_VOLTAGE_OV_FAULT BIT(7) + +/* + * STATUS_INPUT + */ +#define PB_PIN_OP_WARNING BIT(0) +#define PB_IIN_OC_WARNING BIT(1) +#define PB_IIN_OC_FAULT BIT(2) + +/* + * STATUS_TEMPERATURE + */ +#define PB_TEMP_UT_FAULT BIT(4) +#define PB_TEMP_UT_WARNING BIT(5) +#define PB_TEMP_OT_WARNING BIT(6) +#define PB_TEMP_OT_FAULT BIT(7) + +/* + * STATUS_FAN + */ +#define PB_FAN_AIRFLOW_WARNING BIT(0) +#define PB_FAN_AIRFLOW_FAULT BIT(1) +#define PB_FAN_FAN2_SPEED_OVERRIDE BIT(2) +#define PB_FAN_FAN1_SPEED_OVERRIDE BIT(3) +#define PB_FAN_FAN2_WARNING BIT(4) +#define PB_FAN_FAN1_WARNING BIT(5) +#define PB_FAN_FAN2_FAULT BIT(6) +#define PB_FAN_FAN1_FAULT BIT(7) + +/* + * CML_FAULT_STATUS + */ +#define PB_CML_FAULT_OTHER_MEM_LOGIC BIT(0) +#define PB_CML_FAULT_OTHER_COMM BIT(1) +#define PB_CML_FAULT_PROCESSOR BIT(3) +#define PB_CML_FAULT_MEMORY BIT(4) +#define PB_CML_FAULT_PACKET_ERROR BIT(5) +#define PB_CML_FAULT_INVALID_DATA BIT(6) +#define PB_CML_FAULT_INVALID_COMMAND BIT(7) + +enum pmbus_sensor_classes { + PSC_VOLTAGE_IN = 0, + PSC_VOLTAGE_OUT, + PSC_CURRENT_IN, + PSC_CURRENT_OUT, + PSC_POWER, + PSC_TEMPERATURE, + PSC_FAN, + PSC_NUM_CLASSES /* Number of power sensor classes */ +}; + +#define PMBUS_PAGES 32 /* Per PMBus specification */ + +/* Functionality bit mask */ +#define PMBUS_HAVE_VIN BIT(0) +#define PMBUS_HAVE_VCAP BIT(1) +#define PMBUS_HAVE_VOUT BIT(2) +#define PMBUS_HAVE_IIN BIT(3) +#define PMBUS_HAVE_IOUT BIT(4) +#define PMBUS_HAVE_PIN BIT(5) +#define PMBUS_HAVE_POUT BIT(6) +#define PMBUS_HAVE_FAN12 BIT(7) +#define PMBUS_HAVE_FAN34 BIT(8) +#define PMBUS_HAVE_TEMP BIT(9) +#define PMBUS_HAVE_TEMP2 BIT(10) +#define PMBUS_HAVE_TEMP3 BIT(11) +#define PMBUS_HAVE_STATUS_VOUT BIT(12) +#define PMBUS_HAVE_STATUS_IOUT BIT(13) +#define PMBUS_HAVE_STATUS_INPUT BIT(14) +#define PMBUS_HAVE_STATUS_TEMP BIT(15) +#define PMBUS_HAVE_STATUS_FAN12 BIT(16) +#define PMBUS_HAVE_STATUS_FAN34 BIT(17) +#define PMBUS_HAVE_VMON BIT(18) +#define PMBUS_HAVE_STATUS_VMON BIT(19) + +enum pmbus_data_format { linear = 0, direct, vid }; +enum vrm_version { vr11 = 0, vr12, vr13 }; + +struct pmbus_driver_info { + int pages; /* Total number of pages */ + enum pmbus_data_format format[PSC_NUM_CLASSES]; + enum vrm_version vrm_version; + /* + * Support one set of coefficients for each sensor type + * Used for chips providing data in direct mode. + */ + int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */ + int b[PSC_NUM_CLASSES]; /* offset */ + int R[PSC_NUM_CLASSES]; /* exponent */ + + u32 func[PMBUS_PAGES]; /* Functionality, per page */ + /* + * The following functions map manufacturing specific register values + * to PMBus standard register values. Specify only if mapping is + * necessary. + * Functions return the register value (read) or zero (write) if + * successful. A return value of -ENODATA indicates that there is no + * manufacturer specific register, but that a standard PMBus register + * may exist. Any other negative return value indicates that the + * register does not exist, and that no attempt should be made to read + * the standard register. + */ + int (*read_byte_data)(struct i2c_client *client, int page, int reg); + int (*read_word_data)(struct i2c_client *client, int page, int reg); + int (*write_word_data)(struct i2c_client *client, int page, int reg, + u16 word); + int (*write_byte)(struct i2c_client *client, int page, u8 value); + /* + * The identify function determines supported PMBus functionality. + * This function is only necessary if a chip driver supports multiple + * chips, and the chip functionality is not pre-determined. + */ + int (*identify)(struct i2c_client *client, + struct pmbus_driver_info *info); + + /* Regulator functionality, if supported by this chip driver. */ + int num_regulators; + const struct regulator_desc *reg_desc; +}; + +/* Regulator ops */ + +extern const struct regulator_ops pmbus_regulator_ops; + +/* Macro for filling in array of struct regulator_desc */ +#define PMBUS_REGULATOR(_name, _id) \ + [_id] = { \ + .name = (_name # _id), \ + .id = (_id), \ + .of_match = of_match_ptr(_name # _id), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &pmbus_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + } + +/* Function declarations */ + +void pmbus_clear_cache(struct i2c_client *client); +int pmbus_set_page(struct i2c_client *client, u8 page); +int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg); +int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word); +int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg); +int pmbus_write_byte(struct i2c_client *client, int page, u8 value); +int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, + u8 value); +int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, + u8 mask, u8 value); +void pmbus_clear_faults(struct i2c_client *client); +bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); +bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); +int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, + struct pmbus_driver_info *info); +int pmbus_do_remove(struct i2c_client *client); +const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client + *client); + +#endif /* PMBUS_H */ diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/transceiver.c b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/transceiver.c index 6fe8f599fb48..27c45173eef5 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/transceiver.c +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/transceiver.c @@ -1,10 +1,3 @@ -/* - * 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. - */ - #include #include #include @@ -12,7 +5,12 @@ #include "io_expander.h" #include "transceiver.h" +/* For build single module using (Ex: ONL platform) */ +#include +//#include +//#include +extern int io_no_init; /* ========== Register EEPROM address mapping ========== */ struct eeprom_map_s eeprom_map_sfp = { @@ -152,7 +150,7 @@ alarm_msg_2_user(struct transvr_obj_s *self, SWPS_ERR("%s on %s.\n", emsg, self->swp_name); } - +EXPORT_SYMBOL(alarm_msg_2_user); /* ========== Private functions ========== */ @@ -181,6 +179,7 @@ lock_transvr_obj(struct transvr_obj_s *self) { mutex_lock(&self->lock); self->curr_page = VAL_TRANSVR_PAGE_FREE; } +EXPORT_SYMBOL(lock_transvr_obj); void @@ -189,6 +188,7 @@ unlock_transvr_obj(struct transvr_obj_s *self) { self->curr_page = VAL_TRANSVR_PAGE_FREE; mutex_unlock(&self->lock); } +EXPORT_SYMBOL(unlock_transvr_obj); static int @@ -4833,6 +4833,11 @@ _taskfunc_qsfp_setup_power_mod(struct transvr_obj_s *self, int curr_val = DEBUG_TRANSVR_INT_VAL; int err_val = DEBUG_TRANSVR_INT_VAL; char *err_msg = DEBUG_TRANSVR_STR_VAL; + if (io_no_init) { + + SWPS_INFO("%s no_io_init\n",__func__); + return EVENT_TRANSVR_TASK_DONE; + } curr_val = self->ioexp_obj_p->get_lpmod(self->ioexp_obj_p, self->ioexp_virt_offset); @@ -8259,6 +8264,7 @@ create_transvr_obj(char *swp_name, __func__, err_msg, chan_id, ioexp_virt_offset, transvr_type); return NULL; } +EXPORT_SYMBOL(create_transvr_obj); static int @@ -8290,11 +8296,17 @@ _reload_transvr_obj(struct transvr_obj_s *self, if (setup_transvr_private_cb(self, new_type) < 0){ goto err_private_reload_func_3; } + if(old_i2c_p){ + i2c_put_adapter(old_i2c_p->adapter); + } kfree(old_i2c_p); return 0; err_private_reload_func_3: SWPS_INFO("%s: init() fail!\n", __func__); + if(old_i2c_p){ + i2c_put_adapter(old_i2c_p->adapter); + } kfree(old_i2c_p); self->state = STATE_TRANSVR_UNEXCEPTED; self->type = TRANSVR_TYPE_ERROR; @@ -8341,6 +8353,7 @@ isolate_transvr_obj(struct transvr_obj_s *self) { SWPS_INFO("%s: %s be isolated\n", __func__, self->swp_name); return 0; } +EXPORT_SYMBOL(isolate_transvr_obj); int @@ -8359,6 +8372,10 @@ resync_channel_tier_2(struct transvr_obj_s *self) { } return 0; } +EXPORT_SYMBOL(resync_channel_tier_2); + +/* For build single module using (Ex: ONL platform) */ +MODULE_LICENSE("GPL"); /* ----------------------------------------- @@ -8387,3 +8404,5 @@ resync_channel_tier_2(struct transvr_obj_s *self) { + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/transceiver.h b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/transceiver.h index f17b7fde71b1..0438a351271a 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/transceiver.h +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/transceiver.h @@ -1,10 +1,3 @@ -/* - * 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. - */ - #ifndef TRANSCEIVER_H #define TRANSCEIVER_H @@ -813,3 +806,4 @@ void alarm_msg_2_user(struct transvr_obj_s *self, char *emsg); + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/ucd9000.c b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/ucd9000.c new file mode 100644 index 000000000000..3e3aa950277f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/modules/ucd9000.c @@ -0,0 +1,247 @@ +/* + * Hardware monitoring driver for UCD90xxx Sequencer and System Health + * Controller series + * + * Copyright (C) 2011 Ericsson AB. + * + * 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 "pmbus.h" + +enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 }; + +#define UCD9000_MONITOR_CONFIG 0xd5 +#define UCD9000_NUM_PAGES 0xd6 +#define UCD9000_FAN_CONFIG_INDEX 0xe7 +#define UCD9000_FAN_CONFIG 0xe8 +#define UCD9000_DEVICE_ID 0xfd + +#define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07) +#define UCD9000_MON_PAGE(x) ((x) & 0x0f) + +#define UCD9000_MON_VOLTAGE 1 +#define UCD9000_MON_TEMPERATURE 2 +#define UCD9000_MON_CURRENT 3 +#define UCD9000_MON_VOLTAGE_HW 4 + +#define UCD9000_NUM_FAN 4 + +struct ucd9000_data { + u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX]; + struct pmbus_driver_info info; +}; +#define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info) + +static int ucd9000_get_fan_config(struct i2c_client *client, int fan) +{ + int fan_config = 0; + struct ucd9000_data *data + = to_ucd9000_data(pmbus_get_driver_info(client)); + + if (data->fan_data[fan][3] & 1) + fan_config |= PB_FAN_2_INSTALLED; /* Use lower bit position */ + + /* Pulses/revolution */ + fan_config |= (data->fan_data[fan][3] & 0x06) >> 1; + + return fan_config; +} + +static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg) +{ + int ret = 0; + int fan_config; + + switch (reg) { + case PMBUS_FAN_CONFIG_12: + if (page > 0) + return -ENXIO; + + ret = ucd9000_get_fan_config(client, 0); + if (ret < 0) + return ret; + fan_config = ret << 4; + ret = ucd9000_get_fan_config(client, 1); + if (ret < 0) + return ret; + fan_config |= ret; + ret = fan_config; + break; + case PMBUS_FAN_CONFIG_34: + if (page > 0) + return -ENXIO; + + ret = ucd9000_get_fan_config(client, 2); + if (ret < 0) + return ret; + fan_config = ret << 4; + ret = ucd9000_get_fan_config(client, 3); + if (ret < 0) + return ret; + fan_config |= ret; + ret = fan_config; + break; + default: + ret = -ENODATA; + break; + } + return ret; +} + +static const struct i2c_device_id ucd9000_id[] = { + {"ucd9000", ucd9000}, + {"ucd90120", ucd90120}, + {"ucd90124", ucd90124}, + {"ucd90160", ucd90160}, + {"ucd9090", ucd9090}, + {"ucd90910", ucd90910}, + {} +}; +MODULE_DEVICE_TABLE(i2c, ucd9000_id); + +static int ucd9000_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; + struct ucd9000_data *data; + struct pmbus_driver_info *info; + const struct i2c_device_id *mid; + int i, ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA)) + return -ENODEV; + + ret = i2c_smbus_read_block_data(client, UCD9000_DEVICE_ID, + block_buffer); + if (ret < 0) { + dev_err(&client->dev, "Failed to read device ID\n"); + return ret; + } + block_buffer[ret] = '\0'; + dev_info(&client->dev, "Device ID %s\n", block_buffer); + + for (mid = ucd9000_id; mid->name[0]; mid++) { + if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) + break; + } + if (!mid->name[0]) { + dev_err(&client->dev, "Unsupported device\n"); + return -ENODEV; + } + + if (id->driver_data != ucd9000 && id->driver_data != mid->driver_data) + dev_notice(&client->dev, + "Device mismatch: Configured %s, detected %s\n", + id->name, mid->name); + + data = devm_kzalloc(&client->dev, sizeof(struct ucd9000_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + info = &data->info; + + ret = i2c_smbus_read_byte_data(client, UCD9000_NUM_PAGES); + if (ret < 0) { + dev_err(&client->dev, + "Failed to read number of active pages\n"); + return ret; + } + info->pages = ret; + if (!info->pages) { + dev_err(&client->dev, "No pages configured\n"); + return -ENODEV; + } + + /* The internal temperature sensor is always active */ + info->func[0] = PMBUS_HAVE_TEMP; + + /* Everything else is configurable */ + ret = i2c_smbus_read_block_data(client, UCD9000_MONITOR_CONFIG, + block_buffer); + if (ret <= 0) { + dev_err(&client->dev, "Failed to read configuration data\n"); + return -ENODEV; + } + for (i = 0; i < ret; i++) { + int page = UCD9000_MON_PAGE(block_buffer[i]); + + if (page >= info->pages) + continue; + + switch (UCD9000_MON_TYPE(block_buffer[i])) { + case UCD9000_MON_VOLTAGE: + case UCD9000_MON_VOLTAGE_HW: + info->func[page] |= PMBUS_HAVE_VOUT + | PMBUS_HAVE_STATUS_VOUT; + break; + case UCD9000_MON_TEMPERATURE: + info->func[page] |= PMBUS_HAVE_TEMP2 + | PMBUS_HAVE_STATUS_TEMP; + break; + case UCD9000_MON_CURRENT: + info->func[page] |= PMBUS_HAVE_IOUT + | PMBUS_HAVE_STATUS_IOUT; + break; + default: + break; + } + } + + /* Fan configuration */ + if (mid->driver_data == ucd90124) { + for (i = 0; i < UCD9000_NUM_FAN; i++) { + i2c_smbus_write_byte_data(client, + UCD9000_FAN_CONFIG_INDEX, i); + ret = i2c_smbus_read_block_data(client, + UCD9000_FAN_CONFIG, + data->fan_data[i]); + if (ret < 0) + return ret; + } + i2c_smbus_write_byte_data(client, UCD9000_FAN_CONFIG_INDEX, 0); + + info->read_byte_data = ucd9000_read_byte_data; + info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 + | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34; + } + + return pmbus_do_probe(client, mid, info); +} + +/* This is the driver that will be inserted */ +static struct i2c_driver ucd9000_driver = { + .driver = { + .name = "ucd9000", + }, + .probe = ucd9000_probe, + .remove = pmbus_do_remove, + .id_table = ucd9000_id, +}; + +module_i2c_driver(ucd9000_driver); + +MODULE_AUTHOR("Guenter Roeck"); +MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/setup.py b/platform/broadcom/sonic-platform-modules-inventec/d6356/setup.py new file mode 100644 index 000000000000..8b45987a54ec --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/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 Ivnetec D6356 platforms', + + packages=['sonic_platform'], +) + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/__init__.py new file mode 100644 index 000000000000..4bfefa0fb636 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/chassis.py new file mode 100644 index 000000000000..761d21cf46ce --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/chassis.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# +# Name: chassis.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import os + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.eeprom import Eeprom + from sonic_platform.fan import Fan + from sonic_platform.psu import Psu + from sonic_platform.sfp import Sfp + from sonic_platform.qsfp import QSfp + from sonic_platform.thermal import Thermal +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Chassis(ChassisBase): + + def __init__(self): + ChassisBase.__init__(self) + self.__num_of_fans = 8 + self.__num_of_psus = 2 + self.__num_of_sfps = 56 + self.__start_of_qsfp = 48 + self.__num_of_thermals = 5 + + # Initialize EEPROM + self._eeprom = Eeprom() + + # Initialize FAN + for index in range(1, self.__num_of_fans + 1): + fan = Fan(index, False, 0) + self._fan_list.append(fan) + + # Initialize PSU + for index in range(1, self.__num_of_psus + 1): + psu = Psu(index) + self._psu_list.append(psu) + + # Initialize SFP + for index in range(0, self.__num_of_sfps): + if index < self.__start_of_qsfp: + sfp = Sfp(index) + else: + sfp = QSfp(index) + self._sfp_list.append(sfp) + + # Initialize THERMAL + for index in range(0, self.__num_of_thermals): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self._eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self._eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis + Returns: + string: Serial number of chassis + """ + return self._eeprom.serial_number_str() + + def get_status(self): + """ + Retrieves the operational status of the chassis + Returns: + bool: A boolean value, True if chassis is operating properly + False if not + """ + return True + +############################################## +# Chassis methods +############################################## + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self._eeprom.base_mac_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. + """ + raise NotImplementedError diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/eeprom.py new file mode 100644 index 000000000000..5840246fddc2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/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, 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-2/2-0055/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 = (ord(eeprom[9]) << 8) | ord(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 + + ord(eeprom[tlv_index + 1])] + code = "0x%02X" % (ord(tlv[0])) + + if ord(tlv[0]) == self._TLV_CODE_VENDOR_EXT: + value = str((ord(tlv[2]) << 24) | (ord(tlv[3]) << 16) | + (ord(tlv[4]) << 8) | ord(tlv[5])) + value += str(tlv[6:6 + ord(tlv[1])]) + else: + name, value = self.decoder(None, tlv) + + self.__eeprom_tlv_dict[code] = value + if ord(eeprom[tlv_index]) == self._TLV_CODE_CRC_32: + break + + tlv_index += ord(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/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/fan.py new file mode 100644 index 000000000000..b9423e43dcb1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/fan.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python +# +# Name: fan.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import math + import os + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Fan(FanBase): + + def __init__(self, index, is_psu_fan=False, psu_index=0): + self.__index = index + self.__is_psu_fan = is_psu_fan + + if self.__is_psu_fan: + self.__psu_index = psu_index + self.__presence_attr = "/sys/class/hwmon/hwmon{}/fan{}_input".format((self.__psu_index + 6), self.__index) + self.__speed_rpm_attr = "/sys/class/hwmon/hwmon{}/fan{}_input".format((self.__psu_index + 6), self.__index) + self.__pwm_attr = None + else: + self.__presence_attr = "/sys/class/hwmon/hwmon2/device/fan{}_input".format(self.__index) + self.__speed_rpm_attr = "/sys/class/hwmon/hwmon2/device/fan{}_input".format(self.__index) + self.__pwm_attr = "/sys/class/hwmon/hwmon2/device/pwm{}".format((self.__index + 1)/2) + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + if self.__is_psu_fan: + return "PSU{}-FAN{}".format(self.__psu_index, self.__index) + else: + return "FAN{}".format(self.__index) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + attr_path = self.__presence_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (int(attr_rv) != 0): + 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 + """ + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + return "N/A" + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self.get_presence() + +############################################## +# 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 + """ + raise NotImplementedError + + 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_path = self.__speed_rpm_attr + else: + attr_path = self.__pwm_attr + + if self.get_presence() and None != attr_path: + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if self.__is_psu_fan: + fan_speed_rpm = int(attr_rv) + speed = math.ceil(float(fan_speed_rpm) * 100 / 11000) + else: + pwm = int(attr_rv) + speed = math.ceil(float(pwm * 100 / 255)) + + return speed + + 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) + """ + raise NotImplementedError + + 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 + """ + raise NotImplementedError + + 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 + """ + raise NotImplementedError + + 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 + """ + if self.get_status() and self.get_speed() > 0: + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_OFF + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/platform.py new file mode 100644 index 000000000000..7d6bda4502de --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/platform.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# +# Name: platform.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/psu.py new file mode 100644 index 000000000000..3798ef9e5b80 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/psu.py @@ -0,0 +1,202 @@ +#!/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 +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Psu(PsuBase): + + def __init__(self, index): + self.__num_of_fans = 1 + self.__index = index + self.__psu_presence_attr = "/sys/class/hwmon/hwmon2/device/psu{}".format(self.__index) + self.__psu_power_in_attr = "/sys/class/hwmon/hwmon{}/power1_input".format(self.__index + 6) + self.__psu_power_out_attr = "/sys/class/hwmon/hwmon{}/power2_input".format(self.__index + 6) + self.__psu_voltage_out_attr = "/sys/class/hwmon/hwmon{}/in2_input".format(self.__index + 6) + self.__psu_current_out_attr = "/sys/class/hwmon/hwmon{}/curr2_input".format(self.__index + 6) + + # Overriding _fan_list class variable defined in PsuBase, to make it unique per Psu object + self._fan_list = [] + + # Initialize FAN + for x in range(1, self.__num_of_fans + 1): + fan = Fan(x, True, self.__index) + self._fan_list.append(fan) + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return "PSU{}".format(self.__index) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + attr_normal = "1:normal" + attr_path = self.__psu_presence_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == attr_normal): + presence = True + + return presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + return "N/A" + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + status = False + attr_path = self.__psu_power_in_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (int(attr_rv) != 0): + status = True + + return status + +############################################## +# PSU methods +############################################## + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_out = 0.0 + attr_path = self.__psu_voltage_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + voltage_out = float(attr_rv) / 1000 + + return voltage_out + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_out = 0.0 + attr_path = self.__psu_current_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + current_out = float(attr_rv) / 1000 + + return current_out + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, e.g. 302.6 + """ + power_out = 0.0 + attr_path = self.__psu_power_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + power_out = float(attr_rv) / 1000000 + + 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 + """ + if self.get_powergood_status(): + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_OFF + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/qsfp.py b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/qsfp.py new file mode 100644 index 000000000000..f3f873be08ce --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/qsfp.py @@ -0,0 +1,925 @@ +#!/usr/bin/env python +# +# Name: qsfp.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import os + import sys + import time + 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.sfputilhelper import SfpUtilHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +INFO_OFFSET = 128 +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_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 + +class QSfp(SfpBase): + + def __init__(self, index): + self.__index = index + + self.__platform = "x86_64-inventec_d6356-r0" + self.__hwsku = "INVENTEC-D6356" + + self.__port_to_i2c_mapping = { + 0:22, 1:23, 2:24, 3:25, 4:26, 5:27, 6:28, 7:29, + 8:30, 9:31, 10:32, 11:33, 12:34, 13:35, 14:36, 15:37, + 16:38, 17:39, 18:40, 19:41, 20:42, 21:43, 22:44, 23:45, + 24:46, 25:47, 26:48, 27:49, 28:50, 29:51, 30:52, 31:53, + 32:54, 33:55, 34:56, 35:57, 36:58, 37:59, 38:60, 39:61, + 40:62, 41:63, 42:64, 43:65, 44:66, 45:67, 46:68, 47:69, + 48:14, 49:15, 50:16, 51:17, 52:18, 53:19, 54:20, 55:21 + } + self.__port_end = len(self.__port_to_i2c_mapping) - 1; + + self.__presence_attr = None + self.__eeprom_path = None + if self.__index in range(0, self.__port_end + 1): + self.__presence_attr = "/sys/class/swps/port{}/present".format(self.__index) + self.__lpmode_attr = "/sys/class/swps/port{}/lpmod".format(self.__index) + self.__reset_attr = "/sys/class/swps/port{}/reset".format(self.__index) + self.__eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom".format(self.__port_to_i2c_mapping[self.__index]) + + #print(self.__eeprom_path) + + 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(ord(raw[n]))[2:].zfill(2) + except: + 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_path = self.__presence_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (int(attr_rv) == 0): + 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 + """ + 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() + +############################################## +# 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 + 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', 'hardwarerev', + '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['manufacturename'] = sfp_vendor_name_data['data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A' + transceiver_info_dict['modelname'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A' + transceiver_info_dict['hardwarerev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' + transceiver_info_dict['serialnum'] = 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'] + + 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 = 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_qsfp_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 = DOM_OFFSET + + dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw: + 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_path = self.__reset_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (int(attr_rv) == 0): + 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 = False + 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) + rx_los = rx_los_list[0] and rx_los_list[1] and rx_los_list[2] and rx_los_list[3] + 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 + 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) + tx_fault = tx_fault_list[0] and tx_fault_list[1] and tx_fault_list[2] and tx_fault_list[3] + + 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_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] and tx_disable_list[1] and tx_disable_list[2] and 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) == 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 + """ + 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") + tx2_bs = transceiver_dom_info_dict.get("tx2bias", "N/A") + tx3_bs = transceiver_dom_info_dict.get("tx3bias", "N/A") + tx4_bs = transceiver_dom_info_dict.get("tx4bias", "N/A") + return [tx1_bs, tx2_bs, tx3_bs, tx4_bs] 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") + rx2_pw = transceiver_dom_info_dict.get("rx2power", "N/A") + rx3_pw = transceiver_dom_info_dict.get("rx3power", "N/A") + rx4_pw = transceiver_dom_info_dict.get("rx4power", "N/A") + return [rx1_pw, rx2_pw, rx3_pw, rx4_pw] 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") + tx2_pw = transceiver_dom_info_dict.get("tx2power", "N/A") + tx3_pw = transceiver_dom_info_dict.get("tx3power", "N/A") + tx4_pw = transceiver_dom_info_dict.get("tx4power", "N/A") + return [tx1_pw, tx2_pw, tx3_pw, tx4_pw] + + 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 = 0 + 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 = 1 + 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 + """ + sysfs_eeprom_path = self.__eeprom_path + sysfsfile_eeprom = None + try: + tx_disable_ctl = 0xf if tx_disable else 0x0 + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom = open(sysfs_eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + 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 + """ + sysfs_eeprom_path = self.__eeprom_path + sysfsfile_eeprom = None + try: + channel_state = self.get_tx_disable_channel() + tx_enable_mask = [0xe, 0xd, 0xb, 0x7] + tx_disable_mask = [0x1, 0x3, 0x7, 0xf] + tx_disable_ctl = channel_state | tx_disable_mask[channel] if disable else channel_state & tx_enable_mask[channel] + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom = open(sysfs_eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + 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 + """ + sysfs_eeprom_path = self.__eeprom_path + sysfsfile_eeprom = None + try: + power_override_bit = 0 + if power_override: + power_override_bit |= 1 << 0 + + power_set_bit = 0 + if power_set: + power_set_bit |= 1 << 1 + + buffer = create_string_buffer(1) + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + sysfsfile_eeprom = open(sysfs_eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/sfp.py new file mode 100644 index 000000000000..d8d88a2df2b0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/sfp.py @@ -0,0 +1,739 @@ +#!/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 +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 + +class Sfp(SfpBase): + + def __init__(self, index): + self.__index = index + + self.__platform = "x86_64-inventec_d6356-r0" + self.__hwsku = "INVENTEC-D6356" + + self.__port_to_i2c_mapping = { + 0:22, 1:23, 2:24, 3:25, 4:26, 5:27, 6:28, 7:29, + 8:30, 9:31, 10:32, 11:33, 12:34, 13:35, 14:36, 15:37, + 16:38, 17:39, 18:40, 19:41, 20:42, 21:43, 22:44, 23:45, + 24:46, 25:47, 26:48, 27:49, 28:50, 29:51, 30:52, 31:53, + 32:54, 33:55, 34:56, 35:57, 36:58, 37:59, 38:60, 39:61, + 40:62, 41:63, 42:64, 43:65, 44:66, 45:67, 46:68, 47:69, + 48:14, 49:15, 50:16, 51:17, 52:18, 53:19, 54:20, 55:21 + } + self.__port_end = len(self.__port_to_i2c_mapping) - 1; + + self.__presence_attr = None + self.__eeprom_path = None + if self.__index in range(0, self.__port_end + 1): + self.__presence_attr = "/sys/class/swps/port{}/present".format(self.__index) + self.__eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom".format(self.__port_to_i2c_mapping[self.__index]) + + 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(ord(raw[n]))[2:].zfill(2) + except: + 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_path = self.__presence_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (int(attr_rv) == 0): + 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 + """ + 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() + +############################################## +# 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 + 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', 'hardwarerev', + 'serialnum', 'manufacturename', + 'modelname', '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['manufacturename'] = sfp_vendor_name_data['data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A' + transceiver_info_dict['modelname'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A' + transceiver_info_dict['hardwarerev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' + transceiver_info_dict['serialnum'] = 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 {} + + 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 {} + + 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: + #print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + return False + + 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/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/thermal.py new file mode 100644 index 000000000000..eba7ba728de9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/sonic_platform/thermal.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python +# +# Name: thermal.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import os + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Thermal(ThermalBase): + + def __init__(self, index): + self.__index = index + + #thermal name list + self.__thermal_name_list = [ "PCH Temperature Sensor", + "CPU Board Temperature Sensor", + "FrontSide Temperature Sensor", + "NearASIC Temperature Sensor", + "RearSide Temperature Sensor" ] + + offset = 0 + if 0 != self.__index: + offset = 2 + self.__presence_attr = "/sys/class/hwmon/hwmon{}/temp1_input".format(self.__index + offset) + self.__temperature_attr = "/sys/class/hwmon/hwmon{}/temp1_input".format(self.__index + offset) + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return self.__thermal_name_list[self.__index] or "Unknown" + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + attr_path = self.__presence_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (int(attr_rv) != 0): + 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 + """ + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + return "N/A" + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self.get_presence() + +############################################## +# THERMAL methods +############################################## + + 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 + attr_path = self.__temperature_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + 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 + """ + raise NotImplementedError + + 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 + """ + raise NotImplementedError + + 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 + """ + raise NotImplementedError + + 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 + """ + raise NotImplementedError + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d6356/utils/inventec_d6356_util.py b/platform/broadcom/sonic-platform-modules-inventec/d6356/utils/inventec_d6356_util.py index e3e696c088cd..890973cb8356 100755 --- a/platform/broadcom/sonic-platform-modules-inventec/d6356/utils/inventec_d6356_util.py +++ b/platform/broadcom/sonic-platform-modules-inventec/d6356/utils/inventec_d6356_util.py @@ -126,7 +126,7 @@ def exec_cmd(cmd, show): 'inv_eeprom', 'inv_cpld', 'inv_platform', -'monitor', +#'monitor', 'swps'] @@ -141,7 +141,7 @@ def system_install(): status, output = exec_cmd("rmmod lpc_ich ", 1) #insert extra module - status, output = exec_cmd("insmod /lib/modules/3.16.0-5-amd64/extra/gpio-ich.ko gpiobase=0",1) + status, output = exec_cmd("insmod /lib/modules/4.9.0-9-2-amd64/kernel/drivers/gpio/gpio-ich.ko gpiobase=0",1) #install drivers for i in range(0,len(drivers)): @@ -159,52 +159,49 @@ def system_install(): print output if FORCE == 0: return status - - #swps map to i2c-bus +# +# INV_FIX-4037 +# It replaces the original sff8436 driver with the optoe driver +# + #optoe map to i2c-bus for i in range(14,22): - status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-6/i2c-"+str(i)+"/new_device", 1) + status, output =exec_cmd("echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-6/i2c-"+str(i)+"/new_device", 1) if status: print output if FORCE == 0: return status for i in range(22,30): - status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-7/i2c-"+str(i)+"/new_device", 1) - status, output =exec_cmd("echo sff8436 0x51 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-7/i2c-"+str(i)+"/new_device", 1) + status, output =exec_cmd("echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-7/i2c-"+str(i)+"/new_device", 1) if status: print output if FORCE == 0: return status for i in range(30,38): - status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-8/i2c-"+str(i)+"/new_device", 1) - status, output =exec_cmd("echo sff8436 0x51 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-8/i2c-"+str(i)+"/new_device", 1) + status, output =exec_cmd("echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-8/i2c-"+str(i)+"/new_device", 1) if status: print output if FORCE == 0: return status for i in range(38,46): - status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-9/i2c-"+str(i)+"/new_device", 1) - status, output =exec_cmd("echo sff8436 0x51 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-9/i2c-"+str(i)+"/new_device", 1) + status, output =exec_cmd("echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-9/i2c-"+str(i)+"/new_device", 1) if status: print output if FORCE == 0: return status for i in range(46,54): - status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-10/i2c-"+str(i)+"/new_device", 1) - status, output =exec_cmd("echo sff8436 0x51 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-10/i2c-"+str(i)+"/new_device", 1) + status, output =exec_cmd("echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-10/i2c-"+str(i)+"/new_device", 1) if status: print output if FORCE == 0: return status for i in range(54,62): - status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-11/i2c-"+str(i)+"/new_device", 1) - status, output =exec_cmd("echo sff8436 0x51 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-11/i2c-"+str(i)+"/new_device", 1) + status, output =exec_cmd("echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-11/i2c-"+str(i)+"/new_device", 1) if status: print output if FORCE == 0: return status for i in range(62,70): - status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-12/i2c-"+str(i)+"/new_device", 1) - status, output =exec_cmd("echo sff8436 0x51 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-12/i2c-"+str(i)+"/new_device", 1) + status, output =exec_cmd("echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-1/i2c-5/i2c-12/i2c-"+str(i)+"/new_device", 1) if status: print output if FORCE == 0: @@ -243,7 +240,7 @@ def uninstall(): def device_found(): ret1, log = exec_cmd("ls "+i2c_prefix+"*0072", 0) ret2, log = exec_cmd("ls "+i2c_prefix+"i2c-5", 0) - return not(ret1 or ret2) + return not(ret1 or ret2) if __name__ == "__main__": main() diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/control b/platform/broadcom/sonic-platform-modules-inventec/debian/control index b3af29108f5f..6cb61630823f 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/debian/control +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/control @@ -27,7 +27,7 @@ Description: kernel modules for platform devices such as fan, led Package: platform-modules-d6356 Architecture: amd64 -Depends: linux-image-4.9.0-8-2-amd64 +Depends: linux-image-4.9.0-9-2-amd64 Description: kernel modules for platform devices such as fan, led Package: platform-modules-d7264q28b diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d6356.install b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d6356.install index 4c668b9816c4..6f03ede72e05 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d6356.install +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d6356.install @@ -1 +1,3 @@ -d6356/utils/inventec_d6356_util.py /usr/local/bin +d6356/utils/inventec_d6356_util.py usr/local/bin +d6356/utils/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-inventec_d6356-r0 +systemd/platform-modules-d6356.service lib/systemd/system diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/rules b/platform/broadcom/sonic-platform-modules-inventec/debian/rules index 8bfe6e6582d9..6340540f0354 100755 --- a/platform/broadcom/sonic-platform-modules-inventec/debian/rules +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/rules @@ -17,11 +17,17 @@ MOD_SRC_DIR:= $(shell pwd) MODULE_DIRS:= d7032q28b d7054q28b d6254qs d6556 d6356 d7264q28b %: - dh $@ --with=systemd + dh $@ --with python2,systemd override_dh_auto_build: (for mod in $(MODULE_DIRS); do \ make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ + if [ $$mod = "d6356" ]; then \ + cd $(MOD_SRC_DIR)/$${mod}; \ + python2 setup.py build; \ + python2 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/utils; \ + cd $(MOD_SRC_DIR); \ + fi \ done) override_dh_auto_install: @@ -30,11 +36,13 @@ override_dh_auto_install: $(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ cp $(MOD_SRC_DIR)/$${mod}/modules/*.ko \ debian/platform-modules-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ - dh_installdirs -pplatform-modules-$${mod} usr/local/bin; \ - cp $(MOD_SRC_DIR)/$${mod}/utils/* \ - debian/platform-modules-$${mod}/usr/local/bin; \ + if [ $$mod = "d6356" ]; then \ + cd $(MOD_SRC_DIR)/$${mod}; \ + python2 setup.py install --root=$(MOD_SRC_DIR)/debian/platform-modules-$${mod} --install-layout=deb; \ + cd $(MOD_SRC_DIR); \ + fi \ done) - + override_dh_usrlocal: override_dh_pysupport: diff --git a/platform/broadcom/sonic-platform-modules-inventec/systemd/platform-modules-d6356.service b/platform/broadcom/sonic-platform-modules-inventec/systemd/platform-modules-d6356.service new file mode 100644 index 000000000000..85fa47a72611 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/systemd/platform-modules-d6356.service @@ -0,0 +1,13 @@ +[Unit] +Description=Inventec d6356 Platform modules +After=local-fs.target +Before=pmon.service + +[Service] +Type=oneshot +ExecStart=-/etc/init.d/platform-modules-d6356 start +ExecStop=-/etc/init.d/platform-modules-d6356 stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target From 9bdd693e810b3b0fa75f3754b6ac37e86ede0314 Mon Sep 17 00:00:00 2001 From: Ying Xie Date: Wed, 9 Oct 2019 17:28:33 -0700 Subject: [PATCH 060/278] [bcm SAI] upgrade Broadcom SAI to version 3.5.3.1m-25 (#48) - Built with SAI header version v1.5.0. Signed-off-by: Ying Xie --- platform/broadcom/sai.mk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/broadcom/sai.mk b/platform/broadcom/sai.mk index d29e0907796d..6ef784e21ced 100644 --- a/platform/broadcom/sai.mk +++ b/platform/broadcom/sai.mk @@ -1,9 +1,9 @@ -BRCM_SAI = libsaibcm_3.5.3.1-15_amd64.deb -$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm_3.5.3.1-15_amd64.deb?sv=2015-04-05&sr=b&sig=zXY%2FK%2FeGlxteIFlEkPdE%2FNDRet5T%2Fc1LgL0qyX9%2FmfQ%3D&se=2033-06-03T17%3A45%3A51Z&sp=r" +BRCM_SAI = libsaibcm_3.5.3.1m-25_amd64.deb +$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm_3.5.3.1m-25_amd64.deb?sv=2015-04-05&sr=b&sig=kLfhfLeBmENmTXVa%2BZ90k2Fq8ZOQ84kxn5%2FzY3KLV2s%3D&se=2033-06-17T23%3A45%3A50Z&sp=r" -BRCM_SAI_DEV = libsaibcm-dev_3.5.3.1-15_amd64.deb +BRCM_SAI_DEV = libsaibcm-dev_3.5.3.1m-25_amd64.deb $(eval $(call add_derived_package,$(BRCM_SAI),$(BRCM_SAI_DEV))) -$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm-dev_3.5.3.1-15_amd64.deb?sv=2015-04-05&sr=b&sig=%2BYOVgRo6dLxv3sLb8JE1wLoD%2FneYDABadwFv5xH3XRE%3D&se=2033-06-03T17%3A46%3A14Z&sp=r" +$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm-dev_3.5.3.1m-25_amd64.deb?sv=2015-04-05&sr=b&sig=a%2BvxIrNcVwnp0CBXS%2BTGiGl%2F%2Fl8mo9ZKPkZyroPY0bI%3D&se=2033-06-17T23%3A45%3A21Z&sp=r" SONIC_ONLINE_DEBS += $(BRCM_SAI) $(BRCM_SAI_DEV)_DEPENDS += $(BRCM_SAI) From 1b5c65fcf15b8359ff0ee387529e9de7e650f5a4 Mon Sep 17 00:00:00 2001 From: Qi Luo Date: Wed, 9 Oct 2019 17:38:53 -0700 Subject: [PATCH 061/278] [build]: Update comments on build_debian.sh (#3533) --- build_debian.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_debian.sh b/build_debian.sh index 5c7a9344f43c..34bf6eba6ab1 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -170,7 +170,7 @@ sudo chmod +x $FILESYSTEM_ROOT/etc/initramfs-tools/scripts/init-premount/resize- ## Hook into initramfs: after partition mount and loop file mount ## 1. Prepare layered file system -## 2. Bind-mount docker working directory (docker aufs cannot work over aufs rootfs) +## 2. Bind-mount docker working directory (docker overlay storage cannot work over overlay rootfs) sudo cp files/initramfs-tools/union-mount $FILESYSTEM_ROOT/etc/initramfs-tools/scripts/init-bottom/union-mount sudo chmod +x $FILESYSTEM_ROOT/etc/initramfs-tools/scripts/init-bottom/union-mount sudo cp files/initramfs-tools/varlog $FILESYSTEM_ROOT/etc/initramfs-tools/scripts/init-bottom/varlog @@ -206,7 +206,7 @@ sudo LANG=C chroot $FILESYSTEM_ROOT apt-get update sudo LANG=C chroot $FILESYSTEM_ROOT apt-get -y install docker-ce=${DOCKER_VERSION} sudo LANG=C chroot $FILESYSTEM_ROOT apt-get -y remove software-properties-common gnupg2 -## Add docker config drop-in to select aufs, otherwise it may select other storage driver +## Add docker config drop-in to specify dockerd command line sudo mkdir -p $FILESYSTEM_ROOT/etc/systemd/system/docker.service.d/ ## Note: $_ means last argument of last command sudo cp files/docker/docker.service.conf $_ From 368c4fa9fe1cbf7e8eb7ab74c9556ee13e34093f Mon Sep 17 00:00:00 2001 From: tiantianlv <38775940+tiantianlv@users.noreply.github.com> Date: Thu, 10 Oct 2019 08:47:46 +0800 Subject: [PATCH 062/278] [devices]: support Silverstone platform (#3474) * [device/celestica] Add silverstone device plugins and configs * add port led fireware of PAM4! * [platform/broadcom] Add Celestica silverstone platform module. * Add switch configuration Silverstone! * Add 128x100 configuration! * Delete serdes copper parameter! * [device/celestica] Fix incorrect index in Silverstone 128x100G port cfg * [platform/broadcom] Remove unrelated platform other than Silverstone * [device/celestica] Silverstone remove minigraphs * [device/celestica] Silverstone update sai.profile to use hwsku path * [device/celestica] Silverstone format sfputil codes * [device/celestica] Add speed column to Silverstone 32x400G port conf * [device/celestica] Silverstone disable 10G ports prevent orchagent crash *These ports will be added later after BRCM SAI support SFP. * Remove LED redundancy configuration and add comments! * [plugins/sfputil] update Silverstone ports to QSFP-DD type * [plugins/sfputil] Silverstone fix return NotImplementedError with raise --- .../Silverstone-128x100/port_config.ini | 129 + .../Silverstone-128x100/sai.profile | 1 + .../th3-128x100G.config.bcm | 441 ++++ .../Silverstone/port_config.ini | 33 + .../Silverstone/sai.profile | 1 + .../Silverstone/th3-32x400G.config.bcm | 231 ++ .../x86_64-cel_silverstone-r0/custom.bin | Bin 0 -> 1216 bytes .../x86_64-cel_silverstone-r0/default_sku | 1 + .../x86_64-cel_silverstone-r0/installer.conf | 1 + .../led_proc_init.soc | 2 + .../x86_64-cel_silverstone-r0/linkscan_fw.bin | Bin 0 -> 6100 bytes .../plugins/eeprom.py | 23 + .../plugins/psuutil.py | 91 + .../plugins/sfputil.py | 186 ++ platform/broadcom/one-image.mk | 3 +- platform/broadcom/platform-modules-cel.mk | 6 + .../sonic-platform-modules-cel/debian/control | 5 + .../debian/platform-modules-silverstone.init | 49 + .../platform-modules-silverstone.install | 2 + .../platform-modules-silverstone.postinst | 3 + .../sonic-platform-modules-cel/debian/rules | 2 +- .../silverstone/cfg/silverstone-modules.conf | 15 + .../silverstone/modules/Makefile | 1 + .../silverstone/modules/baseboard-lpc.c | 433 ++++ .../silverstone/modules/mc24lc64t.c | 174 ++ .../silverstone/modules/switchboard.c | 2106 +++++++++++++++++ .../platform-modules-silverstone.service | 13 + 27 files changed, 3950 insertions(+), 2 deletions(-) create mode 100644 device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/port_config.ini create mode 100644 device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/sai.profile create mode 100644 device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/th3-128x100G.config.bcm create mode 100644 device/celestica/x86_64-cel_silverstone-r0/Silverstone/port_config.ini create mode 100644 device/celestica/x86_64-cel_silverstone-r0/Silverstone/sai.profile create mode 100644 device/celestica/x86_64-cel_silverstone-r0/Silverstone/th3-32x400G.config.bcm create mode 100644 device/celestica/x86_64-cel_silverstone-r0/custom.bin create mode 100644 device/celestica/x86_64-cel_silverstone-r0/default_sku create mode 100644 device/celestica/x86_64-cel_silverstone-r0/installer.conf create mode 100644 device/celestica/x86_64-cel_silverstone-r0/led_proc_init.soc create mode 100644 device/celestica/x86_64-cel_silverstone-r0/linkscan_fw.bin create mode 100644 device/celestica/x86_64-cel_silverstone-r0/plugins/eeprom.py create mode 100644 device/celestica/x86_64-cel_silverstone-r0/plugins/psuutil.py create mode 100755 device/celestica/x86_64-cel_silverstone-r0/plugins/sfputil.py create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.init create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.postinst create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone/cfg/silverstone-modules.conf create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone/modules/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone/modules/baseboard-lpc.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone/modules/mc24lc64t.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switchboard.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone/systemd/platform-modules-silverstone.service diff --git a/device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/port_config.ini b/device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/port_config.ini new file mode 100644 index 000000000000..238c9fa4be79 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/port_config.ini @@ -0,0 +1,129 @@ +# name lanes alias index speed +Ethernet0 33,34 QSFP1/1 1 100000 +Ethernet1 35,36 QSFP1/2 1 100000 +Ethernet2 37,38 QSFP1/3 1 100000 +Ethernet3 39,40 QSFP1/4 1 100000 +Ethernet4 41,42 QSFP2/1 2 100000 +Ethernet5 43,44 QSFP2/2 2 100000 +Ethernet6 45,46 QSFP2/3 2 100000 +Ethernet7 47,48 QSFP2/4 2 100000 +Ethernet8 49,50 QSFP3/1 3 100000 +Ethernet9 51,52 QSFP3/2 3 100000 +Ethernet10 53,54 QSFP3/3 3 100000 +Ethernet11 55,56 QSFP3/4 3 100000 +Ethernet12 57,58 QSFP4/1 4 100000 +Ethernet13 59,60 QSFP4/2 4 100000 +Ethernet14 61,62 QSFP4/3 4 100000 +Ethernet15 63,64 QSFP4/4 4 100000 +Ethernet16 65,66 QSFP5/1 5 100000 +Ethernet17 67,68 QSFP5/2 5 100000 +Ethernet18 69,70 QSFP5/3 5 100000 +Ethernet19 71,72 QSFP5/4 5 100000 +Ethernet20 73,74 QSFP6/1 6 100000 +Ethernet21 75,76 QSFP6/2 6 100000 +Ethernet22 77,78 QSFP6/3 6 100000 +Ethernet23 79,80 QSFP6/4 6 100000 +Ethernet24 81,82 QSFP7/1 7 100000 +Ethernet25 83,84 QSFP7/2 7 100000 +Ethernet26 85,86 QSFP7/3 7 100000 +Ethernet27 87,88 QSFP7/4 7 100000 +Ethernet28 89,90 QSFP8/1 8 100000 +Ethernet29 91,92 QSFP8/2 8 100000 +Ethernet30 93,94 QSFP8/3 8 100000 +Ethernet31 95,96 QSFP8/4 8 100000 +Ethernet32 1,2 QSFP9/1 9 100000 +Ethernet33 3,4 QSFP9/2 9 100000 +Ethernet34 5,6 QSFP9/3 9 100000 +Ethernet35 7,8 QSFP9/4 9 100000 +Ethernet36 9,10 QSFP10/1 10 100000 +Ethernet37 11,12 QSFP10/2 10 100000 +Ethernet38 13,14 QSFP10/3 10 100000 +Ethernet39 15,16 QSFP10/4 10 100000 +Ethernet40 17,18 QSFP11/1 11 100000 +Ethernet41 19,20 QSFP11/2 11 100000 +Ethernet42 21,22 QSFP11/3 11 100000 +Ethernet43 23,24 QSFP11/4 11 100000 +Ethernet44 25,26 QSFP12/1 12 100000 +Ethernet45 27,28 QSFP12/2 12 100000 +Ethernet46 29,30 QSFP12/3 12 100000 +Ethernet47 31,32 QSFP12/4 12 100000 +Ethernet48 97,98 QSFP13/1 13 100000 +Ethernet49 99,100 QSFP13/2 13 100000 +Ethernet50 101,102 QSFP13/3 13 100000 +Ethernet51 103,104 QSFP13/4 13 100000 +Ethernet52 105,106 QSFP14/1 14 100000 +Ethernet53 107,108 QSFP14/2 14 100000 +Ethernet54 109,110 QSFP14/3 14 100000 +Ethernet55 111,112 QSFP14/4 14 100000 +Ethernet56 113,114 QSFP15/1 15 100000 +Ethernet57 115,116 QSFP15/2 15 100000 +Ethernet58 117,118 QSFP15/3 15 100000 +Ethernet59 119,120 QSFP15/4 15 100000 +Ethernet60 121,122 QSFP16/1 16 100000 +Ethernet61 123,124 QSFP16/2 16 100000 +Ethernet62 125,126 QSFP16/3 16 100000 +Ethernet63 127,128 QSFP16/4 16 100000 +Ethernet64 129,130 QSFP17/1 17 100000 +Ethernet65 131,132 QSFP17/2 17 100000 +Ethernet66 133,134 QSFP17/3 17 100000 +Ethernet67 135,136 QSFP17/4 17 100000 +Ethernet68 137,138 QSFP18/1 18 100000 +Ethernet69 139,140 QSFP18/2 18 100000 +Ethernet70 141,142 QSFP18/3 18 100000 +Ethernet71 143,144 QSFP18/4 18 100000 +Ethernet72 145,146 QSFP19/1 19 100000 +Ethernet73 147,148 QSFP19/2 19 100000 +Ethernet74 149,150 QSFP19/3 19 100000 +Ethernet75 151,152 QSFP19/4 19 100000 +Ethernet76 153,154 QSFP20/1 20 100000 +Ethernet77 155,156 QSFP20/2 20 100000 +Ethernet78 157,158 QSFP20/3 20 100000 +Ethernet79 159,160 QSFP20/4 20 100000 +Ethernet80 225,226 QSFP21/1 21 100000 +Ethernet81 227,228 QSFP21/2 21 100000 +Ethernet82 229,230 QSFP21/3 21 100000 +Ethernet83 231,232 QSFP21/4 21 100000 +Ethernet84 233,234 QSFP22/1 22 100000 +Ethernet85 235,236 QSFP22/2 22 100000 +Ethernet86 237,238 QSFP22/3 22 100000 +Ethernet87 239,240 QSFP22/4 22 100000 +Ethernet88 241,242 QSFP23/1 23 100000 +Ethernet89 243,244 QSFP23/2 23 100000 +Ethernet90 245,246 QSFP23/3 23 100000 +Ethernet91 247,248 QSFP23/4 23 100000 +Ethernet92 249,250 QSFP24/1 24 100000 +Ethernet93 251,252 QSFP24/2 24 100000 +Ethernet94 253,254 QSFP24/3 24 100000 +Ethernet95 255,256 QSFP24/4 24 100000 +Ethernet96 161,162 QSFP25/1 25 100000 +Ethernet97 163,164 QSFP25/2 25 100000 +Ethernet98 165,166 QSFP25/3 25 100000 +Ethernet99 167,168 QSFP25/4 25 100000 +Ethernet100 169,170 QSFP26/1 26 100000 +Ethernet101 171,172 QSFP26/2 26 100000 +Ethernet102 173,174 QSFP26/3 26 100000 +Ethernet103 175,176 QSFP26/4 26 100000 +Ethernet104 177,178 QSFP27/1 27 100000 +Ethernet105 179,180 QSFP27/2 27 100000 +Ethernet106 181,182 QSFP27/3 27 100000 +Ethernet107 183,184 QSFP27/4 27 100000 +Ethernet108 185,186 QSFP28/1 28 100000 +Ethernet109 187,188 QSFP28/2 28 100000 +Ethernet110 189,190 QSFP28/3 28 100000 +Ethernet111 191,192 QSFP28/4 28 100000 +Ethernet112 193,194 QSFP29/1 29 100000 +Ethernet113 195,196 QSFP29/2 29 100000 +Ethernet114 197,198 QSFP29/3 29 100000 +Ethernet115 199,200 QSFP29/4 29 100000 +Ethernet116 201,202 QSFP30/1 30 100000 +Ethernet117 203,204 QSFP30/2 30 100000 +Ethernet118 205,206 QSFP30/3 30 100000 +Ethernet119 207,208 QSFP30/4 30 100000 +Ethernet120 209,210 QSFP31/1 31 100000 +Ethernet121 211,212 QSFP31/2 31 100000 +Ethernet122 213,214 QSFP31/3 31 100000 +Ethernet123 215,216 QSFP31/4 31 100000 +Ethernet124 217,218 QSFP32/1 32 100000 +Ethernet125 219,220 QSFP32/2 32 100000 +Ethernet126 221,222 QSFP32/3 32 100000 +Ethernet127 223,224 QSFP32/4 32 100000 \ No newline at end of file diff --git a/device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/sai.profile b/device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/sai.profile new file mode 100644 index 000000000000..bc7681f0272f --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/th3-128x100G.config.bcm diff --git a/device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/th3-128x100G.config.bcm b/device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/th3-128x100G.config.bcm new file mode 100644 index 000000000000..0b66c8b53814 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/th3-128x100G.config.bcm @@ -0,0 +1,441 @@ +pbmp_xport_xe.0=0x8ffff8ffffcffff8ffff8ffff8ffffcffff9fffe +ccm_dma_enable=0 +ccmdma_intr_enable=0 +ctr_evict_enable=0 +mem_cache_enable=0 +parity_correction=0 +parity_enable=0 +phy_enable=0 +phy_null=1 +pll_bypass=1 + +init_all_modules=0 + +portmap_20=33:100:2 +portmap_21=35:100:2 +portmap_22=37:100:2 +portmap_23=39:100:2 + +portmap_24=41:100:2 +portmap_25=43:100:2 +portmap_26=45:100:2 +portmap_27=47:100:2 + +portmap_28=49:100:2 +portmap_29=51:100:2 +portmap_30=53:100:2 +portmap_31=55:100:2 + +portmap_32=57:100:2 +portmap_33=59:100:2 +portmap_34=61:100:2 +portmap_35=63:100:2 + +portmap_40=65:100:2 +portmap_41=67:100:2 +portmap_42=69:100:2 +portmap_43=71:100:2 + +portmap_44=73:100:2 +portmap_45=75:100:2 +portmap_46=77:100:2 +portmap_47=79:100:2 + +portmap_48=81:100:2 +portmap_49=83:100:2 +portmap_50=85:100:2 +portmap_51=87:100:2 + +portmap_52=89:100:2 +portmap_53=91:100:2 +portmap_54=93:100:2 +portmap_55=95:100:2 + +portmap_1=1:100:2 +portmap_2=3:100:2 +portmap_3=5:100:2 +portmap_4=7:100:2 + +portmap_5=9:100:2 +portmap_6=11:100:2 +portmap_7=13:100:2 +portmap_8=15:100:2 + +portmap_9=17:100:2 +portmap_10=19:100:2 +portmap_11=21:100:2 +portmap_12=23:100:2 + +portmap_13=25:100:2 +portmap_14=27:100:2 +portmap_15=29:100:2 +portmap_16=31:100:2 + +portmap_60=97:100:2 +portmap_61=99:100:2 +portmap_62=101:100:2 +portmap_63=103:100:2 + +portmap_64=105:100:2 +portmap_65=107:100:2 +portmap_66=109:100:2 +portmap_67=111:100:2 + +portmap_68=113:100:2 +portmap_69=115:100:2 +portmap_70=117:100:2 +portmap_71=119:100:2 + +portmap_72=121:100:2 +portmap_73=123:100:2 +portmap_74=125:100:2 +portmap_75=127:100:2 + +portmap_80=129:100:2 +portmap_81=131:100:2 +portmap_82=133:100:2 +portmap_83=135:100:2 + +portmap_84=137:100:2 +portmap_85=139:100:2 +portmap_86=141:100:2 +portmap_87=143:100:2 + +portmap_88=145:100:2 +portmap_89=147:100:2 +portmap_90=149:100:2 +portmap_91=151:100:2 + +portmap_92=153:100:2 +portmap_93=155:100:2 +portmap_94=157:100:2 +portmap_95=159:100:2 + +portmap_140=225:100:2 +portmap_141=227:100:2 +portmap_142=229:100:2 +portmap_143=231:100:2 + +portmap_144=233:100:2 +portmap_145=235:100:2 +portmap_146=237:100:2 +portmap_147=239:100:2 + +portmap_148=241:100:2 +portmap_149=243:100:2 +portmap_150=245:100:2 +portmap_151=247:100:2 + +portmap_152=249:100:2 +portmap_153=251:100:2 +portmap_154=253:100:2 +portmap_155=255:100:2 + +portmap_100=161:100:2 +portmap_101=163:100:2 +portmap_102=165:100:2 +portmap_103=167:100:2 + +portmap_104=169:100:2 +portmap_105=171:100:2 +portmap_106=173:100:2 +portmap_107=175:100:2 + +portmap_108=177:100:2 +portmap_109=179:100:2 +portmap_110=181:100:2 +portmap_111=183:100:2 + +portmap_112=185:100:2 +portmap_113=187:100:2 +portmap_114=189:100:2 +portmap_115=191:100:2 + +portmap_120=193:100:2 +portmap_121=195:100:2 +portmap_122=197:100:2 +portmap_123=199:100:2 + +portmap_124=201:100:2 +portmap_125=203:100:2 +portmap_126=205:100:2 +portmap_127=207:100:2 + +portmap_128=209:100:2 +portmap_129=211:100:2 +portmap_130=213:100:2 +portmap_131=215:100:2 + +portmap_132=217:100:2 +portmap_133=219:100:2 +portmap_134=221:100:2 +portmap_135=223:100:2 + +phy_chain_rx_lane_map_physical{33.0}=0x65732041 +phy_chain_tx_lane_map_physical{33.0}=0x47206531 +phy_chain_rx_lane_map_physical{41.0}=0x07561243 +phy_chain_tx_lane_map_physical{41.0}=0x36207514 +phy_chain_rx_lane_map_physical{49.0}=0x54632071 +phy_chain_tx_lane_map_physical{49.0}=0x06241735 +phy_chain_rx_lane_map_physical{57.0}=0x07561243 +phy_chain_tx_lane_map_physical{57.0}=0x35207614 +phy_chain_rx_lane_map_physical{65.0}=0x45623170 +phy_chain_tx_lane_map_physical{65.0}=0x51260734 +phy_chain_rx_lane_map_physical{73.0}=0x07561243 +phy_chain_tx_lane_map_physical{73.0}=0x37245610 +phy_chain_rx_lane_map_physical{81.0}=0x45632071 +phy_chain_tx_lane_map_physical{81.0}=0x51260734 +phy_chain_rx_lane_map_physical{89.0}=0x07561243 +phy_chain_tx_lane_map_physical{89.0}=0x26437510 +phy_chain_rx_lane_map_physical{1.0}=0x30176524 +phy_chain_tx_lane_map_physical{1.0}=0x20615374 +phy_chain_rx_lane_map_physical{9.0}=0x37562041 +phy_chain_tx_lane_map_physical{9.0}=0x05176432 +phy_chain_rx_lane_map_physical{17.0}=0x43607251 +phy_chain_tx_lane_map_physical{17.0}=0x70261435 +phy_chain_rx_lane_map_physical{25.0}=0x60347125 +phy_chain_tx_lane_map_physical{25.0}=0x46357120 +phy_chain_rx_lane_map_physical{97.0}=0x47601352 +phy_chain_tx_lane_map_physical{97.0}=0x04265137 +phy_chain_rx_lane_map_physical{105.0}=0x73206415 +phy_chain_tx_lane_map_physical{105.0}=0x26374150 +phy_chain_rx_lane_map_physical{113.0}=0x47632051 +phy_chain_tx_lane_map_physical{113.0}=0x03254617 +phy_chain_rx_lane_map_physical{121.0}=0x63027415 +phy_chain_tx_lane_map_physical{121.0}=0x63721045 +phy_chain_rx_lane_map_physical{129.0}=0x30154627 +phy_chain_tx_lane_map_physical{129.0}=0x04735261 +phy_chain_rx_lane_map_physical{137.0}=0x24753061 +phy_chain_tx_lane_map_physical{137.0}=0x37614520 +phy_chain_rx_lane_map_physical{145.0}=0x47601352 +phy_chain_tx_lane_map_physical{145.0}=0x63274510 +phy_chain_rx_lane_map_physical{153.0}=0x07361524 +phy_chain_tx_lane_map_physical{153.0}=0x36527104 +phy_chain_rx_lane_map_physical{225.0}=0x56410273 +phy_chain_tx_lane_map_physical{225.0}=0x10274635 +phy_chain_rx_lane_map_physical{233.0}=0x15740263 +phy_chain_tx_lane_map_physical{233.0}=0x24351607 +phy_chain_rx_lane_map_physical{241.0}=0x74015263 +phy_chain_tx_lane_map_physical{241.0}=0x04152637 +phy_chain_rx_lane_map_physical{249.0}=0x62037514 +phy_chain_tx_lane_map_physical{249.0}=0x72453160 +phy_chain_rx_lane_map_physical{161.0}=0x46510273 +phy_chain_tx_lane_map_physical{161.0}=0x01653724 +phy_chain_rx_lane_map_physical{169.0}=0x25743160 +phy_chain_tx_lane_map_physical{169.0}=0x07216435 +phy_chain_rx_lane_map_physical{177.0}=0x46510273 +phy_chain_tx_lane_map_physical{177.0}=0x01652734 +phy_chain_rx_lane_map_physical{185.0}=0x25743160 +phy_chain_tx_lane_map_physical{185.0}=0x37016425 +phy_chain_rx_lane_map_physical{193.0}=0x46510372 +phy_chain_tx_lane_map_physical{193.0}=0x06153724 +phy_chain_rx_lane_map_physical{201.0}=0x25743160 +phy_chain_tx_lane_map_physical{201.0}=0x36017524 +phy_chain_rx_lane_map_physical{209.0}=0x47601352 +phy_chain_tx_lane_map_physical{209.0}=0x04152736 +phy_chain_rx_lane_map_physical{217.0}=0x26453170 +phy_chain_tx_lane_map_physical{217.0}=0x36027415 + +serdes_core_rx_polarity_flip_physical{33}=0x29 +serdes_core_tx_polarity_flip_physical{33}=0xfe +serdes_core_rx_polarity_flip_physical{41}=0xb1 +serdes_core_tx_polarity_flip_physical{41}=0xe8 +serdes_core_rx_polarity_flip_physical{49}=0xca +serdes_core_tx_polarity_flip_physical{49}=0xb6 +serdes_core_rx_polarity_flip_physical{57}=0x9b +serdes_core_tx_polarity_flip_physical{57}=0xdc +serdes_core_rx_polarity_flip_physical{65}=0x17 +serdes_core_tx_polarity_flip_physical{65}=0x86 +serdes_core_rx_polarity_flip_physical{73}=0x9b +serdes_core_tx_polarity_flip_physical{73}=0x55 +serdes_core_rx_polarity_flip_physical{81}=0xa +serdes_core_tx_polarity_flip_physical{81}=0x6 +serdes_core_rx_polarity_flip_physical{89}=0x9b +serdes_core_tx_polarity_flip_physical{89}=0x48 +serdes_core_rx_polarity_flip_physical{1}=0xec +serdes_core_tx_polarity_flip_physical{1}=0x56 +serdes_core_rx_polarity_flip_physical{9}=0x13 +serdes_core_tx_polarity_flip_physical{9}=0xa6 +serdes_core_rx_polarity_flip_physical{17}=0x5a +serdes_core_tx_polarity_flip_physical{17}=0xc6 +serdes_core_rx_polarity_flip_physical{25}=0xf +serdes_core_tx_polarity_flip_physical{25}=0x4e +serdes_core_rx_polarity_flip_physical{97}=0x17 +serdes_core_tx_polarity_flip_physical{97}=0x2e +serdes_core_rx_polarity_flip_physical{105}=0xce +serdes_core_tx_polarity_flip_physical{105}=0x7c +serdes_core_rx_polarity_flip_physical{113}=0xa +serdes_core_tx_polarity_flip_physical{113}=0x35 + +serdes_core_rx_polarity_flip_physical{121}=0xb9 +serdes_core_tx_polarity_flip_physical{121}=0xef +serdes_core_rx_polarity_flip_physical{129}=0xe8 +serdes_core_tx_polarity_flip_physical{129}=0xac +serdes_core_rx_polarity_flip_physical{137}=0xcb +serdes_core_tx_polarity_flip_physical{137}=0x9c +serdes_core_rx_polarity_flip_physical{145}=0x17 +serdes_core_tx_polarity_flip_physical{145}=0x32 +serdes_core_rx_polarity_flip_physical{153}=0xb9 +serdes_core_tx_polarity_flip_physical{153}=0xaf +serdes_core_rx_polarity_flip_physical{225}=0xaa +serdes_core_tx_polarity_flip_physical{225}=0x7 +serdes_core_rx_polarity_flip_physical{233}=0x31 +serdes_core_tx_polarity_flip_physical{233}=0x47 +serdes_core_rx_polarity_flip_physical{241}=0xe8 +serdes_core_tx_polarity_flip_physical{241}=0x9e +serdes_core_rx_polarity_flip_physical{249}=0xec +serdes_core_tx_polarity_flip_physical{249}=0x1f +serdes_core_rx_polarity_flip_physical{161}=0x6a +serdes_core_tx_polarity_flip_physical{161}=0xd4 +serdes_core_rx_polarity_flip_physical{169}=0x9e +serdes_core_tx_polarity_flip_physical{169}=0x7b +serdes_core_rx_polarity_flip_physical{177}=0x6a +serdes_core_tx_polarity_flip_physical{177}=0xcc +serdes_core_rx_polarity_flip_physical{185}=0x9e +serdes_core_tx_polarity_flip_physical{185}=0x58 +serdes_core_rx_polarity_flip_physical{193}=0x6f +serdes_core_tx_polarity_flip_physical{193}=0x24 +serdes_core_rx_polarity_flip_physical{201}=0x9e +serdes_core_tx_polarity_flip_physical{201}=0xdf +serdes_core_rx_polarity_flip_physical{209}=0x17 +serdes_core_tx_polarity_flip_physical{209}=0xe9 +serdes_core_rx_polarity_flip_physical{217}=0xec +serdes_core_tx_polarity_flip_physical{217}=0x68 + + +dport_map_port_20=1 +dport_map_port_21=2 +dport_map_port_22=3 +dport_map_port_23=4 +dport_map_port_24=5 +dport_map_port_25=6 +dport_map_port_26=7 +dport_map_port_27=8 +dport_map_port_28=9 +dport_map_port_29=10 +dport_map_port_30=11 +dport_map_port_31=12 +dport_map_port_32=13 +dport_map_port_33=14 +dport_map_port_34=15 +dport_map_port_35=16 +dport_map_port_40=17 +dport_map_port_41=18 +dport_map_port_42=19 +dport_map_port_43=20 +dport_map_port_44=21 +dport_map_port_45=22 +dport_map_port_46=23 +dport_map_port_47=24 +dport_map_port_48=25 +dport_map_port_49=26 +dport_map_port_50=27 +dport_map_port_51=28 +dport_map_port_52=29 +dport_map_port_53=30 +dport_map_port_54=31 +dport_map_port_55=32 +dport_map_port_1=33 +dport_map_port_2=34 +dport_map_port_3=35 +dport_map_port_4=36 +dport_map_port_5=37 +dport_map_port_6=38 +dport_map_port_7=39 +dport_map_port_8=40 +dport_map_port_9=41 +dport_map_port_10=42 +dport_map_port_11=43 +dport_map_port_12=44 +dport_map_port_13=45 +dport_map_port_14=46 +dport_map_port_15=47 +dport_map_port_16=48 +dport_map_port_60=49 +dport_map_port_61=50 +dport_map_port_62=51 +dport_map_port_63=52 +dport_map_port_64=53 +dport_map_port_65=54 +dport_map_port_66=55 +dport_map_port_67=56 +dport_map_port_68=57 +dport_map_port_69=58 +dport_map_port_70=59 +dport_map_port_71=60 +dport_map_port_72=61 +dport_map_port_73=62 +dport_map_port_74=63 +dport_map_port_75=64 +dport_map_port_80=65 +dport_map_port_81=66 +dport_map_port_82=67 +dport_map_port_83=68 +dport_map_port_84=69 +dport_map_port_85=70 +dport_map_port_86=71 +dport_map_port_87=72 +dport_map_port_88=73 +dport_map_port_89=74 +dport_map_port_90=75 +dport_map_port_91=76 +dport_map_port_92=77 +dport_map_port_93=78 +dport_map_port_94=79 +dport_map_port_95=80 +dport_map_port_140=81 +dport_map_port_141=82 +dport_map_port_142=83 +dport_map_port_143=84 +dport_map_port_144=85 +dport_map_port_145=86 +dport_map_port_146=87 +dport_map_port_147=88 +dport_map_port_148=89 +dport_map_port_149=90 +dport_map_port_150=91 +dport_map_port_151=92 +dport_map_port_152=93 +dport_map_port_153=94 +dport_map_port_154=95 +dport_map_port_155=96 +dport_map_port_100=97 +dport_map_port_101=98 +dport_map_port_102=99 +dport_map_port_103=100 +dport_map_port_104=101 +dport_map_port_105=102 +dport_map_port_106=103 +dport_map_port_107=104 +dport_map_port_108=105 +dport_map_port_109=106 +dport_map_port_110=107 +dport_map_port_111=108 +dport_map_port_112=109 +dport_map_port_113=110 +dport_map_port_114=111 +dport_map_port_115=112 +dport_map_port_120=113 +dport_map_port_121=114 +dport_map_port_122=115 +dport_map_port_123=116 +dport_map_port_124=117 +dport_map_port_125=118 +dport_map_port_126=119 +dport_map_port_127=120 +dport_map_port_128=121 +dport_map_port_129=122 +dport_map_port_130=123 +dport_map_port_131=124 +dport_map_port_132=125 +dport_map_port_133=126 +dport_map_port_134=127 +dport_map_port_135=128 + +core_clock_frequency=1325 +dpr_clock_frequency=1000 +device_clock_frequency=1325 +port_flex_enable=1 + +#firmware load method, use fast load +load_firmware=0x2 diff --git a/device/celestica/x86_64-cel_silverstone-r0/Silverstone/port_config.ini b/device/celestica/x86_64-cel_silverstone-r0/Silverstone/port_config.ini new file mode 100644 index 000000000000..9cd85ee34798 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/Silverstone/port_config.ini @@ -0,0 +1,33 @@ +# name lanes alias index speed +Ethernet0 33,34,35,36,37,38,39,40 QSFPDD1 1 400000 +Ethernet4 41,42,43,44,45,46,47,48 QSFPDD2 2 400000 +Ethernet8 49,50,51,52,53,54,55,56 QSFPDD3 3 400000 +Ethernet12 57,58,59,60,61,62,63,64 QSFPDD4 4 400000 +Ethernet16 65,66,67,68,69,70,71,72 QSFPDD5 5 400000 +Ethernet20 73,74,75,76,77,78,79,80 QSFPDD6 6 400000 +Ethernet24 81,82,83,84,85,86,87,88 QSFPDD7 7 400000 +Ethernet28 89,90,91,92,93,94,95,96 QSFPDD8 8 400000 +Ethernet32 1,2,3,4,5,6,7,8 QSFPDD9 9 400000 +Ethernet36 9,10,11,12,13,14,15,16 QSFPDD10 10 400000 +Ethernet40 17,18,19,20,21,22,23,24 QSFPDD11 11 400000 +Ethernet44 25,26,27,28,29,30,31,32 QSFPDD12 12 400000 +Ethernet48 97,98,99,100,101,102,103,104 QSFPDD13 13 400000 +Ethernet52 105,106,107,108,109,110,111,112 QSFPDD14 14 400000 +Ethernet56 113,114,115,116,117,118,119,120 QSFPDD15 15 400000 +Ethernet60 121,122,123,124,125,126,127,128 QSFPDD16 16 400000 +Ethernet64 129,130,131,132,133,134,135,136 QSFPDD17 17 400000 +Ethernet68 137,138,139,140,141,142,143,144 QSFPDD18 18 400000 +Ethernet72 145,146,147,148,149,150,151,152 QSFPDD19 19 400000 +Ethernet76 153,154,155,156,157,158,159,160 QSFPDD20 20 400000 +Ethernet80 225,226,227,228,229,230,231,232 QSFPDD21 21 400000 +Ethernet84 233,234,235,236,237,238,239,240 QSFPDD22 22 400000 +Ethernet88 241,242,243,244,245,246,247,248 QSFPDD23 23 400000 +Ethernet92 249,250,251,252,253,254,255,256 QSFPDD24 24 400000 +Ethernet96 161,162,163,164,165,166,167,168 QSFPDD25 25 400000 +Ethernet100 169,170,171,172,173,174,175,176 QSFPDD26 26 400000 +Ethernet104 177,178,179,180,181,182,183,184 QSFPDD27 27 400000 +Ethernet108 185,186,187,188,189,190,191,192 QSFPDD28 28 400000 +Ethernet112 193,194,195,196,197,198,199,200 QSFPDD29 29 400000 +Ethernet116 201,202,203,204,205,206,207,208 QSFPDD30 30 400000 +Ethernet120 209,210,211,212,213,214,215,216 QSFPDD31 31 400000 +Ethernet124 217,218,219,220,221,222,223,224 QSFPDD32 32 400000 \ No newline at end of file diff --git a/device/celestica/x86_64-cel_silverstone-r0/Silverstone/sai.profile b/device/celestica/x86_64-cel_silverstone-r0/Silverstone/sai.profile new file mode 100644 index 000000000000..1915eb9b35a1 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/Silverstone/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/th3-32x400G.config.bcm diff --git a/device/celestica/x86_64-cel_silverstone-r0/Silverstone/th3-32x400G.config.bcm b/device/celestica/x86_64-cel_silverstone-r0/Silverstone/th3-32x400G.config.bcm new file mode 100644 index 000000000000..5e5fc82aeace --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/Silverstone/th3-32x400G.config.bcm @@ -0,0 +1,231 @@ + +pbmp_xport_xe.0=0x8111181111c1111811118111181111c111182222 +ccm_dma_enable=0 +ccmdma_intr_enable=0 +ctr_evict_enable=0 +mem_cache_enable=0 +parity_correction=0 +parity_enable=0 +phy_enable=0 +phy_null=1 +pll_bypass=1 + +init_all_modules=0 + + + +#portmap_38=257:10 +#portmap_118=258:10 + + +portmap_20=33:400 +portmap_24=41:400 +portmap_28=49:400 +portmap_32=57:400 +portmap_40=65:400 +portmap_44=73:400 +portmap_48=81:400 +portmap_52=89:400 +portmap_1=1:400 +portmap_5=9:400 +portmap_9=17:400 +portmap_13=25:400 +portmap_60=97:400 +portmap_64=105:400 +portmap_68=113:400 +portmap_72=121:400 +portmap_80=129:400 +portmap_84=137:400 +portmap_88=145:400 +portmap_92=153:400 +portmap_140=225:400 +portmap_144=233:400 +portmap_148=241:400 +portmap_152=249:400 +portmap_100=161:400 +portmap_104=169:400 +portmap_108=177:400 +portmap_112=185:400 +portmap_120=193:400 +portmap_124=201:400 +portmap_128=209:400 +portmap_132=217:400 + +phy_chain_rx_lane_map_physical{33.0}=0x65732041 +phy_chain_tx_lane_map_physical{33.0}=0x47206531 +phy_chain_rx_lane_map_physical{41.0}=0x07561243 +phy_chain_tx_lane_map_physical{41.0}=0x36207514 +phy_chain_rx_lane_map_physical{49.0}=0x54632071 +phy_chain_tx_lane_map_physical{49.0}=0x06241735 +phy_chain_rx_lane_map_physical{57.0}=0x07561243 +phy_chain_tx_lane_map_physical{57.0}=0x35207614 +phy_chain_rx_lane_map_physical{65.0}=0x45623170 +phy_chain_tx_lane_map_physical{65.0}=0x51260734 +phy_chain_rx_lane_map_physical{73.0}=0x07561243 +phy_chain_tx_lane_map_physical{73.0}=0x37245610 +phy_chain_rx_lane_map_physical{81.0}=0x45632071 +phy_chain_tx_lane_map_physical{81.0}=0x51260734 +phy_chain_rx_lane_map_physical{89.0}=0x07561243 +phy_chain_tx_lane_map_physical{89.0}=0x26437510 +phy_chain_rx_lane_map_physical{1.0}=0x30176524 +phy_chain_tx_lane_map_physical{1.0}=0x20615374 +phy_chain_rx_lane_map_physical{9.0}=0x37562041 +phy_chain_tx_lane_map_physical{9.0}=0x05176432 +phy_chain_rx_lane_map_physical{17.0}=0x43607251 +phy_chain_tx_lane_map_physical{17.0}=0x70261435 +phy_chain_rx_lane_map_physical{25.0}=0x60347125 +phy_chain_tx_lane_map_physical{25.0}=0x46357120 +phy_chain_rx_lane_map_physical{97.0}=0x47601352 +phy_chain_tx_lane_map_physical{97.0}=0x04265137 +phy_chain_rx_lane_map_physical{105.0}=0x73206415 +phy_chain_tx_lane_map_physical{105.0}=0x26374150 +phy_chain_rx_lane_map_physical{113.0}=0x47632051 +phy_chain_tx_lane_map_physical{113.0}=0x03254617 +phy_chain_rx_lane_map_physical{121.0}=0x63027415 +phy_chain_tx_lane_map_physical{121.0}=0x63721045 +phy_chain_rx_lane_map_physical{129.0}=0x30154627 +phy_chain_tx_lane_map_physical{129.0}=0x04735261 +phy_chain_rx_lane_map_physical{137.0}=0x24753061 +phy_chain_tx_lane_map_physical{137.0}=0x37614520 +phy_chain_rx_lane_map_physical{145.0}=0x47601352 +phy_chain_tx_lane_map_physical{145.0}=0x63274510 +phy_chain_rx_lane_map_physical{153.0}=0x07361524 +phy_chain_tx_lane_map_physical{153.0}=0x36527104 +phy_chain_rx_lane_map_physical{225.0}=0x56410273 +phy_chain_tx_lane_map_physical{225.0}=0x10274635 +phy_chain_rx_lane_map_physical{233.0}=0x15740263 +phy_chain_tx_lane_map_physical{233.0}=0x24351607 +phy_chain_rx_lane_map_physical{241.0}=0x74015263 +phy_chain_tx_lane_map_physical{241.0}=0x04152637 +phy_chain_rx_lane_map_physical{249.0}=0x62037514 +phy_chain_tx_lane_map_physical{249.0}=0x72453160 +phy_chain_rx_lane_map_physical{161.0}=0x46510273 +phy_chain_tx_lane_map_physical{161.0}=0x01653724 +phy_chain_rx_lane_map_physical{169.0}=0x25743160 +phy_chain_tx_lane_map_physical{169.0}=0x07216435 +phy_chain_rx_lane_map_physical{177.0}=0x46510273 +phy_chain_tx_lane_map_physical{177.0}=0x01652734 +phy_chain_rx_lane_map_physical{185.0}=0x25743160 +phy_chain_tx_lane_map_physical{185.0}=0x37016425 +phy_chain_rx_lane_map_physical{193.0}=0x46510372 +phy_chain_tx_lane_map_physical{193.0}=0x06153724 +phy_chain_rx_lane_map_physical{201.0}=0x25743160 +phy_chain_tx_lane_map_physical{201.0}=0x36017524 +phy_chain_rx_lane_map_physical{209.0}=0x47601352 +phy_chain_tx_lane_map_physical{209.0}=0x04152736 +phy_chain_rx_lane_map_physical{217.0}=0x26453170 +phy_chain_tx_lane_map_physical{217.0}=0x36027415 + +serdes_core_rx_polarity_flip_physical{33}=0x29 +serdes_core_tx_polarity_flip_physical{33}=0xfe +serdes_core_rx_polarity_flip_physical{41}=0xb1 +serdes_core_tx_polarity_flip_physical{41}=0xe8 +serdes_core_rx_polarity_flip_physical{49}=0xca +serdes_core_tx_polarity_flip_physical{49}=0xb6 +serdes_core_rx_polarity_flip_physical{57}=0x9b +serdes_core_tx_polarity_flip_physical{57}=0xdc +serdes_core_rx_polarity_flip_physical{65}=0x17 +serdes_core_tx_polarity_flip_physical{65}=0x86 +serdes_core_rx_polarity_flip_physical{73}=0x9b +serdes_core_tx_polarity_flip_physical{73}=0x55 +serdes_core_rx_polarity_flip_physical{81}=0xa +serdes_core_tx_polarity_flip_physical{81}=0x6 +serdes_core_rx_polarity_flip_physical{89}=0x9b +serdes_core_tx_polarity_flip_physical{89}=0x48 +serdes_core_rx_polarity_flip_physical{1}=0xec +serdes_core_tx_polarity_flip_physical{1}=0x56 +serdes_core_rx_polarity_flip_physical{9}=0x13 +serdes_core_tx_polarity_flip_physical{9}=0xa6 +serdes_core_rx_polarity_flip_physical{17}=0x5a +serdes_core_tx_polarity_flip_physical{17}=0xc6 +serdes_core_rx_polarity_flip_physical{25}=0xf +serdes_core_tx_polarity_flip_physical{25}=0x4e +serdes_core_rx_polarity_flip_physical{97}=0x17 +serdes_core_tx_polarity_flip_physical{97}=0x2e +serdes_core_rx_polarity_flip_physical{105}=0xce +serdes_core_tx_polarity_flip_physical{105}=0x7c +serdes_core_rx_polarity_flip_physical{113}=0xa +serdes_core_tx_polarity_flip_physical{113}=0x35 + +serdes_core_rx_polarity_flip_physical{121}=0xb9 +serdes_core_tx_polarity_flip_physical{121}=0xef +serdes_core_rx_polarity_flip_physical{129}=0xe8 +serdes_core_tx_polarity_flip_physical{129}=0xac +serdes_core_rx_polarity_flip_physical{137}=0xcb +serdes_core_tx_polarity_flip_physical{137}=0x9c +serdes_core_rx_polarity_flip_physical{145}=0x17 +serdes_core_tx_polarity_flip_physical{145}=0x32 +serdes_core_rx_polarity_flip_physical{153}=0xb9 +serdes_core_tx_polarity_flip_physical{153}=0xaf +serdes_core_rx_polarity_flip_physical{225}=0xaa +serdes_core_tx_polarity_flip_physical{225}=0x7 +serdes_core_rx_polarity_flip_physical{233}=0x31 +serdes_core_tx_polarity_flip_physical{233}=0x47 +serdes_core_rx_polarity_flip_physical{241}=0xe8 +serdes_core_tx_polarity_flip_physical{241}=0x9e +serdes_core_rx_polarity_flip_physical{249}=0xec +serdes_core_tx_polarity_flip_physical{249}=0x1f +serdes_core_rx_polarity_flip_physical{161}=0x6a +serdes_core_tx_polarity_flip_physical{161}=0xd4 +serdes_core_rx_polarity_flip_physical{169}=0x9e +serdes_core_tx_polarity_flip_physical{169}=0x7b +serdes_core_rx_polarity_flip_physical{177}=0x6a +serdes_core_tx_polarity_flip_physical{177}=0xcc +serdes_core_rx_polarity_flip_physical{185}=0x9e +serdes_core_tx_polarity_flip_physical{185}=0x58 +serdes_core_rx_polarity_flip_physical{193}=0x6f +serdes_core_tx_polarity_flip_physical{193}=0x24 +serdes_core_rx_polarity_flip_physical{201}=0x9e +serdes_core_tx_polarity_flip_physical{201}=0xdf +serdes_core_rx_polarity_flip_physical{209}=0x17 +serdes_core_tx_polarity_flip_physical{209}=0xe9 +serdes_core_rx_polarity_flip_physical{217}=0xec +serdes_core_tx_polarity_flip_physical{217}=0x68 + +dport_map_port_20=1 +dport_map_port_24=2 +dport_map_port_28=3 +dport_map_port_32=4 +dport_map_port_40=5 +dport_map_port_44=6 +dport_map_port_48=7 +dport_map_port_52=8 +dport_map_port_1=9 +dport_map_port_5=10 +dport_map_port_9=11 +dport_map_port_13=12 +dport_map_port_60=13 +dport_map_port_64=14 +dport_map_port_68=15 +dport_map_port_72=16 +dport_map_port_80=17 +dport_map_port_84=18 +dport_map_port_88=19 +dport_map_port_92=20 +dport_map_port_140=21 +dport_map_port_144=22 +dport_map_port_148=23 +dport_map_port_152=24 +dport_map_port_100=25 +dport_map_port_104=26 +dport_map_port_108=27 +dport_map_port_112=28 +dport_map_port_120=29 +dport_map_port_124=30 +dport_map_port_128=31 +dport_map_port_132=32 + +#dport_map_port_38=33 +#dport_map_port_118=34 + + + +core_clock_frequency=1325 +dpr_clock_frequency=1000 +device_clock_frequency=1325 +port_flex_enable=1 + +#firmware load method, use fast load +load_firmware=0x2 + + diff --git a/device/celestica/x86_64-cel_silverstone-r0/custom.bin b/device/celestica/x86_64-cel_silverstone-r0/custom.bin new file mode 100644 index 0000000000000000000000000000000000000000..a08ba6c06661ed90e3aa17c0239615b96259b509 GIT binary patch literal 1216 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 literal 0 HcmV?d00001 diff --git a/device/celestica/x86_64-cel_silverstone-r0/plugins/eeprom.py b/device/celestica/x86_64-cel_silverstone-r0/plugins/eeprom.py new file mode 100644 index 000000000000..34c50a6ce31f --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/plugins/eeprom.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica Silverstone +# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + + +class board(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self, name, path, cpld_root, ro): + self.eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0056/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) + diff --git a/device/celestica/x86_64-cel_silverstone-r0/plugins/psuutil.py b/device/celestica/x86_64-cel_silverstone-r0/plugins/psuutil.py new file mode 100644 index 000000000000..d5e197e82d2b --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/plugins/psuutil.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python + +import os.path +import subprocess +import sys +import re + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + self.ipmi_raw = "docker exec -ti pmon ipmitool raw 0x4 0x2d" + self.psu1_id = "0x2f" + self.psu2_id = "0x39" + PsuBase.__init__(self) + + def run_command(self, command): + proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) + (out, err) = proc.communicate() + + if proc.returncode != 0: + sys.exit(proc.returncode) + + return out + + def find_value(self, in_string): + result = re.search("^.+ ([0-9a-f]{2}) .+$", in_string) + if result: + return result.group(1) + else: + return result + + def get_num_psus(self): + """ + Retrieves the number of PSUs available on the device + :return: An integer, the number of PSUs available on the device + """ + return 2 + + def get_psu_status(self, index): + """ + Retrieves the oprational status of power supply unit (PSU) defined + by 1-based index + :param index: An integer, 1-based index of the PSU of which to query status + :return: Boolean, True if PSU is operating properly, False if PSU is faulty + """ + if index is None: + return False + + psu_id = self.psu1_id if index == 1 else self.psu2_id + res_string = self.run_command(self.ipmi_raw + ' ' + psu_id) + status_byte = self.find_value(res_string) + + if status_byte is None: + return False + + failure_detected = (int(status_byte, 16) >> 1) & 1 + input_lost = (int(status_byte, 16) >> 3) & 1 + if failure_detected or input_lost: + return False + else: + return True + + def get_psu_presence(self, index): + """ + Retrieves the presence status of power supply unit (PSU) defined + by 1-based index + :param index: An integer, 1-based index of the PSU of which to query status + :return: Boolean, True if PSU is plugged, False if not + """ + if index is None: + return False + + psu_id = self.psu1_id if index == 1 else self.psu2_id + res_string = self.run_command(self.ipmi_raw + ' ' + psu_id) + status_byte = self.find_value(res_string) + + if status_byte is None: + return False + + presence = ( int(status_byte, 16) >> 0 ) & 1 + if presence: + return True + else: + return False \ No newline at end of file diff --git a/device/celestica/x86_64-cel_silverstone-r0/plugins/sfputil.py b/device/celestica/x86_64-cel_silverstone-r0/plugins/sfputil.py new file mode 100755 index 000000000000..33b761b9397a --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/plugins/sfputil.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +# +# Platform-specific SFP transceiver interface for SONiC +# This plugin supports QSFP-DD, QSFP and SFP. + +try: + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 34 + OSFP_PORT_START = 1 + OSFP_PORT_END = 32 + SFP_PORT_START = 33 + SFP_PORT_END = 34 + + EEPROM_OFFSET = 9 + PORT_INFO_PATH = '/sys/class/silverstone_fpga' + + _port_name = "" + _port_to_eeprom_mapping = {} + _port_to_i2cbus_mapping = {} + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return [] + + @property + def osfp_ports(self): + return range(self.OSFP_PORT_START, self.OSFP_PORT_END + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + @property + def port_to_i2cbus_mapping(self): + return self._port_to_i2cbus_mapping + + def get_port_name(self, port_num): + if port_num in self.osfp_ports: + self._port_name = "QSFP" + str(port_num - self.OSFP_PORT_START + 1) + else: + self._port_name = "SFP" + str(port_num - self.SFP_PORT_START + 1) + return self._port_name + + def get_eeprom_dom_raw(self, port_num): + if port_num in self.osfp_ports: + # QSFP DOM EEPROM is also at addr 0x50 and thus also stored in eeprom_ifraw + return None + else: + # Read dom eeprom at addr 0x51 + return self._read_eeprom_devid(port_num, self.DOM_EEPROM_ADDR, 256) + + def __init__(self): + # Override port_to_eeprom_mapping for class initialization + eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + + for x in range(self.PORT_START, self.PORT_END+1): + self.port_to_i2cbus_mapping[x] = (x + self.EEPROM_OFFSET) + self.port_to_eeprom_mapping[x] = eeprom_path.format( + x + self.EEPROM_OFFSET) + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num not in range(self.port_start, self.port_end + 1): + return False + + # Get path for access port presence status + port_name = self.get_port_name(port_num) + sysfs_filename = "qsfp_modprs" if port_num in self.osfp_ports else "sfp_modabs" + reg_path = "/".join([self.PORT_INFO_PATH, port_name, sysfs_filename]) + + # Read status + try: + reg_file = open(reg_path) + content = reg_file.readline().rstrip() + reg_value = int(content) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + # Module present is active low + if reg_value == 0: + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid QSFP port_num + if port_num not in self.osfp_ports: + return False + + try: + port_name = self.get_port_name(port_num) + reg_file = open("/".join([self.PORT_INFO_PATH, + port_name, "qsfp_lpmode"])) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + # Read status + content = reg_file.readline().rstrip() + reg_value = int(content) + # low power mode is active high + if reg_value == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid QSFP port_num + if port_num not in self.osfp_ports: + return False + + try: + port_name = self.get_port_name(port_num) + reg_file = open("/".join([self.PORT_INFO_PATH, + port_name, "qsfp_lpmode"]), "r+") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = hex(lpmode) + + reg_file.seek(0) + reg_file.write(content) + reg_file.close() + + return True + + def reset(self, port_num): + # Check for invalid QSFP port_num + if port_num not in self.osfp_ports: + return False + + try: + port_name = self.get_port_name(port_num) + reg_file = open("/".join([self.PORT_INFO_PATH, + port_name, "qsfp_reset"]), "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + # Convert our register value back to a hex string and write back + reg_file.seek(0) + reg_file.write(hex(0)) + reg_file.close() + + # Sleep 1 second to allow it to settle + time.sleep(1) + + # Flip the bit back high and write back to the register to take port out of reset + try: + reg_file = open( + "/".join([self.PORT_INFO_PATH, port_name, "qsfp_reset"]), "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_file.seek(0) + reg_file.write(hex(1)) + reg_file.close() + + return True + + def get_transceiver_change_event(self, timeout=0): + """ + TBD + """ + raise NotImplementedError diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index 7d50b133ac6f..3582116932b1 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -53,7 +53,8 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(ALPHANETWORKS_SNH60B0_640F_PLATFORM_MODULE) \ $(BRCM_XLR_GTS_PLATFORM_MODULE) \ $(DELTA_AG9032V2A_PLATFORM_MODULE) \ - $(JUNIPER_QFX5210_PLATFORM_MODULE) + $(JUNIPER_QFX5210_PLATFORM_MODULE) \ + $(CEL_SILVERSTONE_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)) diff --git a/platform/broadcom/platform-modules-cel.mk b/platform/broadcom/platform-modules-cel.mk index 1224faaa6750..b7371e3282de 100644 --- a/platform/broadcom/platform-modules-cel.mk +++ b/platform/broadcom/platform-modules-cel.mk @@ -2,9 +2,11 @@ CEL_DX010_PLATFORM_MODULE_VERSION = 0.9 CEL_HALIBURTON_PLATFORM_MODULE_VERSION = 0.9 +CEL_SILVERSTONE_PLATFORM_MODULE_VERSION = 0.9 export CEL_DX010_PLATFORM_MODULE_VERSION export CEL_HALIBURTON_PLATFORM_MODULE_VERSION +export CEL_SILVERSTONE_PLATFORM_MODULE_VERSION CEL_DX010_PLATFORM_MODULE = platform-modules-dx010_$(CEL_DX010_PLATFORM_MODULE_VERSION)_amd64.deb $(CEL_DX010_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-cel @@ -16,4 +18,8 @@ CEL_HALIBURTON_PLATFORM_MODULE = platform-modules-haliburton_$(CEL_HALIBURTON_PL $(CEL_HALIBURTON_PLATFORM_MODULE)_PLATFORM = x86_64-cel_e1031-r0 $(eval $(call add_extra_package,$(CEL_DX010_PLATFORM_MODULE),$(CEL_HALIBURTON_PLATFORM_MODULE))) +CEL_SILVERSTONE_PLATFORM_MODULE = platform-modules-silverstone_$(CEL_SILVERSTONE_PLATFORM_MODULE_VERSION)_amd64.deb +$(CEL_SILVERSTONE_PLATFORM_MODULE)_PLATFORM = x86_64-cel_silverstone-r0 +$(eval $(call add_extra_package,$(CEL_DX010_PLATFORM_MODULE),$(CEL_SILVERSTONE_PLATFORM_MODULE))) + SONIC_STRETCH_DEBS += $(CEL_DX010_PLATFORM_MODULE) diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/control b/platform/broadcom/sonic-platform-modules-cel/debian/control index 445189822039..2e9b578872fa 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/control +++ b/platform/broadcom/sonic-platform-modules-cel/debian/control @@ -15,3 +15,8 @@ Package: platform-modules-haliburton Architecture: amd64 Depends: linux-image-4.9.0-9-2-amd64 Description: kernel modules for platform devices such as fan, led, sfp + +Package: platform-modules-silverstone +Architecture: amd64 +Depends: linux-image-4.9.0-9-2-amd64 +Description: kernel modules for platform devices such as led, sfp. diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.init new file mode 100644 index 000000000000..c1d4c10b48fc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.init @@ -0,0 +1,49 @@ +#!/bin/bash + +### BEGIN INIT INFO +# Provides: setup-board +# Required-Start: $portmap +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Setup SilverStone board. +### END INIT INFO + + +case "$1" in +start) + echo -n "Setting up board... " + + modprobe i2c-dev + modprobe baseboard-lpc + modprobe switchboard + modprobe mc24lc64t + modprobe ipmi_devintf + + # Instantiate TLV EEPROM device on I801 bus + devname=`cat /sys/bus/i2c/devices/i2c-0/name` + if [[ $devname == 'SMBus I801 adapter at '* ]]; then + echo 24lc64t 0x56 > /sys/bus/i2c/devices/i2c-0/new_device + fi + decode-syseeprom --init 2> /dev/null & + + echo "done." + ;; + +stop) + echo "done." + ;; + +force-reload|restart) + echo "Not supported" + ;; + +*) + echo "Usage: /etc/init.d/platform-modules-silverstone.init {start|stop}" + exit 1 + ;; +esac + +exit 0 \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install new file mode 100644 index 000000000000..a3a8b3d424a1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install @@ -0,0 +1,2 @@ +silverstone/cfg/silverstone-modules.conf etc/modules-load.d +silverstone/systemd/platform-modules-silverstone.service lib/systemd/system \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.postinst new file mode 100644 index 000000000000..771057bed0dc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.postinst @@ -0,0 +1,3 @@ +depmod -a +systemctl enable platform-modules-silverstone.service +systemctl start platform-modules-silverstone.service \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/rules b/platform/broadcom/sonic-platform-modules-cel/debian/rules index 6f35290bce26..dd5452ccaa11 100755 --- a/platform/broadcom/sonic-platform-modules-cel/debian/rules +++ b/platform/broadcom/sonic-platform-modules-cel/debian/rules @@ -5,7 +5,7 @@ export INSTALL_MOD_DIR:=extra KVERSION ?= $(shell uname -r) KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) -MODULE_DIRS:= dx010 haliburton +MODULE_DIRS:= dx010 haliburton silverstone %: dh $@ diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/cfg/silverstone-modules.conf b/platform/broadcom/sonic-platform-modules-cel/silverstone/cfg/silverstone-modules.conf new file mode 100644 index 000000000000..cb8dcf640ba3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/cfg/silverstone-modules.conf @@ -0,0 +1,15 @@ +# /etc/modules: kernel modules to load at boot time. +# +# This file contains the names of kernel modules that should be loaded +# at boot time, one per line. Lines beginning with "#" are ignored. + +i2c-i801 +i2c-isch +i2c-ismt +i2c-dev +i2c-mux +i2c-smbus + +i2c-mux-pca954x +ipmi_devintf +ipmi_si \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/Makefile b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/Makefile new file mode 100644 index 000000000000..f6ad4d9ba4d1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/Makefile @@ -0,0 +1 @@ +obj-m := baseboard-lpc.o mc24lc64t.o switchboard.o \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/baseboard-lpc.c b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/baseboard-lpc.c new file mode 100644 index 000000000000..b6291f7d3ce4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/baseboard-lpc.c @@ -0,0 +1,433 @@ +/* + * baseboard-lpc.c - The CPLD driver for the Base Board of Silverstone + * The driver implement sysfs to access CPLD register on the baseboard of Silverstone via LPC bus. + * Copyright (C) 2018 Celestica 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 Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "baseboard-lpc" +/** + * CPLD register address for read and write. + */ +#define VERSION_ADDR 0xA100 +#define SCRATCH_ADDR 0xA101 +#define BLT_MONTH_ADDR 0xA102 +#define BLT_DATE_ADDR 0xA103 +#define REBOOT_CAUSE 0xA106 +#define SYS_LED_ADDR 0xA162 +#define CPLD_REGISTER_SIZE 0x93 + +/* System reboot cause recorded in CPLD */ +static const struct { + const char *reason; + u8 reset_code; +} reboot_causes[] = { + {"POR", 0x11}, + {"soft-warm-rst", 0x22}, + {"soft-cold-rst", 0x33}, + {"warm-rst", 0x44}, + {"cold-rst", 0x55}, + {"wdt-rst", 0x66}, + {"power-cycle", 0x77} +}; + +struct cpld_b_data { + struct mutex cpld_lock; + uint16_t read_addr; +}; + +struct cpld_b_data *cpld_data; + +static ssize_t scratch_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + unsigned char data = 0; + mutex_lock(&cpld_data->cpld_lock); + data = inb(SCRATCH_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + return sprintf(buf,"0x%2.2x\n", data); +} + +static ssize_t scratch_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + unsigned long data; + char *last; + + mutex_lock(&cpld_data->cpld_lock); + data = (uint16_t)strtoul(buf,&last,16); + if(data == 0 && buf == last){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + outb(data, SCRATCH_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + return count; +} +static DEVICE_ATTR_RW(scratch); + + +/* CPLD version attributes */ +static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 version; + mutex_lock(&cpld_data->cpld_lock); + version = inb(VERSION_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + return sprintf(buf, "%d.%d\n", version >> 4, version & 0x0F); +} +static DEVICE_ATTR_RO(version); + +/* CPLD version attributes */ +static ssize_t build_date_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 month, day_of_month; + mutex_lock(&cpld_data->cpld_lock); + day_of_month = inb(BLT_DATE_ADDR); + month = inb(BLT_MONTH_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + return sprintf(buf, "%x/%x\n", day_of_month, month); +} +static DEVICE_ATTR_RO(build_date); + + +static ssize_t getreg_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + uint16_t addr; + char *last; + + addr = (uint16_t)strtoul(buf,&last,16); + if(addr == 0 && buf == last){ + return -EINVAL; + } + cpld_data->read_addr = addr; + return count; +} + +static ssize_t getreg_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int len = 0; + + mutex_lock(&cpld_data->cpld_lock); + len = sprintf(buf, "0x%2.2x\n",inb(cpld_data->read_addr)); + mutex_unlock(&cpld_data->cpld_lock); + return len; +} +static DEVICE_ATTR_RW(getreg); + +static ssize_t setreg_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + uint16_t addr; + uint8_t value; + char *tok; + char clone[count]; + char *pclone = clone; + char *last; + + strcpy(clone, buf); + + mutex_lock(&cpld_data->cpld_lock); + tok = strsep((char**)&pclone, " "); + if(tok == NULL){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + addr = (uint16_t)strtoul(tok,&last,16); + if(addr == 0 && tok == last){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + + tok = strsep((char**)&pclone, " "); + if(tok == NULL){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + value = (uint8_t)strtoul(tok,&last,16); + if(value == 0 && tok == last){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + + outb(value,addr); + mutex_unlock(&cpld_data->cpld_lock); + return count; +} +static DEVICE_ATTR_WO(setreg); + +/** + * Read all CPLD register in binary mode. + */ +static ssize_t dump_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + unsigned long i=0; + ssize_t status; + + mutex_lock(&cpld_data->cpld_lock); +begin: + if(i < count){ + buf[i++] = inb(VERSION_ADDR + off); + off++; + msleep(1); + goto begin; + } + status = count; + + mutex_unlock(&cpld_data->cpld_lock); + return status; +} +static BIN_ATTR_RO(dump, CPLD_REGISTER_SIZE); + +/** + * Show system led status - on/off/1hz/4hz + * @return Hex string read from scratch register. + */ +static ssize_t sys_led_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + unsigned char data = 0; + mutex_lock(&cpld_data->cpld_lock); + data = inb(SYS_LED_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + data = data & 0x3; + return sprintf(buf, "%s\n", + data == 0x03 ? "off" : data == 0x02 ? "4hz" : data ==0x01 ? "1hz": "on"); +} + +/** + * Set the status of system led - on/off/1hz/4hz + */ +static ssize_t sys_led_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + unsigned char led_status,data; + if(sysfs_streq(buf, "off")){ + led_status = 0x03; + }else if(sysfs_streq(buf, "4hz")){ + led_status = 0x02; + }else if(sysfs_streq(buf, "1hz")){ + led_status = 0x01; + }else if(sysfs_streq(buf, "on")){ + led_status = 0x00; + }else{ + count = -EINVAL; + return count; + } + mutex_lock(&cpld_data->cpld_lock); + data = inb(SYS_LED_ADDR); + data = data & ~(0x3); + data = data | led_status; + outb(data, SYS_LED_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + return count; +} +static DEVICE_ATTR_RW(sys_led); + +/** + * Show system led color - both/green/yellow/none + * @return Current led color. + */ +static ssize_t sys_led_color_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + unsigned char data = 0; + mutex_lock(&cpld_data->cpld_lock); + data = inb(SYS_LED_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + data = (data >> 4) & 0x3; + return sprintf(buf, "%s\n", + data == 0x03 ? "off" : data == 0x02 ? "yellow" : data ==0x01 ? "green": "both"); +} + +/** + * Set the color of system led - both/green/yellow/none + */ +static ssize_t sys_led_color_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + unsigned char led_status,data; + if(sysfs_streq(buf, "off")){ + led_status = 0x03; + }else if(sysfs_streq(buf, "yellow")){ + led_status = 0x02; + }else if(sysfs_streq(buf, "green")){ + led_status = 0x01; + }else if(sysfs_streq(buf, "both")){ + led_status = 0x00; + }else{ + count = -EINVAL; + return count; + } + mutex_lock(&cpld_data->cpld_lock); + data = inb(SYS_LED_ADDR); + data = data & ~( 0x3 << 4); + data = data | (led_status << 4); + outb(data, SYS_LED_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + return count; +} +static DEVICE_ATTR_RW(sys_led_color); + +static ssize_t reboot_cause_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t status; + u8 reg; + int i; + + mutex_lock(&cpld_data->cpld_lock); + reg = inb(REBOOT_CAUSE); + mutex_unlock(&cpld_data->cpld_lock); + + status = 0; + dev_dbg(dev,"reboot: 0x%x\n", (u8)reg); + for(i = 0; i < ARRAY_SIZE(reboot_causes); i++){ + if((u8)reg == reboot_causes[i].reset_code){ + status = sprintf(buf, "%s\n", + reboot_causes[i].reason); + break; + } + } + return status; +} +DEVICE_ATTR_RO(reboot_cause); + +static struct attribute *cpld_b_attrs[] = { + &dev_attr_version.attr, + &dev_attr_build_date.attr, + &dev_attr_scratch.attr, + &dev_attr_getreg.attr, + &dev_attr_setreg.attr, + &dev_attr_sys_led.attr, + &dev_attr_sys_led_color.attr, + &dev_attr_reboot_cause.attr, + NULL, +}; + +static struct bin_attribute *cpld_b_bin_attrs[] = { + &bin_attr_dump, + NULL, +}; + +static struct attribute_group cpld_b_attrs_grp = { + .attrs = cpld_b_attrs, + .bin_attrs = cpld_b_bin_attrs, +}; + +static struct resource cpld_b_resources[] = { + { + .start = 0xA100, + .end = 0xA192, + .flags = IORESOURCE_IO, + }, +}; + +static void cpld_b_dev_release( struct device * dev) +{ + return; +} + +static struct platform_device cpld_b_dev = { + .name = DRIVER_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(cpld_b_resources), + .resource = cpld_b_resources, + .dev = { + .release = cpld_b_dev_release, + } +}; + +static int cpld_b_drv_probe(struct platform_device *pdev) +{ + struct resource *res; + int err = 0; + + cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct cpld_b_data), + GFP_KERNEL); + if (!cpld_data) + return -ENOMEM; + + mutex_init(&cpld_data->cpld_lock); + + cpld_data->read_addr = VERSION_ADDR; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (unlikely(!res)) { + printk(KERN_ERR "Specified Resource Not Available...\n"); + return -ENODEV; + } + + err = sysfs_create_group(&pdev->dev.kobj, &cpld_b_attrs_grp); + if (err) { + printk(KERN_ERR "Cannot create sysfs for baseboard CPLD\n"); + return err; + } + return 0; +} + +static int cpld_b_drv_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &cpld_b_attrs_grp); + return 0; +} + +static struct platform_driver cpld_b_drv = { + .probe = cpld_b_drv_probe, + .remove = __exit_p(cpld_b_drv_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + +int cpld_b_init(void) +{ + // Register platform device and platform driver + platform_device_register(&cpld_b_dev); + platform_driver_register(&cpld_b_drv); + return 0; +} + +void cpld_b_exit(void) +{ + // Unregister platform device and platform driver + platform_driver_unregister(&cpld_b_drv); + platform_device_unregister(&cpld_b_dev); +} + +module_init(cpld_b_init); +module_exit(cpld_b_exit); + + +MODULE_AUTHOR("Celestica Inc."); +MODULE_DESCRIPTION("Celestica Silverstone CPLD baseboard driver"); +MODULE_VERSION("0.2.0"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/mc24lc64t.c b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/mc24lc64t.c new file mode 100644 index 000000000000..fc15bb74b68d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/mc24lc64t.c @@ -0,0 +1,174 @@ +/* + * mc24lc64t.c - driver for Microchip 24LC64T + * + * Copyright (C) 2017 Celestica 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 Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define EEPROM_SIZE 8192 //mc24lt64t eeprom size in bytes. + +struct mc24lc64t_data { + struct mutex update_lock; +}; + +static ssize_t mc24lc64t_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct i2c_client *client = kobj_to_i2c_client(kobj); + struct mc24lc64t_data *drvdata = i2c_get_clientdata(client); + unsigned long timeout, read_time, i = 0; + int status; + + mutex_lock(&drvdata->update_lock); + + if (i2c_smbus_write_byte_data(client, off>>8, off)) + { + status = -EIO; + goto exit; + } + + msleep(1); + +begin: + + if (i < count) + { + timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/ + do { + read_time = jiffies; + + status = i2c_smbus_read_byte(client); + if (status >= 0) + { + buf[i++] = status; + goto begin; + } + } while (time_before(read_time, timeout)); + + status = -ETIMEDOUT; + goto exit; + } + + status = count; + +exit: + mutex_unlock(&drvdata->update_lock); + + return status; +} + + +static ssize_t mc24lc64t_write (struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count){ + + struct i2c_client *client = kobj_to_i2c_client(kobj); + struct mc24lc64t_data *drvdata = i2c_get_clientdata(client); + unsigned long timeout, write_time, i = 0; + int status; + u16 value; + + mutex_lock(&drvdata->update_lock); + +begin: + if (i < count){ + timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/ + value = (buf[i] << 8 | ( off &0xff)); + do { + write_time = jiffies; + status = i2c_smbus_write_word_data(client, off>>8, value); + if (status >= 0) + { + // increase offset + off++; + // increase buffer index + i++; + goto begin; + } + } while (time_before(write_time, timeout)); + status = -ETIMEDOUT; + goto exit; + } + status = count; + +exit: + mutex_unlock(&drvdata->update_lock); + return status; +} + + +static struct bin_attribute mc24lc64t_bit_attr = { + .attr = { + .name = "eeprom", + .mode = S_IRUGO | S_IWUGO, + }, + .size = EEPROM_SIZE, + .read = mc24lc64t_read, + .write = mc24lc64t_write, +}; + +static int mc24lc64t_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = client->adapter; + struct mc24lc64t_data *drvdata; + int err; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA + | I2C_FUNC_SMBUS_READ_BYTE)) + return -EPFNOSUPPORT; + + if (!(drvdata = devm_kzalloc(&client->dev, + sizeof(struct mc24lc64t_data), GFP_KERNEL))) + return -ENOMEM; + + i2c_set_clientdata(client, drvdata); + mutex_init(&drvdata->update_lock); + + err = sysfs_create_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr); + return err; +} + +static int mc24lc64t_remove(struct i2c_client *client) +{ + struct mc24lc64t_data *drvdata = i2c_get_clientdata(client); + sysfs_remove_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr); + + return 0; +} + +static const struct i2c_device_id mc24lc64t_id[] = { + { "24lc64t", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mc24lc64t_id); + +static struct i2c_driver mc24lc64t_driver = { + .driver = { + .name = "mc24lc64t", + .owner = THIS_MODULE, + }, + .probe = mc24lc64t_probe, + .remove = mc24lc64t_remove, + .id_table = mc24lc64t_id, +}; + +module_i2c_driver(mc24lc64t_driver); + +MODULE_AUTHOR("Abhisit Sangjan "); +MODULE_DESCRIPTION("Microchip 24LC64T Driver"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switchboard.c b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switchboard.c new file mode 100644 index 000000000000..2ee6c858a8b6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switchboard.c @@ -0,0 +1,2106 @@ +/* + * switchboard.c - driver for Silverstone Switch board FPGA/CPLD. + * + * Author: Pradchaya Phucharoen + * + * Copyright (C) 2018 Celestica 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 Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * / + * \--sys + * \--devices + * \--platform + * \--silverstone + * |--FPGA + * |--CPLD1 + * |--CPLD2 + * \--SFF + * |--QSFP[1..32] + * \--SFP[1..2] + * + */ + +#ifndef TEST_MODE +#define MOD_VERSION "1.2.0" +#else +#define MOD_VERSION "TEST" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int majorNumber; + +#define CLASS_NAME "silverstone_fpga" +#define DRIVER_NAME "switchboard" +#define FPGA_PCI_NAME "Silverstone_fpga_pci" +#define DEVICE_NAME "fwupgrade" + + +static int smbus_access(struct i2c_adapter *adapter, u16 addr, + unsigned short flags, char rw, u8 cmd, + int size, union i2c_smbus_data *data); + +static int fpga_i2c_access(struct i2c_adapter *adapter, u16 addr, + unsigned short flags, char rw, u8 cmd, + int size, union i2c_smbus_data *data); + +static int fpgafw_init(void); +static void fpgafw_exit(void); + + +/* +======================================== +FPGA PCIe BAR 0 Registers +======================================== +Misc Control 0x00000000 – 0x000000FF. +I2C_CH1 0x00000100 - 0x00000110 +I2C_CH2 0x00000200 - 0x00000210. +I2C_CH3 0x00000300 - 0x00000310. +I2C_CH4 0x00000400 - 0x00000410. +I2C_CH5 0x00000500 - 0x00000510. +I2C_CH6 0x00000600 - 0x00000610. +I2C_CH7 0x00000700 - 0x00000710. +I2C_CH8 0x00000800 - 0x00000810. +I2C_CH9 0x00000900 - 0x00000910. +I2C_CH10 0x00000A00 - 0x00000A10. +I2C_CH11 0x00000B00 - 0x00000B10. +I2C_CH12 0x00000C00 - 0x00000C10. +I2C_CH13 0x00000D00 - 0x00000D10. +SPI Master 0x00001200 - 0x00001300. +DPLL SPI Master 0x00001320 - 0x0000132F. +PORT XCVR 0x00004000 - 0x00004FFF. +*/ + +/* MISC */ +#define FPGA_VERSION 0x0000 +#define FPGA_VERSION_MJ_MSK 0xff00 +#define FPGA_VERSION_MN_MSK 0x00ff +#define FPGA_SCRATCH 0x0004 +#define FPGA_BROAD_TYPE 0x0008 +#define FPGA_BROAD_REV_MSK 0x0038 +#define FPGA_BROAD_ID_MSK 0x0007 +#define FPGA_PLL_STATUS 0x0014 +#define BMC_I2C_SCRATCH 0x0020 +#define FPGA_SLAVE_CPLD_REST 0x0030 +#define FPGA_PERIPH_RESET_CTRL 0x0034 +#define FPGA_INT_STATUS 0x0040 +#define FPGA_INT_SRC_STATUS 0x0044 +#define FPGA_INT_FLAG 0x0048 +#define FPGA_INT_MASK 0x004c +#define FPGA_MISC_CTRL 0x0050 +#define FPGA_MISC_STATUS 0x0054 +#define FPGA_AVS_VID_STATUS 0x0068 +#define FPGA_PORT_XCVR_READY 0x000c + +/* I2C_MASTER BASE ADDR */ +#define I2C_MASTER_FREQ_1 0x0100 +#define I2C_MASTER_CTRL_1 0x0104 +#define I2C_MASTER_STATUS_1 0x0108 +#define I2C_MASTER_DATA_1 0x010c +#define I2C_MASTER_PORT_ID_1 0x0110 +#define I2C_MASTER_CH_1 1 +#define I2C_MASTER_CH_2 2 +#define I2C_MASTER_CH_3 3 +#define I2C_MASTER_CH_4 4 +#define I2C_MASTER_CH_5 5 +#define I2C_MASTER_CH_6 6 +#define I2C_MASTER_CH_7 7 +#define I2C_MASTER_CH_8 8 +#define I2C_MASTER_CH_9 9 +#define I2C_MASTER_CH_10 10 +#define I2C_MASTER_CH_11 11 +#define I2C_MASTER_CH_12 12 +#define I2C_MASTER_CH_13 13 + +#define I2C_MASTER_CH_TOTAL I2C_MASTER_CH_5 + +/* SPI_MASTER */ +#define SPI_MASTER_WR_EN 0x1200 /* one bit */ +#define SPI_MASTER_WR_DATA 0x1204 /* 32 bits */ +#define SPI_MASTER_CHK_ID 0x1208 /* one bit */ +#define SPI_MASTER_VERIFY 0x120c /* one bit */ +#define SPI_MASTER_STATUS 0x1210 /* 15 bits */ +#define SPI_MASTER_MODULE_RST 0x1214 /* one bit */ + +/* FPGA FRONT PANEL PORT MGMT */ +#define SFF_PORT_CTRL_BASE 0x4000 +#define SFF_PORT_STATUS_BASE 0x4004 +#define SFF_PORT_INT_STATUS_BASE 0x4008 +#define SFF_PORT_INT_MASK_BASE 0x400c + +#define PORT_XCVR_REGISTER_SIZE 0x1000 + +/* PORT CTRL REGISTER +[31:7] RSVD +[6] LPMOD 6 +[5] RSVD +[4] RST 4 +[3:1] RSVD +[0] TXDIS 0 +*/ +#define CTRL_LPMOD 6 +#define CTRL_RST 4 +#define CTRL_TXDIS 0 + +/* PORT STATUS REGISTER +[31:6] RSVD +[5] IRQ 5 +[4] PRESENT 4 +[3] RSVD +[2] TXFAULT 2 +[1] RXLOS 1 +[0] MODABS 0 +*/ +#define STAT_IRQ 5 +#define STAT_PRESENT 4 +#define STAT_TXFAULT 2 +#define STAT_RXLOS 1 +#define STAT_MODABS 0 + +/* PORT INTRPT REGISTER +[31:6] RSVD +[5] INT_N 5 +[4] PRESENT 4 +[3] RSVD +[2] RSVD +[1] RXLOS 1 +[0] MODABS 0 +*/ +#define INTR_INT_N 5 +#define INTR_PRESENT 4 +#define INTR_TXFAULT 2 +#define INTR_RXLOS 1 +#define INTR_MODABS 0 + +/* PORT INT MASK REGISTER +[31:6] RSVD +[5] INT_N 5 +[4] PRESENT 4 +[3] RSVD +[2] RSVD +[1] RXLOS_INT 1 +[0] MODABS 0 +*/ +#define MASK_INT_N 5 +#define MASK_PRESENT 4 +#define MASK_TXFAULT 2 +#define MASK_RXLOS 1 +#define MASK_MODABS 0 + +enum { + I2C_SR_BIT_RXAK = 0, + I2C_SR_BIT_MIF, + I2C_SR_BIT_SRW, + I2C_SR_BIT_BCSTM, + I2C_SR_BIT_MAL, + I2C_SR_BIT_MBB, + I2C_SR_BIT_MAAS, + I2C_SR_BIT_MCF +}; + +enum { + I2C_CR_BIT_BCST = 0, + I2C_CR_BIT_RSTA = 2, + I2C_CR_BIT_TXAK, + I2C_CR_BIT_MTX, + I2C_CR_BIT_MSTA, + I2C_CR_BIT_MIEN, + I2C_CR_BIT_MEN, +}; + +/** + * + * The function is i2c algorithm implement to allow master access to + * correct endpoint devices trough the PCA9548 switch devices. + * + * FPGA I2C Master [mutex resource] + * | + * | + * --------------------------- + * | PCA9548(s) | + * ---1--2--3--4--5--6--7--8-- + * | | | | | | | | + * EEPROM ... EEPROM + * + */ + +#define VIRTUAL_I2C_QSFP_PORT 32 +#define VIRTUAL_I2C_SFP_PORT 2 + +#define SFF_PORT_TOTAL VIRTUAL_I2C_QSFP_PORT + VIRTUAL_I2C_SFP_PORT + +#define VIRTUAL_I2C_BUS_OFFSET 10 +#define CPLD1_SLAVE_ADDR 0x30 +#define CPLD2_SLAVE_ADDR 0x31 + +static struct class* fpgafwclass = NULL; // < The device-driver class struct pointer +static struct device* fpgafwdev = NULL; // < The device-driver device struct pointer + +#define PCI_VENDOR_ID_TEST 0x1af4 + +#ifndef PCI_VENDOR_ID_XILINX +#define PCI_VENDOR_ID_XILINX 0x10EE +#endif + +#define FPGA_PCIE_DEVICE_ID 0x7021 +#define TEST_PCIE_DEVICE_ID 0x1110 + + +#ifdef DEBUG_KERN +#define info(fmt,args...) printk(KERN_INFO "line %3d : "fmt,__LINE__,##args) +#define check(REG) printk(KERN_INFO "line %3d : %-8s = %2.2X",__LINE__,#REG,ioread8(REG)); +#else +#define info(fmt,args...) +#define check(REG) +#endif + +#define GET_REG_BIT(REG,BIT) ((ioread8(REG) >> BIT) & 0x01) +#define SET_REG_BIT_H(REG,BIT) iowrite8(ioread8(REG) | (0x01 << BIT),REG) +#define SET_REG_BIT_L(REG,BIT) iowrite8(ioread8(REG) & ~(0x01 << BIT),REG) + +static struct mutex fpga_i2c_master_locks[I2C_MASTER_CH_TOTAL]; +/* Store lasted switch address and channel */ +static uint16_t fpga_i2c_lasted_access_port[I2C_MASTER_CH_TOTAL]; + +enum PORT_TYPE { + NONE, + QSFP, + SFP +}; + +struct i2c_switch { + unsigned char master_bus; // I2C bus number + unsigned char switch_addr; // PCA9548 device address, 0xFF if directly connect to a bus. + unsigned char channel; // PCA9548 channel number. If the switch_addr is 0xFF, this value is ignored. + enum PORT_TYPE port_type; // QSFP/SFP tranceiver port type. + char calling_name[20]; // Calling name. +}; + +struct i2c_dev_data { + int portid; + struct i2c_switch pca9548; +}; + +/* PREDEFINED I2C SWITCH DEVICE TOPOLOGY */ +static struct i2c_switch fpga_i2c_bus_dev[] = { + /* BUS3 QSFP Exported as virtual bus */ + {I2C_MASTER_CH_3, 0x71, 2, QSFP, "QSFP1"}, {I2C_MASTER_CH_3, 0x71, 3, QSFP, "QSFP2"}, + {I2C_MASTER_CH_3, 0x71, 0, QSFP, "QSFP3"}, {I2C_MASTER_CH_3, 0x71, 1, QSFP, "QSFP4"}, + {I2C_MASTER_CH_3, 0x71, 6, QSFP, "QSFP5"}, {I2C_MASTER_CH_3, 0x71, 5, QSFP, "QSFP6"}, + {I2C_MASTER_CH_3, 0x73, 7, QSFP, "QSFP7"}, {I2C_MASTER_CH_3, 0x71, 4, QSFP, "QSFP8"}, + + {I2C_MASTER_CH_3, 0x73, 4, QSFP, "QSFP9"}, {I2C_MASTER_CH_3, 0x73, 3, QSFP, "QSFP10"}, + {I2C_MASTER_CH_3, 0x73, 6, QSFP, "QSFP11"}, {I2C_MASTER_CH_3, 0x73, 2, QSFP, "QSFP12"}, + {I2C_MASTER_CH_3, 0x73, 1, QSFP, "QSFP13"}, {I2C_MASTER_CH_3, 0x73, 5, QSFP, "QSFP14"}, + {I2C_MASTER_CH_3, 0x71, 7, QSFP, "QSFP15"}, {I2C_MASTER_CH_3, 0x73, 0, QSFP, "QSFP16"}, + + {I2C_MASTER_CH_3, 0x72, 1, QSFP, "QSFP17"}, {I2C_MASTER_CH_3, 0x72, 7, QSFP, "QSFP18"}, + {I2C_MASTER_CH_3, 0x72, 4, QSFP, "QSFP19"}, {I2C_MASTER_CH_3, 0x72, 0, QSFP, "QSFP20"}, + {I2C_MASTER_CH_3, 0x72, 5, QSFP, "QSFP21"}, {I2C_MASTER_CH_3, 0x72, 2, QSFP, "QSFP22"}, + {I2C_MASTER_CH_3, 0x70, 5, QSFP, "QSFP23"}, {I2C_MASTER_CH_3, 0x72, 6, QSFP, "QSFP24"}, + + {I2C_MASTER_CH_3, 0x72, 3, QSFP, "QSFP25"}, {I2C_MASTER_CH_3, 0x70, 6, QSFP, "QSFP26"}, + {I2C_MASTER_CH_3, 0x70, 0, QSFP, "QSFP27"}, {I2C_MASTER_CH_3, 0x70, 7, QSFP, "QSFP28"}, + {I2C_MASTER_CH_3, 0x70, 2, QSFP, "QSFP29"}, {I2C_MASTER_CH_3, 0x70, 4, QSFP, "QSFP30"}, + {I2C_MASTER_CH_3, 0x70, 3, QSFP, "QSFP31"}, {I2C_MASTER_CH_3, 0x70, 1, QSFP, "QSFP32"}, + /* BUS1 SFP+ Exported as virtual bus */ + {I2C_MASTER_CH_1, 0xFF, 0, SFP, "SFP1"}, + /* BUS2 SFP+ Exported as virtual bus */ + {I2C_MASTER_CH_2, 0xFF, 0, SFP, "SFP2"}, + /* BUS4 CPLD Access via I2C */ + {I2C_MASTER_CH_4, 0xFF, 0, NONE, "CPLD_S"}, + /* BUS5 CPLD_B */ + {I2C_MASTER_CH_5, 0xFF, 0, NONE, "CPLD_B"}, +}; + +#define VIRTUAL_I2C_PORT_LENGTH ARRAY_SIZE(fpga_i2c_bus_dev) +#define SW_I2C_CPLD_INDEX SFF_PORT_TOTAL + +struct fpga_device { + /* data mmio region */ + void __iomem *data_base_addr; + resource_size_t data_mmio_start; + resource_size_t data_mmio_len; +}; + +static struct fpga_device fpga_dev = { + .data_base_addr = 0, + .data_mmio_start = 0, + .data_mmio_len = 0, +}; + +struct silverstone_fpga_data { + struct device *sff_devices[SFF_PORT_TOTAL]; + struct i2c_client *sff_i2c_clients[SFF_PORT_TOTAL]; + struct i2c_adapter *i2c_adapter[VIRTUAL_I2C_PORT_LENGTH]; + struct mutex fpga_lock; // For FPGA internal lock + void __iomem * fpga_read_addr; + uint8_t cpld1_read_addr; + uint8_t cpld2_read_addr; +}; + +struct sff_device_data { + int portid; + enum PORT_TYPE port_type; +}; + +struct silverstone_fpga_data *fpga_data; + +/* + * Kernel object for other module drivers. + * Other module can use these kobject as a parent. + */ + +static struct kobject *fpga = NULL; +static struct kobject *cpld1 = NULL; +static struct kobject *cpld2 = NULL; + +/** + * Device node in sysfs tree. + */ +static struct device *sff_dev = NULL; + + +static ssize_t version_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + u32 version; + + mutex_lock(&fpga_data->fpga_lock); + version = ioread32(fpga_dev.data_base_addr + FPGA_VERSION); + mutex_unlock(&fpga_data->fpga_lock); + return sprintf(buf, "%d.%d\n", version >> 16, version & 0xFFFF); +} + +/** + * Show the value of the register set by 'set_fpga_reg_address' + * If the address is not set by 'set_fpga_reg_address' first, + * The version register is selected by default. + * @param buf register value in hextring + * @return number of bytes read, or an error code + */ +static ssize_t get_fpga_reg_value(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + // read data from the address + uint32_t data; + data = ioread32(fpga_data->fpga_read_addr); + return sprintf(buf, "0x%8.8x\n", data); +} +/** + * Store the register address + * @param buf address wanted to be read value of + * @return number of bytes stored, or an error code + */ +static ssize_t set_fpga_reg_address(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + uint32_t addr; + char *last; + + addr = (uint32_t)strtoul(buf, &last, 16); + if (addr == 0 && buf == last) { + return -EINVAL; + } + fpga_data->fpga_read_addr = fpga_dev.data_base_addr + addr; + return count; +} +/** + * Show value of fpga scratch register + * @param buf register value in hexstring + * @return number of bytes read, or an error code + */ +static ssize_t get_fpga_scratch(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + return sprintf(buf, "0x%8.8x\n", ioread32(fpga_dev.data_base_addr + FPGA_SCRATCH) & 0xffffffff); +} +/** + * Store value of fpga scratch register + * @param buf scratch register value passing from user space + * @return number of bytes stored, or an error code + */ +static ssize_t set_fpga_scratch(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + uint32_t data; + char *last; + data = (uint32_t)strtoul(buf, &last, 16); + if (data == 0 && buf == last) { + return -EINVAL; + } + iowrite32(data, fpga_dev.data_base_addr + FPGA_SCRATCH); + return count; +} +/** + * Store a value in a specific register address + * @param buf the value and address in format '0xhhhh 0xhhhhhhhh' + * @return number of bytes sent by user space, or an error code + */ +static ssize_t set_fpga_reg_value(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + // register are 4 bytes + uint32_t addr; + uint32_t value; + uint32_t mode = 8; + char *tok; + char clone[count]; + char *pclone = clone; + char *last; + + strcpy(clone, buf); + + mutex_lock(&fpga_data->fpga_lock); + tok = strsep((char**)&pclone, " "); + if (tok == NULL) { + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; + } + addr = (uint32_t)strtoul(tok, &last, 16); + if (addr == 0 && tok == last) { + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; + } + tok = strsep((char**)&pclone, " "); + if (tok == NULL) { + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; + } + value = (uint32_t)strtoul(tok, &last, 16); + if (value == 0 && tok == last) { + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; + } + tok = strsep((char**)&pclone, " "); + if (tok == NULL) { + mode = 32; + } else { + mode = (uint32_t)strtoul(tok, &last, 10); + if (mode == 0 && tok == last) { + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; + } + } + if (mode == 32) { + iowrite32(value, fpga_dev.data_base_addr + addr); + } else if (mode == 8) { + iowrite8(value, fpga_dev.data_base_addr + addr); + } else { + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; + } + mutex_unlock(&fpga_data->fpga_lock); + return count; +} + +/** + * Show FPGA port XCVR ready status + * @param buf 1 if the functin is ready, 0 if not. + * @return number of bytes read, or an error code + */ +static ssize_t ready_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u32 data; + unsigned int REGISTER = FPGA_PORT_XCVR_READY; + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + return sprintf(buf, "%d\n", (data >> 0) & 1U); +} + +/* FPGA attributes */ +static DEVICE_ATTR( getreg, 0600, get_fpga_reg_value, set_fpga_reg_address); +static DEVICE_ATTR( scratch, 0600, get_fpga_scratch, set_fpga_scratch); +static DEVICE_ATTR( setreg, 0200, NULL , set_fpga_reg_value); +static DEVICE_ATTR_RO(ready); +static DEVICE_ATTR_RO(version); + +static struct attribute *fpga_attrs[] = { + &dev_attr_getreg.attr, + &dev_attr_scratch.attr, + &dev_attr_setreg.attr, + &dev_attr_ready.attr, + &dev_attr_version.attr, + NULL, +}; + +static struct attribute_group fpga_attr_grp = { + .attrs = fpga_attrs, +}; + +static ssize_t cpld1_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 version; + int err; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], + CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x00, + I2C_SMBUS_BYTE_DATA, + (union i2c_smbus_data *)&version); + if (err < 0) + return err; + return sprintf(buf, "%d.%d\n", version >> 4, version & 0x0F); +} +struct device_attribute dev_attr_cpld1_version = __ATTR(version, 0444, cpld1_version_show , NULL); + +/* SW CPLDs attributes */ +static ssize_t cpld1_getreg_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + // CPLD register is one byte + uint8_t data; + fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, fpga_data->cpld1_read_addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + return sprintf(buf, "0x%2.2x\n", data); +} +static ssize_t cpld1_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + uint8_t addr; + char *last; + addr = (uint8_t)strtoul(buf, &last, 16); + if (addr == 0 && buf == last) { + return -EINVAL; + } + fpga_data->cpld1_read_addr = addr; + return size; +} +struct device_attribute dev_attr_cpld1_getreg = __ATTR(getreg, 0600, cpld1_getreg_show, cpld1_getreg_store); + +static ssize_t cpld1_scratch_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + // CPLD register is one byte + __u8 data; + int err; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + if (err < 0) + return err; + return sprintf(buf, "0x%2.2x\n", data); +} +static ssize_t cpld1_scratch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + // CPLD register is one byte + __u8 data; + char *last; + int err; + data = (uint8_t)strtoul(buf, &last, 16); + if (data == 0 && buf == last) { + return -EINVAL; + } + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + if (err < 0) + return err; + return size; +} +struct device_attribute dev_attr_cpld1_scratch = __ATTR(scratch, 0600, cpld1_scratch_show, cpld1_scratch_store); + +static ssize_t cpld1_setreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + + uint8_t addr, value; + char *tok; + char clone[size]; + char *pclone = clone; + int err; + char *last; + + strcpy(clone, buf); + + tok = strsep((char**)&pclone, " "); + if (tok == NULL) { + return -EINVAL; + } + addr = (uint8_t)strtoul(tok, &last, 16); + if (addr == 0 && tok == last) { + return -EINVAL; + } + tok = strsep((char**)&pclone, " "); + if (tok == NULL) { + return -EINVAL; + } + value = (uint8_t)strtoul(tok, &last, 16); + if (value == 0 && tok == last) { + return -EINVAL; + } + + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&value); + if (err < 0) + return err; + + return size; +} +struct device_attribute dev_attr_cpld1_setreg = __ATTR(setreg, 0200, NULL, cpld1_setreg_store); + +static struct attribute *cpld1_attrs[] = { + &dev_attr_cpld1_version.attr, + &dev_attr_cpld1_getreg.attr, + &dev_attr_cpld1_scratch.attr, + &dev_attr_cpld1_setreg.attr, + NULL, +}; + +static struct attribute_group cpld1_attr_grp = { + .attrs = cpld1_attrs, +}; + +static ssize_t cpld2_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 version; + int err; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], + CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x00, + I2C_SMBUS_BYTE_DATA, + (union i2c_smbus_data *)&version); + if (err < 0) + return err; + return sprintf(buf, "%d.%d\n", version >> 4, version & 0x0F); +} +struct device_attribute dev_attr_cpld2_version = __ATTR(version, 0444, cpld2_version_show , NULL); + +static ssize_t cpld2_getreg_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + // CPLD register is one byte + uint8_t data; + fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, fpga_data->cpld2_read_addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t cpld2_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + // CPLD register is one byte + uint32_t addr; + char *last; + addr = (uint8_t)strtoul(buf, &last, 16); + if (addr == 0 && buf == last) { + return -EINVAL; + } + fpga_data->cpld2_read_addr = addr; + return size; +} +struct device_attribute dev_attr_cpld2_getreg = __ATTR(getreg, 0600, cpld2_getreg_show, cpld2_getreg_store); + +static ssize_t cpld2_scratch_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + // CPLD register is one byte + __u8 data; + int err; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + if (err < 0) + return err; + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t cpld2_scratch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + // CPLD register is one byte + __u8 data; + char *last; + int err; + + data = (uint8_t)strtoul(buf, &last, 16); + if (data == 0 && buf == last) { + return -EINVAL; + } + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + if (err < 0) + return err; + return size; +} +struct device_attribute dev_attr_cpld2_scratch = __ATTR(scratch, 0600, cpld2_scratch_show, cpld2_scratch_store); + +static ssize_t cpld2_setreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + uint8_t addr, value; + char *tok; + char clone[size]; + char *pclone = clone; + int err; + char *last; + + strcpy(clone, buf); + + tok = strsep((char**)&pclone, " "); + if (tok == NULL) { + return -EINVAL; + } + addr = (uint8_t)strtoul(tok, &last, 16); + if (addr == 0 && tok == last) { + return -EINVAL; + } + tok = strsep((char**)&pclone, " "); + if (tok == NULL) { + return -EINVAL; + } + value = (uint8_t)strtoul(tok, &last, 16); + if (value == 0 && tok == last) { + return -EINVAL; + } + + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&value); + if (err < 0) + return err; + + return size; +} +struct device_attribute dev_attr_cpld2_setreg = __ATTR(setreg, 0200, NULL, cpld2_setreg_store); + +static struct attribute *cpld2_attrs[] = { + &dev_attr_cpld2_version.attr, + &dev_attr_cpld2_getreg.attr, + &dev_attr_cpld2_scratch.attr, + &dev_attr_cpld2_setreg.attr, + NULL, +}; + +static struct attribute_group cpld2_attr_grp = { + .attrs = cpld2_attrs, +}; + +/* QSFP/SFP+ attributes */ +static ssize_t qsfp_modirq_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u32 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid - 1) * 0x10; + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + return sprintf(buf, "%d\n", (data >> STAT_IRQ) & 1U); +} +DEVICE_ATTR_RO(qsfp_modirq); + +static ssize_t qsfp_modprs_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u32 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid - 1) * 0x10; + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + return sprintf(buf, "%d\n", (data >> STAT_PRESENT) & 1U); +} +DEVICE_ATTR_RO(qsfp_modprs); + +static ssize_t sfp_txfault_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u32 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid - 1) * 0x10; + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + return sprintf(buf, "%d\n", (data >> STAT_TXFAULT) & 1U); +} +DEVICE_ATTR_RO(sfp_txfault); + +static ssize_t sfp_rxlos_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u32 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid - 1) * 0x10; + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + return sprintf(buf, "%d\n", (data >> STAT_RXLOS) & 1U); +} +DEVICE_ATTR_RO(sfp_rxlos); + +static ssize_t sfp_modabs_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u32 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_STATUS_BASE + (portid - 1) * 0x10; + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + return sprintf(buf, "%d\n", (data >> STAT_MODABS) & 1U); +} +DEVICE_ATTR_RO(sfp_modabs); + +static ssize_t qsfp_lpmode_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u32 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid - 1) * 0x10; + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + return sprintf(buf, "%d\n", (data >> CTRL_LPMOD) & 1U); +} +static ssize_t qsfp_lpmode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + ssize_t status; + long value; + u32 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid - 1) * 0x10; + + mutex_lock(&fpga_data->fpga_lock); + status = kstrtol(buf, 0, &value); + if (status == 0) { + // if value is 0, disable the lpmode + data = ioread32(fpga_dev.data_base_addr + REGISTER); + if (!value) + data = data & ~( (u32)0x1 << CTRL_LPMOD); + else + data = data | ((u32)0x1 << CTRL_LPMOD); + iowrite32(data, fpga_dev.data_base_addr + REGISTER); + status = size; + } + mutex_unlock(&fpga_data->fpga_lock); + return status; +} +DEVICE_ATTR_RW(qsfp_lpmode); + +static ssize_t qsfp_reset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u32 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid - 1) * 0x10; + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + return sprintf(buf, "%d\n", (data >> CTRL_RST) & 1U); +} + +static ssize_t qsfp_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + ssize_t status; + long value; + u32 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid - 1) * 0x10; + + mutex_lock(&fpga_data->fpga_lock); + status = kstrtol(buf, 0, &value); + if (status == 0) { + // if value is 0, reset signal is low + data = ioread32(fpga_dev.data_base_addr + REGISTER); + if (!value) + data = data & ~( (u32)0x1 << CTRL_RST); + else + data = data | ((u32)0x1 << CTRL_RST); + iowrite32(data, fpga_dev.data_base_addr + REGISTER); + status = size; + } + mutex_unlock(&fpga_data->fpga_lock); + return status; +} +DEVICE_ATTR_RW(qsfp_reset); + +static ssize_t sfp_txdisable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u32 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid - 1) * 0x10; + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + return sprintf(buf, "%d\n", (data >> CTRL_TXDIS) & 1U); +} +static ssize_t sfp_txdisable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + ssize_t status; + long value; + u32 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_CTRL_BASE + (portid - 1) * 0x10; + + mutex_lock(&fpga_data->fpga_lock); + status = kstrtol(buf, 0, &value); + if (status == 0) { + // check if value is 0 clear + data = ioread32(fpga_dev.data_base_addr + REGISTER); + if (!value) + data = data & ~( (u32)0x1 << CTRL_TXDIS); + else + data = data | ((u32)0x1 << CTRL_TXDIS); + iowrite32(data, fpga_dev.data_base_addr + REGISTER); + status = size; + } + mutex_unlock(&fpga_data->fpga_lock); + return status; +} +DEVICE_ATTR_RW(sfp_txdisable); + +static struct attribute *sff_attrs[] = { + &dev_attr_qsfp_modirq.attr, + &dev_attr_qsfp_modprs.attr, + &dev_attr_qsfp_lpmode.attr, + &dev_attr_qsfp_reset.attr, + &dev_attr_sfp_txfault.attr, + &dev_attr_sfp_rxlos.attr, + &dev_attr_sfp_modabs.attr, + &dev_attr_sfp_txdisable.attr, + NULL, +}; + +static struct attribute_group sff_attr_grp = { + .attrs = sff_attrs, +}; + +static const struct attribute_group *sff_attr_grps[] = { + &sff_attr_grp, + NULL +}; + + +static ssize_t port_led_mode_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + // value can be "nomal", "test" + __u8 led_mode_1, led_mode_2; + int err; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1); + if (err < 0) + return err; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_2); + if (err < 0) + return err; + return sprintf(buf, "%s %s\n", + led_mode_1 ? "test" : "normal", + led_mode_2 ? "test" : "normal"); +} +static ssize_t port_led_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + int status; + __u8 led_mode_1; + if (sysfs_streq(buf, "test")) { + led_mode_1 = 0x01; + } else if (sysfs_streq(buf, "normal")) { + led_mode_1 = 0x00; + } else { + return -EINVAL; + } + status = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, + I2C_SMBUS_WRITE, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1); + status = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, + I2C_SMBUS_WRITE, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1); + return size; +} +DEVICE_ATTR_RW(port_led_mode); + +// Only work when port_led_mode set to 1 +static ssize_t port_led_color_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + // value can be R/G/B/C/M/Y/W/OFF + __u8 led_color1, led_color2; + int err; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color1); + if (err < 0) + return err; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color2); + if (err < 0) + return err; + return sprintf(buf, "%s %s\n", + led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "red" : led_color1 == 0x04 ? + "yellow" : led_color1 == 0x03 ? "blue" : led_color1 == 0x02 ? "cyan" : led_color1 == 0x01 ? "magenta" : "white", + led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "red" : led_color1 == 0x04 ? + "yellow" : led_color1 == 0x03 ? "blue" : led_color1 == 0x02 ? "cyan" : led_color1 == 0x01 ? "magenta" : "white"); +} + +static ssize_t port_led_color_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + int status; + __u8 led_color; + if (sysfs_streq(buf, "off")) { + led_color = 0x07; + } else if (sysfs_streq(buf, "green")) { + led_color = 0x06; + } else if (sysfs_streq(buf, "red")) { + led_color = 0x05; + } else if (sysfs_streq(buf, "yellow")) { + led_color = 0x04; + } else if (sysfs_streq(buf, "blue")) { + led_color = 0x03; + } else if (sysfs_streq(buf, "cyan")) { + led_color = 0x02; + } else if (sysfs_streq(buf, "magenta")) { + led_color = 0x01; + } else if (sysfs_streq(buf, "white")) { + led_color = 0x00; + } else { + status = -EINVAL; + return status; + } + status = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, + I2C_SMBUS_WRITE, 0x0A, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color); + status = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, + I2C_SMBUS_WRITE, 0x0A, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color); + return size; +} +DEVICE_ATTR_RW(port_led_color); + +static struct attribute *sff_led_test[] = { + &dev_attr_port_led_mode.attr, + &dev_attr_port_led_color.attr, + NULL, +}; + +static struct attribute_group sff_led_test_grp = { + .attrs = sff_led_test, +}; + +static struct device * silverstone_sff_init(int portid) { + struct sff_device_data *new_data; + struct device *new_device; + + new_data = kzalloc(sizeof(*new_data), GFP_KERNEL); + if (!new_data) { + printk(KERN_ALERT "Cannot alloc sff device data @port%d", portid); + return NULL; + } + /* The QSFP port ID start from 1 */ + new_data->portid = portid + 1; + new_data->port_type = fpga_i2c_bus_dev[portid].port_type; + new_device = device_create_with_groups(fpgafwclass, sff_dev, MKDEV(0, 0), new_data, sff_attr_grps, "%s", fpga_i2c_bus_dev[portid].calling_name); + if (IS_ERR(new_device)) { + printk(KERN_ALERT "Cannot create sff device @port%d", portid); + kfree(new_data); + return NULL; + } + return new_device; +} + +static int i2c_wait_ack(struct i2c_adapter *a, unsigned long timeout, int writing) { + int error = 0; + int Status; + + struct i2c_dev_data *new_data = i2c_get_adapdata(a); + void __iomem *pci_bar = fpga_dev.data_base_addr; + + unsigned int REG_FDR0; + unsigned int REG_CR0; + unsigned int REG_SR0; + unsigned int REG_DR0; + unsigned int REG_ID0; + + unsigned int master_bus = new_data->pca9548.master_bus; + + if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) { + error = -EINVAL; + return error; + } + + REG_FDR0 = I2C_MASTER_FREQ_1 + (master_bus - 1) * 0x0100; + REG_CR0 = I2C_MASTER_CTRL_1 + (master_bus - 1) * 0x0100; + REG_SR0 = I2C_MASTER_STATUS_1 + (master_bus - 1) * 0x0100; + REG_DR0 = I2C_MASTER_DATA_1 + (master_bus - 1) * 0x0100; + REG_ID0 = I2C_MASTER_PORT_ID_1 + (master_bus - 1) * 0x0100; + + check(pci_bar + REG_SR0); + check(pci_bar + REG_CR0); + + timeout = jiffies + msecs_to_jiffies(timeout); + while (1) { + Status = ioread8(pci_bar + REG_SR0); + if (jiffies > timeout) { + info("Status %2.2X", Status); + info("Error Timeout"); + error = -ETIMEDOUT; + break; + } + + + if (Status & (1 << I2C_SR_BIT_MIF)) { + break; + } + + if (writing == 0 && (Status & (1 << I2C_SR_BIT_MCF))) { + break; + } + } + Status = ioread8(pci_bar + REG_SR0); + iowrite8(0, pci_bar + REG_SR0); + + if (error < 0) { + info("Status %2.2X", Status); + return error; + } + + if (!(Status & (1 << I2C_SR_BIT_MCF))) { + info("Error Unfinish"); + return -EIO; + } + + if (Status & (1 << I2C_SR_BIT_MAL)) { + info("Error MAL"); + return -EAGAIN; + } + + if (Status & (1 << I2C_SR_BIT_RXAK)) { + info( "SL No Acknowlege"); + if (writing) { + info("Error No Acknowlege"); + iowrite8(1 << I2C_CR_BIT_MEN, pci_bar + REG_CR0); + return -ENXIO; + } + } else { + info( "SL Acknowlege"); + } + + return 0; +} + +static int smbus_access(struct i2c_adapter *adapter, u16 addr, + unsigned short flags, char rw, u8 cmd, + int size, union i2c_smbus_data *data) +{ + int error = 0; + int cnt = 0; + int bid = 0; + struct i2c_dev_data *dev_data; + void __iomem *pci_bar; + unsigned int portid, master_bus; + unsigned int REG_FDR0; + unsigned int REG_CR0; + unsigned int REG_SR0; + unsigned int REG_DR0; + unsigned int REG_ID0; + + /* Write the command register */ + dev_data = i2c_get_adapdata(adapter); + portid = dev_data->portid; + pci_bar = fpga_dev.data_base_addr; + master_bus = dev_data->pca9548.master_bus; + REG_FDR0 = I2C_MASTER_FREQ_1 + (master_bus - 1) * 0x0100; + REG_CR0 = I2C_MASTER_CTRL_1 + (master_bus - 1) * 0x0100; + REG_SR0 = I2C_MASTER_STATUS_1 + (master_bus - 1) * 0x0100; + REG_DR0 = I2C_MASTER_DATA_1 + (master_bus - 1) * 0x0100; + REG_ID0 = I2C_MASTER_PORT_ID_1 + (master_bus - 1) * 0x0100; + + if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) { + error = -EINVAL; + goto Done; + } + +#ifdef DEBUG_KERN + printk(KERN_INFO "portid %2d|@ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-10s|CMD %2.2X " + , portid, addr, flags, rw, rw == 1 ? "READ " : "WRITE" + , size, size == 0 ? "QUICK" : + size == 1 ? "BYTE" : + size == 2 ? "BYTE_DATA" : + size == 3 ? "WORD_DATA" : + size == 4 ? "PROC_CALL" : + size == 5 ? "BLOCK_DATA" : "ERROR" + , cmd); +#endif + /* Map the size to what the chip understands */ + switch (size) { + case I2C_SMBUS_QUICK: + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_BLOCK_DATA: + break; + default: + printk(KERN_INFO "Unsupported transaction %d\n", size); + error = -EOPNOTSUPP; + goto Done; + } + + iowrite8(portid, pci_bar + REG_ID0); + + ////[S][ADDR/R] + //Clear status register + iowrite8(0, pci_bar + REG_SR0); + iowrite8(1 << I2C_CR_BIT_MIEN | 1 << I2C_CR_BIT_MTX | 1 << I2C_CR_BIT_MSTA , pci_bar + REG_CR0); + SET_REG_BIT_H(pci_bar + REG_CR0, I2C_CR_BIT_MEN); + + if (rw == I2C_SMBUS_READ && + (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)) { + // sent device address with Read mode + iowrite8(addr << 1 | 0x01, pci_bar + REG_DR0); + } else { + // sent device address with Write mode + iowrite8(addr << 1 | 0x00, pci_bar + REG_DR0); + } + + + + info( "MS Start"); + + //// Wait {A} + error = i2c_wait_ack(adapter, 12, 1); + if (error < 0) { + info( "get error %d", error); + goto Done; + } + + //// [CMD]{A} + if (size == I2C_SMBUS_BYTE_DATA || + size == I2C_SMBUS_WORD_DATA || + size == I2C_SMBUS_BLOCK_DATA || + (size == I2C_SMBUS_BYTE && rw == I2C_SMBUS_WRITE)) { + + //sent command code to data register + iowrite8(cmd, pci_bar + REG_DR0); + info( "MS Send CMD 0x%2.2X", cmd); + + // Wait {A} + error = i2c_wait_ack(adapter, 12, 1); + if (error < 0) { + info( "get error %d", error); + goto Done; + } + } + + switch (size) { + case I2C_SMBUS_BYTE_DATA: + cnt = 1; break; + case I2C_SMBUS_WORD_DATA: + cnt = 2; break; + case I2C_SMBUS_BLOCK_DATA: + // in block data mode keep number of byte in block[0] + cnt = data->block[0]; + break; + default: + cnt = 0; break; + } + + // [CNT] used only bloack data write + if (size == I2C_SMBUS_BLOCK_DATA && rw == I2C_SMBUS_WRITE) { + + iowrite8(cnt, pci_bar + REG_DR0); + info( "MS Send CNT 0x%2.2X", cnt); + + // Wait {A} + error = i2c_wait_ack(adapter, 12, 1); + if (error < 0) { + info( "get error %d", error); + goto Done; + } + } + + // [DATA]{A} + if ( rw == I2C_SMBUS_WRITE && ( + size == I2C_SMBUS_BYTE || + size == I2C_SMBUS_BYTE_DATA || + size == I2C_SMBUS_WORD_DATA || + size == I2C_SMBUS_BLOCK_DATA + )) { + int bid = 0; + info( "MS prepare to sent [%d bytes]", cnt); + if (size == I2C_SMBUS_BLOCK_DATA ) { + bid = 1; // block[0] is cnt; + cnt += 1; // offset from block[0] + } + for (; bid < cnt; bid++) { + + iowrite8(data->block[bid], pci_bar + REG_DR0); + info( " Data > %2.2X", data->block[bid]); + // Wait {A} + error = i2c_wait_ack(adapter, 12, 1); + if (error < 0) { + goto Done; + } + } + } + + //REPEATE START + if ( rw == I2C_SMBUS_READ && ( + size == I2C_SMBUS_BYTE_DATA || + size == I2C_SMBUS_WORD_DATA || + size == I2C_SMBUS_BLOCK_DATA + )) { + info( "MS Repeated Start"); + + SET_REG_BIT_L(pci_bar + REG_CR0, I2C_CR_BIT_MEN); + iowrite8(1 << I2C_CR_BIT_MIEN | + 1 << I2C_CR_BIT_MTX | + 1 << I2C_CR_BIT_MSTA | + 1 << I2C_CR_BIT_RSTA , pci_bar + REG_CR0); + SET_REG_BIT_H(pci_bar + REG_CR0, I2C_CR_BIT_MEN); + + // sent Address with Read mode + iowrite8( addr << 1 | 0x1 , pci_bar + REG_DR0); + + // Wait {A} + error = i2c_wait_ack(adapter, 12, 1); + if (error < 0) { + goto Done; + } + + } + + if ( rw == I2C_SMBUS_READ && ( + size == I2C_SMBUS_BYTE || + size == I2C_SMBUS_BYTE_DATA || + size == I2C_SMBUS_WORD_DATA || + size == I2C_SMBUS_BLOCK_DATA + )) { + + switch (size) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + cnt = 1; break; + case I2C_SMBUS_WORD_DATA: + cnt = 2; break; + case I2C_SMBUS_BLOCK_DATA: + //will be changed after recived first data + cnt = 3; break; + default: + cnt = 0; break; + } + + info( "MS Receive"); + + //set to Receive mode + iowrite8(1 << I2C_CR_BIT_MEN | + 1 << I2C_CR_BIT_MIEN | + 1 << I2C_CR_BIT_MSTA , pci_bar + REG_CR0); + + for (bid = -1; bid < cnt; bid++) { + + // Wait {A} + error = i2c_wait_ack(adapter, 12, 0); + if (error < 0) { + goto Done; + } + + if (bid == cnt - 2) { + info( "SET NAK"); + SET_REG_BIT_H(pci_bar + REG_CR0, I2C_CR_BIT_TXAK); + } + + if (bid < 0) { + ioread8(pci_bar + REG_DR0); + info( "READ Dummy Byte" ); + } else { + + if (bid == cnt - 1) { + info ( "SET STOP in read loop"); + SET_REG_BIT_L(pci_bar + REG_CR0, I2C_CR_BIT_MSTA); + } + data->block[bid] = ioread8(pci_bar + REG_DR0); + + info( "DATA IN [%d] %2.2X", bid, data->block[bid]); + + if (size == I2C_SMBUS_BLOCK_DATA && bid == 0) { + cnt = data->block[0] + 1; + } + } + } + } + + //[P] + SET_REG_BIT_L(pci_bar + REG_CR0, I2C_CR_BIT_MSTA); + i2c_wait_ack(adapter, 12, 0); + info( "MS STOP"); + +Done: + iowrite8(1 << I2C_CR_BIT_MEN, pci_bar + REG_CR0); + check(pci_bar + REG_CR0); + check(pci_bar + REG_SR0); +#ifdef DEBUG_KERN + printk(KERN_INFO "END --- Error code %d", error); +#endif + + return error; +} + +/** + * Wrapper of smbus_access access with PCA9548 I2C switch management. + * This function set PCA9548 switches to the proper slave channel. + * Only one channel among switches chip is selected during communication time. + * + * Note: If the bus does not have any PCA9548 on it, the switch_addr must be + * set to 0xFF, it will use normal smbus_access function. + */ +static int fpga_i2c_access(struct i2c_adapter *adapter, u16 addr, + unsigned short flags, char rw, u8 cmd, + int size, union i2c_smbus_data *data) +{ + int error = 0; + struct i2c_dev_data *dev_data; + unsigned char master_bus; + unsigned char switch_addr; + unsigned char channel; + uint16_t prev_port = 0; + unsigned char prev_switch; + unsigned char prev_ch; + int retry; + + dev_data = i2c_get_adapdata(adapter); + master_bus = dev_data->pca9548.master_bus; + switch_addr = dev_data->pca9548.switch_addr; + channel = dev_data->pca9548.channel; + + // Acquire the master resource. + mutex_lock(&fpga_i2c_master_locks[master_bus - 1]); + prev_port = fpga_i2c_lasted_access_port[master_bus - 1]; + prev_switch = (unsigned char)(prev_port >> 8) & 0xFF; + prev_ch = (unsigned char)(prev_port & 0xFF); + + if (switch_addr != 0xFF) { + + // Check lasted access switch address on a master + if ( prev_switch != switch_addr && prev_switch != 0 ) { + // reset prev_port PCA9548 chip + retry = 3; + while(retry--){ + error = smbus_access(adapter, (u16)(prev_switch), flags, I2C_SMBUS_WRITE, 0x00, I2C_SMBUS_BYTE, NULL); + if(error >= 0){ + break; + }else{ + dev_dbg(&adapter->dev,"Failed to deselect ch %d of 0x%x, CODE %d\n", prev_ch, prev_switch, error); + } + } + if(retry == 0) + goto release_unlock; + // set PCA9548 to current channel + retry = 3; + while(retry--){ + error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_WRITE, 1 << channel, I2C_SMBUS_BYTE, NULL); + if(error >= 0){ + break; + }else{ + dev_dbg(&adapter->dev,"Failed to select ch %d of 0x%x, CODE %d\n", channel, switch_addr, error); + } + } + if(retry == 0) + goto release_unlock; + // update lasted port + fpga_i2c_lasted_access_port[master_bus - 1] = switch_addr << 8 | channel; + + } else { + // check if channel is also changes + if ( prev_ch != channel || prev_switch == 0 ) { + // set new PCA9548 at switch_addr to current + retry = 3; + while(retry--){ + error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_WRITE, 1 << channel, I2C_SMBUS_BYTE, NULL); + if(error >= 0){ + break; + }else{ + dev_dbg(&adapter->dev,"Failed to select ch %d of 0x%x, CODE %d\n", channel, switch_addr, error); + } + } + if(retry == 0) + goto release_unlock; + // update lasted port + fpga_i2c_lasted_access_port[master_bus - 1] = switch_addr << 8 | channel; + } + } + } + + // Do SMBus communication + error = smbus_access(adapter, addr, flags, rw, cmd, size, data); + if(error < 0){ + dev_dbg( &adapter->dev,"smbus_xfer failed (%d) @ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-10s|CMD %2.2X " + , error, addr, flags, rw, rw == 1 ? "READ " : "WRITE" + , size, size == 0 ? "QUICK" : + size == 1 ? "BYTE" : + size == 2 ? "BYTE_DATA" : + size == 3 ? "WORD_DATA" : + size == 4 ? "PROC_CALL" : + size == 5 ? "BLOCK_DATA" : + size == 8 ? "I2C_BLOCK_DATA" : "ERROR" + , cmd); + } + +release_unlock: + mutex_unlock(&fpga_i2c_master_locks[master_bus - 1]); + dev_dbg(&adapter->dev,"switch ch %d of 0x%x -> ch %d of 0x%x\n", prev_ch, prev_switch, channel, switch_addr); + return error; +} + + + +/** + * A callback function show available smbus functions. + */ +static u32 fpga_i2c_func(struct i2c_adapter *a) +{ + return I2C_FUNC_SMBUS_QUICK | + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static const struct i2c_algorithm silverstone_i2c_algorithm = { + .smbus_xfer = fpga_i2c_access, + .functionality = fpga_i2c_func, +}; + +/** + * Create virtual I2C bus adapter for switch devices + * @param pdev platform device pointer + * @param portid virtual i2c port id for switch device mapping + * @param bus_number_offset bus offset for virtual i2c adapter in system + * @return i2c adapter. + * + * When bus_number_offset is -1, created adapter with dynamic bus number. + * Otherwise create adapter at i2c bus = bus_number_offset + portid. + */ +static struct i2c_adapter * silverstone_i2c_init(struct platform_device *pdev, int portid, int bus_number_offset) +{ + int error; + + struct i2c_adapter *new_adapter; + struct i2c_dev_data *new_data; + void __iomem *i2c_freq_base_reg; + + new_adapter = kzalloc(sizeof(*new_adapter), GFP_KERNEL); + if (!new_adapter) { + printk(KERN_ALERT "Cannot alloc i2c adapter for %s", fpga_i2c_bus_dev[portid].calling_name); + return NULL; + } + + new_adapter->owner = THIS_MODULE; + new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + new_adapter->algo = &silverstone_i2c_algorithm; + /* If the bus offset is -1, use dynamic bus number */ + if (bus_number_offset == -1) { + new_adapter->nr = -1; + } else { + new_adapter->nr = bus_number_offset + portid; + } + + new_data = kzalloc(sizeof(*new_data), GFP_KERNEL); + if (!new_data) { + printk(KERN_ALERT "Cannot alloc i2c data for %s", fpga_i2c_bus_dev[portid].calling_name); + kzfree(new_adapter); + return NULL; + } + + new_data->portid = portid; + new_data->pca9548.master_bus = fpga_i2c_bus_dev[portid].master_bus; + new_data->pca9548.switch_addr = fpga_i2c_bus_dev[portid].switch_addr; + new_data->pca9548.channel = fpga_i2c_bus_dev[portid].channel; + strcpy(new_data->pca9548.calling_name, fpga_i2c_bus_dev[portid].calling_name); + + snprintf(new_adapter->name, sizeof(new_adapter->name), + "SMBus I2C Adapter PortID: %s", new_data->pca9548.calling_name); + + i2c_freq_base_reg = fpga_dev.data_base_addr + I2C_MASTER_FREQ_1; + iowrite8(0x07, i2c_freq_base_reg + (new_data->pca9548.master_bus - 1) * 0x100); // 0x07 400kHz + i2c_set_adapdata(new_adapter, new_data); + error = i2c_add_numbered_adapter(new_adapter); + if (error < 0) { + printk(KERN_ALERT "Cannot add i2c adapter %s", new_data->pca9548.calling_name); + kzfree(new_adapter); + kzfree(new_data); + return NULL; + } + + return new_adapter; +}; + +static void silverstone_dev_release( struct device * dev) +{ + return; +} + +static struct platform_device silverstone_dev = { + .name = DRIVER_NAME, + .id = -1, + .num_resources = 0, + .resource = NULL, + .dev = { + .release = silverstone_dev_release, + } +}; + +/** + * Board info for QSFP/SFP+ eeprom. + * Note: Using OOM optoe as I2C eeprom driver. + * https://www.opencompute.org/wiki/Networking/SpecsAndDesigns#Open_Optical_Monitoring + */ +static struct i2c_board_info sff8436_eeprom_info[] = { + { I2C_BOARD_INFO("optoe1", 0x50) }, //For QSFP w/ sff8436 + { I2C_BOARD_INFO("optoe2", 0x50) }, //For SFP+ w/ sff8472 +}; + +static int silverstone_drv_probe(struct platform_device *pdev) +{ + int ret = 0; + int portid_count; + uint8_t cpld1_version, cpld2_version; + uint16_t prev_i2c_switch = 0; + struct sff_device_data *sff_data; + + /* The device class need to be instantiated before this function called */ + BUG_ON(fpgafwclass == NULL); + + fpga_data = devm_kzalloc(&pdev->dev, sizeof(struct silverstone_fpga_data), + GFP_KERNEL); + + if (!fpga_data) + return -ENOMEM; + + // Set default read address to VERSION + fpga_data->fpga_read_addr = fpga_dev.data_base_addr + FPGA_VERSION; + fpga_data->cpld1_read_addr = 0x00; + fpga_data->cpld2_read_addr = 0x00; + + mutex_init(&fpga_data->fpga_lock); + for (ret = I2C_MASTER_CH_1 ; ret <= I2C_MASTER_CH_TOTAL; ret++) { + mutex_init(&fpga_i2c_master_locks[ret - 1]); + } + + fpga = kobject_create_and_add("FPGA", &pdev->dev.kobj); + if (!fpga) { + kzfree(fpga_data); + return -ENOMEM; + } + + ret = sysfs_create_group(fpga, &fpga_attr_grp); + if (ret != 0) { + printk(KERN_ERR "Cannot create FPGA sysfs attributes\n"); + kobject_put(fpga); + kzfree(fpga_data); + return ret; + } + + cpld1 = kobject_create_and_add("CPLD1", &pdev->dev.kobj); + if (!cpld1) { + sysfs_remove_group(fpga, &fpga_attr_grp); + kobject_put(fpga); + kzfree(fpga_data); + return -ENOMEM; + } + ret = sysfs_create_group(cpld1, &cpld1_attr_grp); + if (ret != 0) { + printk(KERN_ERR "Cannot create CPLD1 sysfs attributes\n"); + kobject_put(cpld1); + sysfs_remove_group(fpga, &fpga_attr_grp); + kobject_put(fpga); + kzfree(fpga_data); + return ret; + } + + cpld2 = kobject_create_and_add("CPLD2", &pdev->dev.kobj); + if (!cpld2) { + sysfs_remove_group(cpld1, &cpld1_attr_grp); + kobject_put(cpld1); + sysfs_remove_group(fpga, &fpga_attr_grp); + kobject_put(fpga); + kzfree(fpga_data); + return -ENOMEM; + } + ret = sysfs_create_group(cpld2, &cpld2_attr_grp); + if (ret != 0) { + printk(KERN_ERR "Cannot create CPLD2 sysfs attributes\n"); + kobject_put(cpld2); + sysfs_remove_group(cpld1, &cpld1_attr_grp); + kobject_put(cpld1); + sysfs_remove_group(fpga, &fpga_attr_grp); + kobject_put(fpga); + kzfree(fpga_data); + return ret; + } + + sff_dev = device_create(fpgafwclass, NULL, MKDEV(0, 0), NULL, "sff_device"); + if (IS_ERR(sff_dev)) { + printk(KERN_ERR "Failed to create sff device\n"); + sysfs_remove_group(cpld2, &cpld2_attr_grp); + kobject_put(cpld2); + sysfs_remove_group(cpld1, &cpld1_attr_grp); + kobject_put(cpld1); + sysfs_remove_group(fpga, &fpga_attr_grp); + kobject_put(fpga); + kzfree(fpga_data); + return PTR_ERR(sff_dev); + } + + ret = sysfs_create_group(&sff_dev->kobj, &sff_led_test_grp); + if (ret != 0) { + printk(KERN_ERR "Cannot create SFF attributes\n"); + device_destroy(fpgafwclass, MKDEV(0, 0)); + sysfs_remove_group(cpld2, &cpld2_attr_grp); + kobject_put(cpld2); + sysfs_remove_group(cpld1, &cpld1_attr_grp); + kobject_put(cpld1); + sysfs_remove_group(fpga, &fpga_attr_grp); + kobject_put(fpga); + kzfree(fpga_data); + return ret; + } + + ret = sysfs_create_link(&pdev->dev.kobj, &sff_dev->kobj, "SFF"); + if (ret != 0) { + sysfs_remove_group(&sff_dev->kobj, &sff_led_test_grp); + device_destroy(fpgafwclass, MKDEV(0, 0)); + sysfs_remove_group(cpld2, &cpld2_attr_grp); + kobject_put(cpld2); + sysfs_remove_group(cpld1, &cpld1_attr_grp); + kobject_put(cpld1); + sysfs_remove_group(fpga, &fpga_attr_grp); + kobject_put(fpga); + kzfree(fpga_data); + return ret; + } + + for (portid_count = 0 ; portid_count < VIRTUAL_I2C_PORT_LENGTH ; portid_count++) { + fpga_data->i2c_adapter[portid_count] = silverstone_i2c_init(pdev, portid_count, VIRTUAL_I2C_BUS_OFFSET); + } + + /* Init SFF devices */ + for (portid_count = 0; portid_count < SFF_PORT_TOTAL; portid_count++) { + struct i2c_adapter *i2c_adap = fpga_data->i2c_adapter[portid_count]; + if (i2c_adap) { + fpga_data->sff_devices[portid_count] = silverstone_sff_init(portid_count); + sff_data = dev_get_drvdata(fpga_data->sff_devices[portid_count]); + BUG_ON(sff_data == NULL); + if ( sff_data->port_type == QSFP ) { + fpga_data->sff_i2c_clients[portid_count] = i2c_new_device(i2c_adap, &sff8436_eeprom_info[0]); + } else { + fpga_data->sff_i2c_clients[portid_count] = i2c_new_device(i2c_adap, &sff8436_eeprom_info[1]); + } + sff_data = NULL; + sysfs_create_link(&fpga_data->sff_devices[portid_count]->kobj, + &fpga_data->sff_i2c_clients[portid_count]->dev.kobj, + "i2c"); + } + } + +#ifdef TEST_MODE + return 0; +#endif + fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, + I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld1_version); + fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, + I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld2_version); + + printk(KERN_INFO "Switch CPLD1 VERSION: %2.2x\n", cpld1_version); + printk(KERN_INFO "Switch CPLD2 VERSION: %2.2x\n", cpld2_version); + + + /* Init I2C buses that has PCA9548 switch device. */ + for (portid_count = 0; portid_count < VIRTUAL_I2C_PORT_LENGTH; portid_count++) { + + struct i2c_dev_data *dev_data; + unsigned char master_bus; + unsigned char switch_addr; + + dev_data = i2c_get_adapdata(fpga_data->i2c_adapter[portid_count]); + master_bus = dev_data->pca9548.master_bus; + switch_addr = dev_data->pca9548.switch_addr; + + if (switch_addr != 0xFF) { + + if (prev_i2c_switch != ( (master_bus << 8) | switch_addr) ) { + // Found the bus with PCA9548, trying to clear all switch in it. + smbus_access(fpga_data->i2c_adapter[portid_count], switch_addr, 0x00, I2C_SMBUS_WRITE, 0x00, I2C_SMBUS_BYTE, NULL); + prev_i2c_switch = ( master_bus << 8 ) | switch_addr; + } + } + } + return 0; +} + +static int silverstone_drv_remove(struct platform_device *pdev) +{ + int portid_count; + struct sff_device_data *rem_data; + + for (portid_count = 0; portid_count < SFF_PORT_TOTAL; portid_count++) { + sysfs_remove_link(&fpga_data->sff_devices[portid_count]->kobj, "i2c"); + i2c_unregister_device(fpga_data->sff_i2c_clients[portid_count]); + } + + for (portid_count = 0 ; portid_count < VIRTUAL_I2C_PORT_LENGTH ; portid_count++) { + if (fpga_data->i2c_adapter[portid_count] != NULL) { + info(KERN_INFO "<%x>", fpga_data->i2c_adapter[portid_count]); + i2c_del_adapter(fpga_data->i2c_adapter[portid_count]); + } + } + + for (portid_count = 0; portid_count < SFF_PORT_TOTAL; portid_count++) { + if (fpga_data->sff_devices[portid_count] != NULL) { + rem_data = dev_get_drvdata(fpga_data->sff_devices[portid_count]); + device_unregister(fpga_data->sff_devices[portid_count]); + put_device(fpga_data->sff_devices[portid_count]); + kfree(rem_data); + } + } + + sysfs_remove_group(fpga, &fpga_attr_grp); + sysfs_remove_group(cpld1, &cpld1_attr_grp); + sysfs_remove_group(cpld2, &cpld2_attr_grp); + sysfs_remove_group(&sff_dev->kobj, &sff_led_test_grp); + kobject_put(fpga); + kobject_put(cpld1); + kobject_put(cpld2); + device_destroy(fpgafwclass, MKDEV(0, 0)); + devm_kfree(&pdev->dev, fpga_data); + return 0; +} + +#ifdef TEST_MODE +#define FPGA_PCI_BAR_NUM 2 +#else +#define FPGA_PCI_BAR_NUM 0 +#endif + +static struct platform_driver silverstone_drv = { + .probe = silverstone_drv_probe, + .remove = __exit_p(silverstone_drv_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + +static const struct pci_device_id fpga_id_table[] = { + { PCI_VDEVICE(XILINX, FPGA_PCIE_DEVICE_ID) }, + { PCI_VDEVICE(TEST, TEST_PCIE_DEVICE_ID) }, + {0, } +}; + +MODULE_DEVICE_TABLE(pci, fpga_id_table); + +static int fpga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int err; + struct device *dev = &pdev->dev; + uint32_t fpga_version; + + if ((err = pci_enable_device(pdev))) { + dev_err(dev, "pci_enable_device probe error %d for device %s\n", + err, pci_name(pdev)); + return err; + } + + if ((err = pci_request_regions(pdev, FPGA_PCI_NAME)) < 0) { + dev_err(dev, "pci_request_regions error %d\n", err); + goto pci_disable; + } + + /* bar0: data mmio region */ + fpga_dev.data_mmio_start = pci_resource_start(pdev, FPGA_PCI_BAR_NUM); + fpga_dev.data_mmio_len = pci_resource_len(pdev, FPGA_PCI_BAR_NUM); + fpga_dev.data_base_addr = pci_iomap(pdev, FPGA_PCI_BAR_NUM, 0); + if (!fpga_dev.data_base_addr) { + dev_err(dev, "cannot iomap region of size %lu\n", + (unsigned long)fpga_dev.data_mmio_len); + goto pci_release; + } + dev_info(dev, "data_mmio iomap base = 0x%lx \n", + (unsigned long)fpga_dev.data_base_addr); + dev_info(dev, "data_mmio_start = 0x%lx data_mmio_len = %lu\n", + (unsigned long)fpga_dev.data_mmio_start, + (unsigned long)fpga_dev.data_mmio_len); + + printk(KERN_INFO "FPGA PCIe driver probe OK.\n"); + printk(KERN_INFO "FPGA ioremap registers of size %lu\n", (unsigned long)fpga_dev.data_mmio_len); + printk(KERN_INFO "FPGA Virtual BAR %d at %8.8lx - %8.8lx\n", FPGA_PCI_BAR_NUM, + (unsigned long)fpga_dev.data_base_addr, + (unsigned long)(fpga_dev.data_base_addr + fpga_dev.data_mmio_len)); + printk(KERN_INFO ""); + fpga_version = ioread32(fpga_dev.data_base_addr); + printk(KERN_INFO "FPGA VERSION : %8.8x\n", fpga_version); + fpgafw_init(); + platform_device_register(&silverstone_dev); + platform_driver_register(&silverstone_drv); + return 0; + +pci_release: + pci_release_regions(pdev); +pci_disable: + pci_disable_device(pdev); + return -EBUSY; +} + +static void fpga_pci_remove(struct pci_dev *pdev) +{ + platform_driver_unregister(&silverstone_drv); + platform_device_unregister(&silverstone_dev); + fpgafw_exit(); + pci_iounmap(pdev, fpga_dev.data_base_addr); + pci_release_regions(pdev); + pci_disable_device(pdev); + printk(KERN_INFO "FPGA PCIe driver remove OK.\n"); +}; + +static struct pci_driver pci_dev_ops = { + .name = FPGA_PCI_NAME, + .probe = fpga_pci_probe, + .remove = fpga_pci_remove, + .id_table = fpga_id_table, +}; + +enum { + READREG, + WRITEREG +}; + +struct fpga_reg_data { + uint32_t addr; + uint32_t value; +}; + +static long fpgafw_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + int ret = 0; + struct fpga_reg_data data; + mutex_lock(&fpga_data->fpga_lock); + +#ifdef TEST_MODE + static uint32_t status_reg; +#endif + // Switch function to read and write. + switch (cmd) { + case READREG: + if (copy_from_user(&data, (void __user*)arg, sizeof(data)) != 0) { + mutex_unlock(&fpga_data->fpga_lock); + return -EFAULT; + } + data.value = ioread32(fpga_dev.data_base_addr + data.addr); + if (copy_to_user((void __user*)arg , &data, sizeof(data)) != 0) { + mutex_unlock(&fpga_data->fpga_lock); + return -EFAULT; + } +#ifdef TEST_MODE + if (data.addr == 0x1210) { + switch (status_reg) { + case 0x0000 : status_reg = 0x8000; + break; + + case 0x8080 : status_reg = 0x80C0; + break; + case 0x80C0 : status_reg = 0x80F0; + break; + case 0x80F0 : status_reg = 0x80F8; + break; + + } + iowrite32(status_reg, fpga_dev.data_base_addr + 0x1210); + } +#endif + + + break; + case WRITEREG: + if (copy_from_user(&data, (void __user*)arg, sizeof(data)) != 0) { + mutex_unlock(&fpga_data->fpga_lock); + return -EFAULT; + } + iowrite32(data.value, fpga_dev.data_base_addr + data.addr); + +#ifdef TEST_MODE + if (data.addr == 0x1204) { + status_reg = 0x8080; + iowrite32(status_reg, fpga_dev.data_base_addr + 0x1210); + } +#endif + + break; + default: + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; + } + mutex_unlock(&fpga_data->fpga_lock); + return ret; +} + + +const struct file_operations fpgafw_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = fpgafw_unlocked_ioctl, +}; + + +static int fpgafw_init(void) { + printk(KERN_INFO "Initializing the switchboard driver\n"); + // Try to dynamically allocate a major number for the device -- more difficult but worth it + majorNumber = register_chrdev(0, DEVICE_NAME, &fpgafw_fops); + if (majorNumber < 0) { + printk(KERN_ALERT "Failed to register a major number\n"); + return majorNumber; + } + printk(KERN_INFO "Device registered correctly with major number %d\n", majorNumber); + + // Register the device class + fpgafwclass = class_create(THIS_MODULE, CLASS_NAME); + if (IS_ERR(fpgafwclass)) { // Check for error and clean up if there is + unregister_chrdev(majorNumber, DEVICE_NAME); + printk(KERN_ALERT "Failed to register device class\n"); + return PTR_ERR(fpgafwclass); + } + printk(KERN_INFO "Device class registered correctly\n"); + + // Register the device driver + fpgafwdev = device_create(fpgafwclass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME); + if (IS_ERR(fpgafwdev)) { // Clean up if there is an error + class_destroy(fpgafwclass); // Repeated code but the alternative is goto statements + unregister_chrdev(majorNumber, DEVICE_NAME); + printk(KERN_ALERT "Failed to create the FW upgrade device node\n"); + return PTR_ERR(fpgafwdev); + } + printk(KERN_INFO "FPGA fw upgrade device node created correctly\n"); + return 0; +} + +static void fpgafw_exit(void) { + device_destroy(fpgafwclass, MKDEV(majorNumber, 0)); // remove the device + class_unregister(fpgafwclass); // unregister the device class + class_destroy(fpgafwclass); // remove the device class + unregister_chrdev(majorNumber, DEVICE_NAME); // unregister the major number + printk(KERN_INFO "Goodbye!\n"); +} + +int silverstone_init(void) +{ + int rc; + rc = pci_register_driver(&pci_dev_ops); + if (rc) + return rc; + return 0; +} + +void silverstone_exit(void) +{ + pci_unregister_driver(&pci_dev_ops); +} + +module_init(silverstone_init); +module_exit(silverstone_exit); + +MODULE_AUTHOR("Celestica Inc."); +MODULE_DESCRIPTION("Celestica Silverstone platform driver"); +MODULE_VERSION(MOD_VERSION); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/systemd/platform-modules-silverstone.service b/platform/broadcom/sonic-platform-modules-cel/silverstone/systemd/platform-modules-silverstone.service new file mode 100644 index 000000000000..907764153a27 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/systemd/platform-modules-silverstone.service @@ -0,0 +1,13 @@ +[Unit] +Description=Celestica Silverstone platform modules +After=local-fs.target +Before=pmon.service + +[Service] +Type=oneshot +ExecStart=-/etc/init.d/platform-modules-silverstone start +ExecStop=-/etc/init.d/platform-modules-silverstone stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target \ No newline at end of file From 150ed36be2dd5c11e69934c78983c48e984afa8e Mon Sep 17 00:00:00 2001 From: kannankvs Date: Thu, 10 Oct 2019 21:54:18 +0530 Subject: [PATCH 063/278] [snmp]: changes to handle snmp configuration as per the modified CLI (#3586) While doing CLI changes for SNMP configuration, few changes are made in backend to handle the modified CLI. ** Changes** - "community" for "snmp trap" is also made as "configurable". snmpd_conf.j2 is modified to handle the same. - Changed the snmp.yml file generation from postStartAction to preStartAction in docker_image_ctl.j2 specific to SNMP docker, to ensure that the snmp.yml is generated before sonic-cfggen generates the snmpd.conf. - Changed to make the code common for management vrf and default vrf. Users can configure snmp trap and snmp listening IP for both management vrf and default vrf. --- dockers/docker-snmp-sv2/snmpd.conf.j2 | 6 +- files/build_templates/docker_image_ctl.j2 | 108 ++++++++++++++-------- 2 files changed, 72 insertions(+), 42 deletions(-) diff --git a/dockers/docker-snmp-sv2/snmpd.conf.j2 b/dockers/docker-snmp-sv2/snmpd.conf.j2 index 9784cc42e7f7..16d7e5bff79c 100644 --- a/dockers/docker-snmp-sv2/snmpd.conf.j2 +++ b/dockers/docker-snmp-sv2/snmpd.conf.j2 @@ -106,19 +106,19 @@ load 12 10 5 # # send SNMPv1 traps {%if v1_trap_dest and v1_trap_dest != 'NotConfigured' %} -trapsink {{ v1_trap_dest }} public +trapsink {{ v1_trap_dest }} {% else %} #trapsink localhost public {% endif %} # send SNMPv2c traps {%if v2_trap_dest and v2_trap_dest != 'NotConfigured' %} -trap2sink {{ v2_trap_dest }} public +trap2sink {{ v2_trap_dest }} {% else %} #trap2sink localhost public {% endif %} # send SNMPv2c INFORMs {%if v3_trap_dest and v3_trap_dest != 'NotConfigured' %} -informsink {{ v3_trap_dest }} public +informsink {{ v3_trap_dest }} {% else %} #informsink localhost public {% endif %} diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 index 8bf0f2c6d4b0..c485254647b8 100644 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -62,6 +62,75 @@ function preStartAction() echo -n > /tmp/dump.rdb docker cp /tmp/dump.rdb database:/var/lib/redis/ fi +{%- elif docker_container_name == "snmp" %} + docker exec -i database redis-cli -n 6 HSET 'DEVICE_METADATA|localhost' chassis_serial_number $(decode-syseeprom -s) + vrfenabled=`/usr/bin/redis-cli -n 4 hget "MGMT_VRF_CONFIG|vrf_global" mgmtVrfEnabled` + v1SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" DestIp` + v1SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" DestPort` + v1Vrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" vrf` + v1Comm=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" Community` + v2SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" DestIp` + v2SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" DestPort` + v2Vrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" vrf` + v2Comm=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" Community` + v3SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" DestIp` + v3SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" DestPort` + v3Vrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" vrf` + v3Comm=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" Community` + + if [ "${v1SnmpTrapIp}" != "" ] + then + if [ "${v1Vrf}" != "None" ] + then + sed -i "s/v1_trap_dest:.*/v1_trap_dest: ${v1SnmpTrapIp}:${v1SnmpTrapPort}%${v1Vrf} ${v1Comm}/" "/etc/sonic/snmp.yml" + else + sed -i "s/v1_trap_dest:.*/v1_trap_dest: ${v1SnmpTrapIp}:${v1SnmpTrapPort} ${v1Comm}/" "/etc/sonic/snmp.yml" + fi + else + sed -i "s/v1_trap_dest:.*/v1_trap_dest: NotConfigured/" "/etc/sonic/snmp.yml" + fi + if [ "${v2SnmpTrapIp}" != "" ] + then + if [ "${v2Vrf}" != "None" ] + then + sed -i "s/v2_trap_dest:.*/v2_trap_dest: ${v2SnmpTrapIp}:${v2SnmpTrapPort}%${v2Vrf} ${v2Comm}/" "/etc/sonic/snmp.yml" + else + sed -i "s/v2_trap_dest:.*/v2_trap_dest: ${v2SnmpTrapIp}:${v2SnmpTrapPort} ${v2Comm}/" "/etc/sonic/snmp.yml" + fi + else + sed -i "s/v2_trap_dest:.*/v2_trap_dest: NotConfigured/" "/etc/sonic/snmp.yml" + fi + if [ "${v3SnmpTrapIp}" != "" ] + then + if [ "${v3Vrf}" != "None" ] + then + sed -i "s/v3_trap_dest:.*/v3_trap_dest: ${v3SnmpTrapIp}:${v3SnmpTrapPort}%${v3Vrf} ${v3Comm}/" "/etc/sonic/snmp.yml" + else + sed -i "s/v3_trap_dest:.*/v3_trap_dest: ${v3SnmpTrapIp}:${v3SnmpTrapPort} ${v3Comm}/" "/etc/sonic/snmp.yml" + fi + else + sed -i "s/v3_trap_dest:.*/v3_trap_dest: NotConfigured/" "/etc/sonic/snmp.yml" + fi + + echo -n "" > /tmp/snmpagentaddr.yml + keys=`/usr/bin/redis-cli -n 4 keys "SNMP_AGENT_ADDRESS_CONFIG|*"` + count=1 + for key in $keys;do + ip=`echo $key|cut -d "|" -f2` + echo -n "snmp_agent_address_$count: $ip" >> /tmp/snmpagentaddr.yml + port=`echo $key|cut -d "|" -f3` + if [ -n "$port" ]; then + echo -n ":$port" >> /tmp/snmpagentaddr.yml + fi + vrf=`echo $key|cut -d "|" -f4` + if [ -n "$vrf" ]; then + echo -n "%$vrf" >> /tmp/snmpagentaddr.yml + fi + echo "" >> /tmp/snmpagentaddr.yml + count=$((count+1)) + done + sed -i '/snmp_agent_address_*/d' /etc/sonic/snmp.yml + cat /tmp/snmpagentaddr.yml >> /etc/sonic/snmp.yml {%- else %} : # nothing {%- endif %} @@ -107,45 +176,6 @@ function postStartAction() docker cp $PSENSOR pmon:/usr/bin/ fi fi -{%- elif docker_container_name == "snmp" %} - docker exec -i database redis-cli -n 6 HSET 'DEVICE_METADATA|localhost' chassis_serial_number $(decode-syseeprom -s) - vrfenabled=`/usr/bin/redis-cli -n 4 hget "MGMT_VRF_CONFIG|vrf_global" mgmtVrfEnabled` - v1SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" DestIp` - v1SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" DestPort` - v1MgmtVrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" vrf` - v2SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" DestIp` - v2SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" DestPort` - v2MgmtVrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" vrf` - v3SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" DestIp` - v3SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" DestPort` - v3MgmtVrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" vrf` - - if [ "${v1SnmpTrapIp}" != "" ] - then - sed -i "s/v1_trap_dest:.*/v1_trap_dest: ${v1SnmpTrapIp}:${v1SnmpTrapPort}%${v1MgmtVrf}/" "/etc/sonic/snmp.yml" - fi - if [ "${v2SnmpTrapIp}" != "" ] - then - sed -i "s/v2_trap_dest:.*/v2_trap_dest: ${v2SnmpTrapIp}:${v2SnmpTrapPort}%${v2MgmtVrf}/" "/etc/sonic/snmp.yml" - fi - if [ "${v3SnmpTrapIp}" != "" ] - then - sed -i "s/v3_trap_dest:.*/v3_trap_dest: ${v3SnmpTrapIp}:${v3SnmpTrapPort}%${v3MgmtVrf}/" "/etc/sonic/snmp.yml" - fi - - if [ "${vrfenabled}" == "true" ] - then - keys=`/usr/bin/redis-cli -n 4 keys "SNMP_AGENT_ADDRESS_CONFIG|*"` - count=1 - for key in $keys;do - ip=`echo $key|cut -d "|" -f2` - vrf=`echo $key|cut -d "|" -f3` - echo "snmp_agent_address_$count: $ip%$vrf" >> /tmp/snmpagentaddr.yml - count=$((count+1)) - done - sed -i '/snmp_agent_address_*/d' /etc/sonic/snmp.yml - cat /tmp/snmpagentaddr.yml >> /etc/sonic/snmp.yml - fi {%- else %} : # nothing {%- endif %} From 2694e66074efd5661ef4dbdd50beec6a6bbc96ef Mon Sep 17 00:00:00 2001 From: "arheneus@marvell.com" <51254330+antony-rheneus@users.noreply.github.com> Date: Fri, 11 Oct 2019 03:41:26 +0530 Subject: [PATCH 064/278] [build]: build ARM kernel support from sonic-linux-kernel (#3556) * Makefile: ARM kernel support from sonic-linux-kernel * Fix for multiarch build docker spawn Platform: Install the DTB deb for the platform Signed-off-by: Antony Rheneus --- Makefile.work | 4 +++- build_debian.sh | 7 +------ platform/marvell-armhf/linux-kernel-armhf.mk | 13 +++++-------- platform/marvell-armhf/linux/Makefile | 6 +++--- platform/marvell-armhf/platform.conf | 2 +- rules/linux-kernel.mk | 4 ++++ sonic-slave-stretch/Dockerfile.j2 | 3 +++ 7 files changed, 20 insertions(+), 19 deletions(-) diff --git a/Makefile.work b/Makefile.work index cc433ca98e0c..e18cabeda9ca 100644 --- a/Makefile.work +++ b/Makefile.work @@ -126,7 +126,7 @@ ifneq (,$(filter $(CONFIGURED_ARCH), armhf arm64)) DOCKER_MULTIARCH_CHECK := docker inspect --type image multiarch/qemu-user-static:register &> /dev/null || (echo "multiarch docker not found ..."; docker run --rm --privileged multiarch/qemu-user-static:register --reset --credential yes) - DOCKER_SERVICE_MULTIARCH_CHECK := docker -H unix:///var/run/march/docker.sock info &> /dev/null || (echo "Docker march service not running..."; sudo rm -fr /var/run/march/*; (sudo $(SONIC_NATIVE_DOCKERD_FOR_MUTLIARCH) &) &>/dev/null ; sleep 1; sudo $(SONIC_USERFACL_DOCKERD_FOR_MUTLIARCH);) + DOCKER_SERVICE_MULTIARCH_CHECK := docker -H unix:///var/run/march/docker.sock info &> /dev/null || (echo "Docker march service not running..."; sudo rm -fr /var/run/march/; (sudo $(SONIC_NATIVE_DOCKERD_FOR_MUTLIARCH) &) &>/dev/null ; sleep 1; sudo $(SONIC_USERFACL_DOCKERD_FOR_MUTLIARCH);) # Docker service to load the compiled dockers-*.gz SONIC_NATIVE_DOCKERD_FOR_DOCKERFS := rm -fr $(PWD)/dockerfs/; mkdir -p $(PWD)/dockerfs/; sudo dockerd --storage-driver=overlay2 --iptables=false \ @@ -184,8 +184,10 @@ SONIC_BUILD_INSTRUCTION := make \ %:: ifneq (,$(filter $(CONFIGURED_ARCH), armhf arm64)) @$(DOCKER_MULTIARCH_CHECK) +ifneq ($(BLDENV), ) @$(DOCKER_SERVICE_MULTIARCH_CHECK) @$(DOCKER_SERVICE_DOCKERFS_CHECK) +endif endif @$(OVERLAY_MODULE_CHECK) diff --git a/build_debian.sh b/build_debian.sh index 34bf6eba6ab1..c1a13d1ae7d3 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -132,16 +132,11 @@ fi sudo LANG=C chroot $FILESYSTEM_ROOT apt-get -y install busybox echo '[INFO] Install SONiC linux kernel image' ## Note: duplicate apt-get command to ensure every line return zero -if [[ $CONFIGURED_ARCH == armhf || $CONFIGURED_ARCH == arm64 ]]; then - sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install cpio klibc-utils kmod libklibc udev linux-base - sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/linux-image-*${CONFIGURED_ARCH}*.deb || \ - sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f -fi sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/initramfs-tools-core_*.deb || \ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/initramfs-tools_*.deb || \ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f -sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/linux-image-${LINUX_KERNEL_VERSION}-${CONFIGURED_ARCH}_*.deb || \ +sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/linux-image-${LINUX_KERNEL_VERSION}-*_${CONFIGURED_ARCH}.deb || \ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install acl [[ $CONFIGURED_ARCH == amd64 ]] && sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install dmidecode diff --git a/platform/marvell-armhf/linux-kernel-armhf.mk b/platform/marvell-armhf/linux-kernel-armhf.mk index dc5b489635c8..32e8ea3c604a 100644 --- a/platform/marvell-armhf/linux-kernel-armhf.mk +++ b/platform/marvell-armhf/linux-kernel-armhf.mk @@ -1,10 +1,7 @@ # linux kernel package for marvell armhf -KVERSION = 4.9.168 - - -LINUX_KERNEL = linux-image-4.9.168-armhf.deb -export LINUX_KERNEL - -$(LINUX_KERNEL)_SRC_PATH = $(PLATFORM_PATH)/linux -SONIC_MAKE_DEBS += $(LINUX_KERNEL) +# Add platform specific DTB +LINUX_KERNEL_DTB = linux-image-4.9.168-armhf.deb +$(LINUX_KERNEL_DTB)_URL = https://github.com/Marvell-switching/sonic-marvell-binaries/raw/master/armhf/kernel/$(LINUX_KERNEL_DTB) +SONIC_ONLINE_DEBS += $(LINUX_KERNEL_DTB) +SONIC_STRETCH_DEBS += $(LINUX_KERNEL_DTB) diff --git a/platform/marvell-armhf/linux/Makefile b/platform/marvell-armhf/linux/Makefile index 0a616fa758d9..dba660649abf 100644 --- a/platform/marvell-armhf/linux/Makefile +++ b/platform/marvell-armhf/linux/Makefile @@ -2,9 +2,9 @@ SHELL = /bin/bash .SHELLFLAGS += -e -LINUX_KERNEL_MRVL_URL = https://github.com/Marvell-switching/sonic-marvell-binaries/raw/master/armhf/kernel/$(LINUX_KERNEL) +LINUX_KERNEL_MRVL_URL = https://github.com/Marvell-switching/sonic-marvell-binaries/raw/master/armhf/kernel/$(LINUX_KERNEL_DTB) -$(addprefix $(DEST)/, $(LINUX_KERNEL)): $(DEST)/% : +$(addprefix $(DEST)/, $(LINUX_KERNEL_DTB)): $(DEST)/% : # get deb package - wget -O $(DEST)/$(LINUX_KERNEL) $(LINUX_KERNEL_MRVL_URL) + wget -O $(DEST)/$(LINUX_KERNEL_DTB) $(LINUX_KERNEL_MRVL_URL) diff --git a/platform/marvell-armhf/platform.conf b/platform/marvell-armhf/platform.conf index 51a4dc315acc..e574a8d1a0cd 100644 --- a/platform/marvell-armhf/platform.conf +++ b/platform/marvell-armhf/platform.conf @@ -8,7 +8,7 @@ echo "Preparing for installation ... " kernel_addr=0x1100000 fdt_addr=0x1000000 -image_name="/boot/zImage" +image_name="/vmlinuz" fdt_name="/boot/armada-385-ET6448M_4G_Nand.dtb" # global mount defines diff --git a/rules/linux-kernel.mk b/rules/linux-kernel.mk index bc95255e0dff..5250f8b97e8f 100644 --- a/rules/linux-kernel.mk +++ b/rules/linux-kernel.mk @@ -4,6 +4,10 @@ KVERSION_SHORT = 4.9.0-9-2 KVERSION = $(KVERSION_SHORT)-$(CONFIGURED_ARCH) KERNEL_VERSION = 4.9.168 KERNEL_SUBVERSION = 1+deb9u5 +ifeq ($(CONFIGURED_ARCH), armhf) +# Override kernel version for ARMHF as it uses arm MP (multi-platform) for short version +KVERSION = $(KVERSION_SHORT)-armmp +endif export KVERSION_SHORT KVERSION KERNEL_VERSION KERNEL_SUBVERSION diff --git a/sonic-slave-stretch/Dockerfile.j2 b/sonic-slave-stretch/Dockerfile.j2 index e468cdf354a8..af6e7deadc31 100644 --- a/sonic-slave-stretch/Dockerfile.j2 +++ b/sonic-slave-stretch/Dockerfile.j2 @@ -156,6 +156,9 @@ RUN apt-get update && apt-get install -y \ # For broadcom sdk build {%- if CONFIGURED_ARCH == "amd64" %} linux-compiler-gcc-6-x86 \ +{%- endif %} +{%- if CONFIGURED_ARCH == "armhf" %} + linux-compiler-gcc-6-arm \ {%- endif %} linux-kbuild-4.9 \ # teamd build From 7988deb2884f0719b70cab89c375367160c233b4 Mon Sep 17 00:00:00 2001 From: Haiyang Zheng Date: Fri, 11 Oct 2019 08:15:12 -0700 Subject: [PATCH 065/278] [teamd] fix lacp fallback mode in teamd v1.28 (#3572) In teamd v1.28, the port can only be enabled if sync bit is set in recveived LACPDU from partner by the following commit "teamd: lacp: update port state according to partner's sync bit" (https://github.com/jpirko/libteam/commit/54f137c10579bf97800c61ebb13e732aa1d843e6) However, lacp fallback feature needs to enable port even if partner LACPDU is not received within a given period and fallback cfg is enabled. To fix the lacp fallback breakage, we have to bypass the sync bit check in lacp fallback mode. Signed-off-by: Haiyang Zheng --- ...back-support-for-single-member-port-.patch | 48 ++++++++++++------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/libteam/patch/0003-libteam-Add-fallback-support-for-single-member-port-.patch b/src/libteam/patch/0003-libteam-Add-fallback-support-for-single-member-port-.patch index 8559e476aec1..e1234c294fd8 100644 --- a/src/libteam/patch/0003-libteam-Add-fallback-support-for-single-member-port-.patch +++ b/src/libteam/patch/0003-libteam-Add-fallback-support-for-single-member-port-.patch @@ -1,17 +1,16 @@ -From 9b40af58575a89d06be51cfbb5a2265a59826110 Mon Sep 17 00:00:00 2001 -From: yorke -Date: Mon, 3 Jun 2019 12:02:36 +0800 -Subject: [PATCH 3/8] [libteam] Add fallback support for single-member-port LAG - From: Haiyang Zheng Date: Fri, 15 Dec - 2017 21:07:53 -0800 +commit f475746f56602a40861b8d94eac5f0979c4703f3 +Author: yorke +Date: Mon Jun 3 12:02:36 2019 +0800 -Signed-off-by: yorke ---- - teamd/teamd_runner_lacp.c | 42 ++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 40 insertions(+), 2 deletions(-) + From 9b40af58575a89d06be51cfbb5a2265a59826110 Mon Sep 17 00:00:00 2001 + Subject: [PATCH 3/8] [libteam] Add fallback support for single-member-port LAG + From: Haiyang Zheng Date: Fri, 15 Dec + 2017 21:07:53 -0800 + + Signed-off-by: yorke diff --git a/teamd/teamd_runner_lacp.c b/teamd/teamd_runner_lacp.c -index 4dbd015..9836824 100644 +index 4dbd015..f8a9e16 100644 --- a/teamd/teamd_runner_lacp.c +++ b/teamd/teamd_runner_lacp.c @@ -138,6 +138,8 @@ struct lacp { @@ -71,7 +70,27 @@ index 4dbd015..9836824 100644 return false; return true; } -@@ -1502,6 +1525,16 @@ static int lacp_state_fast_rate_get(struct teamd_context *ctx, +@@ -334,7 +357,8 @@ static int lacp_port_should_be_enabled(struct lacp_port *lacp_port) + + if (lacp_port_selected(lacp_port) && + lacp_port->agg_lead == lacp->selected_agg_lead && +- lacp_port->partner.state & INFO_STATE_SYNCHRONIZATION) ++ (lacp_port->partner.state & INFO_STATE_SYNCHRONIZATION || ++ is_lacp_fallback_eligible(lacp_port))) + return true; + return false; + } +@@ -345,7 +369,8 @@ static int lacp_port_should_be_disabled(struct lacp_port *lacp_port) + + if (!lacp_port_selected(lacp_port) || + lacp_port->agg_lead != lacp->selected_agg_lead || +- !(lacp_port->partner.state & INFO_STATE_SYNCHRONIZATION)) ++ (!(lacp_port->partner.state & INFO_STATE_SYNCHRONIZATION) && ++ !is_lacp_fallback_eligible(lacp_port))) + return true; + return false; + } +@@ -1502,6 +1527,16 @@ static int lacp_state_fast_rate_get(struct teamd_context *ctx, return 0; } @@ -88,7 +107,7 @@ index 4dbd015..9836824 100644 static int lacp_state_select_policy_get(struct teamd_context *ctx, struct team_state_gsc *gsc, void *priv) -@@ -1529,6 +1562,11 @@ static const struct teamd_state_val lacp_state_vals[] = { +@@ -1529,6 +1564,11 @@ static const struct teamd_state_val lacp_state_vals[] = { .getter = lacp_state_fast_rate_get, }, { @@ -100,6 +119,3 @@ index 4dbd015..9836824 100644 .subpath = "select_policy", .type = TEAMD_STATE_ITEM_TYPE_STRING, .getter = lacp_state_select_policy_get, --- -2.7.4 - From bdf7d24962b85e8c830cb9fb12f8c4fdfd99cff2 Mon Sep 17 00:00:00 2001 From: fk410167 <51665572+fk410167@users.noreply.github.com> Date: Sat, 12 Oct 2019 01:55:45 +0530 Subject: [PATCH 066/278] [sonic-cfggen]: yaml.load() is deprecated in latest versions of PyYAML module (#3526) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 5.1 version of PyYAML python module, yaml.load() API is deprecated. Code should be compatible to support both the versions, else error/warning messages are seen like below, 2019-07-02 08:25:35,284 – INFO: [D1] /usr/local/lib/python2.7/dist-packages/sonic_device_util.py:44: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details. --- src/sonic-config-engine/sonic-cfggen | 5 ++++- src/sonic-config-engine/sonic_device_util.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sonic-config-engine/sonic-cfggen b/src/sonic-config-engine/sonic-cfggen index b07172b17e75..2f4e9c5eb89b 100755 --- a/src/sonic-config-engine/sonic-cfggen +++ b/src/sonic-config-engine/sonic-cfggen @@ -229,7 +229,10 @@ def main(): for yaml_file in args.yaml: with open(yaml_file, 'r') as stream: - additional_data = yaml.load(stream) + if yaml.__version__ >= "5.1": + additional_data = yaml.full_load(stream) + else: + additional_data = yaml.load(stream) deep_update(data, FormatConverter.to_deserialized(additional_data)) for json_file in args.json: diff --git a/src/sonic-config-engine/sonic_device_util.py b/src/sonic-config-engine/sonic_device_util.py index c7b2528194fc..34877600fd13 100644 --- a/src/sonic-config-engine/sonic_device_util.py +++ b/src/sonic-config-engine/sonic_device_util.py @@ -42,7 +42,10 @@ def get_sonic_version_info(): return None data = {} with open('/etc/sonic/sonic_version.yml') as stream: - data = yaml.load(stream) + if yaml.__version__ >= "5.1": + data = yaml.full_load(stream) + else: + data = yaml.load(stream) return data def valid_mac_address(mac): From 0d2aa7fb5b383d87cefe52779f9a6dc9b45efc83 Mon Sep 17 00:00:00 2001 From: Wenda Ni Date: Tue, 15 Oct 2019 06:03:48 -0700 Subject: [PATCH 067/278] [devices]: PG headroom change for Arista 7260 (#3600) Signed-off-by: Wenda Ni --- .../pg_profile_lookup.ini | 14 ++++++------- .../Arista-7260CX3-Q64/pg_profile_lookup.ini | 20 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/pg_profile_lookup.ini b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/pg_profile_lookup.ini index c2bf04950b80..ed0005610b71 100644 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/pg_profile_lookup.ini +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/pg_profile_lookup.ini @@ -1,8 +1,8 @@ # PG lossless profiles. -# speed cable size xon xoff threshold xon_offset - 50000 5m 1248 1248 56160 -3 2496 - 100000 5m 1248 1248 96928 -3 2496 - 50000 40m 1248 1248 56160 -3 2496 - 100000 40m 1248 1248 96928 -3 2496 - 50000 300m 1248 1248 56160 -3 2496 - 100000 300m 1248 1248 96928 -3 2496 +# speed cable size xon xoff threshold xon_offset + 50000 5m 1248 1248 56160 -3 2496 + 100000 5m 1248 1248 96928 -3 2496 + 50000 40m 1248 1248 96096 -3 2496 + 100000 40m 1248 1248 177632 -3 2496 + 50000 300m 1248 1248 141856 -3 2496 + 100000 300m 1248 1248 268736 -3 2496 diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-Q64/pg_profile_lookup.ini b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-Q64/pg_profile_lookup.ini index 34ac8b2ca700..ac33b4f961fb 100644 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-Q64/pg_profile_lookup.ini +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-Q64/pg_profile_lookup.ini @@ -1,11 +1,11 @@ # PG lossless profiles. -# speed cable size xon xoff threshold xon_offset - 40000 5m 1248 1248 56160 -3 2496 - 50000 5m 1248 1248 56160 -3 2496 - 100000 5m 1248 1248 96928 -3 2496 - 40000 40m 1248 1248 56160 -3 2496 - 50000 40m 1248 1248 56160 -3 2496 - 100000 40m 1248 1248 96928 -3 2496 - 40000 300m 1248 1248 56160 -3 2496 - 50000 300m 1248 1248 56160 -3 2496 - 100000 300m 1248 1248 96928 -3 2496 +# speed cable size xon xoff threshold xon_offset + 40000 5m 1248 1248 56160 -3 2496 + 50000 5m 1248 1248 56160 -3 2496 + 100000 5m 1248 1248 96928 -3 2496 + 40000 40m 1248 1248 71552 -3 2496 + 50000 40m 1248 1248 96096 -3 2496 + 100000 40m 1248 1248 177632 -3 2496 + 40000 300m 1248 1248 108160 -3 2496 + 50000 300m 1248 1248 141856 -3 2496 + 100000 300m 1248 1248 268736 -3 2496 From 34d8842fbdee1fbd0139ade7279ad0111749322d Mon Sep 17 00:00:00 2001 From: wangshengjun Date: Wed, 16 Oct 2019 02:13:48 +0800 Subject: [PATCH 068/278] [FRR]: Use stg in a proper way. (#3589) * [FRR]: Use stg in a proper way. Signed-off-by: wangshengjun * [FRR]restore the detach status for frr submodule after finish patching Signed-off-by: wangshengjun * [FRR]use the 'FRR_VERSION' exported from 'rule/frr.mk'. Signed-off-by: wangshengjun --- src/sonic-frr/Makefile | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sonic-frr/Makefile b/src/sonic-frr/Makefile index 4a31f23436ec..233696de804a 100644 --- a/src/sonic-frr/Makefile +++ b/src/sonic-frr/Makefile @@ -4,20 +4,23 @@ SHELL = /bin/bash MAIN_TARGET = $(FRR) DERIVED_TARGET = $(FRR_PYTHONTOOLS) $(FRR_DBG) $(FRR_SNMP) $(FRR_SNMP_DBG) -BRANCH = $(shell date +%Y%m%d\.%H%M%S) +FRR_BRANCH = frr/$(FRR_VERSION) +STG_BRANCH = stg_temp $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : # Build the package - pushd ./frr - git checkout -b $(BRANCH) origin/frr/7.1 - stg init + pushd ./frr + git checkout -b $(FRR_BRANCH) origin/$(FRR_BRANCH) + stg branch --create $(STG_BRANCH) $(FRR_BRANCH) stg import -s ../patch/series tools/tarsource.sh -V -e '-sonic' dpkg-buildpackage -rfakeroot -b -us -uc -Ppkg.frr.nortrlib -j$(SONIC_CONFIG_MAKE_JOBS) stg undo git clean -xfdf - git checkout frr/7.1 - git branch -D $(BRANCH) + git checkout $(FRR_BRANCH) + stg branch --delete $(STG_BRANCH) + git rev-parse --short HEAD | xargs git checkout + git branch -D $(FRR_BRANCH) popd mv $(DERIVED_TARGET) $* $(DEST)/ From aea09ba1da612710e725692a097b807aaca95007 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Wed, 16 Oct 2019 02:29:45 +0800 Subject: [PATCH 069/278] [sonic_platform] Correct the wrong log identifiers (#3596) --- .../mellanox/mlnx-platform-api/sonic_platform/chassis.py | 3 +-- platform/mellanox/mlnx-platform-api/sonic_platform/psu.py | 3 +-- platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py | 3 +-- .../mellanox/mlnx-platform-api/sonic_platform/sfp_event.py | 4 +--- .../mellanox/mlnx-platform-api/sonic_platform/thermal.py | 3 +-- src/sonic-daemon-base/sonic_daemon_base/daemon_base.py | 7 +++++-- 6 files changed, 10 insertions(+), 13 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index f5c7c04a4204..f964bf46fe88 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -39,8 +39,7 @@ REBOOT_CAUSE_FILE_LENGTH = 1 # Global logger class instance -SYSLOG_IDENTIFIER = "mlnx-chassis-api" -logger = Logger(SYSLOG_IDENTIFIER) +logger = Logger() # magic code defnition for port number, qsfp port position of each hwsku # port_position_tuple = (PORT_START, QSFP_PORT_START, PORT_END, PORT_IN_BLOCK, EEPROM_OFFSET) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/psu.py b/platform/mellanox/mlnx-platform-api/sonic_platform/psu.py index a6f217d82bd3..0789f67e4f09 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/psu.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/psu.py @@ -17,8 +17,7 @@ raise ImportError (str(e) + "- required module not found") # Global logger class instance -SYSLOG_IDENTIFIER = "mlnx-psu-api" -logger = Logger(SYSLOG_IDENTIFIER) +logger = Logger() psu_list = [] diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py index be59451a8cb7..dac6a8e4d4d6 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py @@ -188,8 +188,7 @@ NVE_MASK = PORT_TYPE_MASK & (PORT_TYPE_NVE << PORT_TYPE_OFFSET) # Global logger class instance -SYSLOG_IDENTIFIER = "mlnx-sfp" -logger = Logger(SYSLOG_IDENTIFIER) +logger = Logger() class SFP(SfpBase): """Platform-specific SFP class""" diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp_event.py b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp_event.py index 439df785b24e..e92884fc3f33 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp_event.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp_event.py @@ -11,8 +11,6 @@ from python_sdk_api.sx_api import * from sonic_daemon_base.daemon_base import Logger -SYSLOG_IDENTIFIER = "sfp-event" - SDK_SFP_STATE_IN = 0x1 SDK_SFP_STATE_OUT = 0x2 STATUS_PLUGIN = '1' @@ -34,7 +32,7 @@ PMPE_PACKET_SIZE = 2000 -logger = Logger(SYSLOG_IDENTIFIER) +logger = Logger() class sfp_event: ''' Listen to plugin/plugout cable events ''' diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal.py b/platform/mellanox/mlnx-platform-api/sonic_platform/thermal.py index 6614e368e547..6862b3fb258b 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/thermal.py @@ -19,8 +19,7 @@ raise ImportError (str(e) + "- required module not found") # Global logger class instance -SYSLOG_IDENTIFIER = "mlnx-thermal-api" -logger = Logger(SYSLOG_IDENTIFIER) +logger = Logger() THERMAL_DEV_CATEGORY_CPU_CORE = "cpu_core" THERMAL_DEV_CATEGORY_CPU_PACK = "cpu_pack" diff --git a/src/sonic-daemon-base/sonic_daemon_base/daemon_base.py b/src/sonic-daemon-base/sonic_daemon_base/daemon_base.py index afdb189de672..a0a5bff0a297 100644 --- a/src/sonic-daemon-base/sonic_daemon_base/daemon_base.py +++ b/src/sonic-daemon-base/sonic_daemon_base/daemon_base.py @@ -48,9 +48,12 @@ def db_connect(db): # class Logger(object): - def __init__(self, syslog_identifier): + def __init__(self, syslog_identifier = None): self.syslog = syslog - self.syslog.openlog(ident=syslog_identifier, logoption=self.syslog.LOG_NDELAY, facility=self.syslog.LOG_DAEMON) + if syslog_identifier is None: + self.syslog.openlog() + else: + self.syslog.openlog(ident=syslog_identifier, logoption=self.syslog.LOG_NDELAY, facility=self.syslog.LOG_DAEMON) def __del__(self): self.syslog.closelog() From 17c21acacfae212cb24c2fd599d81318bd328aab Mon Sep 17 00:00:00 2001 From: Andriy Kokhan <43479230+akokhan@users.noreply.github.com> Date: Tue, 15 Oct 2019 21:32:02 +0300 Subject: [PATCH 070/278] [platform] Fixed return code processing in set_low_power_mode() for BFN platform (#3610) Signed-off-by: Andriy Kokhan --- .../barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/sfputil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/sfputil.py b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/sfputil.py index 5e75376baa27..1daee453573e 100644 --- a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/sfputil.py +++ b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/sfputil.py @@ -135,7 +135,7 @@ def set_low_power_mode(self, port_num, lpmode): self.thrift_setup() status = pltfm_mgr.pltfm_mgr_qsfp_lpmode_set(port_num, lpmode) self.thrift_teardown() - return status + return (status == 0) def reset(self, port_num): # Check for invalid port_num From 9032ad8b121fcee5e4afdd16a7f6c9f7790a38c0 Mon Sep 17 00:00:00 2001 From: shikenghua Date: Wed, 16 Oct 2019 02:45:09 +0800 Subject: [PATCH 071/278] [docker-fpm-frr] Change the ownership of files within /etc/frr/ to frr (#3388) The owner of the generated files (/etc/frr/*.conf) by start.sh is root if it is a new file. This will cause error when executing "copy running-config startup-config" in vtysh because of privilege issue. --- dockers/docker-fpm-frr/start.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dockers/docker-fpm-frr/start.sh b/dockers/docker-fpm-frr/start.sh index fd092919e000..3c732fece943 100755 --- a/dockers/docker-fpm-frr/start.sh +++ b/dockers/docker-fpm-frr/start.sh @@ -16,6 +16,8 @@ elif [ "$CONFIG_TYPE" == "unified" ]; then rm -f /etc/frr/bgpd.conf /etc/frr/zebra.conf /etc/frr/staticd.conf fi +chown -R frr:frr /etc/frr/ + sonic-cfggen -d -t /usr/share/sonic/templates/isolate.j2 > /usr/sbin/bgp-isolate chown root:root /usr/sbin/bgp-isolate chmod 0755 /usr/sbin/bgp-isolate From 2e3fb905a388e9421074bb6057f4eb7c1107eebe Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Wed, 16 Oct 2019 02:46:09 +0800 Subject: [PATCH 072/278] [Mellanox]Correct reboot cause when reboot via power cycle (#3597) * [sonic_platform]remove the handling of reset_sw_reset which indicates rebooted by software. * [sonic_platform]Check "reset_sw_reset" Also check reboot cause file "reset_sw_reset" which indicates the system was rebooted due to software requesting. --- .../mellanox/mlnx-platform-api/sonic_platform/chassis.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index f964bf46fe88..fe4f7d452def 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -319,11 +319,11 @@ def initialize_reboot_cause(self): 'reset_comex_wd' : "Reset requested from ComEx", 'reset_from_asic' : "Reset requested from ASIC", 'reset_reload_bios' : "Reset caused by BIOS reload", - 'reset_sw_reset' : "Software reset", 'reset_hotswap_or_halt' : "Reset caused by hotswap or halt", 'reset_from_comex' : "Reset from ComEx", 'reset_voltmon_upgrade_fail': "Reset due to voltage monitor devices upgrade failure" } + self.reboot_by_software = 'reset_sw_reset' self.reboot_cause_initialized = True @@ -350,6 +350,11 @@ def get_reboot_cause(self): if self._verify_reboot_cause(reset_file): return self.REBOOT_CAUSE_HARDWARE_OTHER, reset_cause + if self._verify_reboot_cause(self.reboot_by_software): + logger.log_info("Hardware reboot cause: the system was rebooted due to software requesting") + else: + logger.log_info("Hardware reboot cause: no hardware reboot cause found") + return self.REBOOT_CAUSE_NON_HARDWARE, '' From 91e785279abd96714902b4b24194c1ca3387e21b Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Wed, 16 Oct 2019 04:40:53 +0800 Subject: [PATCH 073/278] [Mellanox] remove mlnx-sfpd (#3609) * [platform/mellanox] remove mlnx-sfpd * [platform/mellanox] remove mlnx-sfpd source files --- platform/mellanox/docker-syncd-mlnx.mk | 1 - platform/mellanox/docker-syncd-mlnx/start.sh | 2 - .../docker-syncd-mlnx/supervisord.conf | 8 - platform/mellanox/mlnx-sfpd.mk | 5 - platform/mellanox/mlnx-sfpd/scripts/mlnx-sfpd | 305 ------------------ platform/mellanox/mlnx-sfpd/setup.py | 28 -- platform/mellanox/rules.mk | 1 - 7 files changed, 350 deletions(-) delete mode 100644 platform/mellanox/mlnx-sfpd.mk delete mode 100644 platform/mellanox/mlnx-sfpd/scripts/mlnx-sfpd delete mode 100644 platform/mellanox/mlnx-sfpd/setup.py diff --git a/platform/mellanox/docker-syncd-mlnx.mk b/platform/mellanox/docker-syncd-mlnx.mk index b46c6478cf0e..db582e517bff 100644 --- a/platform/mellanox/docker-syncd-mlnx.mk +++ b/platform/mellanox/docker-syncd-mlnx.mk @@ -4,7 +4,6 @@ DOCKER_SYNCD_PLATFORM_CODE = mlnx include $(PLATFORM_PATH)/../template/docker-syncd-base.mk $(DOCKER_SYNCD_BASE)_DEPENDS += $(SYNCD) $(PYTHON_SDK_API) -$(DOCKER_SYNCD_BASE)_PYTHON_DEBS += $(MLNX_SFPD) $(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $(SYNCD_DBG) \ $(LIBSWSSCOMMON_DBG) \ diff --git a/platform/mellanox/docker-syncd-mlnx/start.sh b/platform/mellanox/docker-syncd-mlnx/start.sh index 61ccd2db8933..96e2a9128081 100755 --- a/platform/mellanox/docker-syncd-mlnx/start.sh +++ b/platform/mellanox/docker-syncd-mlnx/start.sh @@ -6,5 +6,3 @@ supervisorctl start rsyslogd supervisorctl start syncd -supervisorctl start mlnx-sfpd - diff --git a/platform/mellanox/docker-syncd-mlnx/supervisord.conf b/platform/mellanox/docker-syncd-mlnx/supervisord.conf index 8860bd6c0205..1af5d70a1d0c 100644 --- a/platform/mellanox/docker-syncd-mlnx/supervisord.conf +++ b/platform/mellanox/docker-syncd-mlnx/supervisord.conf @@ -26,11 +26,3 @@ autostart=false autorestart=false stdout_logfile=syslog stderr_logfile=syslog - -[program:mlnx-sfpd] -command=/usr/bin/mlnx-sfpd -priority=4 -autostart=false -autorestart=false -stdout_logfile=syslog -stderr_logfile=syslog diff --git a/platform/mellanox/mlnx-sfpd.mk b/platform/mellanox/mlnx-sfpd.mk deleted file mode 100644 index 416dd7d0f2cd..000000000000 --- a/platform/mellanox/mlnx-sfpd.mk +++ /dev/null @@ -1,5 +0,0 @@ -# mlnx-sfpd (SONiC MLNX platform sfp event monitoring daemon) Debian package - -MLNX_SFPD = python-mlnx-sfpd_1.0-1_all.deb -$(MLNX_SFPD)_SRC_PATH = $(PLATFORM_PATH)/mlnx-sfpd -SONIC_PYTHON_STDEB_DEBS += $(MLNX_SFPD) diff --git a/platform/mellanox/mlnx-sfpd/scripts/mlnx-sfpd b/platform/mellanox/mlnx-sfpd/scripts/mlnx-sfpd deleted file mode 100644 index b11403b31514..000000000000 --- a/platform/mellanox/mlnx-sfpd/scripts/mlnx-sfpd +++ /dev/null @@ -1,305 +0,0 @@ -#!/usr/bin/env python -''' -This code is for a mlnx platform specific daemon, mlnx-sfpd. -Which listen to the SDK for the SFP change event and post the event to DB. -''' - -from __future__ import print_function -import sys, errno -import os -import time -import syslog -import signal -import select -import json -import threading -from python_sdk_api.sx_api import * -from swsssdk import SonicV2Connector - -VERSION = '1.0' - -SYSLOG_IDENTIFIER = "mlnx-sfpd" - -REDIS_HOSTIP = "127.0.0.1" - -SDK_SFP_STATE_IN = 0x1 -SDK_SFP_STATE_OUT = 0x2 -STATUS_PLUGIN = '1' -STATUS_PLUGOUT = '0' -STATUS_UNKNOWN = '2' - -SFPD_LIVENESS_EXPIRE_SECS = 30 - -SDK_DAEMON_READY_FILE = '/tmp/sdk_ready' - -sfp_value_status_dict = { - SDK_SFP_STATE_IN: STATUS_PLUGIN, - SDK_SFP_STATE_OUT: STATUS_PLUGOUT, -} - -# ========================== Syslog wrappers ========================== -def log_info(msg, also_print_to_console=False): - syslog.openlog(SYSLOG_IDENTIFIER) - syslog.syslog(syslog.LOG_INFO, msg) - syslog.closelog() - - if also_print_to_console: - print(msg) - -def log_warning(msg, also_print_to_console=False): - syslog.openlog(SYSLOG_IDENTIFIER) - syslog.syslog(syslog.LOG_WARNING, msg) - syslog.closelog() - - if also_print_to_console: - print(msg) - -def log_error(msg, also_print_to_console=False): - syslog.openlog(SYSLOG_IDENTIFIER) - syslog.syslog(syslog.LOG_ERR, msg) - syslog.closelog() - - if also_print_to_console: - print(msg) - -# ========================== MlnxSfpd class ========================== -class MlnxSfpd: - ''' Listen to plugin/plugout cable events ''' - - SX_OPEN_RETRIES = 30 - SX_OPEN_TIMEOUT = 5 - SELECT_TIMEOUT = 1 - - def __init__(self): - self.swid = 0 - self.running = False - self.handle = None - - # Allocate SDK fd and user channel structures - self.rx_fd_p = new_sx_fd_t_p() - self.user_channel_p = new_sx_user_channel_t_p() - self.state_db = SonicV2Connector(host=REDIS_HOSTIP) - - # Register our signal handlers - signal.signal(signal.SIGHUP, self.signal_handler) - signal.signal(signal.SIGINT, self.signal_handler) - signal.signal(signal.SIGTERM, self.signal_handler) - - def signal_handler(self, signum, frame): - if signum == signal.SIGHUP: - log_info("Caught SIGHUP - ignoring...") - elif signum == signal.SIGINT: - log_info("Caught SIGINT - exiting...") - self.running = False - elif signum == signal.SIGTERM: - log_info("Caught SIGINT - exiting...") - self.running = False - else: - log_warning("Caught unhandled signal '{}'".format(signum)) - - def initialize(self): - self.state_db.connect("STATE_DB") - - swid_cnt_p = None - - try: - # Wait for SDK daemon to be started with detect the sdk_ready file - retry = 0 - while not os.path.exists(SDK_DAEMON_READY_FILE): - if retry >= self.SX_OPEN_RETRIES: - raise RuntimeError("SDK daemon failed to start after {} retries and {} seconds waiting, exiting..." - .format(retry, self.SX_OPEN_TIMEOUT * self.SX_OPEN_RETRIES)) - else: - log_info("SDK daemon not started yet, retry {} times".format(retry)) - retry = retry + 1 - time.sleep(self.SX_OPEN_TIMEOUT) - - # to make sure SDK daemon has started - time.sleep(self.SX_OPEN_TIMEOUT) - - # After SDK daemon started, sx_api_open and sx_api_host_ifc_open is ready for call - rc, self.handle = sx_api_open(None) - if rc != SX_STATUS_SUCCESS: - raise RuntimeError("failed to call sx_api_open with rc {}, exiting...".format(rc)) - - rc = sx_api_host_ifc_open(self.handle, self.rx_fd_p) - if rc != SX_STATUS_SUCCESS: - raise RuntimeError("failed to call sx_api_host_ifc_open with rc {}, exiting...".format(rc)) - - self.user_channel_p.type = SX_USER_CHANNEL_TYPE_FD - self.user_channel_p.channel.fd = self.rx_fd_p - - # Wait for switch to be created and initialized inside SDK - retry = 0 - swid_cnt_p = new_uint32_t_p() - uint32_t_p_assign(swid_cnt_p, 0) - swid_cnt = 0 - while True: - if retry >= self.SX_OPEN_RETRIES: - raise RuntimeError("switch not created after {} retries and {} seconds waiting, exiting..." - .format(retry, self.SX_OPEN_RETRIES * self.SX_OPEN_TIMEOUT)) - else: - rc = sx_api_port_swid_list_get(self.handle, None, swid_cnt_p) - if rc == SX_STATUS_SUCCESS: - swid_cnt = uint32_t_p_value(swid_cnt_p) - if swid_cnt > 0: - delete_uint32_t_p(swid_cnt_p) - swid_cnt_p = None - break - else: - log_info("switch not created yet, swid_cnt {}, retry {} times and wait for {} seconds" - .format(swid_cnt, retry, self.SX_OPEN_TIMEOUT * retry)) - else: - raise RuntimeError("sx_api_port_swid_list_get fail with rc {}, retry {} times and wait for {} seconds". - format(rc, retry, self.SX_OPEN_TIMEOUT * retry)) - - retry = retry + 1 - time.sleep(self.SX_OPEN_TIMEOUT) - - # After switch was created inside SDK, sx_api_host_ifc_trap_id_register_set is ready to call - rc = sx_api_host_ifc_trap_id_register_set(self.handle, - SX_ACCESS_CMD_REGISTER, - self.swid, - SX_TRAP_ID_PMPE, - self.user_channel_p) - - if rc != SX_STATUS_SUCCESS: - raise RuntimeError("sx_api_host_ifc_trap_id_register_set failed with rc {}, exiting...".format(rc)) - - self.running = True - except Exception as e: - log_error("mlnx-sfpd initialization failed due to {}, exiting...".format(repr(e))) - if swid_cnt_p is not None: - delete_uint32_t_p(swid_cnt_p) - self.deinitialize() - - def deinitialize(self): - # remove mlnx-sfpd liveness key in DB if not expired yet - if self.state_db.exists("STATE_DB", "MLNX_SFPD_TASK|LIVENESS"): - self.state_db.delete("STATE_DB", "MLNX_SFPD_TASK|LIVENESS") - - if self.handle is None: - return - - # unregister trap id - rc = sx_api_host_ifc_trap_id_register_set(self.handle, - SX_ACCESS_CMD_DEREGISTER, - self.swid, - SX_TRAP_ID_PMPE, - self.user_channel_p) - if rc != SX_STATUS_SUCCESS: - log_error("sx_api_host_ifc_trap_id_register_set exited with error, rc {}".format(rc)) - - rc = sx_api_host_ifc_close(self.handle, self.rx_fd_p) - if rc != SX_STATUS_SUCCESS: - log_error("sx_api_host_ifc_close exited with error, rc {}".format(rc)) - - rc = sx_api_close(self.handle) - if rc != SX_STATUS_SUCCESS: - log_error("sx_api_close exited with error, rc {}".format(rc)) - - def run(self): - - while self.running: - try: - read, _, _ = select.select([self.rx_fd_p.fd], [], [], self.SELECT_TIMEOUT) - except select.error as err: - rc, msg = err - if rc == errno.EAGAIN or rc == errno.EINTR: - continue - else: - raise - - for fd in read: - if fd == self.rx_fd_p.fd: - success, port_list, module_state = self.on_pmpe(self.rx_fd_p) - if not success: - raise RuntimeError("failed to read from {}".format(fd)) - - sfp_state = sfp_value_status_dict.get(module_state, STATUS_UNKNOWN) - if sfp_state == STATUS_UNKNOWN: - log_error("unknown module state {} on port {}".format(module_state, port)) - continue - - for port in port_list: - log_info("SFP on port {} state {}".format(port, sfp_state)) - self.send_sfp_notification(str(port), sfp_state) - - self.update_sfpd_liveness_key(SFPD_LIVENESS_EXPIRE_SECS) - - def send_sfp_notification(self, port, state): - sfp_notify = [port, state] - msg = json.dumps(sfp_notify, separators=(',', ':')) - self.state_db.publish('STATE_DB', 'TRANSCEIVER_NOTIFY', msg) - - def update_sfpd_liveness_key(self, timeout_secs): - if not self.state_db.exists('STATE_DB', 'MLNX_SFPD_TASK|LIVENESS'): - self.state_db.set('STATE_DB', 'MLNX_SFPD_TASK|LIVENESS', 'value', 'ok') - self.state_db.expire('STATE_DB', 'MLNX_SFPD_TASK|LIVENESS', timeout_secs) - - def on_pmpe(self, fd_p): - ''' on port module plug event handler ''' - - # recv parameters - pkt_size = 2000 - pkt_size_p = new_uint32_t_p() - uint32_t_p_assign(pkt_size_p, pkt_size) - pkt = new_uint8_t_arr(pkt_size) - recv_info_p = new_sx_receive_info_t_p() - pmpe_t = sx_event_pmpe_t() - port_attributes_list = new_sx_port_attributes_t_arr(64) - port_cnt_p = new_uint32_t_p() - uint32_t_p_assign(port_cnt_p,64) - label_port_list = [] - module_state = 0 - - rc = sx_lib_host_ifc_recv(fd_p, pkt, pkt_size_p, recv_info_p) - if rc != 0: - log_error("sx_lib_host_ifc_recv exited with error, rc %d" % rc) - status = False - else: - status = True - pmpe_t = recv_info_p.event_info.pmpe - port_list_size = pmpe_t.list_size - logical_port_list = pmpe_t.log_port_list - module_state = pmpe_t.module_state - - for i in xrange(port_list_size): - logical_port = sx_port_log_id_t_arr_getitem(logical_port_list, i) - rc = sx_api_port_device_get(self.handle, 1 , 0, port_attributes_list, port_cnt_p) - port_cnt = uint32_t_p_value(port_cnt_p) - - for i in xrange(port_cnt): - port_attributes = sx_port_attributes_t_arr_getitem(port_attributes_list,i) - if port_attributes.log_port == logical_port: - lable_port = port_attributes.port_mapping.module_port - break - label_port_list.append(lable_port) - - delete_uint32_t_p(pkt_size_p) - delete_uint8_t_arr(pkt) - delete_sx_receive_info_t_p(recv_info_p) - delete_sx_port_attributes_t_arr(port_attributes_list) - delete_uint32_t_p(port_cnt_p) - - return status, label_port_list, module_state, - - -# main start -def main(): - log_info("mlnx-sfpd daemon started") - - sfpd = MlnxSfpd() - try: - sfpd.initialize() - sfpd.run() - except (RuntimeError, select.error) as err: - log_error("error: {}".format(err)) - finally: - sfpd.deinitialize() - - log_info("mlnx-sfpd daemon exited") - - -if __name__ == '__main__': - main() diff --git a/platform/mellanox/mlnx-sfpd/setup.py b/platform/mellanox/mlnx-sfpd/setup.py deleted file mode 100644 index ea9b895cb1f4..000000000000 --- a/platform/mellanox/mlnx-sfpd/setup.py +++ /dev/null @@ -1,28 +0,0 @@ -from setuptools import setup - -setup( - name='mlnx-sfpd', - version='1.0', - description='SFP event mmonitoring daemon for SONiC on mellanox platform', - license='Apache 2.0', - author='SONiC Community', - url='https://github.com/Azure/sonic-buildimage/', - maintainer='Kebo Liu', - maintainer_email='kebol@mellanox.com', - scripts=[ - 'scripts/mlnx-sfpd', - ], - classifiers=[ - 'Development Status :: 4 - Beta', - 'Environment :: No Input/Output (Daemon)', - 'Intended Audience :: Developers', - 'Intended Audience :: Information Technology', - 'Intended Audience :: System Administrators', - 'License :: OSI Approved :: Apache Software License', - 'Natural Language :: English', - 'Operating System :: POSIX :: Linux', - 'Programming Language :: Python :: 2.7', - 'Topic :: System :: Hardware', - ], - keywords='sonic SONiC SFP sfp MELLANOX mellanox daemon SFPD sfpd', -) diff --git a/platform/mellanox/rules.mk b/platform/mellanox/rules.mk index c869bfc6cd3d..dd10cefda571 100644 --- a/platform/mellanox/rules.mk +++ b/platform/mellanox/rules.mk @@ -10,7 +10,6 @@ include $(PLATFORM_PATH)/docker-saiserver-mlnx.mk include $(PLATFORM_PATH)/one-image.mk include $(PLATFORM_PATH)/libsaithrift-dev.mk include $(PLATFORM_PATH)/docker-ptf-mlnx.mk -include $(PLATFORM_PATH)/mlnx-sfpd.mk include $(PLATFORM_PATH)/mlnx-ffb.mk include $(PLATFORM_PATH)/issu-version.mk From 249e858926b974c0b7a3fcc198676d2734aad1e4 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Wed, 16 Oct 2019 23:31:27 +0800 Subject: [PATCH 074/278] [Mellanox] Support SN3800 in platform api (#3593) * [sonic_platform]Support 3800 1. add port position tuple for 3800 * [sonic_platform/chassis] address comments --- platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index fe4f7d452def..44ef8981281f 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -43,8 +43,8 @@ # magic code defnition for port number, qsfp port position of each hwsku # port_position_tuple = (PORT_START, QSFP_PORT_START, PORT_END, PORT_IN_BLOCK, EEPROM_OFFSET) -hwsku_dict_port = {'ACS-MSN2700': 0, "LS-SN2700":0, 'ACS-MSN2740': 0, 'ACS-MSN2100': 1, 'ACS-MSN2410': 2, 'ACS-MSN2010': 3, 'ACS-MSN3700': 0, 'ACS-MSN3700C': 0, 'Mellanox-SN2700': 0, 'Mellanox-SN2700-D48C8': 0} -port_position_tuple_list = [(0, 0, 31, 32, 1), (0, 0, 15, 16, 1), (0, 48, 55, 56, 1),(0, 18, 21, 22, 1)] +hwsku_dict_port = {'ACS-MSN2010': 3, 'ACS-MSN2100': 1, 'ACS-MSN2410': 2, 'ACS-MSN2700': 0, 'Mellanox-SN2700': 0, 'Mellanox-SN2700-D48C8': 0, 'LS-SN2700':0, 'ACS-MSN2740': 0, 'ACS-MSN3700': 0, 'ACS-MSN3700C': 0, 'ACS-MSN3800': 4} +port_position_tuple_list = [(0, 0, 31, 32, 1), (0, 0, 15, 16, 1), (0, 48, 55, 56, 1), (0, 18, 21, 22, 1), (0, 0, 63, 64, 1)] class Chassis(ChassisBase): """Platform-specific Chassis class""" From 48e4cf6971bec1fa8ca3b85f9cf989753104e770 Mon Sep 17 00:00:00 2001 From: sudhanshukumar22 <51457531+sudhanshukumar22@users.noreply.github.com> Date: Thu, 17 Oct 2019 01:32:20 +0530 Subject: [PATCH 075/278] commit 4ea6cafbcad4c72186587b45fa5e2f6c6dbec893 (HEAD -> bgp-snmp-socket-issue, origin/bgp-snmp-socket-issue) (#3604) Author: sudhanshukumar22 Date: Tue Oct 15 02:31:20 2019 -0700 lib: changes for making snmp socket non-blocking Description: The changes have been done to make the snmp socket non-blocking before calling snmp_read() FRR Pull request: https://github.com/FRRouting/frr/pull/5134 Problem Description/Summary : vtysh hangs on first try to enter after a reboot with BGP dynamic peers Expected Behavior : VTYSH should not hang. When we debug more into bgpd docker by doing gdb on its threads, we find the below thread of bgpd, which is causing the issue. Thread 1 (Thread 0x7f1e1ec46d40 (LWP 47)): 0x00007f1e1d762593 in recvfrom () from /lib/x86_64-linux-gnu/libpthread.so.0 0x00007f1e1aadd09b in netsnmp_tcpbase_recv () from /usr/lib/x86_64-linux-gnu/libnetsnmp.so.30 0x00007f1e1aad9617 in netsnmp_transport_recv () from /usr/lib/x86_64-linux-gnu/libnetsnmp.so.30 0x00007f1e1aab2c07 in _sess_read () from /usr/lib/x86_64-linux-gnu/libnetsnmp.so.30 0x00007f1e1aab3a29 in snmp_sess_read2 () from /usr/lib/x86_64-linux-gnu/libnetsnmp.so.30 0x00007f1e1aab3a7b in snmp_read2 () from /usr/lib/x86_64-linux-gnu/libnetsnmp.so.30 0x00007f1e1aab3acf in snmp_read () from /usr/lib/x86_64-linux-gnu/libnetsnmp.so.30 0x00007f1e1b44d7ec in agentx_read (t=0x7fffa75f0080) at lib/agentx.c:63 0x00007f1e1e7d6451 in thread_call (thread=0x7fffa75f0080) at lib/thread.c:1620 0x00007f1e1e770699 in frr_run (master=0x559396ea60f0) at lib/libfrr.c:1011 0x0000559395b4d953 in main (argc=5, argv=0x7fffa75f02b8) at bgpd/bgp_main.c:492 (gdb) bt 0x00007f830c89d210 in __read_nocancel () from /lib/x86_64-linux-gnu/libpthread.so.0 0x000056450e1e8238 in vtysh_client_run (vclient=0x56450e4a8b40 , line=0x56450e21add0 enable, callback=0x0, cbarg=0x0) at vtysh/vtysh.c:216 0x000056450e1e8c6b in vtysh_client_run_all (head_client=0x56450e4a8b40 , line=0x56450e21add0 enable, continue_on_err=0, callback=0x0, cbarg=0x0) at vtysh/vtysh.c:356 0x000056450e1e8ddb in vtysh_client_execute (head_client=0x56450e4a8b40 , line=0x56450e21add0 enable) at vtysh/vtysh.c:393 0x000056450e1e9c82 in vtysh_execute_func (line=0x56450e21add0 enable, pager=0) at vtysh/vtysh.c:598 0x000056450e1e9dee in vtysh_execute_no_pager (line=0x56450e21add0 enable) at vtysh/vtysh.c:619 0x000056450e1f7d48 in vtysh_read_file (confp=0x56451000a9d0, top_cfg=1) at vtysh/vtysh_config.c:494 0x000056450e1f7ef2 in vtysh_read_config (config_default_dir=0x56450e4edc20 /etc/frr/frr.conf, top_cfg=1) at vtysh/vtysh_config.c:522 0x000056450e1e5de4 in vtysh_apply_top_level_config () at vtysh/vtysh_main.c:301 0x000056450e1e7842 in main (argc=2, argv=0x7ffc81e6f598, env=0x7ffc81e6f5b0) at vtysh/vtysh_main.c:692 The fix has been taken from the following link. https://sourceforge.net/p/net-snmp/patches/1348/ --- ...-for-making-snmp-socket-non-blocking.patch | 85 +++++++++++++++++++ src/sonic-frr/patch/series | 1 + 2 files changed, 86 insertions(+) create mode 100644 src/sonic-frr/patch/0006-changes-for-making-snmp-socket-non-blocking.patch diff --git a/src/sonic-frr/patch/0006-changes-for-making-snmp-socket-non-blocking.patch b/src/sonic-frr/patch/0006-changes-for-making-snmp-socket-non-blocking.patch new file mode 100644 index 000000000000..a106eca3d831 --- /dev/null +++ b/src/sonic-frr/patch/0006-changes-for-making-snmp-socket-non-blocking.patch @@ -0,0 +1,85 @@ +From 6d43b90540c6aeda0fff001de93c88e01aacadab Mon Sep 17 00:00:00 2001 +From: sudhanshukumar22 +Date: Tue, 15 Oct 2019 02:11:01 -0700 +Subject: [PATCH] lib: changes for making snmp socket non-blocking + +Description: The changes have been done to make the snmp socket +non-blocking before calling snmp_read() +FRR Pull request: https://github.com/FRRouting/frr/pull/5134 + +Problem Description/Summary : +vtysh hangs on first try to enter after a reboot with BGP dynamic peers + +Expected Behavior : +VTYSH should not hang. +When we debug more into bgpd docker by doing gdb on its threads, we find the below thread of bgpd, which is causing the issue. +Thread 1 (Thread 0x7f1e1ec46d40 (LWP 47)): + +0x00007f1e1d762593 in recvfrom () from /lib/x86_64-linux-gnu/libpthread.so.0 +0x00007f1e1aadd09b in netsnmp_tcpbase_recv () from /usr/lib/x86_64-linux-gnu/libnetsnmp.so.30 +0x00007f1e1aad9617 in netsnmp_transport_recv () from /usr/lib/x86_64-linux-gnu/libnetsnmp.so.30 +0x00007f1e1aab2c07 in _sess_read () from /usr/lib/x86_64-linux-gnu/libnetsnmp.so.30 +0x00007f1e1aab3a29 in snmp_sess_read2 () from /usr/lib/x86_64-linux-gnu/libnetsnmp.so.30 +0x00007f1e1aab3a7b in snmp_read2 () from /usr/lib/x86_64-linux-gnu/libnetsnmp.so.30 +0x00007f1e1aab3acf in snmp_read () from /usr/lib/x86_64-linux-gnu/libnetsnmp.so.30 +0x00007f1e1b44d7ec in agentx_read (t=0x7fffa75f0080) at lib/agentx.c:63 +0x00007f1e1e7d6451 in thread_call (thread=0x7fffa75f0080) at lib/thread.c:1620 +0x00007f1e1e770699 in frr_run (master=0x559396ea60f0) at lib/libfrr.c:1011 +0x0000559395b4d953 in main (argc=5, argv=0x7fffa75f02b8) at bgpd/bgp_main.c:492 + +(gdb) bt + +0x00007f830c89d210 in __read_nocancel () from /lib/x86_64-linux-gnu/libpthread.so.0 +0x000056450e1e8238 in vtysh_client_run (vclient=0x56450e4a8b40 , line=0x56450e21add0 enable, callback=0x0, cbarg=0x0) at vtysh/vtysh.c:216 +0x000056450e1e8c6b in vtysh_client_run_all (head_client=0x56450e4a8b40 , line=0x56450e21add0 enable, continue_on_err=0, callback=0x0, cbarg=0x0) at vtysh/vtysh.c:356 +0x000056450e1e8ddb in vtysh_client_execute (head_client=0x56450e4a8b40 , line=0x56450e21add0 enable) at vtysh/vtysh.c:393 +0x000056450e1e9c82 in vtysh_execute_func (line=0x56450e21add0 enable, pager=0) at vtysh/vtysh.c:598 +0x000056450e1e9dee in vtysh_execute_no_pager (line=0x56450e21add0 enable) at vtysh/vtysh.c:619 +0x000056450e1f7d48 in vtysh_read_file (confp=0x56451000a9d0, top_cfg=1) at vtysh/vtysh_config.c:494 +0x000056450e1f7ef2 in vtysh_read_config (config_default_dir=0x56450e4edc20 /etc/frr/frr.conf, top_cfg=1) at vtysh/vtysh_config.c:522 +0x000056450e1e5de4 in vtysh_apply_top_level_config () at vtysh/vtysh_main.c:301 +0x000056450e1e7842 in main (argc=2, argv=0x7ffc81e6f598, env=0x7ffc81e6f5b0) at vtysh/vtysh_main.c:692 + +The fix has been taken from the following link. +https://sourceforge.net/p/net-snmp/patches/1348/ +--- + lib/agentx.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/lib/agentx.c b/lib/agentx.c +index 40cac722a..2c6a43d1a 100644 +--- a/lib/agentx.c ++++ b/lib/agentx.c +@@ -55,13 +55,29 @@ static int agentx_timeout(struct thread *t) + static int agentx_read(struct thread *t) + { + fd_set fds; ++ int flags; ++ int nonblock = false; + struct listnode *ln = THREAD_ARG(t); + list_delete_node(events, ln); + ++ /* fix for non blocking socket */ ++ flags = fcntl(THREAD_FD(t), F_GETFL, 0); ++ if (-1 == flags) ++ return -1; ++ ++ if (flags & O_NONBLOCK) ++ nonblock = true; ++ else ++ fcntl(THREAD_FD(t), F_SETFL, flags | O_NONBLOCK); ++ + FD_ZERO(&fds); + FD_SET(THREAD_FD(t), &fds); + snmp_read(&fds); + ++ /* Reset the flag */ ++ if (!nonblock) ++ fcntl(THREAD_FD(t), F_SETFL, flags); ++ + netsnmp_check_outstanding_agent_requests(); + agentx_events_update(); + return 0; +-- +2.18.0 + diff --git a/src/sonic-frr/patch/series b/src/sonic-frr/patch/series index dc5eaa2fcd36..1acf6d94f435 100644 --- a/src/sonic-frr/patch/series +++ b/src/sonic-frr/patch/series @@ -2,3 +2,4 @@ 0002-Reduce-severity-of-Vty-connected-from-message.patch 0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch 0005-Support-VRF.patch +0006-changes-for-making-snmp-socket-non-blocking.patch From 0a39ee417173fc0cbb3996f6a74400a341126275 Mon Sep 17 00:00:00 2001 From: Nazarii Hnydyn Date: Wed, 16 Oct 2019 23:44:18 +0300 Subject: [PATCH 076/278] [mellanox] Update HW-MGMT: V.7.0000.2300. (#3617) Signed-off-by: Nazarii Hnydyn --- platform/mellanox/hw-management.mk | 2 +- platform/mellanox/hw-management/hw-mgmt | 2 +- src/sonic-linux-kernel | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/mellanox/hw-management.mk b/platform/mellanox/hw-management.mk index 21a16d29dbb2..3e7749e11c4e 100644 --- a/platform/mellanox/hw-management.mk +++ b/platform/mellanox/hw-management.mk @@ -1,6 +1,6 @@ # Mellanox HW Management -MLNX_HW_MANAGEMENT_VERSION = 2.0.0191 +MLNX_HW_MANAGEMENT_VERSION = 7.0000.2300 export MLNX_HW_MANAGEMENT_VERSION diff --git a/platform/mellanox/hw-management/hw-mgmt b/platform/mellanox/hw-management/hw-mgmt index 93076e83b083..a72ba6371380 160000 --- a/platform/mellanox/hw-management/hw-mgmt +++ b/platform/mellanox/hw-management/hw-mgmt @@ -1 +1 @@ -Subproject commit 93076e83b08322207f7b860d34c6c3c2bd655aa0 +Subproject commit a72ba6371380b6d97cadf9f57f11b05dd9ae576c diff --git a/src/sonic-linux-kernel b/src/sonic-linux-kernel index f8bbe29ff896..6d55e9a84c6d 160000 --- a/src/sonic-linux-kernel +++ b/src/sonic-linux-kernel @@ -1 +1 @@ -Subproject commit f8bbe29ff89611d190658118e2c191943dabe3e0 +Subproject commit 6d55e9a84c6d0693fa5532bea2d2ddfa5c501eb6 From 7a7e5c377b454caffc98740bc6039a781b706b26 Mon Sep 17 00:00:00 2001 From: hans-tseng Date: Thu, 17 Oct 2019 04:56:34 +0800 Subject: [PATCH 077/278] [devices/delta]: Update the port_config.ini & th2-ag9064-64x100G.config.bcm (#3615) 1. add the speed and index in port_config.ini 2. rmove the unuse port in the config.bcm file Signed-off-by: hans-tseng --- .../Delta-ag9064/port_config.ini | 130 +++++++++--------- .../th2-ag9064-64x100G.config.bcm | 6 - 2 files changed, 65 insertions(+), 71 deletions(-) diff --git a/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/port_config.ini b/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/port_config.ini index be43857f82b1..ee425d4ad4f6 100644 --- a/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/port_config.ini +++ b/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/port_config.ini @@ -1,65 +1,65 @@ -# name lanes alias -Ethernet0 49,50,51,52 Ethernet1/1 -Ethernet4 53,54,55,56 Ethernet2/1 -Ethernet8 65,66,67,68 Ethernet3/1 -Ethernet12 69,70,71,72 Ethernet4/1 -Ethernet16 81,82,83,84 Ethernet5/1 -Ethernet20 85,86,87,88 Ethernet6/1 -Ethernet24 1,2,3,4 Ethernet7/1 -Ethernet28 101,102,103,104 Ethernet8/1 -Ethernet32 5,6,7,8 Ethernet9/1 -Ethernet36 17,18,19,20 Ethernet10/1 -Ethernet40 21,22,23,24 Ethernet11/1 -Ethernet44 33,34,35,36 Ethernet12/1 -Ethernet48 37,38,39,40 Ethernet13/1 -Ethernet52 97,98,99,100 Ethernet14/1 -Ethernet56 113,114,115,116 Ethernet15/1 -Ethernet60 117,118,119,120 Ethernet16/1 -Ethernet64 129,130,131,132 Ethernet17/1 -Ethernet68 133,134,135,136 Ethernet18/1 -Ethernet72 145,146,147,148 Ethernet19/1 -Ethernet76 209,210,211,212 Ethernet20/1 -Ethernet80 213,214,215,216 Ethernet21/1 -Ethernet84 225,226,227,228 Ethernet22/1 -Ethernet88 229,230,231,232 Ethernet23/1 -Ethernet92 241,242,243,244 Ethernet24/1 -Ethernet96 245,246,247,248 Ethernet25/1 -Ethernet100 157,158,159,160 Ethernet26/1 -Ethernet104 161,162,163,164 Ethernet27/1 -Ethernet108 165,166,167,168 Ethernet28/1 -Ethernet112 177,178,179,180 Ethernet29/1 -Ethernet116 181,182,183,184 Ethernet30/1 -Ethernet120 193,194,195,196 Ethernet31/1 -Ethernet124 197,198,199,200 Ethernet32/1 -Ethernet128 61,62,63,64 Ethernet33/1 -Ethernet132 57,58,59,60 Ethernet34/1 -Ethernet136 77,78,79,80 Ethernet35/1 -Ethernet140 73,74,75,76 Ethernet36/1 -Ethernet144 93,94,95,96 Ethernet37/1 -Ethernet148 89,90,91,92 Ethernet38/1 -Ethernet152 105,106,107,108 Ethernet39/1 -Ethernet156 9,10,11,12 Ethernet40/1 -Ethernet160 25,26,27,28 Ethernet41/1 -Ethernet164 13,14,15,16 Ethernet42/1 -Ethernet168 41,42,43,44 Ethernet43/1 -Ethernet172 29,30,31,32 Ethernet44/1 -Ethernet176 45,46,47,48 Ethernet45/1 -Ethernet180 109,110,111,112 Ethernet46/1 -Ethernet184 125,126,127,128 Ethernet47/1 -Ethernet188 121,122,123,124 Ethernet48/1 -Ethernet192 141,142,143,144 Ethernet49/1 -Ethernet196 137,138,139,140 Ethernet50/1 -Ethernet200 217,218,219,220 Ethernet51/1 -Ethernet204 149,150,151,152 Ethernet52/1 -Ethernet208 233,234,235,236 Ethernet53/1 -Ethernet212 221,222,223,224 Ethernet54/1 -Ethernet216 249,250,251,252 Ethernet55/1 -Ethernet220 237,238,239,240 Ethernet56/1 -Ethernet224 153,154,155,156 Ethernet57/1 -Ethernet228 253,254,255,256 Ethernet58/1 -Ethernet232 173,174,175,176 Ethernet59/1 -Ethernet236 169,170,171,172 Ethernet60/1 -Ethernet240 189,190,191,192 Ethernet61/1 -Ethernet244 185,186,187,188 Ethernet62/1 -Ethernet248 205,206,207,208 Ethernet63/1 -Ethernet252 201,202,203,204 Ethernet64/1 +# name lanes alias index speed +Ethernet0 49,50,51,52 hundredGigE1/1 0 100000 +Ethernet4 53,54,55,56 hundredGigE1/2 1 100000 +Ethernet8 65,66,67,68 hundredGigE1/3 2 100000 +Ethernet12 69,70,71,72 hundredGigE1/4 3 100000 +Ethernet16 81,82,83,84 hundredGigE1/5 4 100000 +Ethernet20 85,86,87,88 hundredGigE1/6 5 100000 +Ethernet24 1,2,3,4 hundredGigE1/7 6 100000 +Ethernet28 101,102,103,104 hundredGigE1/8 7 100000 +Ethernet32 5,6,7,8 hundredGigE1/9 8 100000 +Ethernet36 17,18,19,20 hundredGigE1/10 9 100000 +Ethernet40 21,22,23,24 hundredGigE1/11 10 100000 +Ethernet44 33,34,35,36 hundredGigE1/12 11 100000 +Ethernet48 37,38,39,40 hundredGigE1/13 12 100000 +Ethernet52 97,98,99,100 hundredGigE1/14 13 100000 +Ethernet56 113,114,115,116 hundredGigE1/15 14 100000 +Ethernet60 117,118,119,120 hundredGigE1/16 15 100000 +Ethernet64 129,130,131,132 hundredGigE1/17 16 100000 +Ethernet68 133,134,135,136 hundredGigE1/18 17 100000 +Ethernet72 145,146,147,148 hundredGigE1/19 18 100000 +Ethernet76 209,210,211,212 hundredGigE1/20 19 100000 +Ethernet80 213,214,215,216 hundredGigE1/21 20 100000 +Ethernet84 225,226,227,228 hundredGigE1/22 21 100000 +Ethernet88 229,230,231,232 hundredGigE1/23 22 100000 +Ethernet92 241,242,243,244 hundredGigE1/24 23 100000 +Ethernet96 245,246,247,248 hundredGigE1/25 24 100000 +Ethernet100 157,158,159,160 hundredGigE1/26 25 100000 +Ethernet104 161,162,163,164 hundredGigE1/27 26 100000 +Ethernet108 165,166,167,168 hundredGigE1/28 27 100000 +Ethernet112 177,178,179,180 hundredGigE1/29 28 100000 +Ethernet116 181,182,183,184 hundredGigE1/30 29 100000 +Ethernet120 193,194,195,196 hundredGigE1/31 30 100000 +Ethernet124 197,198,199,200 hundredGigE1/32 31 100000 +Ethernet128 61,62,63,64 hundredGigE1/33 32 100000 +Ethernet132 57,58,59,60 hundredGigE1/34 33 100000 +Ethernet136 77,78,79,80 hundredGigE1/35 34 100000 +Ethernet140 73,74,75,76 hundredGigE1/36 35 100000 +Ethernet144 93,94,95,96 hundredGigE1/37 36 100000 +Ethernet148 89,90,91,92 hundredGigE1/38 37 100000 +Ethernet152 105,106,107,108 hundredGigE1/39 38 100000 +Ethernet156 9,10,11,12 hundredGigE1/40 39 100000 +Ethernet160 25,26,27,28 hundredGigE1/41 40 100000 +Ethernet164 13,14,15,16 hundredGigE1/42 41 100000 +Ethernet168 41,42,43,44 hundredGigE1/43 42 100000 +Ethernet172 29,30,31,32 hundredGigE1/44 43 100000 +Ethernet176 45,46,47,48 hundredGigE1/45 44 100000 +Ethernet180 109,110,111,112 hundredGigE1/46 45 100000 +Ethernet184 125,126,127,128 hundredGigE1/47 46 100000 +Ethernet188 121,122,123,124 hundredGigE1/48 47 100000 +Ethernet192 141,142,143,144 hundredGigE1/49 48 100000 +Ethernet196 137,138,139,140 hundredGigE1/50 49 100000 +Ethernet200 217,218,219,220 hundredGigE1/51 50 100000 +Ethernet204 149,150,151,152 hundredGigE1/52 51 100000 +Ethernet208 233,234,235,236 hundredGigE1/53 52 100000 +Ethernet212 221,222,223,224 hundredGigE1/54 53 100000 +Ethernet216 249,250,251,252 hundredGigE1/55 54 100000 +Ethernet220 237,238,239,240 hundredGigE1/56 55 100000 +Ethernet224 153,154,155,156 hundredGigE1/57 56 100000 +Ethernet228 253,254,255,256 hundredGigE1/58 57 100000 +Ethernet232 173,174,175,176 hundredGigE1/59 58 100000 +Ethernet236 169,170,171,172 hundredGigE1/60 59 100000 +Ethernet240 189,190,191,192 hundredGigE1/61 60 100000 +Ethernet244 185,186,187,188 hundredGigE1/62 61 100000 +Ethernet248 205,206,207,208 hundredGigE1/63 62 100000 +Ethernet252 201,202,203,204 hundredGigE1/64 63 100000 diff --git a/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/th2-ag9064-64x100G.config.bcm b/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/th2-ag9064-64x100G.config.bcm index 3914599abf7c..eae7278a3ab2 100644 --- a/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/th2-ag9064-64x100G.config.bcm +++ b/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/th2-ag9064-64x100G.config.bcm @@ -715,8 +715,6 @@ phy_chain_tx_polarity_flip_physical{96.0}=0x0 phy_chain_tx_polarity_flip_physical{97.0}=0x1 phy_chain_tx_polarity_flip_physical{98.0}=0x0 phy_chain_tx_polarity_flip_physical{99.0}=0x1 -portmap_100=259:10 -portmap_101=262:10 portmap_102=193:100 portmap_103=197:100 portmap_104=201:100 @@ -736,14 +734,12 @@ portmap_116=249:100 portmap_117=253:100 portmap_11=41:100 portmap_12=45:100 -portmap_135=263:10 portmap_13=49:100 portmap_14=53:100 portmap_15=57:100 portmap_16=61:100 portmap_1=1:100 portmap_2=5:100 -portmap_33=260:10 portmap_34=65:100 portmap_35=69:100 portmap_36=73:100 @@ -763,8 +759,6 @@ portmap_48=121:100 portmap_49=125:100 portmap_4=13:100 portmap_5=17:100 -portmap_66=257:10 -portmap_67=261:10 portmap_68=129:100 portmap_69=133:100 portmap_6=21:100 From 2d87ca4a18ef912a989ef984ba0e6e3032f2ef15 Mon Sep 17 00:00:00 2001 From: habeebmohammed Date: Wed, 16 Oct 2019 16:49:39 -0700 Subject: [PATCH 078/278] [inventec/d7054q28b] Add new platform APIs chassis, eeprom,fan, psu, thermal, sfp (#3577) --- .../d7054q28b/setup.py | 15 + .../d7054q28b/sonic_platform/__init__.py | 3 + .../d7054q28b/sonic_platform/chassis.py | 155 ++ .../d7054q28b/sonic_platform/eeprom.py | 110 ++ .../d7054q28b/sonic_platform/fan.py | 213 +++ .../d7054q28b/sonic_platform/platform.py | 20 + .../d7054q28b/sonic_platform/psu.py | 196 +++ .../d7054q28b/sonic_platform/sfp.py | 1285 +++++++++++++++++ .../d7054q28b/sonic_platform/thermal.py | 100 ++ .../debian/platform-modules-d7054q28b.install | 1 + .../debian/rules | 4 +- 11 files changed, 2100 insertions(+), 2 deletions(-) create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/setup.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/__init__.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/chassis.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/eeprom.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/fan.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/platform.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/psu.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/sfp.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/thermal.py diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/setup.py b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/setup.py new file mode 100644 index 000000000000..3bd7b4825f43 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/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 Inventec D7054Q28B platforms', + + packages=['sonic_platform'], +) + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/__init__.py new file mode 100644 index 000000000000..4bfefa0fb636 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/chassis.py new file mode 100644 index 000000000000..b5053cf4e2b4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/chassis.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python +# +# Name: chassis.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import os + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.eeprom import Eeprom + from sonic_platform.psu import Psu + from sonic_platform.sfp import Sfp + from sonic_platform.fan import Fan + from sonic_platform.watchdog import Watchdog + from sonic_platform.thermal import Thermal + +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Chassis(ChassisBase): + + def __init__(self): + ChassisBase.__init__(self) + self.__num_of_psus = 2 + self.__num_of_ports = 54 + self.__num_of_sfps = 48 + self.__num_of_fans = 4 + self.__num_of_thermals = 6 + + # Initialize EEPROM + self._eeprom = Eeprom() + + # Initialize watchdog + #self._watchdog = Watchdog() + + # Initialize FAN + for index in range(1, self.__num_of_fans + 1): + fan = Fan(index) + self._fan_list.append(fan) + + # Initialize thermal + for index in range(1, self.__num_of_thermals + 1): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + # Initialize PSU and PSU_FAN + for index in range(1, self.__num_of_psus + 1): + psu = Psu(index) + self._psu_list.append(psu) + fan = Fan(index, True) + self._fan_list.append(fan) + + # Initialize SFP + for index in range(0, self.__num_of_ports): + if index in range(0,self.__num_of_sfps): + sfp = Sfp(index, 'SFP') + else: + sfp = Sfp(index, 'QSFP') + + self._sfp_list.append(sfp) + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self._eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self._eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis + Returns: + string: Serial number of chassis + """ + return self._eeprom.serial_number_str() + + def get_status(self): + """ + Retrieves the operational status of the chassis + Returns: + bool: A boolean value, True if chassis is operating properly + False if not + """ + return True + +############################################## +# Chassis methods +############################################## + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self._eeprom.base_mac_addr() + + def get_serial_number(self): + """ + Retrieves the hardware serial number for the chassis + + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.serial_number_str() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + """ + return self._eeprom.system_eeprom_info() + + def get_reboot_cause(self): + """ + Retrieves the cause of the previous reboot + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + one of the predefined strings in this class. If the first string + is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used + to pass a description of the reboot cause. + """ + raise NotImplementedError diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/eeprom.py new file mode 100644 index 000000000000..b0ebee54ee24 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/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, 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-0/0-0053/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 = (ord(eeprom[9]) << 8) | ord(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 + + ord(eeprom[tlv_index + 1])] + code = "0x%02X" % (ord(tlv[0])) + + if ord(tlv[0]) == self._TLV_CODE_VENDOR_EXT: + value = str((ord(tlv[2]) << 24) | (ord(tlv[3]) << 16) | + (ord(tlv[4]) << 8) | ord(tlv[5])) + value += str(tlv[6:6 + ord(tlv[1])]) + else: + name, value = self.decoder(None, tlv) + + self.__eeprom_tlv_dict[code] = value + if ord(eeprom[tlv_index]) == self._TLV_CODE_CRC_32: + break + + tlv_index += ord(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_addr(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(TlvInfoDecoder, self).switchaddrstr(e) + + 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/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/fan.py new file mode 100644 index 000000000000..ecfbfe2d8763 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/fan.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python + +############################################################################# +# Inventec d7264 +# +# Module contains an implementation of SONiC Platform Base API and +# provides the FAN information +# +############################################################################# + +try: + import os + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +############### +# Global +############### +FAN_DIR = "/sys/bus/i2c/devices/0-0066/" +MAX_PWM = 255 +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, index, is_psu_fan=False): + self.is_psu_fan = is_psu_fan + + self.fan_gpi = "fan_gpi" + self.fan_index = index + if self.is_psu_fan: + self.fan_pwm = "pwm_psu{}".format(self.fan_index) + self.psu_fan_rpm = "rpm_psu{}".format(self.fan_index) + else: + self.fan_pwm = "pwm{}".format(self.fan_index) + self.fan_status_led_green_color = "fan_led_grn{}".format(self.fan_index) + self.fan_status_led_red_color = "fan_led_red{}".format(self.fan_index) + self.fan_front_rpm = "fan{}_input".format(self.fan_index * 2 - 1) + self.fan_rear_rpm = "fan{}_input".format(self.fan_index * 2) + + +####################### +# private function +####################### + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + + #################### + # Device base + #################### + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + if self.is_psu_fan: + return "PSU-{}_FAN".format(self.fan_index) + else: + return "FAN-{}".format(self.fan_index) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + + Note: + fan_gpi define 8 bits + low byte means fan presense + high byte means fan direction + """ + presence = False + attr_path = FAN_DIR + self.fan_gpi + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + not_presence_bit = 1 << (self.fan_index - 1) + if not (int(attr_rv,16) and not_presence_bit): + presence = True + + return presence + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + if not self.is_psu_fan: + status = False + attr_grn_path = FAN_DIR + self.fan_status_led_green_color + + attr_grn_rv = self.__get_attr_value(attr_grn_path) + if (attr_grn_rv != 'ERR' and attr_grn_rv == '1'): + status = True + return status + + ################# + # fan base + ################# + + def get_direction(self): + """ + Retrieves the direction of fan + + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + + Note: + fan_gpi define 8 bits + low byte means fan presense + high byte means fan direction + """ + direction = self.FAN_DIRECTION_INTAKE + attr_path = FAN_DIR + self.fan_gpi + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + #attr_rv = attr_rv >> 4 + direction_bit = 1 << ((self.fan_index - 1)+4) + if not (int(attr_rv,16) and direction_bit): + direction = self.FAN_DIRECTION_EXHAUST + + 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 + attr_path = FAN_DIR + self.fan_pwm + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + pwm = int(attr_rv,10)if attr_rv else 0 + speed = float(pwm*100/MAX_PWM) + + return int(speed) + + 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) + """ + speed = 0 + attr_path = FAN_DIR + self.fan_pwm + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + pwm = int(attr_rv,10)if attr_rv else 0 + speed = float(pwm*100/MAX_PWM) + + return int(speed) + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + return 20 + + 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 + """ + if self.is_psu_fan: + return self.STATUS_LED_COLOR_OFF + + attr_grn_path = FAN_DIR + self.fan_status_led_green_color + attr_red_path = FAN_DIR + self.fan_status_led_red_color + + attr_grn_rv = self.__get_attr_value(attr_grn_path) + attr_red_rv = self.__get_attr_value(attr_red_path) + if (attr_grn_rv != 'ERR' and attr_red_rv != 'ERR'): + if (attr_grn_rv == '1'): + return self.STATUS_LED_COLOR_GREEN + elif (attr_red_rv == '1'): + return self.STATUS_LED_COLOR_RED + else: + return self.STATUS_LED_COLOR_OFF diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/platform.py new file mode 100644 index 000000000000..ddad8c4c5788 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/platform.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# +# Name: platform.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/psu.py new file mode 100644 index 000000000000..52dd2b12fb20 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/psu.py @@ -0,0 +1,196 @@ +#!/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 +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PSU_DIR = "/sys/bus/i2c/devices/0-0066/" + +class Psu(PsuBase): + def __init__(self, index): + self.index = index + self.psu_presence_attr = "psu{}".format(self.index-1) + self.psu_status_attr = "psoc_psu{}_iout".format(self.index) + self.psu_power_in_attr = "power{}_input".format(self.index) + self.psu_power_out_attr = "power{}_input".format(self.index) + self.psu_voltage_out_attr = "psoc_psu{}_vin".format(self.index) + self.psu_current_out_attr = "psoc_psu{}_iout".format(self.index) + self.psu_serial_attr = "psoc_psu{}_serial".format(self.index) + self.psu_model_attr = "psoc_psu{}_vender".format(self.index) + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return "PSU{}".format(self.index) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + attr_path = PSU_DIR+self.psu_presence_attr + attr_normal = "0 : normal" + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == attr_normal): + presence = True + + return presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + model = "N/A" + attr_path = PSU_DIR+self.psu_model_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + model = attr_rv + + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + serial = "N/A" + attr_path = PSU_DIR+self.psu_serial_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + serial = attr_rv + + return serial + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + status = False + attr_path = PSU_DIR+self.psu_status_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (int(attr_rv) != 0): + status = True + + return status + +############################################## +# PSU methods +############################################## + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_out = 0.0 + attr_path = PSU_DIR+self.psu_voltage_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + voltage_out = float(attr_rv) / 1000 + + return voltage_out + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_out = 0.0 + attr_path = PSU_DIR+self.psu_current_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + current_out = float(attr_rv) / 1000 + + return current_out + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, e.g. 302.6 + """ + power_out = 0.0 + attr_path = PSU_DIR+self.psu_power_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + power_out = float(attr_rv) / 1000000 + + return power_out + + def get_powergood_status(self): + """ + Retrieves the powergood status of PSU + + Returns: + A boolean, True if PSU has stablized its output voltages and passed all + its internal self-tests, False if not. + """ + return self.get_status() + + def get_status_led(self): + """ + Gets the state of the PSU status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + if self.get_powergood_status(): + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_OFF + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/sfp.py new file mode 100644 index 000000000000..47d88afa13a4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/sfp.py @@ -0,0 +1,1285 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import time +import subprocess +import sonic_device_util +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_eeprom import eeprom_dts + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.inf8628 import inf8628InterfaceId + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +INFO_OFFSET = 128 +DOM_OFFSET = 0 + +# 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_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 2 + +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 + +# 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 + +# Offset for values in QSFP eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VOLT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 1 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 +SFP_CHANNL_STATUS_OFFSET = 110 +SFP_CHANNL_STATUS_WIDTH = 1 + +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" + + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + + # Port number + PORT_START = 0 + PORT_END = 53 + + # Path to QSFP sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + HOST_CHK_CMD = "docker > /dev/null 2>&1" + + PLATFORM = "x86_64-inventec_d7054q28b-r0" + HWSKU = "INVENTEC-D7054Q28B-S48-Q6" + + def __init__(self, sfp_index, sfp_type): + # Init index + self.index = sfp_index + self.port_num = self.index + self.dom_supported = False + self.sfp_type = sfp_type + self.__sfp_presence_attr = "/sys/class/swps/port{}/present".format(self.index) + self.__sfp_lpmode_attr = "/sys/class/swps/port{}/lpmod".format(self.index) + self.__sfp_reset_attr = "/sys/class/swps/port{}/reset".format(self.index) + # Init eeprom path + eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + self.port_to_eeprom_mapping = {} + self.port_to_i2c_mapping = { + 0: 10, + 1: 11, + 2: 12, + 3: 13, + 4: 14, + 5: 15, + 6: 16, + 7: 17, + 8: 18, + 9: 19, + 10: 20, + 11: 21, + 12: 22, + 13: 23, + 14: 24, + 15: 25, + 16: 26, + 17: 27, + 18: 28, + 19: 29, + 20: 30, + 21: 31, + 22: 32, + 23: 33, + 24: 34, + 25: 35, + 26: 36, + 27: 37, + 28: 38, + 29: 39, + 30: 40, + 31: 41, + 32: 42, + 33: 43, + 34: 44, + 35: 45, + 36: 46, + 37: 47, + 38: 48, + 39: 49, + 40: 50, + 41: 51, + 42: 52, + 43: 53, + 44: 54, + 45: 55, + 46: 56, + 47: 57, + 48: 58, + 49: 59, + 50: 60, + 51: 61, + 52: 62, + 53: 63 + } + + for x in range(self.PORT_START, self.PORT_END + 1): + port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) + self.port_to_eeprom_mapping[x] = port_eeprom_path + + self.info_dict_keys = ['type', 'hardwarerev', 'serialnum', 'manufacturename', 'modelname', 'Connector', 'encoding', 'ext_identifier', + 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', 'specification_compliance', 'vendor_date', 'vendor_oui'] + + self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] + + self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + SfpBase.__init__(self) + + def __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 _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + presence = False + attr_path = self.__sfp_presence_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (int(attr_rv) == 0): + presence = True + + return presence + + def __read_eeprom_specific_bytes(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except: + pass + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + def _dom_capability_detect(self): + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if self.sfp_type == "QSFP": + self.calibration = 1 + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes((offset + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_version_compliance_raw = self.__read_eeprom_specific_bytes(QSFP_VERSION_COMPLIANCE_OFFSET, QSFP_VERSION_COMPLIANCE_OFFSET) + qsfp_version_compliance = int(qsfp_version_compliance_raw[0], 16) + qspf_dom_capability = int(qsfp_dom_capability_raw[0], 16) + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = (qspf_dom_capability & 0x20 != 0) + self.dom_volt_supported = (qspf_dom_capability & 0x10 != 0) + self.dom_rx_power_supported = (qspf_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = (qspf_dom_capability & 0x04 != 0) + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = (qspf_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = True + self.dom_supported = True + self.calibration = 1 + qsfp_option_value_raw = self.__read_eeprom_specific_bytes(QSFP_OPTION_VALUE_OFFSET, QSFP_OPTION_VALUE_WIDTH) + if qsfp_option_value_raw is not None: + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + self.optional_capability = sfpd_obj.parse_option_params(qsfp_option_value_raw, 0) + self.dom_tx_disable_supported = self.optional_capability['data']['TxDisable']['value'] == 'On' + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + elif self.sfp_type == "SFP": + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self.__read_eeprom_specific_bytes(XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.dom_tx_disable_supported = (int(sfp_dom_capability_raw[1], 16) & 0x40 != 0) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + 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 + nominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + ======================================================================== + """ + transceiver_info_dict = {} + compliance_code_dict = {} + + # ToDo: OSFP tranceiver info parsing not fully supported. + # in inf8628.py lack of some memory map definition + # will be implemented when the inf8628 memory map ready + if self.sfp_type == OSFP_TYPE: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_OSFP + + sfpi_obj = inf8628InterfaceId() + if sfpi_obj is None: + return None + + sfp_type_raw = self.__read_eeprom_specific_bytes((offset + OSFP_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return None + + sfp_vendor_name_raw = self.__read_eeprom_specific_bytes((offset + OSFP_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_vendor_name_raw, 0) + else: + return None + + sfp_vendor_pn_raw = self.__read_eeprom_specific_bytes((offset + OSFP_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_vendor_pn_raw, 0) + else: + return None + + sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes((offset + OSFP_HW_REV_OFFSET), vendor_rev_width) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_vendor_rev_raw, 0) + else: + return None + + sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes((offset + OSFP_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_vendor_sn_raw, 0) + else: + return None + + transceiver_info_dict['type'] = sfp_type_data['data']['type']['value'] + transceiver_info_dict['manufacturename'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['modelname'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardwarerev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serialnum'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = 'N/A' + transceiver_info_dict['vendor_date'] = 'N/A' + transceiver_info_dict['Connector'] = 'N/A' + transceiver_info_dict['encoding'] = 'N/A' + transceiver_info_dict['ext_identifier'] = 'N/A' + transceiver_info_dict['ext_rateselect_compliance'] = 'N/A' + transceiver_info_dict['cable_type'] = 'N/A' + transceiver_info_dict['cable_length'] = 'N/A' + transceiver_info_dict['specification_compliance'] = 'N/A' + transceiver_info_dict['nominal_bit_rate'] = 'N/A' + + else: + if self.sfp_type == QSFP_TYPE: + offset = 128 + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + cable_length_width = XCVR_CABLE_LENGTH_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + sfp_type = 'QSFP' + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return None + + else: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + cable_length_width = XCVR_CABLE_LENGTH_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + sfp_type = 'SFP' + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return None + sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes(offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is None: + return None + + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_interface_bulk_raw[start : end], 0) + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['manufacturename'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['modelname'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardwarerev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serialnum'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['Connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + if self.sfp_type == QSFP_TYPE: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str(sfp_interface_bulk_data['data'][key]['value']) + + for key in qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str(sfp_interface_bulk_data['data'][key]['value']) + + for key in sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_info_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 + | |to channel 3. + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. + ======================================================================== + """ + # check present status + 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(self.dom_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_qsfp_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['lp_mode'] = self.get_lpmode() + + return transceiver_dom_info_dict + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + if not self.dom_supported: + return False + + if self.sfp_type == OSFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + dom_module_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_MODULE_MONITOR_OFFSET), QSFP_MODULE_MONITOR_WIDTH) + + if dom_module_monitor_raw is not None: + return True + else: + return False + elif self.sfp_type == SFP_TYPE: + offset = 0 + sfpd_obj = sff8472Dom() + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + + if dom_channel_monitor_raw is not None: + return True + else: + 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. + """ + if not self.dom_supported: + return None + + rx_los_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + else: + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x02 != 0) + else: + return None + return rx_los_list + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + Returns: + A Boolean, True if SFP has TX fault, False if not + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + if not self.dom_supported: + return None + + tx_fault_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + else: + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + else: + return None + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A Boolean, True if tx_disable is enabled, False if disabled + """ + if not self.dom_supported: + return None + + tx_disable_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + else: + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0xC0 != 0) + else: + return None + return tx_disable_list + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + tx_disable_list = self.get_tx_disable() + if tx_disable_list is None: + return 0 + tx_disabled = 0 + for i in range(len(tx_disable_list)): + if tx_disable_list[i]: + tx_disabled |= 1 << i + return tx_disabled + + 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.__sfp_lpmode_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (int(attr_rv) == 0): + 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 + """ + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self._read_eeprom_specific_bytes((offset + QSFP_CONTROL_OFFSET), QSFP_CONTROL_WIDTH) + if dom_control_raw is not None: + dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) + return ('On' == dom_control_data['data']['PowerOverride']) + else: + return NotImplementedError + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + offset_xcvr = 128 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes((offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = 1 + + dom_temperature_raw = self._read_eeprom_specific_bytes((offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + offset_xcvr = 128 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes((offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + sfpd_obj._calibration_type = self.calibration + + dom_voltage_raw = self._read_eeprom_specific_bytes((offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + offset_xcvr = 128 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX4Bias']['value'])) + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return None + else: + return None + + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + rx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return None + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + offset_xcvr = 128 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_rx_power_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return None + else: + return None + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return None + else: + return None + + return rx_power_list + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + tx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return None + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + offset_xcvr = 128 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_tx_power_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return None + else: + return None + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return None + else: + return None + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + Returns: + A boolean, True if successful, False if not + """ + try: + reg_file = open(self.__sfp_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() + + # Sleep 2 seconds to allow it to settle + time.sleep(2) + + # Flip the value back write back to the register to take port out of reset + try: + reg_file = open(self.__sfp_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() + + return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + if self.sfp_type == SFP_TYPE: + if self.dom_tx_disable_supported: + handle = self._open_sdk() + if handle is None: + return False + + tx_disable_mask = 1 << MCIA_ADDR_TX_DISABLE_BIT + if tx_disable: + tx_disable_bit = tx_disable_mask + else: + tx_disable_bit = 0 + + return self._write_i2c_via_mcia(2, 0x51, MCIA_ADDR_TX_DISABLE, tx_disable_bit, tx_disable_mask) + else: + return False + elif self.sfp_type == QSFP_TYPE: + if self.dom_tx_disable_supported: + channel_mask = 0x0f + if tx_disable: + disable_flag = channel_mask + else: + disable_flag = 0 + + return self._write_i2c_via_mcia(0, 0x50, MCIA_ADDR_TX_CHANNEL_DISABLE, disable_flag, channel_mask) + else: + return False + else: + return NotImplementedError + + 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 + """ + sysfsfile_eeprom = None + try: + channel_state = self.get_tx_disable_channel() + tx_enable_mask = [0xe, 0xd, 0xb, 0x7] + tx_disable_mask = [0x1, 0x3, 0x7, 0xf] + tx_disable_ctl = channel_state | tx_disable_mask[ + channel] if disable else channel_state & tx_enable_mask[channel] + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom = open( + self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + 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 + """ + 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 + """ + try: + power_override_bit = 0 + if power_override: + power_override_bit |= 1 << 0 + + power_set_bit = 0 + if power_set: + power_set_bit |= 1 << 1 + + buffer = create_string_buffer(1) + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + sysfsfile_eeprom = open( + self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings( + self.__get_path_to_port_config_file()) + #print "self.index{}".format(self.index) + name = sfputil_helper.logical[self.index] or "Unknown" + return name + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/thermal.py new file mode 100644 index 000000000000..039067428321 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/sonic_platform/thermal.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python + +############################################################################# +# Inventec d7264 +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermal information +# +############################################################################# + +import os + +try: + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +THERMAL_PATH = "/sys/bus/i2c/devices/0-0066/" + +thermal_name_tup = ( + "FrontSide Temperature", + "FanBoard Temperature", + "NearASIC Temperature", + "Center(U10) Temperature", + "CPU Board Temperature", + "ASIC Temperature" +) + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + def __init__(self, thermal_index): + self.index = thermal_index-1 + self.thermal_tmp = "temp{}_input".format(self.index) + + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return thermal_name_tup[self.index] + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + attr_path = THERMAL_PATH + self.thermal_tmp + return os.path.isfile(attr_path) + + 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 + if (self.get_temperature() > 0): + status = True + + return status + + 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 + attr_path = THERMAL_PATH + self.thermal_tmp + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + temperature = float(attr_rv) / 1000 + + return temperature + diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.install b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.install index 0ffc0a4f92a3..a83009858d6d 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.install +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.install @@ -1,4 +1,5 @@ d7054q28b/utils/inventec_d7054_util.py usr/local/bin +d7054q28b/utils/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-inventec_d7054q28b-r0 common/utils/transceiver_monitor.py usr/share/sonic/device/x86_64-inventec_d7054q28b-r0/plugins common/utils/led_proc.py usr/share/sonic/device/x86_64-inventec_d7054q28b-r0/plugins common/utils/asic_monitor.py usr/share/sonic/device/x86_64-inventec_d7054q28b-r0/plugins diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/rules b/platform/broadcom/sonic-platform-modules-inventec/debian/rules index 6340540f0354..f6c1aa1b2e70 100755 --- a/platform/broadcom/sonic-platform-modules-inventec/debian/rules +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/rules @@ -22,7 +22,7 @@ MODULE_DIRS:= d7032q28b d7054q28b d6254qs d6556 d6356 d7264q28b override_dh_auto_build: (for mod in $(MODULE_DIRS); do \ make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ - if [ $$mod = "d6356" ]; then \ + if [ $$mod = "d7054q28b" ] || [ $$mod = "d6356" ]; then \ cd $(MOD_SRC_DIR)/$${mod}; \ python2 setup.py build; \ python2 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/utils; \ @@ -36,7 +36,7 @@ override_dh_auto_install: $(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ cp $(MOD_SRC_DIR)/$${mod}/modules/*.ko \ debian/platform-modules-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ - if [ $$mod = "d6356" ]; then \ + if [ $$mod = "d7054q28b" ] || [ $$mod = "d6356" ]; then \ cd $(MOD_SRC_DIR)/$${mod}; \ python2 setup.py install --root=$(MOD_SRC_DIR)/debian/platform-modules-$${mod} --install-layout=deb; \ cd $(MOD_SRC_DIR); \ From ee4ca2c0c5a37ccfab200645a6d66e6fe6a77d6a Mon Sep 17 00:00:00 2001 From: Arun Saravanan Balachandran <52521751+ArunSaravananBalachandran@users.noreply.github.com> Date: Thu, 17 Oct 2019 06:27:32 +0530 Subject: [PATCH 079/278] DellEMC : Platform2.0 API Implementation for Component [S6000, S6100, Z9100] (#3588) --- .../s6000/sonic_platform/chassis.py | 63 +------ .../s6000/sonic_platform/component.py | 130 +++++++++++++ .../s6100/sonic_platform/chassis.py | 177 +----------------- .../s6100/sonic_platform/component.py | 177 ++++++++++++++++++ .../s6100/sonic_platform/module.py | 47 +---- .../z9100/sonic_platform/chassis.py | 100 +--------- .../z9100/sonic_platform/component.py | 164 ++++++++++++++++ 7 files changed, 495 insertions(+), 363 deletions(-) create mode 100644 platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/component.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/component.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/component.py diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/chassis.py index 452598773651..005fdd15b269 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/chassis.py @@ -18,6 +18,7 @@ from sonic_platform.fan import Fan from sonic_platform.psu import Psu from sonic_platform.thermal import Thermal + from sonic_platform.component import Component except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -25,17 +26,7 @@ MAX_S6000_FAN = 3 MAX_S6000_PSU = 2 MAX_S6000_THERMAL = 10 - -BIOS_QUERY_VERSION_COMMAND = "dmidecode -s system-version" -#components definitions -COMPONENT_BIOS = "BIOS" -COMPONENT_CPLD1 = "CPLD1" -COMPONENT_CPLD2 = "CPLD2" -COMPONENT_CPLD3 = "CPLD3" - -CPLD1_VERSION = 'system_cpld_ver' -CPLD2_VERSION = 'master_cpld_ver' -CPLD3_VERSION = 'slave_cpld_ver' +MAX_S6000_COMPONENT = 4 class Chassis(ChassisBase): @@ -87,11 +78,9 @@ def __init__(self): thermal = Thermal(i) self._thermal_list.append(thermal) - # Initialize component list - self._component_name_list.append(COMPONENT_BIOS) - self._component_name_list.append(COMPONENT_CPLD1) - self._component_name_list.append(COMPONENT_CPLD2) - self._component_name_list.append(COMPONENT_CPLD3) + for i in range(MAX_S6000_COMPONENT): + component = Component(i) + self._component_list.append(component) def _get_cpld_register(self, reg_name): rv = 'ERR' @@ -178,7 +167,7 @@ def get_system_eeprom_info(self): Returns: A dictionary where keys are the type code defined in - OCP ONIE TlvInfo EEPROM format and values are their + OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ return self.sys_eeprom.system_eeprom_info() @@ -200,46 +189,6 @@ def get_reboot_cause(self): return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) - def _get_command_result(self, cmdline): - try: - proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, - shell=True, stderr=subprocess.STDOUT) - stdout = proc.communicate()[0] - proc.wait() - result = stdout.rstrip('\n') - except OSError: - result = '' - - return result - - def _get_cpld_version(self,cpld_name): - """ - Cpld Version - """ - cpld_ver = int(self._get_cpld_register(cpld_name),16) - return cpld_ver - - def get_firmware_version(self, component_name): - """ - Retrieves platform-specific hardware/firmware versions for - chassis componenets such as BIOS, CPLD, FPGA, etc. - Args: - component_name: A string, the component name. - Returns: - A string containing platform-specific component versions - """ - if component_name in self._component_name_list : - if component_name == COMPONENT_BIOS: - return self._get_command_result(BIOS_QUERY_VERSION_COMMAND) - elif component_name == COMPONENT_CPLD1: - return self._get_cpld_version(CPLD1_VERSION) - elif component_name == COMPONENT_CPLD2: - return self._get_cpld_version(CPLD2_VERSION) - elif component_name == COMPONENT_CPLD3: - return self._get_cpld_version(CPLD3_VERSION) - - return None - def _get_transceiver_status(self): presence_ctrl = self.sfp_control + 'qsfp_modprs' try: diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/component.py new file mode 100644 index 000000000000..daa30eaafa3b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/component.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python + +######################################################################## +# DELLEMC S6000 +# +# 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 subprocess + from sonic_platform_base.component_base import ComponentBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +BIOS_QUERY_VERSION_COMMAND = "dmidecode -s system-version" + + +class Component(ComponentBase): + """DellEMC Platform-specific Component class""" + + CPLD_DIR = "/sys/devices/platform/dell-s6000-cpld.0" + + CHASSIS_COMPONENTS = [ + ["BIOS", ("Performs initialization of hardware components during " + "booting")], + ["System-CPLD", "Used for managing CPU board devices and power"], + ["Master-CPLD", ("Used for managing Fan, PSU, system LEDs, QSFP " + "modules (1-16)")], + ["Slave-CPLD", "Used for managing QSFP modules (17-32)"] + ] + + def __init__(self, component_index): + self.index = component_index + self.name = self.CHASSIS_COMPONENTS[self.index][0] + self.description = self.CHASSIS_COMPONENTS[self.index][1] + + def _get_cpld_register(self, reg_name): + rv = 'ERR' + mb_reg_file = self.CPLD_DIR+'/'+reg_name + + if (not os.path.isfile(mb_reg_file)): + return rv + + try: + with open(mb_reg_file, 'r') as fd: + rv = fd.read() + except Exception as error: + rv = 'ERR' + + rv = rv.rstrip('\r\n') + rv = rv.lstrip(" ") + return rv + + def _get_command_result(self, cmdline): + try: + proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + result = stdout.rstrip('\n') + except OSError: + result = None + + return result + + def _get_cpld_version(self, cpld_number): + cpld_version_reg = { + 1: "system_cpld_ver", + 2: "master_cpld_ver", + 3: "slave_cpld_ver" + } + + cpld_version = self._get_cpld_register(cpld_version_reg[cpld_number]) + + if cpld_version != 'ERR': + return str(int(cpld_version, 16)) + else: + return 'NA' + + def get_name(self): + """ + Retrieves the name of the component + + Returns: + A string containing the name of the component + """ + return self.name + + def get_description(self): + """ + Retrieves the description of the component + + Returns: + A string containing the description of the component + """ + return self.description + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + + Returns: + A string containing the firmware version of the component + """ + if self.index == 0: + bios_ver = self._get_command_result(BIOS_QUERY_VERSION_COMMAND) + + if not bios_ver: + return 'NA' + else: + return bios_ver + + elif self.index <= 3: + return self._get_cpld_version(self.index) + + def install_firmware(self, image_path): + """ + Installs firmware to the component + + Args: + image_path: A string, path to firmware image + + Returns: + A boolean, True if install was successful, False if not + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py index fd9816d6ed32..e39e8480e2c7 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py @@ -10,11 +10,6 @@ try: import os - import sys - import click - import subprocess - import glob - import sonic_device_util from sonic_platform_base.platform_base import PlatformBase from sonic_platform_base.chassis_base import ChassisBase from sonic_platform.sfp import Sfp @@ -22,6 +17,7 @@ from sonic_platform.fan import Fan from sonic_platform.module import Module from sonic_platform.thermal import Thermal + from sonic_platform.component import Component from eeprom import Eeprom except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -30,12 +26,7 @@ MAX_S6100_FAN = 4 MAX_S6100_PSU = 2 MAX_S6100_THERMAL = 10 - -BIOS_QUERY_VERSION_COMMAND = "dmidecode -s system-version" -#components definitions -COMPONENT_BIOS = "BIOS" -SWITCH_CPLD = "CPLD" -SMF_FPGA = "FPGA1" +MAX_S6100_COMPONENT = 3 class Chassis(ChassisBase): @@ -80,10 +71,9 @@ def __init__(self): thermal = Thermal(i) self._thermal_list.append(thermal) - # Initialize component list - self._component_name_list.append(COMPONENT_BIOS) - self._component_name_list.append(SWITCH_CPLD) - self._component_name_list.append(SMF_FPGA) + for i in range(MAX_S6100_COMPONENT): + component = Component(i) + self._component_list.append(component) def _get_reboot_reason_smf_register(self): # Returns 0xAA on software reload @@ -111,19 +101,6 @@ def _get_pmc_register(self, reg_name): rv = rv.lstrip(" ") return rv - # Run bash command and print output to stdout - def run_command(self, command): - click.echo(click.style("Command: ", fg='cyan') + - click.style(command, fg='green')) - - proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) - (out, err) = proc.communicate() - - click.echo(out) - - if proc.returncode != 0: - sys.exit(proc.returncode) - def get_name(self): """ Retrieves the name of the chassis @@ -234,147 +211,3 @@ def get_reboot_cause(self): return (self.reset_reason_dict[reset_reason], None) return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason") - - def _get_command_result(self, cmdline): - try: - proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, - shell=True, stderr=subprocess.STDOUT) - stdout = proc.communicate()[0] - proc.wait() - result = stdout.rstrip('\n') - except OSError: - result = '' - - return result - - def _get_cpld_version(self): - io_resource = "/dev/port" - CPLD1_VERSION_ADDR = 0x100 - - fd = os.open(io_resource, os.O_RDONLY) - if (fd < 0): - return 'NA' - if (os.lseek(fd, CPLD1_VERSION_ADDR, os.SEEK_SET) - != CPLD1_VERSION_ADDR): - return 'NA' - - buf = os.read(fd, 1) - cpld_version = ord(buf) - os.close(fd) - - return "%d.%d" % (((cpld_version & 0xF0) >> 4), cpld_version & 0xF) - - def _get_fpga_version(self): - fpga_ver = float(self._get_pmc_register('smf_firmware_ver')) - return fpga_ver - - def get_firmware_version(self, component_name): - """ - Retrieves platform-specific hardware/firmware versions for - chassis componenets such as BIOS, CPLD, FPGA, etc. - Args: - component_name: A string, the component name. - Returns: - A string containing platform-specific component versions - """ - if component_name in self._component_name_list : - if component_name == COMPONENT_BIOS: - return self._get_command_result(BIOS_QUERY_VERSION_COMMAND) - elif component_name == SWITCH_CPLD: - return self._get_cpld_version() - elif component_name == SMF_FPGA: - return self._get_fpga_version() - - return None - - def install_component_firmware(self, component_name, image_path): - - bios_image = None - bios_version = "3.25.0." - bios_file_name = "S6100*BIOS*" - flashrom = "/usr/local/bin/flashrom" - PLATFORM_ROOT_PATH = '/usr/share/sonic/device' - machine_info = sonic_device_util.get_machine_info() - platform = sonic_device_util.get_platform_info(machine_info) - platform_path = "/".join([PLATFORM_ROOT_PATH, platform, "bin"]) - - warning = """ - ******************************************************************** - * Warning - Upgrading BIOS is inherently risky and should only be * - * attempted when necessary. A failure at this upgrade may cause * - * a board RMA. Proceed with caution ! * - ******************************************************************** - """ - - if component_name in self._component_name_list: - if component_name == COMPONENT_BIOS: # BIOS - - # current BIOS version - current_bios_version = self.get_firmware_version("BIOS") - - # Construct BIOS image path - if image_path is not None: - image_path = image_path + platform_path - for name in glob.glob( - os.path.join(image_path, bios_file_name)): - bios_image = image_path = name - - if not bios_image: - print "BIOS image file not found:", image_path - return False - - # Extract BIOS image version - bios_image = os.path.basename(bios_image) - bios_image = bios_image.strip('S6100-BIOS-') - bios_image_version = bios_image.strip('.bin') - - if bios_image_version.startswith(bios_version): - bios_image_minor = bios_image_version.replace( - bios_image_version[:7], '') - if bios_image_minor.startswith("2"): - bios_image_minor = bios_image_minor.split("-")[1] - - if current_bios_version.startswith(bios_version): - current_bios_minor = current_bios_version.replace( - current_bios_version[:7], '') - if current_bios_minor.startswith("2"): - current_bios_minor = current_bios_minor.split("-")[1] - - # BIOS version check - if bios_image_minor > current_bios_minor: - - print warning - prompt_text = "New BIOS image " + bios_image_version + \ - " available to install, continue?" - yes = click.confirm(prompt_text) - - elif current_bios_minor > bios_image_minor: - - print warning - prompt_text = "Do you want to downgrade BIOS image from " \ - + current_bios_version + " to " + \ - bios_image_version + " continue?" - - yes = click.confirm(prompt_text) - - else: - print("BIOS is already with {} latest version".format( - current_bios_version)) - return True - - if yes: - command = flashrom + " -p" + " internal" + " -w " + \ - image_path - self.run_command(command) - - elif component_name == SWITCH_CPLD: # CPLD - return False - - elif component_name == SMF_FPGA: # SMF - return False - else: - print "Invalid component Name:", component_name - - return True - - diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/component.py new file mode 100644 index 000000000000..a92ab5c85db2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/component.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python + +######################################################################## +# DELLEMC S6100 +# +# 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 subprocess + from sonic_platform_base.component_base import ComponentBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +BIOS_QUERY_VERSION_COMMAND = "dmidecode -s system-version" + + +class Component(ComponentBase): + """DellEMC Platform-specific Component class""" + + HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/" + HWMON_NODE = os.listdir(HWMON_DIR)[0] + MAILBOX_DIR = HWMON_DIR + HWMON_NODE + + CHASSIS_COMPONENTS = [ + ["BIOS", ("Performs initialization of hardware components during " + "booting")], + ["CPLD", "Used for managing IO modules, SFP+ modules and system LEDs"], + ["FPGA", ("Platform management controller for on-board temperature " + "monitoring, in-chassis power, Fan and LED control")] + ] + MODULE_COMPONENT = [ + "IOM{}-CPLD", + "Used for managing QSFP+ modules ({0}-{1})" + ] + + def __init__(self, component_index=0, + is_module=False, iom_index=0, i2c_line=0): + + self.is_module_component = is_module + + if self.is_module_component: + self.index = iom_index + self.name = self.MODULE_COMPONENT[0].format(self.index) + self.description = self.MODULE_COMPONENT[1].format( + ((self.index - 1) * 16) + 1, self.index * 16) + self.cpld_version_file = ("/sys/class/i2c-adapter/i2c-{0}/{0}-003e" + "/iom_cpld_vers").format(i2c_line) + else: + self.index = component_index + self.name = self.CHASSIS_COMPONENTS[self.index][0] + self.description = self.CHASSIS_COMPONENTS[self.index][1] + + def _read_sysfs_file(self, sysfs_file): + # On successful read, returns the value read from given + # sysfs_file and on failure returns 'ERR' + rv = 'ERR' + + if (not os.path.isfile(sysfs_file)): + return rv + + try: + with open(sysfs_file, 'r') as fd: + rv = fd.read() + except Exception as error: + rv = 'ERR' + + rv = rv.rstrip('\r\n') + rv = rv.lstrip(" ") + return rv + + def _get_command_result(self, cmdline): + try: + proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + result = stdout.rstrip('\n') + except OSError: + result = None + + return result + + def _get_cpld_version(self): + io_resource = "/dev/port" + CPLD_VERSION_ADDR = 0x100 + + fd = os.open(io_resource, os.O_RDONLY) + if (fd < 0): + return 'NA' + + if (os.lseek(fd, CPLD_VERSION_ADDR, os.SEEK_SET) != CPLD_VERSION_ADDR): + os.close(fd) + return 'NA' + + buf = os.read(fd, 1) + cpld_version = str(ord(buf)) + os.close(fd) + + return cpld_version + + def _get_iom_cpld_version(self): + ver_str = self._read_sysfs_file(self.cpld_version_file) + if (ver_str != 'ERR'): + if ver_str == 'read error': + return 'NA' + + ver_str = ver_str.rstrip('\r\n') + cpld_version = str(int(ver_str.split(':')[1], 16)) + return cpld_version + else: + return 'NA' + + def _get_fpga_version(self): + fpga_ver_file = self.MAILBOX_DIR + '/smf_firmware_ver' + fpga_ver = self._read_sysfs_file(fpga_ver_file) + if (fpga_ver != 'ERR'): + return fpga_ver + else: + return 'NA' + + def get_name(self): + """ + Retrieves the name of the component + + Returns: + A string containing the name of the component + """ + return self.name + + def get_description(self): + """ + Retrieves the description of the component + + Returns: + A string containing the description of the component + """ + return self.description + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + + Returns: + A string containing the firmware version of the component + """ + if self.is_module_component: # IOM CPLD + return self._get_iom_cpld_version() + else: + if self.index == 0: # BIOS + bios_ver = self._get_command_result(BIOS_QUERY_VERSION_COMMAND) + + if not bios_ver: + return 'NA' + else: + return bios_ver + + elif self.index == 1: # SwitchCard CPLD + return self._get_cpld_version() + elif self.index == 2: # FPGA + return self._get_fpga_version() + + def install_firmware(self, image_path): + """ + Installs firmware to the component + + Args: + image_path: A string, path to firmware image + + Returns: + A boolean, True if install was successful, False if not + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/module.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/module.py index 6b950c4e8366..265dc206ad0c 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/module.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/module.py @@ -13,6 +13,7 @@ import os from sonic_platform_base.module_base import ModuleBase from sonic_platform.sfp import Sfp + from sonic_platform.component import Component except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -54,16 +55,20 @@ def __init__(self, module_index): self.port_start = (self.index - 1) * 16 self.port_end = (self.index * 16) - 1 self.port_i2c_line = self.IOM_I2C_MAPPING[self.index] - self._component_name_list = ['CPLD'] self.eeprom_tlv_dict = dict() self.iom_status_reg = "iom_status" self.iom_presence_reg = "iom_presence" - # Overriding _sfp_list class variable defined in ModuleBase, to - # make it unique per Module object + # Overriding _component_list and _sfp_list class variables defined in + # ModuleBase, to make them unique per Module object + self._component_list = [] self._sfp_list = [] + component = Component(is_module=True, iom_index=self.index, + i2c_line=self.port_i2c_line) + self._component_list.append(component) + eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/i2c-{1}/{1}-0050/eeprom" sfp_ctrl_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-003e/" @@ -188,39 +193,3 @@ def get_system_eeprom_info(self): ‘0x26’:’01’, ‘0x27’:’REV01’, ‘0x28’:’AG9064-C2358-16G’} """ return self.eeprom_tlv_dict - - def get_firmware_version(self, component_name): - """ - Retrieves platform-specific hardware/firmware versions for module - componenets such as BIOS, CPLD, FPGA, etc. - - Args: - component_name: A string, the component name. - - Returns: - A string containing platform-specific component versions - """ - if component_name == 'CPLD': - cpld_version_file = ("/sys/class/i2c-adapter/i2c-{0}/{0}-003e/" - "iom_cpld_vers").format(self.port_i2c_line) - - if (not os.path.isfile(cpld_version_file)): - return 'NA' - - try: - with open(cpld_version_file, 'r') as fd: - ver_str = fd.read() - except Exception as error: - return 'NA' - - if ver_str == 'read error': - return 'NA' - - ver_str = ver_str.rstrip('\r\n') - cpld_version = int(ver_str.split(':')[1], 16) - major_version = (cpld_version & 0xF0) >> 4 - minor_version = cpld_version & 0xF - - return "%d.%d" % (major_version, minor_version) - else: - return 'NA' diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/chassis.py index c3568b3b1e4c..3472bb3e7fb0 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/chassis.py @@ -17,6 +17,7 @@ from sonic_platform.fan import Fan from sonic_platform.psu import Psu from sonic_platform.thermal import Thermal + from sonic_platform.component import Component from eeprom import Eeprom except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -26,15 +27,7 @@ MAX_Z9100_FAN = 2 MAX_Z9100_PSU = 2 MAX_Z9100_THERMAL = 8 - -BIOS_QUERY_VERSION_COMMAND = "dmidecode -s system-version" -#components definitions -COMPONENT_BIOS = "BIOS" -SWITCH_CPLD1 = "CPLD1" -SWITCH_CPLD2 = "CPLD2" -SWITCH_CPLD3 = "CPLD3" -SWITCH_CPLD4 = "CPLD4" -SMF_FPGA = "FPGA1" +MAX_Z9100_COMPONENT = 6 class Chassis(ChassisBase): @@ -115,13 +108,9 @@ def __init__(self): thermal = Thermal(i) self._thermal_list.append(thermal) - # Initialize component list - self._component_name_list.append(COMPONENT_BIOS) - self._component_name_list.append(SWITCH_CPLD1) - self._component_name_list.append(SWITCH_CPLD2) - self._component_name_list.append(SWITCH_CPLD3) - self._component_name_list.append(SWITCH_CPLD4) - self._component_name_list.append(SMF_FPGA) + for i in range(MAX_Z9100_COMPONENT): + component = Component(i) + self._component_list.append(component) def _get_pmc_register(self, reg_name): # On successful read, returns the value read from given @@ -241,82 +230,3 @@ def get_reboot_cause(self): return (self.reset_reason_dict[reset_reason], None) return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason") - - def _get_command_result(self, cmdline): - try: - proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, - shell=True, stderr=subprocess.STDOUT) - stdout = proc.communicate()[0] - proc.wait() - result = stdout.rstrip('\n') - except OSError: - result = '' - - return result - - def _get_cpld_version(self,cpld_number): - io_resource = "/dev/port" - CPLD1_VERSION_ADDR = 0x100 - - if (cpld_number == 1): - fd = os.open(io_resource, os.O_RDONLY) - if (fd < 0): - return 'NA' - if (os.lseek(fd, CPLD1_VERSION_ADDR, os.SEEK_SET) - != CPLD1_VERSION_ADDR): - return 'NA' - - buf = os.read(fd, 1) - cpld_version = ord(buf) - os.close(fd) - - return "%d.%d" % (((cpld_version & 0xF0) >> 4), cpld_version & 0xF) - else: - cpld_version_file = ("/sys/class/i2c-adapter/i2c-{0}/{0}-003e" - "/iom_cpld_vers").format(12 + cpld_number) - - if (not os.path.isfile(cpld_version_file)): - return 'NA' - - try: - with open(cpld_version_file, 'r') as fd: - ver_str = fd.read() - except Exception as error: - return 'NA' - - if ver_str == "read error": - return 'NA' - else: - ver_str = ver_str.rstrip("\r\n") - cpld_version = int(ver_str.split(":")[1], 16) - - return "%d.%d" % (((cpld_version & 0xF0) >> 4), cpld_version & 0xF) - - def _get_fpga_version(self): - fpga_ver = float(self._get_pmc_register('smf_firmware_ver')) - return fpga_ver - - def get_firmware_version(self, component_name): - """ - Retrieves platform-specific hardware/firmware versions for chassis - componenets such as BIOS, CPLD, FPGA, etc. - Args: - component_name: A string, the component name. - Returns: - A string containing platform-specific component versions - """ - if component_name in self._component_name_list : - if component_name == COMPONENT_BIOS: - return self._get_command_result(BIOS_QUERY_VERSION_COMMAND) - elif component_name == SWITCH_CPLD1: - return self._get_cpld_version(1) - elif component_name == SWITCH_CPLD2: - return self._get_cpld_version(2) - elif component_name == SWITCH_CPLD3: - return self._get_cpld_version(3) - elif component_name == SWITCH_CPLD4: - return self._get_cpld_version(4) - elif component_name == SMF_FPGA: - return self._get_fpga_version() - - return None diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/component.py new file mode 100644 index 000000000000..dccb8f6ac2dc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/component.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +######################################################################## +# DELLEMC Z9100 +# +# 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 subprocess + from sonic_platform_base.component_base import ComponentBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +BIOS_QUERY_VERSION_COMMAND = "dmidecode -s system-version" + + +class Component(ComponentBase): + """DellEMC Platform-specific Component class""" + + HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/" + HWMON_NODE = os.listdir(HWMON_DIR)[0] + MAILBOX_DIR = HWMON_DIR + HWMON_NODE + + CHASSIS_COMPONENTS = [ + ["BIOS", ("Performs initialization of hardware components during " + "booting")], + ["CPLD1", "Used for managing the system LEDs"], + ["CPLD2", "Used for managing QSFP28 modules (1-12)"], + ["CPLD3", "Used for managing QSFP28 modules (13-22)"], + ["CPLD4", ("Used for managing QSFP28 modules (23-32) and SFP+ " + "modules")], + ["FPGA", ("Platform management controller for on-board temperature " + "monitoring, in-chassis power, Fan and LED control")] + ] + + def __init__(self, component_index=0): + self.index = component_index + self.name = self.CHASSIS_COMPONENTS[self.index][0] + self.description = self.CHASSIS_COMPONENTS[self.index][1] + + def _read_sysfs_file(self, sysfs_file): + # On successful read, returns the value read from given + # sysfs_file and on failure returns 'ERR' + rv = 'ERR' + + if (not os.path.isfile(sysfs_file)): + return rv + + try: + with open(sysfs_file, 'r') as fd: + rv = fd.read() + except Exception as error: + rv = 'ERR' + + rv = rv.rstrip('\r\n') + rv = rv.lstrip(" ") + return rv + + def _get_command_result(self, cmdline): + try: + proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + result = stdout.rstrip('\n') + except OSError: + result = None + + return result + + def _get_cpld_version(self, cpld_number): + io_resource = "/dev/port" + CPLD1_VERSION_ADDR = 0x100 + + if (cpld_number == 1): + fd = os.open(io_resource, os.O_RDONLY) + if (fd < 0): + return 'NA' + + if (os.lseek(fd, CPLD1_VERSION_ADDR, os.SEEK_SET) + != CPLD1_VERSION_ADDR): + os.close(fd) + return 'NA' + + buf = os.read(fd, 1) + cpld_version = str(ord(buf)) + os.close(fd) + + return cpld_version + else: + cpld_version_file = ("/sys/class/i2c-adapter/i2c-{0}/{0}-003e" + "/iom_cpld_vers").format(12 + cpld_number) + ver_str = self._read_sysfs_file(cpld_version_file) + + if (ver_str == "read error") or (ver_str == 'ERR'): + return 'NA' + + ver_str = ver_str.rstrip("\r\n") + cpld_version = str(int(ver_str.split(":")[1], 16)) + + return cpld_version + + def _get_fpga_version(self): + fpga_ver_file = self.MAILBOX_DIR + '/smf_firmware_ver' + fpga_ver = self._read_sysfs_file(fpga_ver_file) + if (fpga_ver != 'ERR'): + return fpga_ver + else: + return 'NA' + + def get_name(self): + """ + Retrieves the name of the component + + Returns: + A string containing the name of the component + """ + return self.name + + def get_description(self): + """ + Retrieves the description of the component + + Returns: + A string containing the description of the component + """ + return self.description + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + + Returns: + A string containing the firmware version of the component + """ + if self.index == 0: # BIOS + bios_ver = self._get_command_result(BIOS_QUERY_VERSION_COMMAND) + + if not bios_ver: + return 'NA' + else: + return bios_ver + + elif self.index < 5: # CPLD + return self._get_cpld_version(self.index) + elif self.index == 5: # FPGA + return self._get_fpga_version() + + def install_firmware(self, image_path): + """ + Installs firmware to the component + + Args: + image_path: A string, path to firmware image + + Returns: + A boolean, True if install was successful, False if not + """ + return False From 4d8a01c26c6e19773e4e551d1316562ef30900e8 Mon Sep 17 00:00:00 2001 From: Roy Lee Date: Thu, 17 Oct 2019 09:01:38 +0800 Subject: [PATCH 080/278] [device] as4630-54pe: update sfputil for get_transceiver_change_event. (#3315) Signed-off-by: roy_lee --- .../Accton-AS4630-54PE/port_config.ini | 110 ++++++------ .../plugins/sfputil.py | 163 ++++++++++++++---- .../as4630-54pe/classes/fanutil.py | 30 +--- .../as4630-54pe/classes/thermalutil.py | 10 +- .../as4630-54pe-platform-monitor.service | 1 - .../as4630-54pe/utils/README | 78 ++------- 6 files changed, 200 insertions(+), 192 deletions(-) diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/port_config.ini b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/port_config.ini index d008d016ef5c..aabb372bf649 100755 --- a/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/port_config.ini +++ b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/port_config.ini @@ -1,55 +1,55 @@ -# name lanes alias index -Ethernet0 26 thousandE1 0 -Ethernet1 25 thousandE2 1 -Ethernet2 28 thousandE3 2 -Ethernet3 27 thousandE4 3 -Ethernet4 30 thousandE5 4 -Ethernet5 29 thousandE6 5 -Ethernet6 32 thousandE7 6 -Ethernet7 31 thousandE8 7 -Ethernet8 38 thousandE9 8 -Ethernet9 37 thousandE10 9 -Ethernet10 40 thousandE11 10 -Ethernet11 39 thousandE12 11 -Ethernet12 34 thousandE13 12 -Ethernet13 33 thousandE14 13 -Ethernet14 36 thousandE15 14 -Ethernet15 35 thousandE16 15 -Ethernet16 46 thousandE17 16 -Ethernet17 45 thousandE18 17 -Ethernet18 48 thousandE19 18 -Ethernet19 47 thousandE20 19 -Ethernet20 42 thousandE21 20 -Ethernet21 41 thousandE22 21 -Ethernet22 44 thousandE23 22 -Ethernet23 43 thousandE24 23 -Ethernet24 2 thousandE25 24 -Ethernet25 1 thousandE26 25 -Ethernet26 4 thousandE27 26 -Ethernet27 3 thousandE28 27 -Ethernet28 6 thousandE29 28 -Ethernet29 5 thousandE30 29 -Ethernet30 8 thousandE31 30 -Ethernet31 7 thousandE32 31 -Ethernet32 10 thousandE33 32 -Ethernet33 9 thousandE34 33 -Ethernet34 12 thousandE35 34 -Ethernet35 11 thousandE36 35 -Ethernet36 14 thousandE37 36 -Ethernet37 13 thousandE38 37 -Ethernet38 16 thousandE39 38 -Ethernet39 15 thousandE40 39 -Ethernet40 18 thousandE41 40 -Ethernet41 17 thousandE42 41 -Ethernet42 20 thousandE43 42 -Ethernet43 19 thousandE44 43 -Ethernet44 22 thousandE45 44 -Ethernet45 21 thousandE46 45 -Ethernet46 24 thousandE47 46 -Ethernet47 23 thousandE48 47 -Ethernet48 67 twentyfiveGigE49 48 -Ethernet49 66 twentyfiveGigE50 49 -Ethernet50 65 twentyfiveGigE51 50 -Ethernet51 68 twentyfiveGigE52 51 -Ethernet52 73,74,75,76 hundredGigE53 52 -Ethernet56 69,70,71,72 hundredGigE54 56 +# name lanes alias index speed +Ethernet0 26 thousandE1 1 1000 +Ethernet1 25 thousandE2 2 1000 +Ethernet2 28 thousandE3 3 1000 +Ethernet3 27 thousandE4 4 1000 +Ethernet4 30 thousandE5 5 1000 +Ethernet5 29 thousandE6 6 1000 +Ethernet6 32 thousandE7 7 1000 +Ethernet7 31 thousandE8 8 1000 +Ethernet8 38 thousandE9 9 1000 +Ethernet9 37 thousandE10 10 1000 +Ethernet10 40 thousandE11 11 1000 +Ethernet11 39 thousandE12 12 1000 +Ethernet12 34 thousandE13 13 1000 +Ethernet13 33 thousandE14 14 1000 +Ethernet14 36 thousandE15 15 1000 +Ethernet15 35 thousandE16 16 1000 +Ethernet16 46 thousandE17 17 1000 +Ethernet17 45 thousandE18 18 1000 +Ethernet18 48 thousandE19 19 1000 +Ethernet19 47 thousandE20 20 1000 +Ethernet20 42 thousandE21 21 1000 +Ethernet21 41 thousandE22 22 1000 +Ethernet22 44 thousandE23 23 1000 +Ethernet23 43 thousandE24 24 1000 +Ethernet24 2 thousandE25 25 1000 +Ethernet25 1 thousandE26 26 1000 +Ethernet26 4 thousandE27 27 1000 +Ethernet27 3 thousandE28 28 1000 +Ethernet28 6 thousandE29 29 1000 +Ethernet29 5 thousandE30 30 1000 +Ethernet30 8 thousandE31 31 1000 +Ethernet31 7 thousandE32 32 1000 +Ethernet32 10 thousandE33 33 1000 +Ethernet33 9 thousandE34 34 1000 +Ethernet34 12 thousandE35 35 1000 +Ethernet35 11 thousandE36 36 1000 +Ethernet36 14 thousandE37 37 1000 +Ethernet37 13 thousandE38 38 1000 +Ethernet38 16 thousandE39 39 1000 +Ethernet39 15 thousandE40 40 1000 +Ethernet40 18 thousandE41 41 1000 +Ethernet41 17 thousandE42 42 1000 +Ethernet42 20 thousandE43 43 1000 +Ethernet43 19 thousandE44 44 1000 +Ethernet44 22 thousandE45 45 1000 +Ethernet45 21 thousandE46 46 1000 +Ethernet46 24 thousandE47 47 1000 +Ethernet47 23 thousandE48 48 1000 +Ethernet48 67 twentyfiveGigE49 49 25000 +Ethernet49 66 twentyfiveGigE50 50 25000 +Ethernet50 65 twentyfiveGigE51 51 25000 +Ethernet51 68 twentyfiveGigE52 52 25000 +Ethernet52 73,74,75,76 hundredGigE53 53 100000 +Ethernet56 69,70,71,72 hundredGigE54 54 100000 diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as4630_54pe-r0/plugins/sfputil.py index 69c2870669e7..cb18eb0d540c 100755 --- a/device/accton/x86_64-accton_as4630_54pe-r0/plugins/sfputil.py +++ b/device/accton/x86_64-accton_as4630_54pe-r0/plugins/sfputil.py @@ -4,34 +4,39 @@ # try: + import sys import time + import string + from ctypes import create_string_buffer from sonic_sfp.sfputilbase import SfpUtilBase except ImportError as e: raise ImportError("%s - required module not found" % str(e)) +SFP_STATUS_INSERTED = '1' +SFP_STATUS_REMOVED = '0' class SfpUtil(SfpUtilBase): """Platform-specific SfpUtil class""" - - PORT_START = 48 - PORT_END = 53 + PORT_START = 49 + PORT_END = 54 PORTS_IN_BLOCK = 54 - + QSFP_START = 53 + BASE_OOM_PATH = "/sys/bus/i2c/devices/{0}-0050/" BASE_CPLD_PATH = "/sys/bus/i2c/devices/3-0060/" - + _port_to_is_present = {} _port_to_lp_mode = {} _port_to_eeprom_mapping = {} _port_to_i2c_mapping = { - 48: [18], - 49: [19], - 50: [20], - 51: [21], - 52: [22], - 53: [23], + 49: [18], + 50: [19], + 51: [20], + 52: [21], + 53: [22], + 54: [23], } @property @@ -41,7 +46,7 @@ def port_start(self): @property def port_end(self): return self.PORT_END - + @property def qsfp_ports(self): return range(self.PORT_START, self.PORTS_IN_BLOCK + 1) @@ -52,28 +57,23 @@ def port_to_eeprom_mapping(self): def __init__(self): eeprom_path = self.BASE_OOM_PATH + "eeprom" - - for x in range(0, self.port_end+1): - if x < 48: - self.port_to_eeprom_mapping[x] = eeprom_path.format(0) - else: - self.port_to_eeprom_mapping[x] = eeprom_path.format( - self._port_to_i2c_mapping[x][0]) - + for x in range(self.port_start, self.port_end+1): + self.port_to_eeprom_mapping[x] = eeprom_path.format( + self._port_to_i2c_mapping[x][0]) SfpUtilBase.__init__(self) def get_presence(self, port_num): # Check for invalid port_num if port_num < self.port_start or port_num > self.port_end: return False - - present_path = self.BASE_CPLD_PATH + "module_present_" + str(port_num+1) + + present_path = self.BASE_CPLD_PATH + "module_present_" + str(port_num) self.__port_to_is_present = present_path try: val_file = open(self.__port_to_is_present) except IOError as e: - print "Error: unable to open file: %s" % str(e) + print "Error: unable to open file: %s" % str(e) return False content = val_file.readline().rstrip() @@ -84,20 +84,113 @@ def get_presence(self, port_num): return True return False - - def get_low_power_mode(self, port_num): - raise NotImplementedError - def set_low_power_mode(self, port_num, lpmode): - raise NotImplementedError + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.QSFP_START or port_num > self.port_end: + return False + + try: + eeprom = None + if not self.get_presence(port_num): + return False + eeprom = open(self.port_to_eeprom_mapping[port_num], "rb") + eeprom.seek(93) + lpmode = ord(eeprom.read(1)) + + # if "Power override" bit is 1 and "Power set" bit is 1 + if ((lpmode & 0x3) == 0x3): + return True + + # High Power Mode if one of the following conditions is matched: + # 1. "Power override" bit is 0 + # 2. "Power override" bit is 1 and "Power set" bit is 0 + else: + return False + + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.QSFP_START or port_num > self.port_end: + return False + + try: + eeprom = None + if not self.get_presence(port_num): + return False # Port is not present, unable to set the eeprom + + # Fill in write buffer + # 0x3:Low Power Mode, 0x1:High Power Mode + regval = 0x3 if lpmode else 0x1 + + buffer = create_string_buffer(1) + buffer[0] = chr(regval) + + # Write to eeprom + eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b") + eeprom.seek(93) + eeprom.write(buffer[0]) + return True + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) def reset(self, port_num): raise NotImplementedError - def get_transceiver_change_event(self): - """ - TODO: This function need to be implemented - when decide to support monitoring SFP(Xcvrd) - on this platform. - """ - raise NotImplementedError + @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':0} + def get_transceiver_change_event(self, timeout=0): + port_dict = {} + + if timeout == 0: + cd_ms = sys.maxint + 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, {} + return False, {} + diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/fanutil.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/fanutil.py index ca0f3f9da1e3..b6752783dc03 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/fanutil.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/fanutil.py @@ -180,8 +180,6 @@ def get_fan_to_device_path(self, fan_num, node_num): def get_fan_fault(self, fan_num): return self._get_fan_node_val(fan_num, self.FAN_NODE_FAULT_IDX_OF_MAP) - #def get_fan_speed(self, fan_num): - # return self._get_fan_node_val(fan_num, self.FAN_NODE_SPEED_IDX_OF_MAP) def get_fan_dir(self, fan_num): return self._get_fan_node_val(fan_num, self.FAN_NODE_DIR_IDX_OF_MAP) @@ -196,17 +194,9 @@ def get_fan_duty_cycle(self): content = val_file.readline().rstrip() val_file.close() - return int(content) - #self._get_fan_node_val(fan_num, self.FAN_NODE_DUTY_IDX_OF_MAP) -#static u32 reg_val_to_duty_cycle(u8 reg_val) -#{ -# reg_val &= FAN_DUTY_CYCLE_REG_MASK; -# return ((u32)(reg_val+1) * 625 + 75)/ 100; -#} -# + def set_fan_duty_cycle(self, val): - try: fan_file = open(self.FAN_DUTY_PATH, 'r+') except IOError as e: @@ -217,9 +207,6 @@ def set_fan_duty_cycle(self, val): fan_file.close() return True - #def get_fanr_fault(self, fan_num): - # return self._get_fan_node_val(fan_num, self.FANR_NODE_FAULT_IDX_OF_MAP) - def get_fanr_speed(self, fan_num): return self._get_fan_node_val(fan_num, self.FANR_NODE_SPEED_IDX_OF_MAP) @@ -232,20 +219,5 @@ def get_fan_status(self, fan_num): logging.debug('GET. FAN fault. fan_num, %d', fan_num) return False - #if self.get_fanr_fault(fan_num) is not None and self.get_fanr_fault(fan_num) > 0: - # logging.debug('GET. FANR fault. fan_num, %d', fan_num) - # return False - return True -#def main(): -# fan = FanUtil() -# -# print 'get_size_node_map : %d' % fan.get_size_node_map() -# print 'get_size_path_map : %d' % fan.get_size_path_map() -# for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1): -# for y in range(fan.get_idx_node_start(), fan.get_num_nodes()+1): -# print fan.get_fan_to_device_path(x, y) -# -#if __name__ == '__main__': -# main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/thermalutil.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/thermalutil.py index 96163f1d63ab..3af7b3d7df5f 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/thermalutil.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/thermalutil.py @@ -45,7 +45,6 @@ class ThermalUtil(object): """ Dictionary where key1 = thermal id index (integer) starting from 1 value = path to fan device file (string) """ - #_thermal_to_device_path_mapping = {} _thermal_to_device_node_mapping = { THERMAL_NUM_1_IDX: ['55', '48'], @@ -121,11 +120,6 @@ def main(): print "termal3=%d" %thermal._get_thermal_val(3) print "termal4=%d" %thermal._get_thermal_val(4) print "termal5=%d" %thermal._get_thermal_val(5) -# -# print 'get_size_node_map : %d' % thermal.get_size_node_map() -# print 'get_size_path_map : %d' % thermal.get_size_path_map() -# for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1): -# print thermal.get_thermal_to_device_path(x) -# + if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-platform-monitor.service index 47bf4e81d82e..8ed60fca95f3 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-platform-monitor.service +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-platform-monitor.service @@ -9,7 +9,6 @@ ExecStartPre=/usr/local/bin/accton_as4630_54pe_util.py install ExecStart=/usr/local/bin/accton_as4630_54pe_monitor.py KillSignal=SIGKILL SuccessExitStatus=SIGKILL -#StandardOutput=tty # Resource Limitations LimitCORE=infinity diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/README b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/README index 44e03cab5f52..f656d2b0a855 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/README +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/README @@ -1,4 +1,4 @@ -Copyright (C) 2016 Accton Networks, Inc. +Copyright (C) 2019 Accton Networks, 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 @@ -13,79 +13,29 @@ 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 . -Contents of this package: - patch - files under patch/ is for kernel and ONIE installer - for the kernel: - config-accton-as5712_54x.patch - for kernel configuration. - driver-i2c-muxes-pca954x-always-deselect.patch - for i2c_mux deselects after transaction. - driver-patches-for-accton-as5712-fan-psu-cpld.patch - for as5712's fan/psu/cpld/led/sfp drivers. - for ONIE: - onie_installer-accton-AS5712-54X.patch - for console port setting and copy util script o rootfs. - module - Contains source code of as5712 kernel driver modules. - -The late Sonic building scripts, pushed @Dec 5 2016, will automatically -create a docker container and run building process under it. -User is not necessary to handle docker environment creation. - -1. Download sonic-buildimage environment. - - Run "git clone https://github.com/Azure/sonic-buildimage". - - cd to sonic-buildimage and run "git submodule update --init --recursive". -2. Build kernel - - cd ./src/sonic-linux-kernel - - Copy patches and series from patch/kernel of this release to - sonic-linux-kernel/patch. - - Build kernel by "make". - - The built kernel package, linux-image-3.16.0-5-amd64_3.16.51-3+deb8u1_amd64.deb - , is generated. -3. Build installer - - Change directory back to sonic-buildimage/. - - Get onie_installer-accton-AS5712-54X.patch" from patch/installer. - - Change setting for AS5712-54X by patching build_image.sh. - "patch -p1 < onie_installer-accton-AS5712-54X.patch" - !!NOTICE, patching onie_installer-accton-AS5712-54X.patch comments out the - "git status" checking at build_image.sh. - - The account and password of installed OS can be given at rules/config. - The default user and password are "admin" & "YourPaSsWoRd" respectively. - - Run "make configure PLATFORM=broadcom" - - Copy the built kernel debian package to target/debs/. - The file is linux-image-3.16.0-5-amd64_*_amd64.deb under directory - src/sonic-linux-kernel/. - - Run "make target/sonic-generic.bin" - - Get the installer, target/sonic-generic.bin, to target machine and install. - All Linux kernel code is licensed under the GPLv1. All other code is licensed under the GPLv3. Please see the LICENSE file for copies of both licenses. -The code for integacting with Accton AS5712-54X has 2 parts, +The code for integacting with Accton AS4630-54pe has 2 parts, kernel drivers and operational script. The kernel drivers of peripherals are under module/ directory. -1. These drivers are patched into kernel by - driver-patches-for-accton-as5712-fan-psu-cpld.patch - Or you can build the driver under module/ by setting environment variable, - KERNEL_SRC, to proper linux built directory and run make. - It may be sonic-linux-kernel/linux-3.*/debian/build/build_amd64_none_amd64/. -2. A operational script, accton_as5712_util.py, for device initializatian and +1. These drivers are at module dir. +2. A operational script, accton_as4630_util.py, for device initializatian and peripheral accessing should be installed at /usr/bin. - This script is generated by onie_installer-accton-AS5712-54X.patch. - It's done by patching onie_installer-accton-AS5712-54X.patch at build-image. - Run "accton_as5712_util.py install" to install drivers. + Run "accton_as4630_util.py install" to install drivers. -To initialize the system, run "accton_as5712_util.py install". -To clean up the drivers & devices, run "accton_as5712_util.py clean". -To dump information of sensors, run "accton_as5712_util.py show". -To dump SFP EEPROM, run "accton_as5712_util.py sff". -To set fan speed, run "accton_as5712_util.py set fan". -To enable/disable SFP emission, run "accton_as5712_util.py set sfp". -To set system LEDs' color, run "accton_as5712_util.py set led" -For more information, run "accton_as5712_util.py --help". +To initialize the system, run "accton_as4630_util.py install". +To clean up the drivers & devices, run "accton_as4630_util.py clean". +To dump information of sensors, run "accton_as4630_util.py show". +To dump SFP EEPROM, run "accton_as4630_util.py sff". +To set fan speed, run "accton_as4630_util.py set fan". +To enable/disable SFP emission, run "accton_as4630_util.py set sfp". +To set system LEDs' color, run "accton_as4630_util.py set led" +For more information, run "accton_as4630_util.py --help". ==================================================================== -Besides applying accton_as5712_util.py to access peripherals, you can +Besides applying accton_as4630_util.py to access peripherals, you can access peripherals by sysfs nodes directly after the installation is run. System LED: From 6ecec007e35d841612163a2aaeb2defc98e6a43d Mon Sep 17 00:00:00 2001 From: zzhiyuan Date: Wed, 16 Oct 2019 18:38:13 -0700 Subject: [PATCH 081/278] [arista]: Update arista drivers submodule (#3618) Fixed variable name causing problems for sonic-platform-commons for arista. --- platform/barefoot/sonic-platform-modules-arista | 2 +- platform/broadcom/sonic-platform-modules-arista | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/barefoot/sonic-platform-modules-arista b/platform/barefoot/sonic-platform-modules-arista index 73dd2e0fe144..10750325b6cf 160000 --- a/platform/barefoot/sonic-platform-modules-arista +++ b/platform/barefoot/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit 73dd2e0fe144e2bb6778d39d3e051c597bb1c9d8 +Subproject commit 10750325b6cfc7a1dc1a8b0734008bde1bb3ac06 diff --git a/platform/broadcom/sonic-platform-modules-arista b/platform/broadcom/sonic-platform-modules-arista index 73dd2e0fe144..10750325b6cf 160000 --- a/platform/broadcom/sonic-platform-modules-arista +++ b/platform/broadcom/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit 73dd2e0fe144e2bb6778d39d3e051c597bb1c9d8 +Subproject commit 10750325b6cfc7a1dc1a8b0734008bde1bb3ac06 From 5d9bd9c1ad31987d10ac2ad127580b157107ea70 Mon Sep 17 00:00:00 2001 From: sudhanshukumar22 <51457531+sudhanshukumar22@users.noreply.github.com> Date: Thu, 17 Oct 2019 12:50:36 +0530 Subject: [PATCH 082/278] Port a fix from FRR community (#3614) Author: sudhanshukumar22 Date: Tue Oct 16 12:33:20 2019 -0700 https://github.com/donaldsharp/frr/commit/39c93f379a5b57c56739a339ad75ec06e30daef3 If we have a case where have created a fd for i/o and we have removed the handling thread but still have the fd in the poll data structure, there existed a case where we would get the handle this fd return from poll but we would immediately do nothing with it because we didn't have a thread to hand the event to. This leads to an infinite loop. Prevent the infinite loop from happening and log the problem. Signed-off-by: Preetham Singh (preetham.singh@broadcom.com) --- ...-dead-fd-poll-data-port-fix-from-frr.patch | 107 ++++++++++++++++++ src/sonic-frr/patch/series | 1 + 2 files changed, 108 insertions(+) create mode 100644 src/sonic-frr/patch/0007-prevent-dead-fd-poll-data-port-fix-from-frr.patch diff --git a/src/sonic-frr/patch/0007-prevent-dead-fd-poll-data-port-fix-from-frr.patch b/src/sonic-frr/patch/0007-prevent-dead-fd-poll-data-port-fix-from-frr.patch new file mode 100644 index 000000000000..5954e5c7c53d --- /dev/null +++ b/src/sonic-frr/patch/0007-prevent-dead-fd-poll-data-port-fix-from-frr.patch @@ -0,0 +1,107 @@ +From e4225086634fb7ae7fa762f3a45af6ad39e78641 Mon Sep 17 00:00:00 2001 +From: sudhanshukumar22 +Date: Tue, 15 Oct 2019 02:17:00 -0700 +Subject: [PATCH] Port a fix from FRR community + https://github.com/donaldsharp/frr/commit/39c93f379a5b57c56739a339ad75ec06e30daef3 + If we have a case where have created a fd for i/o and we have removed the + handling thread but still have the fd in the poll data structure, there + existed a case where we would get the handle this fd return from poll but we + would immediately do nothing with it because we didn't have a thread to hand + the event to. + +This leads to an infinite loop. Prevent the infinite loop +from happening and log the problem. +--- + lib/lib_errors.c | 6 ++++++ + lib/lib_errors.h | 1 + + lib/thread.c | 25 ++++++++++++++++++------- + 3 files changed, 25 insertions(+), 7 deletions(-) + +diff --git a/lib/lib_errors.c b/lib/lib_errors.c +index b6c764d87..033f27e58 100644 +--- a/lib/lib_errors.c ++++ b/lib/lib_errors.c +@@ -50,6 +50,12 @@ static struct log_ref ferr_lib_warn[] = { + .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug, or some combination therof.", + .suggestion = "Gather log data and open an Issue", + }, ++ { ++ .code = EC_LIB_NO_THREAD, ++ .title = "The Event subsystem has detected an internal FD problem", ++ .description = "The Event subsystem has detected a file descriptor read/write event without an associated handling function. This is a bug, please collect log data and open an issue.", ++ .suggestion = "Gather log data and open an Issue", ++ }, + { + .code = EC_LIB_RMAP_RECURSION_LIMIT, + .title = "Reached the Route-Map Recursion Limit", +diff --git a/lib/lib_errors.h b/lib/lib_errors.h +index 39b39fb06..996a16ba9 100644 +--- a/lib/lib_errors.h ++++ b/lib/lib_errors.h +@@ -45,6 +45,7 @@ enum lib_log_refs { + EC_LIB_STREAM, + EC_LIB_LINUX_NS, + EC_LIB_SLOW_THREAD, ++ EC_LIB_NO_THREAD, + EC_LIB_RMAP_RECURSION_LIMIT, + EC_LIB_BACKUP_CONFIG, + EC_LIB_VRF_LENGTH, +diff --git a/lib/thread.c b/lib/thread.c +index 5ca859a74..82708557d 100644 +--- a/lib/thread.c ++++ b/lib/thread.c +@@ -1235,12 +1235,26 @@ static struct thread *thread_run(struct thread_master *m, struct thread *thread, + } + + static int thread_process_io_helper(struct thread_master *m, +- struct thread *thread, short state, int pos) ++ struct thread *thread, short state, short actual_state, int pos) + { + struct thread **thread_array; + +- if (!thread) ++ /* ++ * If another pthread scheduled this file descriptor for this event ++ * we're responding to, no problem, we're getting to it now. ++ * Additionally if !thread if we don't clear this now we'll ++ * infinaloop( which sucks ) ++ */ ++ m->handler.pfds[pos].events &= ~(state); ++ ++ if (!thread) { ++ if ((actual_state & (POLLHUP | POLLIN)) != POLLHUP) ++ flog_err( EC_LIB_NO_THREAD, ++ "Attempting to process an I/O event but for fd: %d(%d) no thread to handle this!\n", ++ m->handler.pfds[pos].fd, actual_state); + return 0; ++ } ++ + + if (thread->type == THREAD_READ) + thread_array = m->read; +@@ -1250,9 +1264,6 @@ static int thread_process_io_helper(struct thread_master *m, + thread_array[thread->u.fd] = NULL; + thread_list_add_tail(&m->ready, thread); + thread->type = THREAD_READY; +- /* if another pthread scheduled this file descriptor for the event we're +- * responding to, no problem; we're getting to it now */ +- thread->master->handler.pfds[pos].events &= ~(state); + return 1; + } + +@@ -1290,10 +1301,10 @@ static void thread_process_io(struct thread_master *m, unsigned int num) + * should still be a valid index into the master's pfds. */ + if (pfds[i].revents & (POLLIN | POLLHUP)) + thread_process_io_helper(m, m->read[pfds[i].fd], POLLIN, +- i); ++ pfds[i].revents,i); + if (pfds[i].revents & POLLOUT) + thread_process_io_helper(m, m->write[pfds[i].fd], +- POLLOUT, i); ++ POLLOUT, pfds[i].revents, i); + + /* if one of our file descriptors is garbage, remove the same + * from +-- +2.18.0 + diff --git a/src/sonic-frr/patch/series b/src/sonic-frr/patch/series index 1acf6d94f435..edeb30ce1e71 100644 --- a/src/sonic-frr/patch/series +++ b/src/sonic-frr/patch/series @@ -3,3 +3,4 @@ 0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch 0005-Support-VRF.patch 0006-changes-for-making-snmp-socket-non-blocking.patch +0007-prevent-dead-fd-poll-data-port-fix-from-frr.patch From 423d4812848375a9556cc9024db42e2d843a47e9 Mon Sep 17 00:00:00 2001 From: Praveen Chaudhary Date: Thu, 17 Oct 2019 07:08:13 -0700 Subject: [PATCH 083/278] [FRR]: Patch for kernel level graceful restart. (#3621) * [FRR]: Patch for kernel level graceful restart. Original Patch in FRR master: https://github.com/FRRouting/frr/pull/4301 * Rename 0007-zebra-kernel-level-graceful-restart.patch to 0008-zebra-kernel-level-graceful-restart.patch --- ...-zebra-kernel-level-graceful-restart.patch | 227 ++++++++++++++++++ src/sonic-frr/patch/series | 1 + 2 files changed, 228 insertions(+) create mode 100644 src/sonic-frr/patch/0008-zebra-kernel-level-graceful-restart.patch diff --git a/src/sonic-frr/patch/0008-zebra-kernel-level-graceful-restart.patch b/src/sonic-frr/patch/0008-zebra-kernel-level-graceful-restart.patch new file mode 100644 index 000000000000..e2a68a3507b4 --- /dev/null +++ b/src/sonic-frr/patch/0008-zebra-kernel-level-graceful-restart.patch @@ -0,0 +1,227 @@ + + zebra: Add kernel level graceful restart + + + + Add the a `--graceful_restart X` flag to zebra start that + now creates a timer that pops in X seconds and will go + through and remove all routes that are older than startup. + + If graceful_restart is not specified then we will just pop + a timer that cleans everything up immediately. + + Signed-off-by: Praveen Chaudhary + Signed-off-by: Donald Sharp + +diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst +index f38db9d24..40d894929 100644 +--- a/doc/user/zebra.rst ++++ b/doc/user/zebra.rst +@@ -23,9 +23,12 @@ Besides the common invocation options (:ref:`common-invocation-options`), the + Runs in batch mode. *zebra* parses configuration file and terminates + immediately. + +-.. option:: -k, --keep_kernel ++.. option:: -K TIME, --graceful_restart TIME + +- When zebra starts up, don't delete old self inserted routes. ++ If this option is specified, the graceful restart time is TIME seconds. ++ Zebra, when started, will read in routes. Those routes that Zebra ++ identifies that it was the originator of will be swept in TIME seconds. ++ If no time is specified then we will sweep those routes immediately. + + .. option:: -r, --retain + +diff --git a/zebra/main.c b/zebra/main.c +index 184e798bd..3d1d156ad 100644 +--- a/zebra/main.c ++++ b/zebra/main.c +@@ -74,8 +74,7 @@ int retain_mode = 0; + /* Allow non-quagga entities to delete quagga routes */ + int allow_delete = 0; + +-/* Don't delete kernel route. */ +-int keep_kernel_mode = 0; ++int graceful_restart; + + bool v6_rr_semantics = false; + +@@ -89,12 +88,12 @@ uint32_t nl_rcvbufsize = 4194304; + struct option longopts[] = { + {"batch", no_argument, NULL, 'b'}, + {"allow_delete", no_argument, NULL, 'a'}, +- {"keep_kernel", no_argument, NULL, 'k'}, + {"socket", required_argument, NULL, 'z'}, + {"ecmp", required_argument, NULL, 'e'}, + {"label_socket", no_argument, NULL, 'l'}, + {"retain", no_argument, NULL, 'r'}, + {"vrfdefaultname", required_argument, NULL, 'o'}, ++ {"graceful_restart", required_argument, NULL, 'K'}, + #ifdef HAVE_NETLINK + {"vrfwnetns", no_argument, NULL, 'n'}, + {"nl-bufsize", required_argument, NULL, 's'}, +@@ -264,13 +263,14 @@ int main(int argc, char **argv) + char *netlink_fuzzing = NULL; + #endif /* HANDLE_NETLINK_FUZZING */ + ++ graceful_restart = 0; + vrf_configure_backend(VRF_BACKEND_VRF_LITE); + logicalrouter_configure_backend(LOGICALROUTER_BACKEND_NETNS); + + frr_preinit(&zebra_di, argc, argv); + + frr_opt_add( +- "bakz:e:l:o:r" ++ "baz:e:l:o:rK:" + #ifdef HAVE_NETLINK + "s:n" + #endif +@@ -282,24 +282,24 @@ int main(int argc, char **argv) + #endif /* HANDLE_NETLINK_FUZZING */ + , + longopts, +- " -b, --batch Runs in batch mode\n" +- " -a, --allow_delete Allow other processes to delete zebra routes\n" +- " -z, --socket Set path of zebra socket\n" +- " -e, --ecmp Specify ECMP to use.\n" +- " -l, --label_socket Socket to external label manager\n" +- " -k, --keep_kernel Don't delete old routes which were installed by zebra.\n" +- " -r, --retain When program terminates, retain added route by zebra.\n" +- " -o, --vrfdefaultname Set default VRF name.\n" ++ " -b, --batch Runs in batch mode\n" ++ " -a, --allow_delete Allow other processes to delete zebra routes\n" ++ " -z, --socket Set path of zebra socket\n" ++ " -e, --ecmp Specify ECMP to use.\n" ++ " -l, --label_socket Socket to external label manager\n" ++ " -r, --retain When program terminates, retain added route by zebra.\n" ++ " -o, --vrfdefaultname Set default VRF name.\n" ++ " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" + #ifdef HAVE_NETLINK +- " -n, --vrfwnetns Use NetNS as VRF backend\n" +- " -s, --nl-bufsize Set netlink receive buffer size\n" +- " --v6-rr-semantics Use v6 RR semantics\n" ++ " -n, --vrfwnetns Use NetNS as VRF backend\n" ++ " -s, --nl-bufsize Set netlink receive buffer size\n" ++ " --v6-rr-semantics Use v6 RR semantics\n" + #endif /* HAVE_NETLINK */ + #if defined(HANDLE_ZAPI_FUZZING) +- " -c Bypass normal startup and use this file for testing of zapi\n" ++ " -c Bypass normal startup and use this file for testing of zapi\n" + #endif /* HANDLE_ZAPI_FUZZING */ + #if defined(HANDLE_NETLINK_FUZZING) +- " -w Bypass normal startup and use this file for testing of netlink input\n" ++ " -w Bypass normal startup and use this file for testing of netlink input\n" + #endif /* HANDLE_NETLINK_FUZZING */ + ); + +@@ -318,9 +318,6 @@ int main(int argc, char **argv) + case 'a': + allow_delete = 1; + break; +- case 'k': +- keep_kernel_mode = 1; +- break; + case 'e': + multipath_num = atoi(optarg); + if (multipath_num > MULTIPATH_NUM +@@ -350,6 +347,9 @@ int main(int argc, char **argv) + case 'r': + retain_mode = 1; + break; ++ case 'K': ++ graceful_restart = atoi(optarg); ++ break; + #ifdef HAVE_NETLINK + case 's': + nl_rcvbufsize = atoi(optarg); +@@ -437,9 +437,9 @@ int main(int argc, char **argv) + * will be equal to the current getpid(). To know about such routes, + * we have to have route_read() called before. + */ +- if (!keep_kernel_mode) +- rib_sweep_route(); +- ++ zrouter.startup_time = monotime(NULL); ++ thread_add_timer(zrouter.master, rib_sweep_route, ++ NULL, graceful_restart, NULL); + /* Needed for BSD routing socket. */ + pid = getpid(); + +diff --git a/zebra/rib.h b/zebra/rib.h +index 9fe42aef3..69850f3a0 100644 +--- a/zebra/rib.h ++++ b/zebra/rib.h +@@ -351,7 +351,7 @@ extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, + extern void rib_update(vrf_id_t vrf_id, rib_update_event_t event); + extern void rib_update_table(struct route_table *table, + rib_update_event_t event); +-extern void rib_sweep_route(void); ++extern int rib_sweep_route(struct thread *t); + extern void rib_sweep_table(struct route_table *table); + extern void rib_close_table(struct route_table *table); + extern void rib_init(void); +diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c +index 555127b09..b6afcdc8c 100644 +--- a/zebra/zebra_rib.c ++++ b/zebra/zebra_rib.c +@@ -3145,6 +3145,7 @@ void rib_sweep_table(struct route_table *table) + + for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) { + RNODE_FOREACH_RE_SAFE (rn, re, next) { ++ + if (IS_ZEBRA_DEBUG_RIB) + route_entry_dump(&rn->p, NULL, re); + +@@ -3154,6 +3155,14 @@ void rib_sweep_table(struct route_table *table) + if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELFROUTE)) + continue; + ++ /* ++ * If routes are older than startup_time then ++ * we know we read them in from the kernel. ++ * As such we can safely remove them. ++ */ ++ if (zrouter.startup_time < re->uptime) ++ continue; ++ + /* + * So we are starting up and have received + * routes from the kernel that we have installed +@@ -3183,7 +3192,7 @@ void rib_sweep_table(struct route_table *table) + } + + /* Sweep all RIB tables. */ +-void rib_sweep_route(void) ++int rib_sweep_route(struct thread *t) + { + struct vrf *vrf; + struct zebra_vrf *zvrf; +@@ -3197,6 +3206,8 @@ void rib_sweep_route(void) + } + + zebra_router_sweep_route(); ++ ++ return 0; + } + + /* Remove specific by protocol routes from 'table'. */ +diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h +index b316b91d0..b2e92bad0 100644 +--- a/zebra/zebra_router.h ++++ b/zebra/zebra_router.h +@@ -110,8 +110,15 @@ struct zebra_router { + * The EVPN instance, if any + */ + struct zebra_vrf *evpn_vrf; ++ ++ /* ++ * Time for when we sweep the rib from old routes ++ */ ++ time_t startup_time; + }; + ++#define GRACEFUL_RESTART_TIME 60 ++ + extern struct zebra_router zrouter; + + extern void zebra_router_init(void); diff --git a/src/sonic-frr/patch/series b/src/sonic-frr/patch/series index edeb30ce1e71..da0ab7ba47c5 100644 --- a/src/sonic-frr/patch/series +++ b/src/sonic-frr/patch/series @@ -4,3 +4,4 @@ 0005-Support-VRF.patch 0006-changes-for-making-snmp-socket-non-blocking.patch 0007-prevent-dead-fd-poll-data-port-fix-from-frr.patch +0008-zebra-kernel-level-graceful-restart.patch \ No newline at end of file From d1c4deb8113eeefb3dd8007c95f42412a18e4714 Mon Sep 17 00:00:00 2001 From: Wenda Ni Date: Thu, 17 Oct 2019 09:47:46 -0700 Subject: [PATCH 084/278] [minigraph]; Parse backend switches to vlan sub port interface (#3413) * Parse backend switches to vlan sub port interface Signed-off-by: Wenda Ni --- src/sonic-config-engine/minigraph.py | 31 ++++++++++ src/sonic-config-engine/tests/test_cfggen.py | 63 +++++++++++++++++++- 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index f64cbefafbd5..3ee60706d7e2 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -30,6 +30,10 @@ spine_chassis_frontend_role = 'SpineChassisFrontendRouter' chassis_backend_role = 'ChassisBackendRouter' +backend_device_types = ['BackEndToRRouter', 'BackEndLeafRouter'] +VLAN_SUB_INTERFACE_SEPARATOR = '.' +VLAN_SUB_INTERFACE_VLAN_ID = '10' + # Default Virtual Network Index (VNI) vni_default = 8000 @@ -612,6 +616,7 @@ def parse_xml(filename, platform=None, port_config_file=None): vlan_intfs = {} pc_intfs = {} vlan_invert_mapping = { v['alias']:k for k,v in vlans.items() if v.has_key('alias') } + vlan_sub_intfs = {} for intf in intfs: if intf[0][0:4] == 'Vlan': @@ -713,6 +718,32 @@ def parse_xml(filename, platform=None, port_config_file=None): results['PORTCHANNEL_INTERFACE'] = pc_intfs + if current_device['type'] in backend_device_types: + del results['INTERFACE'] + del results['PORTCHANNEL_INTERFACE'] + + for intf in phyport_intfs.keys(): + if isinstance(intf, tuple): + intf_info = list(intf) + intf_info[0] = intf_info[0] + VLAN_SUB_INTERFACE_SEPARATOR + VLAN_SUB_INTERFACE_VLAN_ID + sub_intf = tuple(intf_info) + vlan_sub_intfs[sub_intf] = {} + else: + sub_intf = intf + VLAN_SUB_INTERFACE_SEPARATOR + VLAN_SUB_INTERFACE_VLAN_ID + vlan_sub_intfs[sub_intf] = {"admin_status" : "up"} + + for pc_intf in pc_intfs.keys(): + if isinstance(pc_intf, tuple): + pc_intf_info = list(pc_intf) + pc_intf_info[0] = pc_intf_info[0] + VLAN_SUB_INTERFACE_SEPARATOR + VLAN_SUB_INTERFACE_VLAN_ID + sub_intf = tuple(pc_intf_info) + vlan_sub_intfs[sub_intf] = {} + else: + sub_intf = pc_intf + VLAN_SUB_INTERFACE_SEPARATOR + VLAN_SUB_INTERFACE_VLAN_ID + vlan_sub_intfs[sub_intf] = {"admin_status" : "up"} + + results['VLAN_SUB_INTERFACE'] = vlan_sub_intfs + results['VLAN'] = vlans results['VLAN_MEMBER'] = vlan_members diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index fb85c54cfc90..00c5bfa65ea0 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -2,6 +2,9 @@ import subprocess import os +TOR_ROUTER = 'ToRRouter' +BACKEND_TOR_ROUTER = 'BackEndToRRouter' + class TestCfgGen(TestCase): def setUp(self): @@ -55,10 +58,12 @@ def test_print_data(self): output = self.run_script(argument) self.assertTrue(len(output.strip()) > 0) - def test_jinja_expression(self): - argument = '-m "' + self.sample_graph + '" -v "DEVICE_METADATA[\'localhost\'][\'type\']"' + def test_jinja_expression(self, graph=None, expected_router_type='LeafRouter'): + if graph is None: + graph = self.sample_graph + argument = '-m "' + graph + '" -v "DEVICE_METADATA[\'localhost\'][\'type\']"' output = self.run_script(argument) - self.assertEqual(output.strip(), 'LeafRouter') + self.assertEqual(output.strip(), expected_router_type) def test_additional_json_data(self): argument = '-a \'{"key1":"value1"}\' -v key1' @@ -266,3 +271,55 @@ def test_minigraph_bgp_mon(self): output = self.run_script(argument) self.assertEqual(output.strip(), "{'10.20.30.40': {'rrclient': 0, 'name': 'BGPMonitor', 'local_addr': '10.1.0.32', 'nhopself': 0, 'holdtime': '10', 'asn': '0', 'keepalive': '3'}}") + def test_minigraph_sub_port_interfaces(self, check_stderr=True): + try: + print '\n Change device type to %s' % (BACKEND_TOR_ROUTER) + if check_stderr: + output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (TOR_ROUTER, BACKEND_TOR_ROUTER, self.sample_graph_simple), stderr=subprocess.STDOUT, shell=True) + else: + output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (TOR_ROUTER, BACKEND_TOR_ROUTER, self.sample_graph_simple), shell=True) + + self.test_jinja_expression(self.sample_graph_simple, BACKEND_TOR_ROUTER) + + + # INTERFACE table does not exist + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "INTERFACE"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "") + + # PORTCHANNEL_INTERFACE table does not exist + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "PORTCHANNEL_INTERFACE"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "") + + # All the other tables stay unchanged + self.test_var_json_data() + self.test_minigraph_vlans() + self.test_minigraph_vlan_members() + self.test_minigraph_vlan_interfaces() + self.test_minigraph_portchannels() + self.test_minigraph_ethernet_interfaces() + self.test_minigraph_extra_ethernet_interfaces() + self.test_minigraph_vnet() + self.test_minigraph_vxlan() + + # VLAN_SUB_INTERFACE + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v VLAN_SUB_INTERFACE' + output = self.run_script(argument) + print output.strip() + self.assertEqual(output.strip(), \ + "{('PortChannel01.10', '10.0.0.56/31'): {}, " + "'Ethernet0.10': {'admin_status': 'up'}, " + "('Ethernet0.10', '10.0.0.58/31'): {}, " + "('PortChannel01.10', 'FC00::71/126'): {}, " + "'PortChannel01.10': {'admin_status': 'up'}, " + "('Ethernet0.10', 'FC00::75/126'): {}}") + + finally: + print '\n Change device type back to %s' % (TOR_ROUTER) + if check_stderr: + output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (BACKEND_TOR_ROUTER, TOR_ROUTER, self.sample_graph_simple), stderr=subprocess.STDOUT, shell=True) + else: + output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (BACKEND_TOR_ROUTER, TOR_ROUTER, self.sample_graph_simple), shell=True) + + self.test_jinja_expression(self.sample_graph_simple, TOR_ROUTER) From 41ac24d65832a2cc3053d66c72165a814da720a5 Mon Sep 17 00:00:00 2001 From: Nazarii Hnydyn Date: Fri, 18 Oct 2019 02:10:00 +0300 Subject: [PATCH 085/278] [submodule] Advance SONiC kernel. (#3625) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. IPv6 host and subnet anycast route in VRF to be configured with nhop (#… 5786674 2. Unregister_netdev VRF obsreved and kernel hangs during vrf delete (#109) 5dbf6d5 3. [mellanox] Extend size of QSFP EEPROM for the cable type SSF8436 and … feb42b0 Signed-off-by: Nazarii Hnydyn --- src/sonic-linux-kernel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-linux-kernel b/src/sonic-linux-kernel index 6d55e9a84c6d..feb42b05eb91 160000 --- a/src/sonic-linux-kernel +++ b/src/sonic-linux-kernel @@ -1 +1 @@ -Subproject commit 6d55e9a84c6d0693fa5532bea2d2ddfa5c501eb6 +Subproject commit feb42b05eb912ea64f0b4ce17f4bc890929eb57e From c1848153c30a25f6df257337ec9e335e8f8426d3 Mon Sep 17 00:00:00 2001 From: Danny Allen <52468448+daall@users.noreply.github.com> Date: Thu, 17 Oct 2019 16:29:07 -0700 Subject: [PATCH 086/278] [minigraph.py] Update minigraph parsing logic to include only active ports for mirror tables (#3592) * Update minigraph.py to filter out front-panel ports that are not active * Update cfggen tests to reflect new behavior Signed-off-by: Danny Allen * Incorporate PR comments - Update t0 tests to include additional device neighbors - Refactor xml parsing logic --- src/sonic-config-engine/minigraph.py | 53 ++++++++++++++++--- .../tests/t0-sample-graph.xml | 7 +++ src/sonic-config-engine/tests/test_cfggen.py | 11 +++- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 3ee60706d7e2..37d68bdbfb0c 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -37,6 +37,12 @@ # Default Virtual Network Index (VNI) vni_default = 8000 +############################################################################### +# +# Minigraph parsing functions +# +############################################################################### + class minigraph_encoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, ( @@ -278,15 +284,17 @@ def parse_dpg(dpg, hname): if member.lower().startswith('erspanv6'): is_mirror_v6 = True else: - is_mirror = True; - # Erspan session will be attached to all front panel ports, - # if panel ports is a member port of LAG, should add the LAG - # to acl table instead of the panel ports + is_mirror = True + # Erspan session will be attached to all front panel ports + # initially. If panel ports is a member port of LAG, then + # the LAG will be added to acl table instead of the panel + # ports. Non-active ports will be removed from this list + # later after the rest of the minigraph has been parsed. acl_intfs = pc_intfs[:] for panel_port in port_alias_map.values(): if panel_port not in intfs_inpc: acl_intfs.append(panel_port) - break; + break if acl_intfs: acls[aclname] = {'policy_desc': aclname, 'ports': acl_intfs} @@ -514,6 +522,39 @@ def parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, pc_m # Enslave the port channel interface to a Vnet pc_intfs[pc_intf] = {'vnet_name': chassis_vnet} +############################################################################### +# +# Post-processing functions +# +############################################################################### + +def filter_acl_mirror_table_bindings(acls, neighbors, port_channels): + """ + Filters out inactive front-panel ports from the binding list for mirror + ACL tables. We define an "active" port as one that is a member of a + port channel or one that is connected to a neighboring device. + """ + + for acl_table, group_params in acls.iteritems(): + group_type = group_params.get('type', None) + + if group_type != 'MIRROR' and group_type != 'MIRRORV6': + continue + + active_ports = [ port for port in group_params.get('ports', []) if port in neighbors.keys() or port in port_channels ] + + if not active_ports: + print >> sys.stderr, 'Warning: mirror table {} in ACL_TABLE does not have any ports bound to it'.format(acl_table) + + acls[acl_table]['ports'] = active_ports + + return acls + +############################################################################### +# +# Main functions +# +############################################################################### def parse_xml(filename, platform=None, port_config_file=None): root = ET.parse(filename).getroot() @@ -760,7 +801,7 @@ def parse_xml(filename, platform=None, port_config_file=None): results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers) results['TACPLUS_SERVER'] = dict((item, {'priority': '1', 'tcp_port': '49'}) for item in tacacs_servers) - results['ACL_TABLE'] = acls + results['ACL_TABLE'] = filter_acl_mirror_table_bindings(acls, neighbors, pcs) # Do not configure the minigraph's mirror session, which is currently unused # mirror_sessions = {} diff --git a/src/sonic-config-engine/tests/t0-sample-graph.xml b/src/sonic-config-engine/tests/t0-sample-graph.xml index 180895928fbd..0c641107da06 100644 --- a/src/sonic-config-engine/tests/t0-sample-graph.xml +++ b/src/sonic-config-engine/tests/t0-sample-graph.xml @@ -383,6 +383,13 @@ Ethernet1/33 true + + DeviceInterfaceLink + Servers0 + eth0 + switch-t0 + fortyGigE0/4 + diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index 00c5bfa65ea0..6c9574af3514 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -95,6 +95,9 @@ def test_render_template(self): output = self.run_script(argument) self.assertEqual(output.strip(), 'value1\nvalue2') + # FIXME: This test depends heavily on the ordering of the interfaces and + # it is not at all intuitive what that ordering should be. Could make it + # more robust by adding better parsing logic. def test_minigraph_acl(self): argument = '-m "' + self.sample_graph_t0 + '" -p "' + self.port_config + '" -v ACL_TABLE' output = self.run_script(argument, True) @@ -103,11 +106,11 @@ def test_minigraph_acl(self): "Warning: ignore interface 'fortyGigE0/2' in DEVICE_NEIGHBOR as it is not in the port_config.ini\n" "{'DATAACL': {'type': 'L3', 'policy_desc': 'DATAACL', 'ports': ['PortChannel01', 'PortChannel02', 'PortChannel03', 'PortChannel04']}, " "'NTP_ACL': {'services': ['NTP'], 'type': 'CTRLPLANE', 'policy_desc': 'NTP_ACL'}, " - "'EVERFLOW': {'type': 'MIRROR', 'policy_desc': 'EVERFLOW', 'ports': ['PortChannel01', 'PortChannel02', 'PortChannel03', 'PortChannel04', 'Ethernet24', 'Ethernet40', 'Ethernet20', 'Ethernet44', 'Ethernet48', 'Ethernet28', 'Ethernet96', 'Ethernet92', 'Ethernet76', 'Ethernet72', 'Ethernet52', 'Ethernet80', 'Ethernet56', 'Ethernet32', 'Ethernet16', 'Ethernet36', 'Ethernet12', 'Ethernet60', 'Ethernet8', 'Ethernet4', 'Ethernet0', 'Ethernet64', 'Ethernet68', 'Ethernet84', 'Ethernet88', 'Ethernet108', 'Ethernet104', 'Ethernet100']}, " + "'EVERFLOW': {'type': 'MIRROR', 'policy_desc': 'EVERFLOW', 'ports': ['PortChannel01', 'PortChannel02', 'PortChannel03', 'PortChannel04', 'Ethernet4']}, " "'ROUTER_PROTECT': {'services': ['SSH', 'SNMP'], 'type': 'CTRLPLANE', 'policy_desc': 'ROUTER_PROTECT'}, " "'SNMP_ACL': {'services': ['SNMP'], 'type': 'CTRLPLANE', 'policy_desc': 'SNMP_ACL'}, " "'SSH_ACL': {'services': ['SSH'], 'type': 'CTRLPLANE', 'policy_desc': 'SSH_ACL'}, " - "'EVERFLOWV6': {'type': 'MIRRORV6', 'policy_desc': 'EVERFLOWV6', 'ports': ['PortChannel01', 'PortChannel02', 'PortChannel03', 'PortChannel04', 'Ethernet24', 'Ethernet40', 'Ethernet20', 'Ethernet44', 'Ethernet48', 'Ethernet28', 'Ethernet96', 'Ethernet92', 'Ethernet76', 'Ethernet72', 'Ethernet52', 'Ethernet80', 'Ethernet56', 'Ethernet32', 'Ethernet16', 'Ethernet36', 'Ethernet12', 'Ethernet60', 'Ethernet8', 'Ethernet4', 'Ethernet0', 'Ethernet64', 'Ethernet68', 'Ethernet84', 'Ethernet88', 'Ethernet108', 'Ethernet104', 'Ethernet100']}}") + "'EVERFLOWV6': {'type': 'MIRRORV6', 'policy_desc': 'EVERFLOWV6', 'ports': ['PortChannel01', 'PortChannel02', 'PortChannel03', 'PortChannel04', 'Ethernet4']}}") # everflow portion is not used # def test_minigraph_everflow(self): @@ -165,6 +168,9 @@ def test_minigraph_neighbors(self): output = self.run_script(argument) self.assertEqual(output.strip(), "{'name': 'ARISTA04T1', 'port': 'Ethernet1/1'}") + # FIXME: This test depends heavily on the ordering of the interfaces and + # it is not at all intuitive what that ordering should be. Could make it + # more robust by adding better parsing logic. def test_minigraph_extra_neighbors(self): argument = '-m "' + self.sample_graph_t0 + '" -p "' + self.port_config + '" -v DEVICE_NEIGHBOR' output = self.run_script(argument) @@ -172,6 +178,7 @@ def test_minigraph_extra_neighbors(self): "{'Ethernet116': {'name': 'ARISTA02T1', 'port': 'Ethernet1/1'}, " "'Ethernet124': {'name': 'ARISTA04T1', 'port': 'Ethernet1/1'}, " "'Ethernet112': {'name': 'ARISTA01T1', 'port': 'Ethernet1/1'}, " + "'Ethernet4': {'name': 'Servers0', 'port': 'eth0'}, " "'Ethernet120': {'name': 'ARISTA03T1', 'port': 'Ethernet1/1'}}") def test_minigraph_port_description(self): From 0f87d1fd6b48db0e392e9379af0e1ec6dd8657b4 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Fri, 18 Oct 2019 07:51:58 +0800 Subject: [PATCH 087/278] [Mellanox] Support SAI 1.5 (#49) --- platform/mellanox/mlnx-sai.mk | 2 +- platform/mellanox/mlnx-sai/SAI-Implementation | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/mellanox/mlnx-sai.mk b/platform/mellanox/mlnx-sai.mk index cd736ba256c4..2bf37a7600bb 100644 --- a/platform/mellanox/mlnx-sai.mk +++ b/platform/mellanox/mlnx-sai.mk @@ -1,6 +1,6 @@ # Mellanox SAI -MLNX_SAI_VERSION = SAIRel1.15.0-master +MLNX_SAI_VERSION = SAIRel1.15.1-ptf-rif-vlan-fix export MLNX_SAI_VERSION diff --git a/platform/mellanox/mlnx-sai/SAI-Implementation b/platform/mellanox/mlnx-sai/SAI-Implementation index 350187a41e40..d93eaed7ba8b 160000 --- a/platform/mellanox/mlnx-sai/SAI-Implementation +++ b/platform/mellanox/mlnx-sai/SAI-Implementation @@ -1 +1 @@ -Subproject commit 350187a41e408daaf03380401a0a2351b6cb0f9e +Subproject commit d93eaed7ba8b996fb70e000af468c485bbfbbfae From e6fc1e7bf093697273118f47741c15e98f9d12ae Mon Sep 17 00:00:00 2001 From: "arheneus@marvell.com" <51254330+antony-rheneus@users.noreply.github.com> Date: Fri, 18 Oct 2019 06:46:57 +0530 Subject: [PATCH 088/278] [Platform] Updated Marvell x86 platform makefiles (#3606) Signed-off-by: Antony Rheneus --- platform/marvell/docker-syncd-mrvl.mk | 23 +++++++------------ .../marvell/docker-syncd-mrvl/Dockerfile.j2 | 2 +- platform/marvell/rules.mk | 1 - platform/marvell/sai.mk | 5 +--- platform/marvell/sai/Makefile | 2 +- platform/marvell/sdk.mk | 8 ------- platform/marvell/sdk/Makefile | 9 -------- 7 files changed, 11 insertions(+), 39 deletions(-) delete mode 100644 platform/marvell/sdk.mk delete mode 100644 platform/marvell/sdk/Makefile diff --git a/platform/marvell/docker-syncd-mrvl.mk b/platform/marvell/docker-syncd-mrvl.mk index 85c1bf108f69..5257bf5e68e7 100644 --- a/platform/marvell/docker-syncd-mrvl.mk +++ b/platform/marvell/docker-syncd-mrvl.mk @@ -1,21 +1,14 @@ # docker image for mrvl syncd -DOCKER_SYNCD_MRVL = docker-syncd-mrvl.gz -$(DOCKER_SYNCD_MRVL)_PATH = $(PLATFORM_PATH)/docker-syncd-mrvl -$(DOCKER_SYNCD_MRVL)_DEPENDS += $(SYNCD) $(MRVL_FPA) $(REDIS_TOOLS) -ifeq ($(INSTALL_DEBUG_TOOLS), y) -$(DOCKER_SYNCD_MRVL)_DEPENDS += $(SYNCD_DBG) \ +DOCKER_SYNCD_PLATFORM_CODE = mrvl +include $(PLATFORM_PATH)/../template/docker-syncd-base.mk + +$(DOCKER_SYNCD_BASE)_DEPENDS += $(SYNCD) + +$(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $(SYNCD_DBG) \ $(LIBSWSSCOMMON_DBG) \ $(LIBSAIMETADATA_DBG) \ $(LIBSAIREDIS_DBG) -endif -$(DOCKER_SYNCD_MRVL)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE) -SONIC_DOCKER_IMAGES += $(DOCKER_SYNCD_MRVL) -ifneq ($(ENABLE_SYNCD_RPC),y) -SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_SYNCD_MRVL) -endif -$(DOCKER_SYNCD_MRVL)_CONTAINER_NAME = syncd -$(DOCKER_SYNCD_MRVL)_RUN_OPT += --net=host --privileged -t -$(DOCKER_SYNCD_MRVL)_RUN_OPT += -v /host/machine.conf:/etc/machine.conf -$(DOCKER_SYNCD_MRVL)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro +$(DOCKER_SYNCD_BASE)_RUN_OPT += -v /host/warmboot:/var/warmboot +$(DOCKER_SYNCD_BASE)_RUN_OPT += -v /var/run/docker-syncd:/var/run/sswsyncd diff --git a/platform/marvell/docker-syncd-mrvl/Dockerfile.j2 b/platform/marvell/docker-syncd-mrvl/Dockerfile.j2 index 5017b305f151..889971652c61 100755 --- a/platform/marvell/docker-syncd-mrvl/Dockerfile.j2 +++ b/platform/marvell/docker-syncd-mrvl/Dockerfile.j2 @@ -1,4 +1,4 @@ -FROM docker-config-engine +FROM docker-config-engine-stretch ARG docker_container_name RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%syslogtag%/;" /etc/rsyslog.conf diff --git a/platform/marvell/rules.mk b/platform/marvell/rules.mk index 93fe18eef86d..d819cfb67dae 100644 --- a/platform/marvell/rules.mk +++ b/platform/marvell/rules.mk @@ -1,4 +1,3 @@ -include $(PLATFORM_PATH)/sdk.mk include $(PLATFORM_PATH)/sai.mk include $(PLATFORM_PATH)/docker-syncd-mrvl.mk include $(PLATFORM_PATH)/docker-syncd-mrvl-rpc.mk diff --git a/platform/marvell/sai.mk b/platform/marvell/sai.mk index 5016b47f19a9..7953ad5dd82f 100644 --- a/platform/marvell/sai.mk +++ b/platform/marvell/sai.mk @@ -1,9 +1,6 @@ # Marvell SAI -export MRVL_SAI_VERSION = 1.2.1 -export MRVL_SAI_TAG = SONiC.201803 -export MRVL_SAI = mrvllibsai_$(MRVL_SAI_VERSION).deb +export MRVL_SAI = mrvllibsai_amd64_1.4.1.deb $(MRVL_SAI)_SRC_PATH = $(PLATFORM_PATH)/sai -$(MRVL_SAI)_DEPENDS += $(MRVL_FPA) SONIC_MAKE_DEBS += $(MRVL_SAI) diff --git a/platform/marvell/sai/Makefile b/platform/marvell/sai/Makefile index 1fad592a79ee..1cd6d0267fa2 100644 --- a/platform/marvell/sai/Makefile +++ b/platform/marvell/sai/Makefile @@ -2,7 +2,7 @@ SHELL = /bin/bash .SHELLFLAGS += -e -MRVL_SAI_URL = https://github.com/Marvell-switching/SAI-plugin/raw/$(MRVL_SAI_TAG)/sai_deb/$(MRVL_SAI) +MRVL_SAI_URL = https://github.com/Marvell-switching/sonic-marvell-binaries/raw/master/amd64/sai-plugin/$(MRVL_SAI) $(addprefix $(DEST)/, $(MRVL_SAI)): $(DEST)/% : # get deb package diff --git a/platform/marvell/sdk.mk b/platform/marvell/sdk.mk deleted file mode 100644 index 3d1ce8e04c88..000000000000 --- a/platform/marvell/sdk.mk +++ /dev/null @@ -1,8 +0,0 @@ -# Marvell FPA - -export MRVL_FPA_VERSION = 1.2.1 -export MRVL_FPA_TAG = SONiC.201803 -export MRVL_FPA = mrvllibfpa_$(MRVL_FPA_VERSION).deb - -$(MRVL_FPA)_SRC_PATH = $(PLATFORM_PATH)/sdk -SONIC_MAKE_DEBS += $(MRVL_FPA) diff --git a/platform/marvell/sdk/Makefile b/platform/marvell/sdk/Makefile deleted file mode 100644 index 6822c7d7d274..000000000000 --- a/platform/marvell/sdk/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -.ONESHELL: -SHELL = /bin/bash -.SHELLFLAGS += -e - -MRVL_FPA_URL = https://github.com/Marvell-switching/SAI-plugin/raw/$(MRVL_FPA_TAG)/sdk_deb/$(MRVL_FPA) - -$(addprefix $(DEST)/, $(MRVL_FPA)): $(DEST)/% : - # get deb package - wget -O $(DEST)/$(MRVL_FPA) $(MRVL_FPA_URL) From 60a7f4d653ed3077fc657e239309aec4dda650f3 Mon Sep 17 00:00:00 2001 From: srideepDell Date: Thu, 17 Oct 2019 18:43:59 -0700 Subject: [PATCH 089/278] [device]: Add a new supported device DellEMC s5248f (#3547) * Switch Vendor: DellEMC * Switch SKU: s5248F * ASIC Vendor: Broadcom * Swich ASIC: Trident3 * Port Configuration: 48x25G,4x100G,2x200G * SONiC Image: sonic-broadcom.bin * Changes Include ipmitool implementation for platform_sensors script is inclued in pmon startup * Added 25G,10G configruation(25G is default) 1-48FP. 4x100G,2x200G (49-54 FP) * LED support for s5248f --- .../DellEMC-S5248f-P-10G/buffers.json.j2 | 2 + .../buffers_defaults_t0.j2 | 46 + .../buffers_defaults_t1.j2 | 46 + .../DellEMC-S5248f-P-10G/custom_led.bin | Bin 0 -> 372 bytes .../DellEMC-S5248f-P-10G/linkscan_led_fw.bin | Bin 0 -> 4752 bytes .../DellEMC-S5248f-P-10G/port_config.ini | 57 + .../DellEMC-S5248f-P-10G/qos.json.j2 | 226 +++ .../DellEMC-S5248f-P-10G/sai.profile | 1 + .../DellEMC-S5248f-P-10G/sai_preinit_cmd.soc | 2 + .../td3-s5248f-10g.config.bcm | 353 ++++ .../DellEMC-S5248f-P-25G/buffers.json.j2 | 2 + .../buffers_defaults_t0.j2 | 46 + .../buffers_defaults_t1.j2 | 46 + .../DellEMC-S5248f-P-25G/custom_led.bin | Bin 0 -> 372 bytes .../DellEMC-S5248f-P-25G/linkscan_led_fw.bin | Bin 0 -> 4752 bytes .../DellEMC-S5248f-P-25G/port_config.ini | 57 + .../DellEMC-S5248f-P-25G/qos.json.j2 | 226 +++ .../DellEMC-S5248f-P-25G/sai.profile | 1 + .../DellEMC-S5248f-P-25G/sai_preinit_cmd.soc | 2 + .../td3-s5248f-25g.config.bcm | 355 ++++ .../default_sku | 1 + .../installer.conf | 3 + .../led_proc_init.soc | 6 + .../media_settings.json | 442 +++++ .../plugins/eeprom.py | 22 + .../plugins/psuutil.py | 107 ++ .../plugins/sfputil.py | 289 +++ platform/broadcom/one-image.mk | 1 + .../debian/control | 5 + .../debian/platform-modules-s5248f.init | 40 + .../debian/platform-modules-s5248f.install | 9 + .../debian/platform-modules-s5248f.postinst | 10 + .../sonic-platform-modules-dell/debian/rules | 2 +- .../s5248f/cfg/s5248f-modules.conf | 19 + .../s5248f/modules/Makefile | 2 + .../s5248f/modules/dell_s5248f_fpga_ocores.c | 1626 +++++++++++++++++ .../s5248f/scripts/check_qsfp.sh | 3 + .../s5248f/scripts/pcisysfs.py | 102 ++ .../s5248f/scripts/platform_sensors.py | 277 +++ .../s5248f/scripts/qsfp_irq_enable.py | 32 + .../s5248f/scripts/s5248f_platform.sh | 161 ++ .../s5248f/scripts/sensors | 8 + .../systemd/platform-modules-s5248f.service | 13 + src/sonic-device-data/tests/permitted_list | 7 + 44 files changed, 4654 insertions(+), 1 deletion(-) create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/buffers.json.j2 create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/buffers_defaults_t0.j2 create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/buffers_defaults_t1.j2 create mode 100755 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/custom_led.bin create mode 100755 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/linkscan_led_fw.bin create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/port_config.ini create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/qos.json.j2 create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/sai.profile create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/sai_preinit_cmd.soc create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/td3-s5248f-10g.config.bcm create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/buffers.json.j2 create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/buffers_defaults_t0.j2 create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/buffers_defaults_t1.j2 create mode 100755 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/custom_led.bin create mode 100755 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/linkscan_led_fw.bin create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/port_config.ini create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/qos.json.j2 create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/sai.profile create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/sai_preinit_cmd.soc create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/td3-s5248f-25g.config.bcm create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/default_sku create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/installer.conf create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/led_proc_init.soc create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/media_settings.json create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/eeprom.py create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/psuutil.py create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/sfputil.py create mode 100755 platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.init create mode 100644 platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.install create mode 100644 platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.postinst create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5248f/cfg/s5248f-modules.conf create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5248f/modules/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5248f/modules/dell_s5248f_fpga_ocores.c create mode 100755 platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/check_qsfp.sh create mode 100755 platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/pcisysfs.py create mode 100755 platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/platform_sensors.py create mode 100755 platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/qsfp_irq_enable.py create mode 100755 platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/s5248f_platform.sh create mode 100755 platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/sensors create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5248f/systemd/platform-modules-s5248f.service diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/buffers.json.j2 b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/buffers.json.j2 new file mode 100644 index 000000000000..0b1cb2c541b6 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/buffers.json.j2 @@ -0,0 +1,2 @@ +{%- set default_topo = 't1' %} +{%- include 'buffers_config.j2' %} diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/buffers_defaults_t0.j2 b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/buffers_defaults_t0.j2 new file mode 100644 index 000000000000..c31728e46543 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/buffers_defaults_t0.j2 @@ -0,0 +1,46 @@ + +{%- set default_cable = '40m' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "32744448", + "type": "ingress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "32744448", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "static_th":"32744448" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"0", + "dynamic_th":"3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_active) %} + "BUFFER_PG": { + "{{ port_names_active }}|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + } + }, +{%- endmacro %} + +{% macro generate_queue_buffers(port_names_active) %} + "BUFFER_QUEUE": { + "{{ port_names_active }}|0-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + } + } +{% endmacro %} + diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/buffers_defaults_t1.j2 b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/buffers_defaults_t1.j2 new file mode 100644 index 000000000000..c31728e46543 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/buffers_defaults_t1.j2 @@ -0,0 +1,46 @@ + +{%- set default_cable = '40m' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "32744448", + "type": "ingress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "32744448", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "static_th":"32744448" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"0", + "dynamic_th":"3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_active) %} + "BUFFER_PG": { + "{{ port_names_active }}|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + } + }, +{%- endmacro %} + +{% macro generate_queue_buffers(port_names_active) %} + "BUFFER_QUEUE": { + "{{ port_names_active }}|0-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + } + } +{% endmacro %} + diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/custom_led.bin b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/custom_led.bin new file mode 100755 index 0000000000000000000000000000000000000000..b3966e520c51dd288e36859523157396cb587911 GIT binary patch literal 372 zcmeycHQp`E&DYJv?ZcMl4GumGN)Fz0+!&M_R9Cq%t8H*&ROfeKoNnXU>Bjm%L7V9! zi}D;724zMQMkCdVl?-edosxVV4AU4DXF8<2*=O)Ov0ZQknx>n1GElYl=hC!kkjVADCy0h6qO*I!Jy4_LCjk!f$0IGk_eC%_KwP6 zG>S@KR6d-*oG78>l*pvilz2E%Qkgj^K-oE|DTzV(aMI!A!zru}m=xXJ80P9boxFJF zIr9daJrmq!x-D{B?e<}>j3ooZiVX}5IY8RL(8$=r(#qP#*3RC?*UvvBG%P$OHZGor zmycgWR7_k(R!%-4F)2ACGb_8Gu&9`Uk%?JBQAwGFm5p6PQ%k#|vZ}hKwyxgA)y>_( J(aD(s3IM|vYpehO literal 0 HcmV?d00001 diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/linkscan_led_fw.bin b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/linkscan_led_fw.bin new file mode 100755 index 0000000000000000000000000000000000000000..c2fa94a2d8cb11161cc337d00971e7267f08d32e GIT binary patch literal 4752 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 X`cUsHXR!vGk^Z4y?GFw9z}SBSTZoUr literal 0 HcmV?d00001 diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/port_config.ini b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/port_config.ini new file mode 100644 index 000000000000..3827e7acbe28 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/port_config.ini @@ -0,0 +1,57 @@ +# name lanes alias index speed +Ethernet0 49 tenGigE1/1/1 1 10000 +Ethernet1 50 tenGigE1/1/2 2 10000 +Ethernet2 51 tenGigE1/1/3 3 10000 +Ethernet3 52 tenGigE1/1/4 4 10000 +Ethernet4 57 tenGigE1/2/1 5 10000 +Ethernet5 58 tenGigE1/2/2 6 10000 +Ethernet6 59 tenGigE1/2/3 7 10000 +Ethernet7 60 tenGigE1/2/4 8 10000 +Ethernet8 61 tenGigE1/3/1 9 10000 +Ethernet9 62 tenGigE1/3/2 10 10000 +Ethernet10 63 tenGigE1/3/3 11 10000 +Ethernet11 64 tenGigE1/3/4 12 10000 +Ethernet12 77 tenGigE1/4/1 13 10000 +Ethernet13 78 tenGigE1/4/2 14 10000 +Ethernet14 79 tenGigE1/4/3 15 10000 +Ethernet15 80 tenGigE1/4/4 16 10000 +Ethernet16 85 tenGigE1/5/1 17 10000 +Ethernet17 86 tenGigE1/5/2 18 10000 +Ethernet18 87 tenGigE1/5/3 19 10000 +Ethernet19 88 tenGigE1/5/4 20 10000 +Ethernet20 93 tenGigE1/6/1 21 10000 +Ethernet21 94 tenGigE1/6/2 22 10000 +Ethernet22 95 tenGigE1/6/3 23 10000 +Ethernet23 96 tenGigE1/6/4 24 10000 +Ethernet24 13 tenGigE1/7/1 25 10000 +Ethernet25 14 tenGigE1/7/2 26 10000 +Ethernet26 15 tenGigE1/7/3 27 10000 +Ethernet27 16 tenGigE1/7/4 28 10000 +Ethernet28 21 tenGigE1/8/1 29 10000 +Ethernet29 22 tenGigE1/8/2 30 10000 +Ethernet30 23 tenGigE1/8/3 31 10000 +Ethernet31 24 tenGigE1/8/4 32 10000 +Ethernet32 29 tenGigE1/9/1 33 10000 +Ethernet33 30 tenGigE1/9/2 34 10000 +Ethernet34 31 tenGigE1/9/3 35 10000 +Ethernet35 32 tenGigE1/9/4 36 10000 +Ethernet36 97 tenGigE1/10/1 37 10000 +Ethernet37 98 tenGigE1/10/2 38 10000 +Ethernet38 99 tenGigE1/10/3 39 10000 +Ethernet39 100 tenGigE1/10/4 40 10000 +Ethernet40 105 tenGigE1/11/1 41 10000 +Ethernet41 106 tenGigE1/11/2 42 10000 +Ethernet42 107 tenGigE1/11/3 43 10000 +Ethernet43 108 tenGigE1/11/4 44 10000 +Ethernet44 113 tenGigE1/12/1 45 10000 +Ethernet45 114 tenGigE1/12/2 46 10000 +Ethernet46 115 tenGigE1/12/3 47 10000 +Ethernet47 116 tenGigE1/12/4 48 10000 +Ethernet48 121,122,123,124 hundredGigE1/49 49 100000 +Ethernet49 125,126,127,128 hundredGigE1/50 50 100000 +Ethernet50 69,70,71,72 hundredGigE1/51 51 100000 +Ethernet51 65,66,67,68 hundredGigE1/52 52 100000 +Ethernet52 1,2,3,4 hundredGigE1/53 53 100000 +Ethernet53 33,34,35,36 hundredGigE1/54 54 100000 +Ethernet54 5,6,7,8 hundredGigE1/55 55 100000 +Ethernet55 41,42,43,44 hundredGigE1/56 56 100000 diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/qos.json.j2 b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/qos.json.j2 new file mode 100644 index 000000000000..d2b3d2b0131c --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/qos.json.j2 @@ -0,0 +1,226 @@ +{%- set PORT_ALL = [] %} +{%- for port in PORT %} + {%- if PORT_ALL.append(port) %}{% endif %} +{%- endfor %} +{%- if PORT_ALL | sort_by_port_index %}{% endif %} + +{%- set port_names_list_all = [] %} +{%- for port in PORT_ALL %} + {%- if port_names_list_all.append(port) %}{% endif %} +{%- endfor %} +{%- set port_names_all = port_names_list_all | join(',') -%} + + +{%- set PORT_ACTIVE = [] %} +{%- if DEVICE_NEIGHBOR is not defined %} + {%- set PORT_ACTIVE = PORT_ALL %} +{%- else %} + {%- for port in DEVICE_NEIGHBOR.keys() %} + {%- if PORT_ACTIVE.append(port) %}{%- endif %} + {%- endfor %} +{%- endif %} +{%- if PORT_ACTIVE | sort_by_port_index %}{% endif %} + +{%- set port_names_list_active = [] %} +{%- for port in PORT_ACTIVE %} + {%- if port_names_list_active.append(port) %}{%- endif %} +{%- endfor %} +{%- set port_names_active = port_names_list_active | join(',') -%} + + +{%- set pfc_to_pg_map_supported_asics = ['mellanox', 'barefoot', 'marvell'] -%} + + +{ +{% if generate_tc_to_pg_map is defined %} + {{- generate_tc_to_pg_map() }} +{% else %} + "TC_TO_PRIORITY_GROUP_MAP": { + "DEFAULT": { + "0": "0", + "1": "0", + "2": "0", + "3": "0", + "4": "0", + "5": "0", + "6": "0", + "7": "7" + } + }, +{% endif %} + "MAP_PFC_PRIORITY_TO_QUEUE": { + "DEFAULT": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "TC_TO_QUEUE_MAP": { + "DEFAULT": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "DSCP_TO_TC_MAP": { + "DEFAULT": { + "0" : "0", + "1" : "0", + "2" : "0", + "3" : "0", + "4" : "0", + "5" : "0", + "6" : "0", + "7" : "0", + "8" : "0", + "9" : "0", + "10": "0", + "11": "0", + "12": "0", + "13": "0", + "14": "0", + "15": "0", + "16": "0", + "17": "0", + "18": "0", + "19": "0", + "20": "0", + "21": "0", + "22": "0", + "23": "0", + "24": "0", + "25": "0", + "26": "0", + "27": "0", + "28": "0", + "29": "0", + "30": "0", + "31": "0", + "32": "0", + "33": "0", + "34": "0", + "35": "0", + "36": "0", + "37": "0", + "38": "0", + "39": "0", + "40": "0", + "41": "0", + "42": "0", + "43": "0", + "44": "0", + "45": "0", + "46": "0", + "47": "0", + "48": "0", + "49": "0", + "50": "0", + "51": "0", + "52": "0", + "53": "0", + "54": "0", + "55": "0", + "56": "0", + "57": "0", + "58": "0", + "59": "0", + "60": "0", + "61": "0", + "62": "0", + "63": "0" + } + }, + "SCHEDULER": { + "scheduler.0": { + "type" : "DWRR", + "weight": "1" + }, + "scheduler.1": { + "type" : "DWRR", + "weight": "2" + }, + "scheduler.2": { + "type" : "DWRR", + "weight": "3" + }, + "scheduler.3": { + "type" : "DWRR", + "weight": "4" + }, + "scheduler.4": { + "type" : "DWRR", + "weight": "5" + }, + "scheduler.5": { + "type" : "DWRR", + "weight": "10" + }, + "scheduler.6": { + "type" : "DWRR", + "weight": "25" + }, + "scheduler.7": { + "type" : "DWRR", + "weight": "50" + } + }, + "PORT_QOS_MAP": { + "{{ port_names_active }}": { + "dscp_to_tc_map" : "[DSCP_TO_TC_MAP|DEFAULT]", + "tc_to_queue_map" : "[TC_TO_QUEUE_MAP|DEFAULT]", + "tc_to_pg_map" : "[TC_TO_PRIORITY_GROUP_MAP|DEFAULT]" + } + }, + "QUEUE": { +{% for port in PORT_ACTIVE %} + "{{ port }}|0": { + "scheduler" : "[SCHEDULER|scheduler.0]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|1": { + "scheduler" : "[SCHEDULER|scheduler.1]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|2": { + "scheduler": "[SCHEDULER|scheduler.2]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|3": { + "scheduler": "[SCHEDULER|scheduler.3]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|4": { + "scheduler": "[SCHEDULER|scheduler.4]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|5": { + "scheduler": "[SCHEDULER|scheduler.5]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|6": { + "scheduler": "[SCHEDULER|scheduler.6]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|7": { + "scheduler": "[SCHEDULER|scheduler.7]" + }{% if not loop.last %},{% endif %} +{% endfor %} + } +} diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/sai.profile b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/sai.profile new file mode 100644 index 000000000000..52afc687173c --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td3-s5248f-10g.config.bcm diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/sai_preinit_cmd.soc b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/sai_preinit_cmd.soc new file mode 100644 index 000000000000..4d62900f898f --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/sai_preinit_cmd.soc @@ -0,0 +1,2 @@ +m0 load 0 0x0 /usr/share/sonic/hwsku/linkscan_led_fw.bin +m0 load 0 0x3800 /usr/share/sonic/hwsku/custom_led.bin diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/td3-s5248f-10g.config.bcm b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/td3-s5248f-10g.config.bcm new file mode 100644 index 000000000000..2369f4590795 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-10G/td3-s5248f-10g.config.bcm @@ -0,0 +1,353 @@ +os=unix +dpp_clock_ratio=2:3 +oversubscribe_mode=1 +core_clock_frequency=1525 +l2xmsg_mode=1 +pbmp_oversubscribe=0x7f878787f878787f9fe1e1e1fe1e1e1fe +pbmp_xport_xe=0x7f878787f878787f9fe1e1e1fe1e1e1fe +ifp_inports_support_enable=1 +port_flex_enable=1 +phy_an_c73=3 +l2xmsg_hostbuf_size=8192 +module_64ports=0 +tdma_intr_enable=1 +ipv6_lpm_128b_enable=1 +stat_if_parity_enable=1 +bcm_tunnel_term_compatible_mode=1 +table_dma_enable=1 +schan_intr_enable=0 +parity_enable=1 +parity_correction=1 +miim_intr_enable=1 +max_vp_lags=0 +tdma_intr_enable=1 +tdma_timeout_usec=5000000 +mmu_lossless=0 +pdma_descriptor_prefetch_enable=1 +pktdma_poll_mode_channel_bitmap=1 + +l3_alpm_enable=2 +l3_alpm_ipv6_128b_bkt_rsvd=1 +l2_mem_entries=40960 +l3_mem_entries=40960 +l3_max_ecmp_mode=1 + +stable_size=0x5500000 + +portmap_1.0=1:100 +portmap_5.0=5:100 +portmap_13.0=13:10 +portmap_14.0=14:10 +portmap_15.0=15:10 +portmap_16.0=16:10 +portmap_21.0=21:10 +portmap_22.0=22:10 +portmap_23.0=23:10 +portmap_24.0=24:10 +portmap_29.0=29:10 +portmap_30.0=30:10 +portmap_31.0=31:10 +portmap_32.0=32:10 +portmap_33.0=33:100 +portmap_41.0=41:100 +portmap_49.0=49:10 +portmap_50.0=50:10 +portmap_51.0=51:10 +portmap_52.0=52:10 +portmap_57.0=57:10 +portmap_58.0=58:10 +portmap_59.0=59:10 +portmap_60.0=60:10 +portmap_61.0=61:10 +portmap_62.0=62:10 +portmap_63.0=63:10 +portmap_64.0=64:10 +portmap_67.0=65:100 +portmap_71.0=69:100 +portmap_79.0=77:10 +portmap_80.0=78:10 +portmap_81.0=79:10 +portmap_82.0=80:10 +portmap_87.0=85:10 +portmap_88.0=86:10 +portmap_89.0=87:10 +portmap_90.0=88:10 +portmap_95.0=93:10 +portmap_96.0=94:10 +portmap_97.0=95:10 +portmap_98.0=96:10 +portmap_99.0=97:10 +portmap_100.0=98:10 +portmap_101.0=99:10 +portmap_102.0=100:10 +portmap_107.0=105:10 +portmap_108.0=106:10 +portmap_109.0=107:10 +portmap_110.0=108:10 +portmap_115.0=113:10 +portmap_116.0=114:10 +portmap_117.0=115:10 +portmap_118.0=116:10 +portmap_123.0=121:100 +portmap_127.0=125:100 +phy_chain_tx_lane_map_physical{1.0}=0x0123 +phy_chain_rx_lane_map_physical{1.0}=0x1302 +phy_chain_tx_lane_map_physical{5.0}=0x1032 +phy_chain_rx_lane_map_physical{5.0}=0x1302 +phy_chain_tx_lane_map_physical{13.0}=0x0123 +phy_chain_rx_lane_map_physical{13.0}=0x1032 +phy_chain_tx_lane_map_physical{21.0}=0x0123 +phy_chain_rx_lane_map_physical{21.0}=0x1032 +phy_chain_tx_lane_map_physical{29.0}=0x0123 +phy_chain_rx_lane_map_physical{29.0}=0x1032 +phy_chain_tx_lane_map_physical{33.0}=0x1302 +phy_chain_rx_lane_map_physical{33.0}=0x1032 +phy_chain_tx_lane_map_physical{41.0}=0x3120 +phy_chain_rx_lane_map_physical{41.0}=0x1032 +phy_chain_tx_lane_map_physical{49.0}=0x0123 +phy_chain_rx_lane_map_physical{49.0}=0x1032 +phy_chain_tx_lane_map_physical{57.0}=0x0123 +phy_chain_rx_lane_map_physical{57.0}=0x1032 +phy_chain_tx_lane_map_physical{61.0}=0x0123 +phy_chain_rx_lane_map_physical{61.0}=0x1032 +phy_chain_tx_lane_map_physical{65.0}=0x0123 +phy_chain_rx_lane_map_physical{65.0}=0x2031 +phy_chain_tx_lane_map_physical{69.0}=0x3021 +phy_chain_rx_lane_map_physical{69.0}=0x2130 +phy_chain_tx_lane_map_physical{77.0}=0x3210 +phy_chain_rx_lane_map_physical{77.0}=0x2301 +phy_chain_tx_lane_map_physical{85.0}=0x3210 +phy_chain_rx_lane_map_physical{85.0}=0x2301 +phy_chain_tx_lane_map_physical{93.0}=0x3210 +phy_chain_rx_lane_map_physical{93.0}=0x2301 +phy_chain_tx_lane_map_physical{97.0}=0x3210 +phy_chain_rx_lane_map_physical{97.0}=0x2301 +phy_chain_tx_lane_map_physical{105.0}=0x3210 +phy_chain_rx_lane_map_physical{105.0}=0x2301 +phy_chain_tx_lane_map_physical{113.0}=0x3210 +phy_chain_rx_lane_map_physical{113.0}=0x2301 +phy_chain_tx_lane_map_physical{121.0}=0x0312 +phy_chain_rx_lane_map_physical{121.0}=0x1023 +phy_chain_tx_lane_map_physical{125.0}=0x2301 +phy_chain_rx_lane_map_physical{125.0}=0x3120 +phy_chain_tx_polarity_flip_physical{1.0}=0x0 +phy_chain_rx_polarity_flip_physical{1.0}=0x0 +phy_chain_tx_polarity_flip_physical{2.0}=0x0 +phy_chain_rx_polarity_flip_physical{2.0}=0x1 +phy_chain_tx_polarity_flip_physical{3.0}=0x1 +phy_chain_rx_polarity_flip_physical{3.0}=0x1 +phy_chain_tx_polarity_flip_physical{4.0}=0x0 +phy_chain_rx_polarity_flip_physical{4.0}=0x1 +phy_chain_tx_polarity_flip_physical{5.0}=0x0 +phy_chain_rx_polarity_flip_physical{5.0}=0x1 +phy_chain_tx_polarity_flip_physical{6.0}=0x1 +phy_chain_rx_polarity_flip_physical{6.0}=0x0 +phy_chain_tx_polarity_flip_physical{7.0}=0x1 +phy_chain_rx_polarity_flip_physical{7.0}=0x0 +phy_chain_tx_polarity_flip_physical{8.0}=0x1 +phy_chain_rx_polarity_flip_physical{8.0}=0x0 +phy_chain_tx_polarity_flip_physical{13.0}=0x0 +phy_chain_rx_polarity_flip_physical{13.0}=0x1 +phy_chain_tx_polarity_flip_physical{14.0}=0x1 +phy_chain_rx_polarity_flip_physical{14.0}=0x0 +phy_chain_tx_polarity_flip_physical{15.0}=0x0 +phy_chain_rx_polarity_flip_physical{15.0}=0x1 +phy_chain_tx_polarity_flip_physical{16.0}=0x1 +phy_chain_rx_polarity_flip_physical{16.0}=0x0 +phy_chain_tx_polarity_flip_physical{21.0}=0x0 +phy_chain_rx_polarity_flip_physical{21.0}=0x1 +phy_chain_tx_polarity_flip_physical{22.0}=0x1 +phy_chain_rx_polarity_flip_physical{22.0}=0x0 +phy_chain_tx_polarity_flip_physical{23.0}=0x0 +phy_chain_rx_polarity_flip_physical{23.0}=0x1 +phy_chain_tx_polarity_flip_physical{24.0}=0x1 +phy_chain_rx_polarity_flip_physical{24.0}=0x0 +phy_chain_tx_polarity_flip_physical{29.0}=0x0 +phy_chain_rx_polarity_flip_physical{29.0}=0x1 +phy_chain_tx_polarity_flip_physical{30.0}=0x1 +phy_chain_rx_polarity_flip_physical{30.0}=0x1 +phy_chain_tx_polarity_flip_physical{31.0}=0x0 +phy_chain_rx_polarity_flip_physical{31.0}=0x1 +phy_chain_tx_polarity_flip_physical{32.0}=0x1 +phy_chain_rx_polarity_flip_physical{32.0}=0x0 +phy_chain_tx_polarity_flip_physical{33.0}=0x1 +phy_chain_rx_polarity_flip_physical{33.0}=0x0 +phy_chain_tx_polarity_flip_physical{34.0}=0x1 +phy_chain_rx_polarity_flip_physical{34.0}=0x1 +phy_chain_tx_polarity_flip_physical{35.0}=0x1 +phy_chain_rx_polarity_flip_physical{35.0}=0x0 +phy_chain_tx_polarity_flip_physical{36.0}=0x0 +phy_chain_rx_polarity_flip_physical{36.0}=0x0 +phy_chain_tx_polarity_flip_physical{41.0}=0x0 +phy_chain_rx_polarity_flip_physical{41.0}=0x0 +phy_chain_tx_polarity_flip_physical{42.0}=0x1 +phy_chain_rx_polarity_flip_physical{42.0}=0x1 +phy_chain_tx_polarity_flip_physical{43.0}=0x1 +phy_chain_rx_polarity_flip_physical{43.0}=0x0 +phy_chain_tx_polarity_flip_physical{44.0}=0x0 +phy_chain_rx_polarity_flip_physical{44.0}=0x0 +phy_chain_tx_polarity_flip_physical{49.0}=0x1 +phy_chain_rx_polarity_flip_physical{49.0}=0x0 +phy_chain_tx_polarity_flip_physical{50.0}=0x0 +phy_chain_rx_polarity_flip_physical{50.0}=0x1 +phy_chain_tx_polarity_flip_physical{51.0}=0x1 +phy_chain_rx_polarity_flip_physical{51.0}=0x0 +phy_chain_tx_polarity_flip_physical{52.0}=0x0 +phy_chain_rx_polarity_flip_physical{52.0}=0x1 +phy_chain_tx_polarity_flip_physical{57.0}=0x1 +phy_chain_rx_polarity_flip_physical{57.0}=0x0 +phy_chain_tx_polarity_flip_physical{58.0}=0x0 +phy_chain_rx_polarity_flip_physical{58.0}=0x1 +phy_chain_tx_polarity_flip_physical{59.0}=0x1 +phy_chain_rx_polarity_flip_physical{59.0}=0x0 +phy_chain_tx_polarity_flip_physical{60.0}=0x0 +phy_chain_rx_polarity_flip_physical{60.0}=0x1 +phy_chain_tx_polarity_flip_physical{61.0}=0x1 +phy_chain_rx_polarity_flip_physical{61.0}=0x1 +phy_chain_tx_polarity_flip_physical{62.0}=0x0 +phy_chain_rx_polarity_flip_physical{62.0}=0x0 +phy_chain_tx_polarity_flip_physical{63.0}=0x1 +phy_chain_rx_polarity_flip_physical{63.0}=0x1 +phy_chain_tx_polarity_flip_physical{64.0}=0x0 +phy_chain_rx_polarity_flip_physical{64.0}=0x0 +phy_chain_tx_polarity_flip_physical{65.0}=0x1 +phy_chain_rx_polarity_flip_physical{65.0}=0x1 +phy_chain_tx_polarity_flip_physical{66.0}=0x1 +phy_chain_rx_polarity_flip_physical{66.0}=0x0 +phy_chain_tx_polarity_flip_physical{67.0}=0x0 +phy_chain_rx_polarity_flip_physical{67.0}=0x0 +phy_chain_tx_polarity_flip_physical{68.0}=0x1 +phy_chain_rx_polarity_flip_physical{68.0}=0x0 +phy_chain_tx_polarity_flip_physical{69.0}=0x0 +phy_chain_rx_polarity_flip_physical{69.0}=0x0 +phy_chain_tx_polarity_flip_physical{70.0}=0x0 +phy_chain_rx_polarity_flip_physical{70.0}=0x1 +phy_chain_tx_polarity_flip_physical{71.0}=0x1 +phy_chain_rx_polarity_flip_physical{71.0}=0x1 +phy_chain_tx_polarity_flip_physical{72.0}=0x1 +phy_chain_rx_polarity_flip_physical{72.0}=0x0 +phy_chain_tx_polarity_flip_physical{77.0}=0x0 +phy_chain_rx_polarity_flip_physical{77.0}=0x1 +phy_chain_tx_polarity_flip_physical{78.0}=0x1 +phy_chain_rx_polarity_flip_physical{78.0}=0x0 +phy_chain_tx_polarity_flip_physical{79.0}=0x0 +phy_chain_rx_polarity_flip_physical{79.0}=0x1 +phy_chain_tx_polarity_flip_physical{80.0}=0x1 +phy_chain_rx_polarity_flip_physical{80.0}=0x0 +phy_chain_tx_polarity_flip_physical{85.0}=0x0 +phy_chain_rx_polarity_flip_physical{85.0}=0x1 +phy_chain_tx_polarity_flip_physical{86.0}=0x1 +phy_chain_rx_polarity_flip_physical{86.0}=0x0 +phy_chain_tx_polarity_flip_physical{87.0}=0x0 +phy_chain_rx_polarity_flip_physical{87.0}=0x1 +phy_chain_tx_polarity_flip_physical{88.0}=0x1 +phy_chain_rx_polarity_flip_physical{88.0}=0x0 +phy_chain_tx_polarity_flip_physical{93.0}=0x0 +phy_chain_rx_polarity_flip_physical{93.0}=0x1 +phy_chain_tx_polarity_flip_physical{94.0}=0x1 +phy_chain_rx_polarity_flip_physical{94.0}=0x0 +phy_chain_tx_polarity_flip_physical{95.0}=0x0 +phy_chain_rx_polarity_flip_physical{95.0}=0x1 +phy_chain_tx_polarity_flip_physical{96.0}=0x1 +phy_chain_rx_polarity_flip_physical{96.0}=0x0 +phy_chain_tx_polarity_flip_physical{97.0}=0x1 +phy_chain_rx_polarity_flip_physical{97.0}=0x1 +phy_chain_tx_polarity_flip_physical{98.0}=0x0 +phy_chain_rx_polarity_flip_physical{98.0}=0x0 +phy_chain_tx_polarity_flip_physical{99.0}=0x1 +phy_chain_rx_polarity_flip_physical{99.0}=0x1 +phy_chain_tx_polarity_flip_physical{100.0}=0x0 +phy_chain_rx_polarity_flip_physical{100.0}=0x0 +phy_chain_tx_polarity_flip_physical{105.0}=0x1 +phy_chain_rx_polarity_flip_physical{105.0}=0x0 +phy_chain_tx_polarity_flip_physical{106.0}=0x0 +phy_chain_rx_polarity_flip_physical{106.0}=0x1 +phy_chain_tx_polarity_flip_physical{107.0}=0x1 +phy_chain_rx_polarity_flip_physical{107.0}=0x0 +phy_chain_tx_polarity_flip_physical{108.0}=0x0 +phy_chain_rx_polarity_flip_physical{108.0}=0x1 +phy_chain_tx_polarity_flip_physical{113.0}=0x1 +phy_chain_rx_polarity_flip_physical{113.0}=0x0 +phy_chain_tx_polarity_flip_physical{114.0}=0x0 +phy_chain_rx_polarity_flip_physical{114.0}=0x1 +phy_chain_tx_polarity_flip_physical{115.0}=0x1 +phy_chain_rx_polarity_flip_physical{115.0}=0x0 +phy_chain_tx_polarity_flip_physical{116.0}=0x0 +phy_chain_rx_polarity_flip_physical{116.0}=0x1 +phy_chain_tx_polarity_flip_physical{121.0}=0x0 +phy_chain_rx_polarity_flip_physical{121.0}=0x1 +phy_chain_tx_polarity_flip_physical{122.0}=0x1 +phy_chain_rx_polarity_flip_physical{122.0}=0x1 +phy_chain_tx_polarity_flip_physical{123.0}=0x1 +phy_chain_rx_polarity_flip_physical{123.0}=0x0 +phy_chain_tx_polarity_flip_physical{124.0}=0x0 +phy_chain_rx_polarity_flip_physical{124.0}=0x0 +phy_chain_tx_polarity_flip_physical{125.0}=0x0 +phy_chain_rx_polarity_flip_physical{125.0}=0x1 +phy_chain_tx_polarity_flip_physical{126.0}=0x1 +phy_chain_rx_polarity_flip_physical{126.0}=0x1 +phy_chain_tx_polarity_flip_physical{127.0}=0x0 +phy_chain_rx_polarity_flip_physical{127.0}=0x0 +phy_chain_tx_polarity_flip_physical{128.0}=0x1 +phy_chain_rx_polarity_flip_physical{128.0}=0x0 +dport_map_enable=1 +dport_map_port_49=1 +dport_map_port_50=2 +dport_map_port_51=3 +dport_map_port_52=4 +dport_map_port_57=5 +dport_map_port_58=6 +dport_map_port_59=7 +dport_map_port_60=8 +dport_map_port_61=9 +dport_map_port_62=10 +dport_map_port_63=11 +dport_map_port_64=12 +dport_map_port_79=13 +dport_map_port_80=14 +dport_map_port_81=15 +dport_map_port_82=16 +dport_map_port_87=17 +dport_map_port_88=18 +dport_map_port_89=19 +dport_map_port_90=20 +dport_map_port_95=21 +dport_map_port_96=22 +dport_map_port_97=23 +dport_map_port_98=24 +dport_map_port_13=25 +dport_map_port_14=26 +dport_map_port_15=27 +dport_map_port_16=28 +dport_map_port_21=29 +dport_map_port_22=30 +dport_map_port_23=31 +dport_map_port_24=32 +dport_map_port_29=33 +dport_map_port_30=34 +dport_map_port_31=35 +dport_map_port_32=36 +dport_map_port_99=37 +dport_map_port_100=38 +dport_map_port_101=39 +dport_map_port_102=40 +dport_map_port_107=41 +dport_map_port_108=42 +dport_map_port_109=43 +dport_map_port_110=44 +dport_map_port_115=45 +dport_map_port_116=46 +dport_map_port_117=47 +dport_map_port_118=48 +dport_map_port_123=49 +dport_map_port_127=50 +dport_map_port_71=51 +dport_map_port_67=52 +dport_map_port_1=53 +dport_map_port_33=54 +dport_map_port_5=55 +dport_map_port_41=56 + +mmu_init_config="TD3-DELL-lossless" +#sai_preinit_cmd_file=/usr/share/sonic/hwsku/sai_preinit_cmd.soc + diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/buffers.json.j2 b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/buffers.json.j2 new file mode 100644 index 000000000000..0b1cb2c541b6 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/buffers.json.j2 @@ -0,0 +1,2 @@ +{%- set default_topo = 't1' %} +{%- include 'buffers_config.j2' %} diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/buffers_defaults_t0.j2 b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/buffers_defaults_t0.j2 new file mode 100644 index 000000000000..c31728e46543 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/buffers_defaults_t0.j2 @@ -0,0 +1,46 @@ + +{%- set default_cable = '40m' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "32744448", + "type": "ingress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "32744448", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "static_th":"32744448" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"0", + "dynamic_th":"3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_active) %} + "BUFFER_PG": { + "{{ port_names_active }}|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + } + }, +{%- endmacro %} + +{% macro generate_queue_buffers(port_names_active) %} + "BUFFER_QUEUE": { + "{{ port_names_active }}|0-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + } + } +{% endmacro %} + diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/buffers_defaults_t1.j2 b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/buffers_defaults_t1.j2 new file mode 100644 index 000000000000..c31728e46543 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/buffers_defaults_t1.j2 @@ -0,0 +1,46 @@ + +{%- set default_cable = '40m' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "32744448", + "type": "ingress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "32744448", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "static_th":"32744448" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"0", + "dynamic_th":"3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_active) %} + "BUFFER_PG": { + "{{ port_names_active }}|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + } + }, +{%- endmacro %} + +{% macro generate_queue_buffers(port_names_active) %} + "BUFFER_QUEUE": { + "{{ port_names_active }}|0-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + } + } +{% endmacro %} + diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/custom_led.bin b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/custom_led.bin new file mode 100755 index 0000000000000000000000000000000000000000..b3966e520c51dd288e36859523157396cb587911 GIT binary patch literal 372 zcmeycHQp`E&DYJv?ZcMl4GumGN)Fz0+!&M_R9Cq%t8H*&ROfeKoNnXU>Bjm%L7V9! zi}D;724zMQMkCdVl?-edosxVV4AU4DXF8<2*=O)Ov0ZQknx>n1GElYl=hC!kkjVADCy0h6qO*I!Jy4_LCjk!f$0IGk_eC%_KwP6 zG>S@KR6d-*oG78>l*pvilz2E%Qkgj^K-oE|DTzV(aMI!A!zru}m=xXJ80P9boxFJF zIr9daJrmq!x-D{B?e<}>j3ooZiVX}5IY8RL(8$=r(#qP#*3RC?*UvvBG%P$OHZGor zmycgWR7_k(R!%-4F)2ACGb_8Gu&9`Uk%?JBQAwGFm5p6PQ%k#|vZ}hKwyxgA)y>_( J(aD(s3IM|vYpehO literal 0 HcmV?d00001 diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/linkscan_led_fw.bin b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/linkscan_led_fw.bin new file mode 100755 index 0000000000000000000000000000000000000000..c2fa94a2d8cb11161cc337d00971e7267f08d32e GIT binary patch literal 4752 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 X`cUsHXR!vGk^Z4y?GFw9z}SBSTZoUr literal 0 HcmV?d00001 diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/port_config.ini b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/port_config.ini new file mode 100644 index 000000000000..3dc16e2eb9b9 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/port_config.ini @@ -0,0 +1,57 @@ +# name lanes alias index speed +Ethernet0 49 twentyfiveGigE1/1/1 1 25000 +Ethernet1 50 twentyfiveGigE1/1/2 2 25000 +Ethernet2 51 twentyfiveGigE1/1/3 3 25000 +Ethernet3 52 twentyfiveGigE1/1/4 4 25000 +Ethernet4 57 twentyfiveGigE1/2/1 5 25000 +Ethernet5 58 twentyfiveGigE1/2/2 6 25000 +Ethernet6 59 twentyfiveGigE1/2/3 7 25000 +Ethernet7 60 twentyfiveGigE1/2/4 8 25000 +Ethernet8 61 twentyfiveGigE1/3/1 9 25000 +Ethernet9 62 twentyfiveGigE1/3/2 10 25000 +Ethernet10 63 twentyfiveGigE1/3/3 11 25000 +Ethernet11 64 twentyfiveGigE1/3/4 12 25000 +Ethernet12 77 twentyfiveGigE1/4/1 13 25000 +Ethernet13 78 twentyfiveGigE1/4/2 14 25000 +Ethernet14 79 twentyfiveGigE1/4/3 15 25000 +Ethernet15 80 twentyfiveGigE1/4/4 16 25000 +Ethernet16 85 twentyfiveGigE1/5/1 17 25000 +Ethernet17 86 twentyfiveGigE1/5/2 18 25000 +Ethernet18 87 twentyfiveGigE1/5/3 19 25000 +Ethernet19 88 twentyfiveGigE1/5/4 20 25000 +Ethernet20 93 twentyfiveGigE1/6/1 21 25000 +Ethernet21 94 twentyfiveGigE1/6/2 22 25000 +Ethernet22 95 twentyfiveGigE1/6/3 23 25000 +Ethernet23 96 twentyfiveGigE1/6/4 24 25000 +Ethernet24 13 twentyfiveGigE1/7/1 25 25000 +Ethernet25 14 twentyfiveGigE1/7/2 26 25000 +Ethernet26 15 twentyfiveGigE1/7/3 27 25000 +Ethernet27 16 twentyfiveGigE1/7/4 28 25000 +Ethernet28 21 twentyfiveGigE1/8/1 29 25000 +Ethernet29 22 twentyfiveGigE1/8/2 30 25000 +Ethernet30 23 twentyfiveGigE1/8/3 31 25000 +Ethernet31 24 twentyfiveGigE1/8/4 32 25000 +Ethernet32 29 twentyfiveGigE1/9/1 33 25000 +Ethernet33 30 twentyfiveGigE1/9/2 34 25000 +Ethernet34 31 twentyfiveGigE1/9/3 35 25000 +Ethernet35 32 twentyfiveGigE1/9/4 36 25000 +Ethernet36 97 twentyfiveGigE1/10/1 37 25000 +Ethernet37 98 twentyfiveGigE1/10/2 38 25000 +Ethernet38 99 twentyfiveGigE1/10/3 39 25000 +Ethernet39 100 twentyfiveGigE1/10/4 40 25000 +Ethernet40 105 twentyfiveGigE1/11/1 41 25000 +Ethernet41 106 twentyfiveGigE1/11/2 42 25000 +Ethernet42 107 twentyfiveGigE1/11/3 43 25000 +Ethernet43 108 twentyfiveGigE1/11/4 44 25000 +Ethernet44 113 twentyfiveGigE1/12/1 45 25000 +Ethernet45 114 twentyfiveGigE1/12/2 46 25000 +Ethernet46 115 twentyfiveGigE1/12/3 47 25000 +Ethernet47 116 twentyfiveGigE1/12/4 48 25000 +Ethernet48 121,122,123,124 hundredGigE1/49 49 100000 +Ethernet49 125,126,127,128 hundredGigE1/50 50 100000 +Ethernet50 69,70,71,72 hundredGigE1/51 51 100000 +Ethernet51 65,66,67,68 hundredGigE1/52 52 100000 +Ethernet52 1,2,3,4 hundredGigE1/53 53 100000 +Ethernet53 33,34,35,36 hundredGigE1/54 54 100000 +Ethernet54 5,6,7,8 hundredGigE1/55 55 100000 +Ethernet55 41,42,43,44 hundredGigE1/56 56 100000 diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/qos.json.j2 b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/qos.json.j2 new file mode 100644 index 000000000000..d2b3d2b0131c --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/qos.json.j2 @@ -0,0 +1,226 @@ +{%- set PORT_ALL = [] %} +{%- for port in PORT %} + {%- if PORT_ALL.append(port) %}{% endif %} +{%- endfor %} +{%- if PORT_ALL | sort_by_port_index %}{% endif %} + +{%- set port_names_list_all = [] %} +{%- for port in PORT_ALL %} + {%- if port_names_list_all.append(port) %}{% endif %} +{%- endfor %} +{%- set port_names_all = port_names_list_all | join(',') -%} + + +{%- set PORT_ACTIVE = [] %} +{%- if DEVICE_NEIGHBOR is not defined %} + {%- set PORT_ACTIVE = PORT_ALL %} +{%- else %} + {%- for port in DEVICE_NEIGHBOR.keys() %} + {%- if PORT_ACTIVE.append(port) %}{%- endif %} + {%- endfor %} +{%- endif %} +{%- if PORT_ACTIVE | sort_by_port_index %}{% endif %} + +{%- set port_names_list_active = [] %} +{%- for port in PORT_ACTIVE %} + {%- if port_names_list_active.append(port) %}{%- endif %} +{%- endfor %} +{%- set port_names_active = port_names_list_active | join(',') -%} + + +{%- set pfc_to_pg_map_supported_asics = ['mellanox', 'barefoot', 'marvell'] -%} + + +{ +{% if generate_tc_to_pg_map is defined %} + {{- generate_tc_to_pg_map() }} +{% else %} + "TC_TO_PRIORITY_GROUP_MAP": { + "DEFAULT": { + "0": "0", + "1": "0", + "2": "0", + "3": "0", + "4": "0", + "5": "0", + "6": "0", + "7": "7" + } + }, +{% endif %} + "MAP_PFC_PRIORITY_TO_QUEUE": { + "DEFAULT": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "TC_TO_QUEUE_MAP": { + "DEFAULT": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "DSCP_TO_TC_MAP": { + "DEFAULT": { + "0" : "0", + "1" : "0", + "2" : "0", + "3" : "0", + "4" : "0", + "5" : "0", + "6" : "0", + "7" : "0", + "8" : "0", + "9" : "0", + "10": "0", + "11": "0", + "12": "0", + "13": "0", + "14": "0", + "15": "0", + "16": "0", + "17": "0", + "18": "0", + "19": "0", + "20": "0", + "21": "0", + "22": "0", + "23": "0", + "24": "0", + "25": "0", + "26": "0", + "27": "0", + "28": "0", + "29": "0", + "30": "0", + "31": "0", + "32": "0", + "33": "0", + "34": "0", + "35": "0", + "36": "0", + "37": "0", + "38": "0", + "39": "0", + "40": "0", + "41": "0", + "42": "0", + "43": "0", + "44": "0", + "45": "0", + "46": "0", + "47": "0", + "48": "0", + "49": "0", + "50": "0", + "51": "0", + "52": "0", + "53": "0", + "54": "0", + "55": "0", + "56": "0", + "57": "0", + "58": "0", + "59": "0", + "60": "0", + "61": "0", + "62": "0", + "63": "0" + } + }, + "SCHEDULER": { + "scheduler.0": { + "type" : "DWRR", + "weight": "1" + }, + "scheduler.1": { + "type" : "DWRR", + "weight": "2" + }, + "scheduler.2": { + "type" : "DWRR", + "weight": "3" + }, + "scheduler.3": { + "type" : "DWRR", + "weight": "4" + }, + "scheduler.4": { + "type" : "DWRR", + "weight": "5" + }, + "scheduler.5": { + "type" : "DWRR", + "weight": "10" + }, + "scheduler.6": { + "type" : "DWRR", + "weight": "25" + }, + "scheduler.7": { + "type" : "DWRR", + "weight": "50" + } + }, + "PORT_QOS_MAP": { + "{{ port_names_active }}": { + "dscp_to_tc_map" : "[DSCP_TO_TC_MAP|DEFAULT]", + "tc_to_queue_map" : "[TC_TO_QUEUE_MAP|DEFAULT]", + "tc_to_pg_map" : "[TC_TO_PRIORITY_GROUP_MAP|DEFAULT]" + } + }, + "QUEUE": { +{% for port in PORT_ACTIVE %} + "{{ port }}|0": { + "scheduler" : "[SCHEDULER|scheduler.0]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|1": { + "scheduler" : "[SCHEDULER|scheduler.1]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|2": { + "scheduler": "[SCHEDULER|scheduler.2]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|3": { + "scheduler": "[SCHEDULER|scheduler.3]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|4": { + "scheduler": "[SCHEDULER|scheduler.4]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|5": { + "scheduler": "[SCHEDULER|scheduler.5]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|6": { + "scheduler": "[SCHEDULER|scheduler.6]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|7": { + "scheduler": "[SCHEDULER|scheduler.7]" + }{% if not loop.last %},{% endif %} +{% endfor %} + } +} diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/sai.profile b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/sai.profile new file mode 100644 index 000000000000..4753ec3886c4 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td3-s5248f-25g.config.bcm diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/sai_preinit_cmd.soc b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/sai_preinit_cmd.soc new file mode 100644 index 000000000000..4d62900f898f --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/sai_preinit_cmd.soc @@ -0,0 +1,2 @@ +m0 load 0 0x0 /usr/share/sonic/hwsku/linkscan_led_fw.bin +m0 load 0 0x3800 /usr/share/sonic/hwsku/custom_led.bin diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/td3-s5248f-25g.config.bcm b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/td3-s5248f-25g.config.bcm new file mode 100644 index 000000000000..4095c2d0a4f4 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/DellEMC-S5248f-P-25G/td3-s5248f-25g.config.bcm @@ -0,0 +1,355 @@ +os=unix + +dpp_clock_ratio=2:3 +oversubscribe_mode=1 +core_clock_frequency=1525 +l2xmsg_mode=1 +pbmp_oversubscribe=0x7f878787f878787f9fe1e1e1fe1e1e1fe +pbmp_xport_xe=0x7f878787f878787f9fe1e1e1fe1e1e1fe +ifp_inports_support_enable=1 +port_flex_enable=1 +phy_an_c73=3 +l2xmsg_hostbuf_size=8192 +module_64ports=0 +tdma_intr_enable=1 +ipv6_lpm_128b_enable=1 +stat_if_parity_enable=1 +bcm_tunnel_term_compatible_mode=1 +table_dma_enable=1 +schan_intr_enable=0 +parity_enable=1 +parity_correction=1 +miim_intr_enable=1 +max_vp_lags=0 +tdma_intr_enable=1 +tdma_timeout_usec=5000000 +mmu_lossless=0 +pdma_descriptor_prefetch_enable=1 +pktdma_poll_mode_channel_bitmap=1 + +l3_alpm_enable=2 +l3_alpm_ipv6_128b_bkt_rsvd=1 +l2_mem_entries=40960 +l3_mem_entries=40960 +l3_max_ecmp_mode=1 + + +stable_size=0x5500000 + +portmap_1.0=1:100 +portmap_5.0=5:100 +portmap_13.0=13:25 +portmap_14.0=14:25 +portmap_15.0=15:25 +portmap_16.0=16:25 +portmap_21.0=21:25 +portmap_22.0=22:25 +portmap_23.0=23:25 +portmap_24.0=24:25 +portmap_29.0=29:25 +portmap_30.0=30:25 +portmap_31.0=31:25 +portmap_32.0=32:25 +portmap_33.0=33:100 +portmap_41.0=41:100 +portmap_49.0=49:25 +portmap_50.0=50:25 +portmap_51.0=51:25 +portmap_52.0=52:25 +portmap_57.0=57:25 +portmap_58.0=58:25 +portmap_59.0=59:25 +portmap_60.0=60:25 +portmap_61.0=61:25 +portmap_62.0=62:25 +portmap_63.0=63:25 +portmap_64.0=64:25 +portmap_67.0=65:100 +portmap_71.0=69:100 +portmap_79.0=77:25 +portmap_80.0=78:25 +portmap_81.0=79:25 +portmap_82.0=80:25 +portmap_87.0=85:25 +portmap_88.0=86:25 +portmap_89.0=87:25 +portmap_90.0=88:25 +portmap_95.0=93:25 +portmap_96.0=94:25 +portmap_97.0=95:25 +portmap_98.0=96:25 +portmap_99.0=97:25 +portmap_100.0=98:25 +portmap_101.0=99:25 +portmap_102.0=100:25 +portmap_107.0=105:25 +portmap_108.0=106:25 +portmap_109.0=107:25 +portmap_110.0=108:25 +portmap_115.0=113:25 +portmap_116.0=114:25 +portmap_117.0=115:25 +portmap_118.0=116:25 +portmap_123.0=121:100 +portmap_127.0=125:100 +phy_chain_tx_lane_map_physical{1.0}=0x0123 +phy_chain_rx_lane_map_physical{1.0}=0x1302 +phy_chain_tx_lane_map_physical{5.0}=0x1032 +phy_chain_rx_lane_map_physical{5.0}=0x1302 +phy_chain_tx_lane_map_physical{13.0}=0x0123 +phy_chain_rx_lane_map_physical{13.0}=0x1032 +phy_chain_tx_lane_map_physical{21.0}=0x0123 +phy_chain_rx_lane_map_physical{21.0}=0x1032 +phy_chain_tx_lane_map_physical{29.0}=0x0123 +phy_chain_rx_lane_map_physical{29.0}=0x1032 +phy_chain_tx_lane_map_physical{33.0}=0x1302 +phy_chain_rx_lane_map_physical{33.0}=0x1032 +phy_chain_tx_lane_map_physical{41.0}=0x3120 +phy_chain_rx_lane_map_physical{41.0}=0x1032 +phy_chain_tx_lane_map_physical{49.0}=0x0123 +phy_chain_rx_lane_map_physical{49.0}=0x1032 +phy_chain_tx_lane_map_physical{57.0}=0x0123 +phy_chain_rx_lane_map_physical{57.0}=0x1032 +phy_chain_tx_lane_map_physical{61.0}=0x0123 +phy_chain_rx_lane_map_physical{61.0}=0x1032 +phy_chain_tx_lane_map_physical{65.0}=0x0123 +phy_chain_rx_lane_map_physical{65.0}=0x2031 +phy_chain_tx_lane_map_physical{69.0}=0x3021 +phy_chain_rx_lane_map_physical{69.0}=0x2130 +phy_chain_tx_lane_map_physical{77.0}=0x3210 +phy_chain_rx_lane_map_physical{77.0}=0x2301 +phy_chain_tx_lane_map_physical{85.0}=0x3210 +phy_chain_rx_lane_map_physical{85.0}=0x2301 +phy_chain_tx_lane_map_physical{93.0}=0x3210 +phy_chain_rx_lane_map_physical{93.0}=0x2301 +phy_chain_tx_lane_map_physical{97.0}=0x3210 +phy_chain_rx_lane_map_physical{97.0}=0x2301 +phy_chain_tx_lane_map_physical{105.0}=0x3210 +phy_chain_rx_lane_map_physical{105.0}=0x2301 +phy_chain_tx_lane_map_physical{113.0}=0x3210 +phy_chain_rx_lane_map_physical{113.0}=0x2301 +phy_chain_tx_lane_map_physical{121.0}=0x0312 +phy_chain_rx_lane_map_physical{121.0}=0x1023 +phy_chain_tx_lane_map_physical{125.0}=0x2301 +phy_chain_rx_lane_map_physical{125.0}=0x3120 +phy_chain_tx_polarity_flip_physical{1.0}=0x0 +phy_chain_rx_polarity_flip_physical{1.0}=0x0 +phy_chain_tx_polarity_flip_physical{2.0}=0x0 +phy_chain_rx_polarity_flip_physical{2.0}=0x1 +phy_chain_tx_polarity_flip_physical{3.0}=0x1 +phy_chain_rx_polarity_flip_physical{3.0}=0x1 +phy_chain_tx_polarity_flip_physical{4.0}=0x0 +phy_chain_rx_polarity_flip_physical{4.0}=0x1 +phy_chain_tx_polarity_flip_physical{5.0}=0x0 +phy_chain_rx_polarity_flip_physical{5.0}=0x1 +phy_chain_tx_polarity_flip_physical{6.0}=0x1 +phy_chain_rx_polarity_flip_physical{6.0}=0x0 +phy_chain_tx_polarity_flip_physical{7.0}=0x1 +phy_chain_rx_polarity_flip_physical{7.0}=0x0 +phy_chain_tx_polarity_flip_physical{8.0}=0x1 +phy_chain_rx_polarity_flip_physical{8.0}=0x0 +phy_chain_tx_polarity_flip_physical{13.0}=0x0 +phy_chain_rx_polarity_flip_physical{13.0}=0x1 +phy_chain_tx_polarity_flip_physical{14.0}=0x1 +phy_chain_rx_polarity_flip_physical{14.0}=0x0 +phy_chain_tx_polarity_flip_physical{15.0}=0x0 +phy_chain_rx_polarity_flip_physical{15.0}=0x1 +phy_chain_tx_polarity_flip_physical{16.0}=0x1 +phy_chain_rx_polarity_flip_physical{16.0}=0x0 +phy_chain_tx_polarity_flip_physical{21.0}=0x0 +phy_chain_rx_polarity_flip_physical{21.0}=0x1 +phy_chain_tx_polarity_flip_physical{22.0}=0x1 +phy_chain_rx_polarity_flip_physical{22.0}=0x0 +phy_chain_tx_polarity_flip_physical{23.0}=0x0 +phy_chain_rx_polarity_flip_physical{23.0}=0x1 +phy_chain_tx_polarity_flip_physical{24.0}=0x1 +phy_chain_rx_polarity_flip_physical{24.0}=0x0 +phy_chain_tx_polarity_flip_physical{29.0}=0x0 +phy_chain_rx_polarity_flip_physical{29.0}=0x1 +phy_chain_tx_polarity_flip_physical{30.0}=0x1 +phy_chain_rx_polarity_flip_physical{30.0}=0x1 +phy_chain_tx_polarity_flip_physical{31.0}=0x0 +phy_chain_rx_polarity_flip_physical{31.0}=0x1 +phy_chain_tx_polarity_flip_physical{32.0}=0x1 +phy_chain_rx_polarity_flip_physical{32.0}=0x0 +phy_chain_tx_polarity_flip_physical{33.0}=0x1 +phy_chain_rx_polarity_flip_physical{33.0}=0x0 +phy_chain_tx_polarity_flip_physical{34.0}=0x1 +phy_chain_rx_polarity_flip_physical{34.0}=0x1 +phy_chain_tx_polarity_flip_physical{35.0}=0x1 +phy_chain_rx_polarity_flip_physical{35.0}=0x0 +phy_chain_tx_polarity_flip_physical{36.0}=0x0 +phy_chain_rx_polarity_flip_physical{36.0}=0x0 +phy_chain_tx_polarity_flip_physical{41.0}=0x0 +phy_chain_rx_polarity_flip_physical{41.0}=0x0 +phy_chain_tx_polarity_flip_physical{42.0}=0x1 +phy_chain_rx_polarity_flip_physical{42.0}=0x1 +phy_chain_tx_polarity_flip_physical{43.0}=0x1 +phy_chain_rx_polarity_flip_physical{43.0}=0x0 +phy_chain_tx_polarity_flip_physical{44.0}=0x0 +phy_chain_rx_polarity_flip_physical{44.0}=0x0 +phy_chain_tx_polarity_flip_physical{49.0}=0x1 +phy_chain_rx_polarity_flip_physical{49.0}=0x0 +phy_chain_tx_polarity_flip_physical{50.0}=0x0 +phy_chain_rx_polarity_flip_physical{50.0}=0x1 +phy_chain_tx_polarity_flip_physical{51.0}=0x1 +phy_chain_rx_polarity_flip_physical{51.0}=0x0 +phy_chain_tx_polarity_flip_physical{52.0}=0x0 +phy_chain_rx_polarity_flip_physical{52.0}=0x1 +phy_chain_tx_polarity_flip_physical{57.0}=0x1 +phy_chain_rx_polarity_flip_physical{57.0}=0x0 +phy_chain_tx_polarity_flip_physical{58.0}=0x0 +phy_chain_rx_polarity_flip_physical{58.0}=0x1 +phy_chain_tx_polarity_flip_physical{59.0}=0x1 +phy_chain_rx_polarity_flip_physical{59.0}=0x0 +phy_chain_tx_polarity_flip_physical{60.0}=0x0 +phy_chain_rx_polarity_flip_physical{60.0}=0x1 +phy_chain_tx_polarity_flip_physical{61.0}=0x1 +phy_chain_rx_polarity_flip_physical{61.0}=0x1 +phy_chain_tx_polarity_flip_physical{62.0}=0x0 +phy_chain_rx_polarity_flip_physical{62.0}=0x0 +phy_chain_tx_polarity_flip_physical{63.0}=0x1 +phy_chain_rx_polarity_flip_physical{63.0}=0x1 +phy_chain_tx_polarity_flip_physical{64.0}=0x0 +phy_chain_rx_polarity_flip_physical{64.0}=0x0 +phy_chain_tx_polarity_flip_physical{65.0}=0x1 +phy_chain_rx_polarity_flip_physical{65.0}=0x1 +phy_chain_tx_polarity_flip_physical{66.0}=0x1 +phy_chain_rx_polarity_flip_physical{66.0}=0x0 +phy_chain_tx_polarity_flip_physical{67.0}=0x0 +phy_chain_rx_polarity_flip_physical{67.0}=0x0 +phy_chain_tx_polarity_flip_physical{68.0}=0x1 +phy_chain_rx_polarity_flip_physical{68.0}=0x0 +phy_chain_tx_polarity_flip_physical{69.0}=0x0 +phy_chain_rx_polarity_flip_physical{69.0}=0x0 +phy_chain_tx_polarity_flip_physical{70.0}=0x0 +phy_chain_rx_polarity_flip_physical{70.0}=0x1 +phy_chain_tx_polarity_flip_physical{71.0}=0x1 +phy_chain_rx_polarity_flip_physical{71.0}=0x1 +phy_chain_tx_polarity_flip_physical{72.0}=0x1 +phy_chain_rx_polarity_flip_physical{72.0}=0x0 +phy_chain_tx_polarity_flip_physical{77.0}=0x0 +phy_chain_rx_polarity_flip_physical{77.0}=0x1 +phy_chain_tx_polarity_flip_physical{78.0}=0x1 +phy_chain_rx_polarity_flip_physical{78.0}=0x0 +phy_chain_tx_polarity_flip_physical{79.0}=0x0 +phy_chain_rx_polarity_flip_physical{79.0}=0x1 +phy_chain_tx_polarity_flip_physical{80.0}=0x1 +phy_chain_rx_polarity_flip_physical{80.0}=0x0 +phy_chain_tx_polarity_flip_physical{85.0}=0x0 +phy_chain_rx_polarity_flip_physical{85.0}=0x1 +phy_chain_tx_polarity_flip_physical{86.0}=0x1 +phy_chain_rx_polarity_flip_physical{86.0}=0x0 +phy_chain_tx_polarity_flip_physical{87.0}=0x0 +phy_chain_rx_polarity_flip_physical{87.0}=0x1 +phy_chain_tx_polarity_flip_physical{88.0}=0x1 +phy_chain_rx_polarity_flip_physical{88.0}=0x0 +phy_chain_tx_polarity_flip_physical{93.0}=0x0 +phy_chain_rx_polarity_flip_physical{93.0}=0x1 +phy_chain_tx_polarity_flip_physical{94.0}=0x1 +phy_chain_rx_polarity_flip_physical{94.0}=0x0 +phy_chain_tx_polarity_flip_physical{95.0}=0x0 +phy_chain_rx_polarity_flip_physical{95.0}=0x1 +phy_chain_tx_polarity_flip_physical{96.0}=0x1 +phy_chain_rx_polarity_flip_physical{96.0}=0x0 +phy_chain_tx_polarity_flip_physical{97.0}=0x1 +phy_chain_rx_polarity_flip_physical{97.0}=0x1 +phy_chain_tx_polarity_flip_physical{98.0}=0x0 +phy_chain_rx_polarity_flip_physical{98.0}=0x0 +phy_chain_tx_polarity_flip_physical{99.0}=0x1 +phy_chain_rx_polarity_flip_physical{99.0}=0x1 +phy_chain_tx_polarity_flip_physical{100.0}=0x0 +phy_chain_rx_polarity_flip_physical{100.0}=0x0 +phy_chain_tx_polarity_flip_physical{105.0}=0x1 +phy_chain_rx_polarity_flip_physical{105.0}=0x0 +phy_chain_tx_polarity_flip_physical{106.0}=0x0 +phy_chain_rx_polarity_flip_physical{106.0}=0x1 +phy_chain_tx_polarity_flip_physical{107.0}=0x1 +phy_chain_rx_polarity_flip_physical{107.0}=0x0 +phy_chain_tx_polarity_flip_physical{108.0}=0x0 +phy_chain_rx_polarity_flip_physical{108.0}=0x1 +phy_chain_tx_polarity_flip_physical{113.0}=0x1 +phy_chain_rx_polarity_flip_physical{113.0}=0x0 +phy_chain_tx_polarity_flip_physical{114.0}=0x0 +phy_chain_rx_polarity_flip_physical{114.0}=0x1 +phy_chain_tx_polarity_flip_physical{115.0}=0x1 +phy_chain_rx_polarity_flip_physical{115.0}=0x0 +phy_chain_tx_polarity_flip_physical{116.0}=0x0 +phy_chain_rx_polarity_flip_physical{116.0}=0x1 +phy_chain_tx_polarity_flip_physical{121.0}=0x0 +phy_chain_rx_polarity_flip_physical{121.0}=0x1 +phy_chain_tx_polarity_flip_physical{122.0}=0x1 +phy_chain_rx_polarity_flip_physical{122.0}=0x1 +phy_chain_tx_polarity_flip_physical{123.0}=0x1 +phy_chain_rx_polarity_flip_physical{123.0}=0x0 +phy_chain_tx_polarity_flip_physical{124.0}=0x0 +phy_chain_rx_polarity_flip_physical{124.0}=0x0 +phy_chain_tx_polarity_flip_physical{125.0}=0x0 +phy_chain_rx_polarity_flip_physical{125.0}=0x1 +phy_chain_tx_polarity_flip_physical{126.0}=0x1 +phy_chain_rx_polarity_flip_physical{126.0}=0x1 +phy_chain_tx_polarity_flip_physical{127.0}=0x0 +phy_chain_rx_polarity_flip_physical{127.0}=0x0 +phy_chain_tx_polarity_flip_physical{128.0}=0x1 +phy_chain_rx_polarity_flip_physical{128.0}=0x0 +dport_map_enable=1 +dport_map_port_49=1 +dport_map_port_50=2 +dport_map_port_51=3 +dport_map_port_52=4 +dport_map_port_57=5 +dport_map_port_58=6 +dport_map_port_59=7 +dport_map_port_60=8 +dport_map_port_61=9 +dport_map_port_62=10 +dport_map_port_63=11 +dport_map_port_64=12 +dport_map_port_79=13 +dport_map_port_80=14 +dport_map_port_81=15 +dport_map_port_82=16 +dport_map_port_87=17 +dport_map_port_88=18 +dport_map_port_89=19 +dport_map_port_90=20 +dport_map_port_95=21 +dport_map_port_96=22 +dport_map_port_97=23 +dport_map_port_98=24 +dport_map_port_13=25 +dport_map_port_14=26 +dport_map_port_15=27 +dport_map_port_16=28 +dport_map_port_21=29 +dport_map_port_22=30 +dport_map_port_23=31 +dport_map_port_24=32 +dport_map_port_29=33 +dport_map_port_30=34 +dport_map_port_31=35 +dport_map_port_32=36 +dport_map_port_99=37 +dport_map_port_100=38 +dport_map_port_101=39 +dport_map_port_102=40 +dport_map_port_107=41 +dport_map_port_108=42 +dport_map_port_109=43 +dport_map_port_110=44 +dport_map_port_115=45 +dport_map_port_116=46 +dport_map_port_117=47 +dport_map_port_118=48 +dport_map_port_123=49 +dport_map_port_127=50 +dport_map_port_71=51 +dport_map_port_67=52 +dport_map_port_1=53 +dport_map_port_33=54 +dport_map_port_5=55 +dport_map_port_41=56 + +mmu_init_config="TD3-DELL-lossless" +#sai_preinit_cmd_file=/usr/share/sonic/hwsku/sai_preinit_cmd.soc + diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/default_sku b/device/dell/x86_64-dellemc_s5248f_c3538-r0/default_sku new file mode 100644 index 000000000000..618471d5629d --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/default_sku @@ -0,0 +1 @@ +DellEMC-S5248f-P-25G t1 \ No newline at end of file diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/installer.conf b/device/dell/x86_64-dellemc_s5248f_c3538-r0/installer.conf new file mode 100644 index 000000000000..925a32fc0c3a --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/installer.conf @@ -0,0 +1,3 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/led_proc_init.soc b/device/dell/x86_64-dellemc_s5248f_c3538-r0/led_proc_init.soc new file mode 100644 index 000000000000..69072c369a64 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/led_proc_init.soc @@ -0,0 +1,6 @@ +# LED microprocessor initialization for Dell S5232 +# +# +#Led0 +led auto on +led start diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/media_settings.json b/device/dell/x86_64-dellemc_s5248f_c3538-r0/media_settings.json new file mode 100644 index 000000000000..8bdc0e7aa984 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/media_settings.json @@ -0,0 +1,442 @@ +{ + "GLOBAL_MEDIA_SETTINGS": { + "1-32": { + "QSFP28-40GBASE-CR4-1M":{ + "preemphasis": { + "lane0":"0x16440A", + "lane1":"0x16440A", + "lane2":"0x16440A", + "lane3":"0x16440A" + } + }, + "QSFP28-40GBASE-CR4-2M":{ + "preemphasis": { + "lane0":"0x18420A", + "lane1":"0x18420A", + "lane2":"0x18420A", + "lane3":"0x18420A" + } + }, + "QSFP28-40GBASE-CR4-3M":{ + "preemphasis": { + "lane0":"0x1A400A", + "lane1":"0x1A400A", + "lane2":"0x1A400A", + "lane3":"0x1A400A" + } + }, + "QSFP28-40GBASE-CR4-4M":{ + "preemphasis": { + "lane0":"0x1A400A", + "lane1":"0x1A400A", + "lane2":"0x1A400A", + "lane3":"0x1A400A" + } + }, + "QSFP28-40GBASE-CR4-5M":{ + "preemphasis": { + "lane0":"0x1A400A", + "lane1":"0x1A400A", + "lane2":"0x1A400A", + "lane3":"0x1A400A" + } + }, + "QSFP28-40GBASE-CR4-7M":{ + "preemphasis": { + "lane0":"0x1A400A", + "lane1":"0x1A400A", + "lane2":"0x1A400A", + "lane3":"0x1A400A" + } + }, + "QSFP28-40GBASE-CR4-10M":{ + "preemphasis": { + "lane0":"0x1A400A", + "lane1":"0x1A400A", + "lane2":"0x1A400A", + "lane3":"0x1A400A" + } + }, + "QSFP+-40GBASE-CR4-1M":{ + "preemphasis": { + "lane0":"0x16440A", + "lane1":"0x16440A", + "lane2":"0x16440A", + "lane3":"0x16440A" + } + }, + "QSFP+-40GBASE-CR4-2M":{ + "preemphasis": { + "lane0":"0x18420A", + "lane1":"0x18420A", + "lane2":"0x18420A", + "lane3":"0x18420A" + } + }, + "QSFP+-40GBASE-CR4-3M":{ + "preemphasis": { + "lane0":"0x1A400A", + "lane1":"0x1A400A", + "lane2":"0x1A400A", + "lane3":"0x1A400A" + } + }, + "QSFP+-40GBASE-CR4-4M":{ + "preemphasis": { + "lane0":"0x1A400A", + "lane1":"0x1A400A", + "lane2":"0x1A400A", + "lane3":"0x1A400A" + } + }, + "QSFP+-40GBASE-CR4-5M":{ + "preemphasis": { + "lane0":"0x1A400A", + "lane1":"0x1A400A", + "lane2":"0x1A400A", + "lane3":"0x1A400A" + } + }, + "QSFP+-40GBASE-CR4-7M":{ + "preemphasis": { + "lane0":"0x1A400A", + "lane1":"0x1A400A", + "lane2":"0x1A400A", + "lane3":"0x1A400A" + } + }, + "QSFP+-40GBASE-CR4-10M":{ + "preemphasis": { + "lane0":"0x1A400A", + "lane1":"0x1A400A", + "lane2":"0x1A400A", + "lane3":"0x1A400A" + } + } + } + }, + + "PORT_MEDIA_SETTINGS": { + "1": { + "Default": { + "preemphasis": { + "lane0":"0x164509", + "lane1":"0x164509", + "lane2":"0x164509", + "lane3":"0x164509" + } + } + }, + "2": { + "Default": { + "preemphasis": { + "lane0":"0x164509", + "lane1":"0x164509", + "lane2":"0x164509", + "lane3":"0x164509" + } + } + }, + "3": { + "Default": { + "preemphasis": { + "lane0":"0x144808", + "lane1":"0x144808", + "lane2":"0x144808", + "lane3":"0x144808" + } + } + }, + "4": { + "Default": { + "preemphasis": { + "lane0":"0x144808", + "lane1":"0x144808", + "lane2":"0x144808", + "lane3":"0x144808" + } + } + }, + "5": { + "Default": { + "preemphasis": { + "lane0":"0x144808", + "lane1":"0x144808", + "lane2":"0x144808", + "lane3":"0x144808" + } + } + }, + "6": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "7": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "8": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "9": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "10": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "11": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "12": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "13": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "14": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "15": { + "Default": { + "preemphasis": { + "lane0":"0x0E4E08", + "lane1":"0x0E4E08", + "lane2":"0x0E4E08", + "lane3":"0x0E4E08" + } + } + }, + "16": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "17": { + "Default": { + "preemphasis": { + "lane0":"0x0E4E08", + "lane1":"0x0E4E08", + "lane2":"0x0E4E08", + "lane3":"0x0E4E08" + } + } + }, + "18": { + "Default": { + "preemphasis": { + "lane0":"0x0E4E08", + "lane1":"0x0E4E08", + "lane2":"0x0E4E08", + "lane3":"0x0E4E08" + } + } + }, + "19": { + "Default": { + "preemphasis": { + "lane0":"0x0E4E08", + "lane1":"0x0E4E08", + "lane2":"0x0E4E08", + "lane3":"0x0E4E08" + } + } + }, + "20": { + "Default": { + "preemphasis": { + "lane0":"0x0E4E08", + "lane1":"0x0E4E08", + "lane2":"0x0E4E08", + "lane3":"0x0E4E08" + } + } + }, + "21": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "22": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "23": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "24": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "25": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "26": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "27": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "28": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "29": { + "Default": { + "preemphasis": { + "lane0":"0x124A08", + "lane1":"0x124A08", + "lane2":"0x124A08", + "lane3":"0x124A08" + } + } + }, + "30": { + "Default": { + "preemphasis": { + "lane0":"0x144808", + "lane1":"0x144808", + "lane2":"0x144808", + "lane3":"0x144808" + } + } + }, + "31": { + "Default": { + "preemphasis": { + "lane0":"0x144808", + "lane1":"0x144808", + "lane2":"0x144808", + "lane3":"0x144808" + } + } + }, + "32": { + "Default": { + "preemphasis": { + "lane0":"0x144808", + "lane1":"0x144808", + "lane2":"0x144808", + "lane3":"0x144808" + } + } + } + } +} + diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/eeprom.py b/device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/eeprom.py new file mode 100644 index 000000000000..5b044d0ee30a --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/eeprom.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +############################################################################# +# DellEMC S5248f +# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + + +class board(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self, name, path, cpld_root, ro): + self.eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0050/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/psuutil.py b/device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/psuutil.py new file mode 100644 index 000000000000..8004697d7c0a --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/psuutil.py @@ -0,0 +1,107 @@ +# +# psuutil.py +# Platform-specific PSU status interface for SONiC +# + + +import os.path +import logging +import commands +import sys + + +S5248F_MAX_PSUS = 2 +IPMI_PSU_DATA = "docker exec -it pmon ipmitool sdr list" +IPMI_PSU_DATA_DOCKER = "ipmitool sdr list" +PSU_PRESENCE = "PSU{0}_stat" +# Use this for older firmware +# PSU_PRESENCE="PSU{0}_prsnt" +ipmi_sdr_list = "" + + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + PsuBase.__init__(self) + + def isDockerEnv(self): + num_docker = open('/proc/self/cgroup', 'r').read().count(":/docker") + if num_docker > 0: + return True + else: + return False + + # Fetch a BMC register + def get_pmc_register(self, reg_name): + + status = 1 + global ipmi_sdr_list + ipmi_dev_node = "/dev/pmi0" + ipmi_cmd = IPMI_PSU_DATA + dockerenv = self.isDockerEnv() + if dockerenv == True: + ipmi_cmd = IPMI_PSU_DATA_DOCKER + + status, ipmi_sdr_list = commands.getstatusoutput(ipmi_cmd) + + if status: + logging.error('Failed to execute:' + ipmi_sdr_list) + sys.exit(0) + + for item in ipmi_sdr_list.split("\n"): + if reg_name in item: + output = item.strip() + + if not output: + print('\nFailed to fetch: ' + reg_name + ' sensor ') + sys.exit(0) + + output = output.split('|')[1] + + logging.basicConfig(level=logging.DEBUG) + return output + + 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 + """ + S5248F_MAX_PSUS = 2 + return S5248F_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 + """ + # Until psu_status is implemented this is hardcoded temporarily + + 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 + psu_reg_name = PSU_PRESENCE.format(index) + psu_status = int(self.get_pmc_register(psu_reg_name), 16) + if (psu_status != 'ERR'): + # Check for PSU presence + if (psu_status == 0x00): + status = 1 + return status + diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/sfputil.py new file mode 100644 index 000000000000..e6680dc8d919 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/sfputil.py @@ -0,0 +1,289 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# +# For S5248F-ON, hardware version X01 + +try: + import struct + import sys + import getopt + import time + from sonic_sfp.sfputilbase import SfpUtilBase + from os import * + from mmap import * + +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 56 + PORTS_IN_BLOCK = 56 + + BASE_RES_PATH = "/sys/bus/pci/devices/0000:04:00.0/resource0" + + _port_to_i2c_mapping = { + 1: 2, + 2: 3, + 3: 4, + 4: 5, + 5: 6, + 6: 7, + 7: 8, + 8: 9, + 9: 10, + 10: 11, + 11: 12, + 12: 13, + 13: 14, + 14: 15, + 15: 16, + 16: 17, + 17: 18, + 18: 19, + 19: 20, + 20: 21, + 21: 22, + 22: 23, + 23: 24, + 24: 25, + 25: 26, + 26: 27, + 27: 28, + 28: 29, + 29: 30, + 30: 31, + 31: 32, + 32: 33, + 33: 34, + 34: 35, + 35: 36, + 36: 37, + 37: 38, + 38: 39, + 39: 40, + 40: 41, + 41: 42, + 42: 43, + 43: 44, + 44: 45, + 45: 46, + 46: 47, + 47: 48, + 48: 49, + # DD + QSFP28 + 49: 50, + 50: 50, + 51: 51, + 52: 51, + 53: 52, + 54: 53, + 55: 54, + 56: 55, + } + + _port_to_eeprom_mapping = {} + + + _global_port_pres_dict = {} + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(49, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def pci_mem_read(self, mm, offset): + mm.seek(offset) + read_data_stream=mm.read(4) + reg_val=struct.unpack('I',read_data_stream) + mem_val = str(reg_val)[1:-2] + # print "reg_val read:%x"%reg_val + return mem_val + + def pci_mem_write(self, mm, offset, data): + mm.seek(offset) + # print "data to write:%x"%data + mm.write(struct.pack('I',data)) + + def pci_set_value(self, resource, val, offset): + fd = open(resource, O_RDWR) + mm = mmap(fd, 0) + val = self.pci_mem_write(mm, offset, val) + mm.close() + close(fd) + return val + + def pci_get_value(self, resource, offset): + fd = open(resource, O_RDWR) + mm = mmap(fd, 0) + val = self.pci_mem_read(mm, offset) + mm.close() + close(fd) + return val + + def init_global_port_presence(self): + for port_num in range(self.port_start, (self.port_end + 1)): + presence = self.get_presence(port_num) + if(presence): + self._global_port_pres_dict[port_num] = '1' + else: + self._global_port_pres_dict[port_num] = '0' + + def __init__(self): + eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" + + for x in range(self.port_start, self.port_end + 1): + self.port_to_eeprom_mapping[x] = eeprom_path.format( + self._port_to_i2c_mapping[x]) + self.init_global_port_presence() + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # Port offset starts with 0x4004 + port_offset = 16388 + ((port_num-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == "" ): + return False + + # Mask off bit for presence + mask = (1 << 1) + if (port_num > 48): + mask = (1 << 4) + + + # ModPrsL is active low + if reg_value & mask == 0: + return True + + return False + + def get_low_power_mode(self, port_num): + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == "" ): + return False + + # Mask off 4th bit for presence + mask = (1 << 6) + + # LPMode is active high + if reg_value & mask == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == "" ): + return False + + # Mask off 4th bit for presence + mask = (1 << 6) + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = reg_value | mask + else: + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + return True + + def reset(self, port_num): + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == "" ): + return False + + # Mask off 4th bit for presence + mask = (1 << 6) + + # ResetL is active low + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + # Sleep 1 second to allow it to settle + time.sleep(1) + + reg_value = reg_value | mask + + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + return True + + def get_transceiver_change_event(self, timeout=0): + port_dict = {} + while True: + for port_num in range(self.port_start, (self.port_end + 1)): + presence = self.get_presence(port_num) + if(presence and self._global_port_pres_dict[port_num] == '0'): + self._global_port_pres_dict[port_num] = '1' + port_dict[port_num] = '1' + elif(not presence and + self._global_port_pres_dict[port_num] == '1'): + self._global_port_pres_dict[port_num] = '0' + port_dict[port_num] = '0' + + if(len(port_dict) > 0): + return True, port_dict + + time.sleep(0.5) diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index 3582116932b1..8cbf72695920 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -8,6 +8,7 @@ $(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(DELL_Z9264F_PLATFORM_MODULE) \ $(DELL_S5232F_PLATFORM_MODULE) \ + $(DELL_S5248F_PLATFORM_MODULE) \ $(DELL_Z9100_PLATFORM_MODULE) \ $(DELL_S6100_PLATFORM_MODULE) \ $(INGRASYS_S8900_54XC_PLATFORM_MODULE) \ diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/control b/platform/broadcom/sonic-platform-modules-dell/debian/control index d714de5ab2ad..f32fa7244acc 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/control +++ b/platform/broadcom/sonic-platform-modules-dell/debian/control @@ -29,3 +29,8 @@ Package: platform-modules-s5232f Architecture: amd64 Depends: linux-image-4.9.0-9-2-amd64 Description: kernel modules for platform devices such as fan, led, sfp + +Package: platform-modules-s5248f +Architecture: amd64 +Depends: linux-image-4.9.0-9-2-amd64 +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.init b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.init new file mode 100755 index 000000000000..0e02b00bc38a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.init @@ -0,0 +1,40 @@ +#!/bin/bash + +### BEGIN INIT INFO +# Provides: setup-board +# Required-Start: +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Setup S5248f board. +### END INIT INFO + +case "$1" in +start) + echo -n "Setting up board... " + + # /usr/local/bin/iom_power_on.sh + /usr/local/bin/s5248f_platform.sh init + + echo "done." + ;; + +stop) + /usr/local/bin/s5248f_platform.sh deinit + echo "done." + + ;; + +force-reload|restart) + echo "Not supported" + ;; + +*) + echo "Usage: /etc/init.d/platform-modules-s5248f.init {start|stop}" + exit 1 + ;; +esac + +exit 0 diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.install new file mode 100644 index 000000000000..084208955317 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.install @@ -0,0 +1,9 @@ +s5248f/scripts/s5248f_platform.sh usr/local/bin +s5248f/scripts/check_qsfp.sh usr/local/bin +s5248f/scripts/platform_sensors.py usr/local/bin +s5248f/scripts/sensors usr/bin +s5248f/scripts/pcisysfs.py usr/bin +s5248f/scripts/qsfp_irq_enable.py usr/bin +s5248f/cfg/s5248f-modules.conf etc/modules-load.d +s5248f/systemd/platform-modules-s5248f.service etc/systemd/system +common/platform_reboot usr/share/sonic/device/x86_64-dellemc_s5248f_c3538-r0 diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.postinst b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.postinst new file mode 100644 index 000000000000..f13e2f703130 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.postinst @@ -0,0 +1,10 @@ +# postinst script for S5248f + +# Enable Dell-S5248f-platform-service +depmod -a +systemctl enable platform-modules-s5248f.service +systemctl start platform-modules-s5248f.service + + +#DEBHELPER# + diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/rules b/platform/broadcom/sonic-platform-modules-dell/debian/rules index 0a30bebfa301..a7f68a21f55a 100755 --- a/platform/broadcom/sonic-platform-modules-dell/debian/rules +++ b/platform/broadcom/sonic-platform-modules-dell/debian/rules @@ -5,7 +5,7 @@ export INSTALL_MOD_DIR:=extra KVERSION ?= $(shell uname -r) KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) -MODULE_DIRS:= s6000 z9100 s6100 z9264f s5232f +MODULE_DIRS:= s6000 z9100 s6100 z9264f s5232f s5248f COMMON_DIR := common %: diff --git a/platform/broadcom/sonic-platform-modules-dell/s5248f/cfg/s5248f-modules.conf b/platform/broadcom/sonic-platform-modules-dell/s5248f/cfg/s5248f-modules.conf new file mode 100644 index 000000000000..94639bd3f6e5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5248f/cfg/s5248f-modules.conf @@ -0,0 +1,19 @@ +# /etc/modules: kernel modules to load at boot time. +# +# This file contains the names of kernel modules that should be loaded +# at boot time, one per line. Lines beginning with "#" are ignored. + +i2c-i801 +i2c-isch +i2c-ismt +i2c-dev +i2c-mux +i2c-smbus + +i2c-mux-gpio +i2c-mux-pca954x + +ipmi_devintf +ipmi_si +dell_s5248f_fpga_ocores +i2c_ocores diff --git a/platform/broadcom/sonic-platform-modules-dell/s5248f/modules/Makefile b/platform/broadcom/sonic-platform-modules-dell/s5248f/modules/Makefile new file mode 100644 index 000000000000..c179aa5dc931 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5248f/modules/Makefile @@ -0,0 +1,2 @@ +obj-m := dell_s5248f_fpga_ocores.o + diff --git a/platform/broadcom/sonic-platform-modules-dell/s5248f/modules/dell_s5248f_fpga_ocores.c b/platform/broadcom/sonic-platform-modules-dell/s5248f/modules/dell_s5248f_fpga_ocores.c new file mode 100644 index 000000000000..b9a50c69b225 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5248f/modules/dell_s5248f_fpga_ocores.c @@ -0,0 +1,1626 @@ +/* +* Copyright (C) 2018 Dell Inc +* +* Licensed under the GNU General Public License Version 2 +* +* 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. +* +*/ + +/** +* @file fpga_i2ccore.c +* @brief This is a driver to interface with Linux Open Cores drivber for FPGA i2c access +* +************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include //siginfo +#include //rcu_read_lock +#include //kernel_version +#include +#include +#include +#include +#include + + +void __iomem * fpga_base_addr = NULL; +void __iomem * fpga_ctl_addr = NULL; + +#define DRIVER_NAME "fpgapci" +#define PCI_NUM_BARS 4 + +#ifdef DEBUG +# define PRINT(fmt, ...) printk(fmt, ##__VA_ARGS__) +#else +# define PRINT(fmt, ...) +#endif + +/* Maximum size of driver buffer (allocated with kalloc()). + * Needed to copy data from user to kernel space, among other + * things. */ +static const size_t BUF_SIZE = PAGE_SIZE; + +/* Device data used by this driver. */ +struct fpgapci_dev { + /* the kernel pci device data structure */ + struct pci_dev *pci_dev; + + /* upstream root node */ + struct pci_dev *upstream; + + /* kernels virtual addr. for the mapped BARs */ + void * __iomem bar[PCI_NUM_BARS]; + + /* length of each memory region. Used for error checking. */ + size_t bar_length[PCI_NUM_BARS]; + + /* Debug data */ + /* number of hw interrupts handled. */ + int num_handled_interrupts; + int num_undelivered_signals; + int pci_gen; + int pci_num_lanes; + + unsigned int irq_first; + unsigned int irq_length; + unsigned int irq_assigned; + unsigned int xcvr_intr_count; +}; + +static int use_irq = 1; +module_param(use_irq, int, 0644); +MODULE_PARM_DESC(use_irq, "Get an use_irq value from user...\n"); + +static uint32_t num_bus = 0; +module_param(num_bus, int, 0); +MODULE_PARM_DESC(num_bus, + "Number of i2c busses supported by the FPGA on this platform."); + + +/* Xilinx FPGA PCIE info: */ +/* Non-VGA unclassified device: Xilinx Corporation Device 7021*/ +/* Subsystem: Xilinx Corporation Device 0007 */ +//#define VENDOR 0x10EE +#define DEVICE 0x7021 +static phys_addr_t fpga_phys_addr; + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + + +/* struct to hold data related to the pcie device */ +struct pci_data_struct{ + struct pci_dev* dev; + unsigned long long phy_addr_bar0; + unsigned long long phy_len_bar0; + unsigned long long phy_flags_bar0; + unsigned int irq_first; + unsigned int irq_length; + unsigned int irq_assigned; + void * kvirt_addr_bar0; +}; + +/* global variable declarations */ + +/* Static function declarations */ +static int fpgapci_probe(struct pci_dev *dev, const struct pci_device_id *id); +static void fpgapci_remove(struct pci_dev *dev); + +static int scan_bars(struct fpgapci_dev *fpgapci, struct pci_dev *dev); +static int map_bars(struct fpgapci_dev *fpgapci, struct pci_dev *dev); +static void free_bars(struct fpgapci_dev *fpgapci, struct pci_dev *dev); + + +struct fpgalogic_i2c { + void __iomem *base; + u32 reg_shift; + u32 reg_io_width; + wait_queue_head_t wait; + struct i2c_msg *msg; + int pos; + int nmsgs; + int state; /* see STATE_ */ + int ip_clock_khz; + int bus_clock_khz; + void (*reg_set)(struct fpgalogic_i2c *i2c, int reg, u8 value); + u8 (*reg_get)(struct fpgalogic_i2c *i2c, int reg); + u32 timeout; + struct mutex lock; +}; +/* registers */ +#define FPGAI2C_REG_PRELOW 0 +#define FPGAI2C_REG_PREHIGH 1 +#define FPGAI2C_REG_CONTROL 2 +#define FPGAI2C_REG_DATA 3 +#define FPGAI2C_REG_CMD 4 /* write only */ +#define FPGAI2C_REG_STATUS 4 /* read only, same address as FPGAI2C_REG_CMD */ +#define FPGAI2C_REG_VER 5 + + + +#define FPGAI2C_REG_CTRL_IEN 0x40 +#define FPGAI2C_REG_CTRL_EN 0x80 + +#define FPGAI2C_REG_CMD_START 0x91 +#define FPGAI2C_REG_CMD_STOP 0x41 +#define FPGAI2C_REG_CMD_READ 0x21 +#define FPGAI2C_REG_CMD_WRITE 0x11 +#define FPGAI2C_REG_CMD_READ_ACK 0x21 +#define FPGAI2C_REG_CMD_READ_NACK 0x29 +#define FPGAI2C_REG_CMD_IACK 0x01 + +#define FPGAI2C_REG_STAT_IF 0x01 +#define FPGAI2C_REG_STAT_TIP 0x02 +#define FPGAI2C_REG_STAT_ARBLOST 0x20 +#define FPGAI2C_REG_STAT_BUSY 0x40 +#define FPGAI2C_REG_STAT_NACK 0x80 + +/* SR[7:0] - Status register */ +#define FPGAI2C_REG_SR_RXACK (1 << 7) /* Receive acknowledge from slave ‘1’ = No acknowledge received*/ +#define FPGAI2C_REG_SR_BUSY (1 << 6) /* Busy, I2C bus busy (as defined by start / stop bits) */ +#define FPGAI2C_REG_SR_AL (1 << 5) /* Arbitration lost - fpga i2c logic lost arbitration */ +#define FPGAI2C_REG_SR_TIP (1 << 1) /* Transfer in progress */ +#define FPGAI2C_REG_SR_IF (1 << 0) /* Interrupt flag */ + +enum { + STATE_DONE = 0, + STATE_INIT, + STATE_ADDR, + STATE_ADDR10, + STATE_START, + STATE_WRITE, + STATE_READ, + STATE_STOP, + STATE_ERROR, +}; + +#define TYPE_FPGALOGIC 0 +#define TYPE_GRLIB 1 + +/*I2C_CH1 Offset address from PCIE BAR 0*/ +#define FPGALOGIC_I2C_BASE 0x00006000 +#define FPGALOGIC_CH_OFFSET 0x10 + +#define i2c_bus_controller_numb 1 +#define I2C_PCI_MAX_BUS (16) +#define I2C_PCI_MAX_BUS_REV00 (7) +#define DELL_I2C_CLOCK_LEGACY 0 +#define DELL_I2C_CLOCK_PRESERVE (~0U) +#define I2C_PCI_BUS_NUM_5 5 +#define I2C_PCI_BUS_NUM_7 7 +#define I2C_PCI_BUS_NUM_8 8 +#define I2C_PCI_BUS_NUM_10 10 +#define I2C_PCI_BUS_NUM_12 12 +#define I2C_PCI_BUS_NUM_16 16 + +#define IRQ_LTCH_STS 0x20 +#define PRSNT_LTCH_STS 0x10 + +#define PORT_CTRL_OFFSET 0x4000 +#define PORT_STS_OFFSET 0x4004 +#define PORT_IRQ_STS_OFFSET 0x4008 +#define PORT_IRQ_EN_OFFSET 0x400C +#define MB_BRD_REV_TYPE 0x0008 +#define MB_BRD_REV_MASK 0x00f0 +#define MB_BRD_REV_00 0x0000 +#define MB_BRD_REV_01 0x0010 +#define MB_BRD_REV_02 0x0020 +#define MB_BRD_REV_03 0x0030 +#define MB_BRD_TYPE_MASK 0x000f +#define BRD_TYPE_Z9232_NON_NEBS 0x0 +#define BRD_TYPE_Z9232_NEBS 0x1 +#define BRD_TYPE_Z9264_NON_NEBS 0x2 +#define BRD_TYPE_Z9264_NEBS 0x3 +#define BRD_TYPE_S5212_NON_NEBS 0x4 +#define BRD_TYPE_S5212_NEBS 0x5 +#define BRD_TYPE_S5224_NON_NEBS 0x6 +#define BRD_TYPE_S5224_NEBS 0x7 +#define BRD_TYPE_S5248_NON_NEBS 0x8 +#define BRD_TYPE_S5248_NEBS 0x9 +#define BRD_TYPE_S5296_NON_NEBS 0xa +#define BRD_TYPE_S5296_NEBS 0xb +#define BRD_TYPE_S5232_NON_NEBS 0xc +#define BRD_TYPE_S5232_NEBS 0xd + +#define FPGA_CTL_REG_SIZE 0x6000 +#define MSI_VECTOR_MAP_MASK 0x1f +#define MSI_VECTOR_MAP1 0x58 +#define I2C_CH1_MSI_MAP_VECT_8 0x00000008 +#define I2C_CH2_MSI_MAP_VECT_9 0x00000120 +#define I2C_CH3_MSI_MAP_VECT_10 0x00002800 +#define I2C_CH4_MSI_MAP_VECT_11 0x00058000 +#define I2C_CH5_MSI_MAP_VECT_12 0x00c00000 +#define I2C_CH6_MSI_MAP_VECT_13 0x15000000 +#define MSI_VECTOR_MAP2 0x5c +#define I2C_CH7_MSI_MAP_VECT_14 0x0000000e +#define MSI_VECTOR_MAP3 0x9c +#define I2C_CH8_MSI_MAP_VECT_8 0x00800000 +#define I2C_CH8_MSI_MAP_VECT_16 0x01100000 +#define I2C_CH9_MSI_MAP_VECT_9 0x12000000 +#define I2C_CH9_MSI_MAP_VECT_17 0x24000000 +#define MSI_VECTOR_MAP4 0xa0 +#define I2C_CH10_MSI_MAP_VECT_10 0x0000000a +#define I2C_CH10_MSI_MAP_VECT_18 0x00000012 +#define I2C_CH11_MSI_MAP_VECT_11 0x00000120 +#define I2C_CH11_MSI_MAP_VECT_19 0x00000260 +#define I2C_CH12_MSI_MAP_VECT_12 0x00002800 +#define I2C_CH12_MSI_MAP_VECT_20 0x00005000 +#define I2C_CH13_MSI_MAP_VECT_13 0x00058000 +#define I2C_CH13_MSI_MAP_VECT_21 0x000a8000 +#define I2C_CH14_MSI_MAP_VECT_14 0x00c00000 +#define I2C_CH14_MSI_MAP_VECT_22 0x01600000 +#define I2C_CH15_MSI_MAP_VECT_8 0x10000000 +#define I2C_CH15_MSI_MAP_VECT_23 0x2e000000 +#define MSI_VECTOR_MAP5 0xa4 +#define I2C_CH16_MSI_MAP_VECT_9 0x00000009 +#define I2C_CH16_MSI_MAP_VECT_24 0x00000018 + +#define MSI_VECTOR_REV_00 16 +#define MSI_VECTOR_REV_01 32 + +#define FPGA_MSI_VECTOR_ID_4 4 +#define FPGA_MSI_VECTOR_ID_5 5 +#define FPGA_MSI_VECTOR_ID_8 8 +#define FPGA_MSI_VECTOR_ID_9 9 +#define FPGA_MSI_VECTOR_ID_10 10 +#define FPGA_MSI_VECTOR_ID_11 11 +#define FPGA_MSI_VECTOR_ID_12 12 +#define FPGA_MSI_VECTOR_ID_13 13 +#define FPGA_MSI_VECTOR_ID_14 14 +#define FPGA_MSI_VECTOR_ID_15 15 /*Note: this is external MSI vector id */ +#define FPGA_MSI_VECTOR_ID_16 16 +#define FPGA_MSI_VECTOR_ID_17 17 +#define FPGA_MSI_VECTOR_ID_18 18 +#define FPGA_MSI_VECTOR_ID_19 19 +#define FPGA_MSI_VECTOR_ID_20 20 +#define FPGA_MSI_VECTOR_ID_21 21 +#define FPGA_MSI_VECTOR_ID_22 22 +#define FPGA_MSI_VECTOR_ID_23 23 +#define FPGA_MSI_VECTOR_ID_24 24 + + + +static int total_i2c_pci_bus = 0; +static uint32_t board_rev_type = 0; +static struct fpgalogic_i2c fpgalogic_i2c[I2C_PCI_MAX_BUS]; +static struct i2c_adapter i2c_pci_adap[I2C_PCI_MAX_BUS]; +static struct mutex i2c_xfer_lock[I2C_PCI_MAX_BUS]; + +static void fpgai2c_reg_set_8(struct fpgalogic_i2c *i2c, int reg, u8 value) +{ + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void fpgai2c_reg_set_16(struct fpgalogic_i2c *i2c, int reg, u8 value) +{ + iowrite16(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void fpgai2c_reg_set_32(struct fpgalogic_i2c *i2c, int reg, u8 value) +{ + iowrite32(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void fpgai2c_reg_set_16be(struct fpgalogic_i2c *i2c, int reg, u8 value) +{ + iowrite16be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void fpgai2c_reg_set_32be(struct fpgalogic_i2c *i2c, int reg, u8 value) +{ + iowrite32be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 fpgai2c_reg_get_8(struct fpgalogic_i2c *i2c, int reg) +{ + return ioread8(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 fpgai2c_reg_get_16(struct fpgalogic_i2c *i2c, int reg) +{ + return ioread16(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 fpgai2c_reg_get_32(struct fpgalogic_i2c *i2c, int reg) +{ + return ioread32(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 fpgai2c_reg_get_16be(struct fpgalogic_i2c *i2c, int reg) +{ + return ioread16be(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 fpgai2c_reg_get_32be(struct fpgalogic_i2c *i2c, int reg) +{ + return ioread32be(i2c->base + (reg << i2c->reg_shift)); +} + +static inline void fpgai2c_reg_set(struct fpgalogic_i2c *i2c, int reg, u8 value) +{ + i2c->reg_set(i2c, reg, value); + udelay(100); +} + +static inline u8 fpgai2c_reg_get(struct fpgalogic_i2c *i2c, int reg) +{ + udelay(100); + return i2c->reg_get(i2c, reg); +} + +static void fpgai2c_dump(struct fpgalogic_i2c *i2c) +{ + u8 tmp; + + PRINT("Logic register dump:\n"); + + tmp = fpgai2c_reg_get(i2c, FPGAI2C_REG_PRELOW); + PRINT("FPGAI2C_REG_PRELOW (%d) = 0x%x\n",FPGAI2C_REG_PRELOW,tmp); + + tmp = fpgai2c_reg_get(i2c, FPGAI2C_REG_PREHIGH); + PRINT("FPGAI2C_REG_PREHIGH(%d) = 0x%x\n",FPGAI2C_REG_PREHIGH,tmp); + + tmp = fpgai2c_reg_get(i2c, FPGAI2C_REG_CONTROL); + PRINT("FPGAI2C_REG_CONTROL(%d) = 0x%x\n",FPGAI2C_REG_CONTROL,tmp); + + tmp = fpgai2c_reg_get(i2c, FPGAI2C_REG_DATA); + PRINT("FPGAI2C_REG_DATA (%d) = 0x%x\n",FPGAI2C_REG_DATA,tmp); + + tmp = fpgai2c_reg_get(i2c, FPGAI2C_REG_CMD); + PRINT("FPGAI2C_REG_CMD (%d) = 0x%x\n",FPGAI2C_REG_CMD,tmp); +} + +static void fpgai2c_stop(struct fpgalogic_i2c *i2c) +{ + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_STOP); +} + +/* + * dell_get_mutex must be called prior to calling this function. + */ +static int fpgai2c_poll(struct fpgalogic_i2c *i2c) +{ + u8 stat = fpgai2c_reg_get(i2c, FPGAI2C_REG_STATUS); + struct i2c_msg *msg = i2c->msg; + u8 addr; + + /* Ready? */ + if (stat & FPGAI2C_REG_STAT_TIP) + return -EBUSY; + + if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) { + /* Stop has been sent */ + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK); + if (i2c->state == STATE_ERROR) + return -EIO; + return 0; + } + + /* Error? */ + if (stat & FPGAI2C_REG_STAT_ARBLOST) { + i2c->state = STATE_ERROR; + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_STOP); + return -EAGAIN; + } + + if (i2c->state == STATE_INIT) { + if (stat & FPGAI2C_REG_STAT_BUSY) + return -EBUSY; + + i2c->state = STATE_ADDR; + } + + if (i2c->state == STATE_ADDR) { + /* 10 bit address? */ + if (i2c->msg->flags & I2C_M_TEN) { + addr = 0xf0 | ((i2c->msg->addr >> 7) & 0x6); + i2c->state = STATE_ADDR10; + } else { + addr = (i2c->msg->addr << 1); + i2c->state = STATE_START; + } + + /* Set read bit if necessary */ + addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0; + + fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, addr); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_START); + + return 0; + } + + /* Second part of 10 bit addressing */ + if (i2c->state == STATE_ADDR10) { + fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, i2c->msg->addr & 0xff); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_WRITE); + + i2c->state = STATE_START; + return 0; + } + + if (i2c->state == STATE_START || i2c->state == STATE_WRITE) { + i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; + + if (stat & FPGAI2C_REG_STAT_NACK) { + i2c->state = STATE_ERROR; + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_STOP); + return -ENXIO; + } + } else { + msg->buf[i2c->pos++] = fpgai2c_reg_get(i2c, FPGAI2C_REG_DATA); + } + + if (i2c->pos >= msg->len) { + i2c->nmsgs--; + i2c->msg++; + i2c->pos = 0; + msg = i2c->msg; + + if (i2c->nmsgs) { + if (!(msg->flags & I2C_M_NOSTART)) { + i2c->state = STATE_ADDR; + return 0; + } else { + i2c->state = (msg->flags & I2C_M_RD) + ? STATE_READ : STATE_WRITE; + } + } else { + i2c->state = STATE_DONE; + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_STOP); + return 0; + } + } + + if (i2c->state == STATE_READ) { + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, i2c->pos == (msg->len - 1) ? + FPGAI2C_REG_CMD_READ_NACK : FPGAI2C_REG_CMD_READ_ACK); + } else { + fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, msg->buf[i2c->pos++]); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_WRITE); + } + + return 0; +} + +static ssize_t get_mod_msi(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ind = 0, port_status=0, port_irq_status=0; + struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(dev); + PRINT("%s:xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count); + for(ind=0;ind<64;ind++) + { + port_status = ioread32(fpga_ctl_addr + PORT_STS_OFFSET + (ind*16)); + port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status); + } + return sprintf(buf,"0x%04x\n",fpgapci->xcvr_intr_count); +} +static DEVICE_ATTR(port_msi, S_IRUGO, get_mod_msi, NULL); + +static struct attribute *port_attrs[] = { + &dev_attr_port_msi.attr, + NULL, +}; + +static struct attribute_group port_attr_grp = { + .attrs = port_attrs, +}; + + +static irqreturn_t fpgaport_1_32_isr(int irq, void *dev) +{ + struct pci_dev *pdev = dev; + struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&pdev->dev); + int ind = 0, port_status=0, port_irq_status=0; + for(ind=0;ind<32;ind++) + { + port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + if(port_irq_status&(IRQ_LTCH_STS|PRSNT_LTCH_STS)) + { + PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status); + //write on clear + iowrite32( IRQ_LTCH_STS|PRSNT_LTCH_STS,fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + } + } + fpgapci->xcvr_intr_count++; + PRINT("%s: xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count); + sysfs_notify(&pdev->dev.kobj, NULL, "port_msi"); + return IRQ_HANDLED; +} + +static irqreturn_t fpgaport_33_64_isr(int irq, void *dev) +{ + struct pci_dev *pdev = dev; + struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&pdev->dev); + int ind = 0, port_status=0, port_irq_status=0; + for(ind=32;ind<64;ind++) + { + port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + if(port_irq_status| (IRQ_LTCH_STS|PRSNT_LTCH_STS)) + { + PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status); + iowrite32( IRQ_LTCH_STS|PRSNT_LTCH_STS,fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + } + } + fpgapci->xcvr_intr_count++; + PRINT("%s: xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count); + sysfs_notify(&pdev->dev.kobj, NULL, "port_msi"); + return IRQ_HANDLED; +} + +static void fpgai2c_process(struct fpgalogic_i2c *i2c) +{ + struct i2c_msg *msg = i2c->msg; + u8 stat = fpgai2c_reg_get(i2c, FPGAI2C_REG_STATUS); + + PRINT("fpgai2c_process in. status reg :0x%x\n", stat); + + if ((i2c->state == STATE_STOP) || (i2c->state == STATE_ERROR)) { + /* stop has been sent */ + PRINT("fpgai2c_process FPGAI2C_REG_CMD_IACK stat = 0x%x Set FPGAI2C_REG_CMD(0%x) FPGAI2C_REG_CMD_IACK = 0x%x\n" \ + ,stat, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK); + if(i2c->state == STATE_STOP) { + i2c->state = STATE_DONE; + } + wake_up(&i2c->wait); + return; + } + + + /* error? */ + if (stat & FPGAI2C_REG_STAT_ARBLOST) { + i2c->state = STATE_ERROR; + PRINT("fpgai2c_process FPGAI2C_REG_STAT_ARBLOST FPGAI2C_REG_CMD_STOP\n"); + fpgai2c_stop(i2c); + return; + } + + if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { + i2c->state = + (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; + + if (stat & FPGAI2C_REG_STAT_NACK) { + i2c->state = STATE_ERROR; + fpgai2c_stop(i2c); + return; + } + } else + { + msg->buf[i2c->pos++] = fpgai2c_reg_get(i2c, FPGAI2C_REG_DATA); + } + + /* end of msg? */ + if (i2c->pos == msg->len) { + i2c->nmsgs--; + i2c->msg++; + i2c->pos = 0; + msg = i2c->msg; + + if (i2c->nmsgs) { /* end? */ + /* send start? */ + if (!(msg->flags & I2C_M_NOSTART)) { + + u8 addr = (msg->addr << 1); + + if (msg->flags & I2C_M_RD) + addr |= 1; + + i2c->state = STATE_START; + fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, addr); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_START); + return; + } else + { + i2c->state = (msg->flags & I2C_M_RD) + ? STATE_READ : STATE_WRITE; + } + } else { + i2c->state = STATE_STOP; + fpgai2c_stop(i2c); + return; + } + } + + if (i2c->state == STATE_READ) { + PRINT("fpgai2c_poll STATE_READ i2c->pos=%d msg->len-1 = 0x%x set FPGAI2C_REG_CMD = 0x%x\n",i2c->pos, msg->len-1, + i2c->pos == (msg->len-1) ? FPGAI2C_REG_CMD_READ_NACK : FPGAI2C_REG_CMD_READ_ACK); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, i2c->pos == (msg->len-1) ? + FPGAI2C_REG_CMD_READ_NACK : FPGAI2C_REG_CMD_READ_ACK); + } else { + PRINT("fpgai2c_process set FPGAI2C_REG_DATA(0x%x)\n",FPGAI2C_REG_DATA); + fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, msg->buf[i2c->pos++]); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_WRITE); + } +} + +static irqreturn_t fpgai2c_isr(int irq, void *dev_id) +{ + struct fpgalogic_i2c *i2c = dev_id; + fpgai2c_process(i2c); + + return IRQ_HANDLED; +} +void dell_get_mutex(struct fpgalogic_i2c *i2c) +{ + mutex_lock(&i2c->lock); +} + +/** + * dell_release_mutex - release mutex + */ +void dell_release_mutex(struct fpgalogic_i2c *i2c) +{ + mutex_unlock(&i2c->lock); +} + +static int fpgai2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct fpgalogic_i2c *i2c = i2c_get_adapdata(adap); + int ret; + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + i2c->msg = msgs; + i2c->pos = 0; + i2c->nmsgs = num; + i2c->state = (use_irq == 1) ? STATE_START : STATE_INIT; + + PRINT("i2c->msg->addr = 0x%x i2c->msg->flags = 0x%x\n",i2c->msg->addr,i2c->msg->flags); + PRINT("I2C_M_RD = 0x%x i2c->msg->addr << 1 = 0x%x\n",I2C_M_RD,i2c->msg->addr << 1); + + if (!use_irq) { + /* Handle the transfer */ + while (time_before(jiffies, timeout)) { + dell_get_mutex(i2c); + ret = fpgai2c_poll(i2c); + dell_release_mutex(i2c); + + if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) + return (i2c->state == STATE_DONE) ? num : ret; + + if (ret == 0) + timeout = jiffies + HZ; + + usleep_range(5, 15); + } + + i2c->state = STATE_ERROR; + + return -ETIMEDOUT; + + + } else { + ret = -ETIMEDOUT; + PRINT("Set FPGAI2C_REG_DATA(0%x) val = 0x%x\n",FPGAI2C_REG_DATA, + (i2c->msg->addr << 1) | ((i2c->msg->flags & I2C_M_RD) ? 1:0)); + + fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, + (i2c->msg->addr << 1) | + ((i2c->msg->flags & I2C_M_RD) ? 1:0)); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_START); + + /* Interrupt mode */ + if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || + (i2c->state == STATE_DONE), HZ)) + ret = (i2c->state == STATE_DONE) ? num : -EIO; + return ret; + } +} + +static int fpgai2c_init(struct fpgalogic_i2c *i2c) +{ + int prescale; + int diff; + u8 ctrl; + + if (i2c->reg_io_width == 0) + i2c->reg_io_width = 1; /* Set to default value */ + + if (!i2c->reg_set || !i2c->reg_get) { + bool be = 0; //1:big_endian 0:little_endian + + switch (i2c->reg_io_width) { + case 1: + i2c->reg_set = fpgai2c_reg_set_8; + i2c->reg_get = fpgai2c_reg_get_8; + break; + + case 2: + i2c->reg_set = be ? fpgai2c_reg_set_16be : fpgai2c_reg_set_16; + i2c->reg_get = be ? fpgai2c_reg_get_16be : fpgai2c_reg_get_16; + break; + + case 4: + i2c->reg_set = be ? fpgai2c_reg_set_32be : fpgai2c_reg_set_32; + i2c->reg_get = be ? fpgai2c_reg_get_32be : fpgai2c_reg_get_32; + break; + + default: + PRINT("Unsupported I/O width (%d)\n", + i2c->reg_io_width); + return -EINVAL; + } + } + + ctrl = fpgai2c_reg_get(i2c, FPGAI2C_REG_CONTROL); + + PRINT("%s(), line:%d\n", __func__, __LINE__); + PRINT("i2c->base = 0x%p\n",i2c->base); + + PRINT("ctrl = 0x%x\n",ctrl); + PRINT("set ctrl = 0x%x\n",ctrl & ~(FPGAI2C_REG_CTRL_EN|FPGAI2C_REG_CTRL_IEN)); + + /* make sure the device is disabled */ + fpgai2c_reg_set(i2c, FPGAI2C_REG_CONTROL, ctrl & ~(FPGAI2C_REG_CTRL_EN|FPGAI2C_REG_CTRL_IEN)); + + /* + * I2C Frequency depends on host clock + * input clock of 100MHz + * prescale to 100MHz / ( 5*100kHz) -1 = 199 = 0x4F 100000/(5*100)-1=199=0xc7 + */ + prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1; + prescale = clamp(prescale, 0, 0xffff); + + diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz; + if (abs(diff) > i2c->bus_clock_khz / 10) { + PRINT("Unsupported clock settings: core: %d KHz, bus: %d KHz\n", + i2c->ip_clock_khz, i2c->bus_clock_khz); + return -EINVAL; + } + + fpgai2c_reg_set(i2c, FPGAI2C_REG_PRELOW, prescale & 0xff); + fpgai2c_reg_set(i2c, FPGAI2C_REG_PREHIGH, prescale >> 8); + + /* Init the device */ + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK); + if (!use_irq) + fpgai2c_reg_set(i2c, FPGAI2C_REG_CONTROL, ctrl | FPGAI2C_REG_CTRL_EN); + else + fpgai2c_reg_set(i2c, FPGAI2C_REG_CONTROL, ctrl | FPGAI2C_REG_CTRL_IEN | FPGAI2C_REG_CTRL_EN); + + fpgai2c_dump(i2c); + + /* Initialize interrupt handlers if not already done */ + init_waitqueue_head(&i2c->wait); + + return 0; +} + + +static u32 fpgai2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm fpgai2c_algorithm = { + .master_xfer = fpgai2c_xfer, + .functionality = fpgai2c_func, +}; + +static int i2c_pci_add_bus (struct i2c_adapter *adap) +{ + int ret = 0; + /* Register new adapter */ + adap->algo = &fpgai2c_algorithm; + ret = i2c_add_numbered_adapter(adap); + return ret; +} + +static int i2c_init_internal_data(void) +{ + int i; + PRINT("%s(), line:%d\n", __func__, __LINE__); + + for( i = 0; i < total_i2c_pci_bus; i++ ) + { + fpgalogic_i2c[i].reg_shift = 0; /* 8 bit registers */ + fpgalogic_i2c[i].reg_io_width = 1; /* 8 bit read/write */ + fpgalogic_i2c[i].timeout = 500;//1000;//1ms + fpgalogic_i2c[i].ip_clock_khz = 100000;//100000;/* input clock of 100MHz */ + fpgalogic_i2c[i].bus_clock_khz = 100; + fpgalogic_i2c[i].base = fpga_base_addr + i*FPGALOGIC_CH_OFFSET; + mutex_init(&fpgalogic_i2c[i].lock); + fpgai2c_init(&fpgalogic_i2c[i]); + } + + return 0; +} + + +static int i2c_pci_init (void) +{ + int i; + + if (num_bus == 0) { + board_rev_type = ioread32(fpga_ctl_addr + MB_BRD_REV_TYPE); + + if ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_00) { + num_bus = I2C_PCI_MAX_BUS_REV00; + } else if (((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_01) || + ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_02) || + ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_03)) { + switch (board_rev_type & MB_BRD_TYPE_MASK){ + case BRD_TYPE_S5212_NON_NEBS: + case BRD_TYPE_S5212_NEBS: + num_bus = I2C_PCI_BUS_NUM_5; + break; + case BRD_TYPE_S5224_NON_NEBS: + case BRD_TYPE_S5224_NEBS: + num_bus = I2C_PCI_BUS_NUM_7; + break; + case BRD_TYPE_Z9232_NON_NEBS: + case BRD_TYPE_Z9232_NEBS: + case BRD_TYPE_S5232_NON_NEBS: + case BRD_TYPE_S5232_NEBS: + num_bus = I2C_PCI_BUS_NUM_8; + break; + case BRD_TYPE_S5248_NON_NEBS: + case BRD_TYPE_S5248_NEBS: + num_bus = I2C_PCI_BUS_NUM_10; + break; + case BRD_TYPE_Z9264_NON_NEBS: + case BRD_TYPE_Z9264_NEBS: + num_bus = I2C_PCI_BUS_NUM_12; + break; + case BRD_TYPE_S5296_NON_NEBS: + case BRD_TYPE_S5296_NEBS: + num_bus = I2C_PCI_BUS_NUM_16; + break; + default: + num_bus = I2C_PCI_BUS_NUM_16; + printk("Wrong BRD_TYPE: 0x%x\n", board_rev_type); + break; + } + } else { + printk("Wrong board_rev_type 0x%x\n", board_rev_type); + } + } + + printk("board_rev_type 0x%x, num_bus 0x%x\n", board_rev_type, num_bus); + total_i2c_pci_bus = num_bus; + + memset (&i2c_pci_adap, 0, sizeof(i2c_pci_adap)); + memset (&fpgalogic_i2c, 0, sizeof(fpgalogic_i2c)); + for(i=0; i < i2c_bus_controller_numb; i++) + mutex_init(&i2c_xfer_lock[i]); + + /* Initialize driver's itnernal data structures */ + i2c_init_internal_data(); + + for (i = 0 ; i < total_i2c_pci_bus; i ++) { + + i2c_pci_adap[i].owner = THIS_MODULE; + i2c_pci_adap[i].class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + + i2c_pci_adap[i].algo_data = &fpgalogic_i2c[i]; + /* /dev/i2c-600 ~ /dev/i2c-615 for FPGA LOGIC I2C channel controller 1-7 */ + i2c_pci_adap[i].nr = i+600; + sprintf( i2c_pci_adap[ i ].name, "i2c-pci-%d", i ); + /* Add the bus via the algorithm code */ + if( i2c_pci_add_bus( &i2c_pci_adap[ i ] ) != 0 ) + { + PRINT("Cannot add bus %d to algorithm layer\n", i ); + return( -ENODEV ); + } + i2c_set_adapdata(&i2c_pci_adap[i], &fpgalogic_i2c[i]); + + PRINT( "Registered bus id: %s\n", kobject_name(&i2c_pci_adap[ i ].dev.kobj)); + } + + return 0; +} + +static void i2c_pci_deinit(void) +{ + int i; + for( i = 0; i < total_i2c_pci_bus; i++ ){ + i2c_del_adapter(&i2c_pci_adap[i]); + } + +} + +/* Find upstream PCIe root node. + * Used for re-training and disabling AER. */ +static struct pci_dev* find_upstream_dev (struct pci_dev *dev) +{ + struct pci_bus *bus = 0; + struct pci_dev *bridge = 0; + struct pci_dev *cur = 0; + int found_dev = 0; + + bus = dev->bus; + if (bus == 0) { + PRINT ( "Device doesn't have an associated bus!\n"); + return 0; + } + + bridge = bus->self; + if (bridge == 0) { + PRINT ( "Can't get the bridge for the bus!\n"); + return 0; + } + + PRINT ( "Upstream device %x/%x, bus:slot.func %02x:%02x.%02x\n", + bridge->vendor, bridge->device, + bridge->bus->number, PCI_SLOT(bridge->devfn), PCI_FUNC(bridge->devfn)); + + PRINT ( "List of downstream devices:"); + list_for_each_entry (cur, &bus->devices, bus_list) { + if (cur != 0) { + PRINT ( " %x/%x", cur->vendor, cur->device); + if (cur == dev) { + found_dev = 1; + } + } + } + PRINT ( "\n"); + if (found_dev) { + return bridge; + } else { + PRINT ( "Couldn't find upstream device!\n"); + return 0; + } +} + + +static int scan_bars(struct fpgapci_dev *fpgapci, struct pci_dev *dev) +{ + int i; + + for (i = 0; i < PCI_NUM_BARS; i++) { + unsigned long bar_start = pci_resource_start(dev, i); + if (bar_start) { + unsigned long bar_end = pci_resource_end(dev, i); + unsigned long bar_flags = pci_resource_flags(dev, i); + PRINT ( "BAR[%d] 0x%08lx-0x%08lx flags 0x%08lx", + i, bar_start, bar_end, bar_flags); + } + } + + return 0; +} + + +/** + * Map the device memory regions into kernel virtual address space + * after verifying their sizes respect the minimum sizes needed, given + * by the bar_min_len[] array. + */ +static int map_bars(struct fpgapci_dev *fpgapci, struct pci_dev *dev) +{ + int i; + + for (i = 0; i < PCI_NUM_BARS; i++){ + phys_addr_t bar_start = pci_resource_start(dev, i); + phys_addr_t bar_end = pci_resource_end(dev, i); + unsigned long bar_length = bar_end - bar_start + 1; + fpgapci->bar_length[i] = bar_length; + + + if (!bar_start || !bar_end) { + fpgapci->bar_length[i] = 0; + continue; + } + + if (bar_length < 1) { + PRINT ( "BAR #%d length is less than 1 byte\n", i); + continue; + } + + PRINT ( "bar_start=%llx, bar_end=%llx, bar_length=%lx, flag=%lx\n", bar_start, + bar_end, bar_length, pci_resource_flags(dev, i)); + + /* map the device memory or IO region into kernel virtual + * address space */ + fpgapci->bar[i] = ioremap_nocache (bar_start + FPGALOGIC_I2C_BASE, I2C_PCI_MAX_BUS * FPGALOGIC_CH_OFFSET); + + if (!fpgapci->bar[i]) { + PRINT ( "Could not map BAR #%d.\n", i); + return -1; + } + + PRINT ( "BAR[%d] mapped at 0x%p with length %lu.", i, + fpgapci->bar[i], bar_length); + + if(i == 0) //FPGA register is in the BAR[0] + { + + fpga_phys_addr = bar_start; + fpga_ctl_addr = ioremap_nocache (bar_start, FPGA_CTL_REG_SIZE); + fpga_base_addr = fpgapci->bar[i]; + } + + PRINT ( "BAR[%d] mapped at 0x%p with length %lu.\n", i, + fpgapci->bar[i], bar_length); + } + return 0; +} + +static void free_bars(struct fpgapci_dev *fpgapci, struct pci_dev *dev) +{ + int i; + + for (i = 0; i < PCI_NUM_BARS; i++) { + if (fpgapci->bar[i]) { + pci_iounmap(dev, fpgapci->bar[i]); + fpgapci->bar[i] = NULL; + } + } +} + +#define FPGA_PCI_NAME "FPGA_PCI" + +/** + * @brief Register specific function with msi interrupt line + * @param dev Pointer to pci-device, which should be allocated + * @param int interrupt number relative to global interrupt number + * @return Returns error code or zero if success + * */ +static int register_intr_handler(struct pci_dev *dev, int irq_num_id) +{ + int err = 0; + struct fpgapci_dev *fpgapci = 0; + + fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&dev->dev); + if (fpgapci == 0) { + PRINT ( ": fpgapci_dev is 0\n"); + return err; + } + + if ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_00) { + /* Request interrupt line for unique function + * alternatively function will be called from free_irq as well + * with flag IRQF_SHARED */ + switch(irq_num_id) { + /* Currently we only support test vector 2 for FPGA Logic I2C channel + * controller 1-7 interrupt*/ + case FPGA_MSI_VECTOR_ID_4: + err = request_irq(dev->irq + irq_num_id, fpgaport_1_32_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, dev); + PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_5: + err = request_irq(dev->irq + irq_num_id, fpgaport_33_64_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, dev); + PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_8: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[0]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_9: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[1]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_10: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[2]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_11: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[3]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_12: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[4]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_13: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[5]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_14: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[6]); + fpgapci->irq_assigned++; + break; + + default: + PRINT("No more interrupt handler for number (%d)\n", + dev->irq + irq_num_id); + break; + } + } else if (((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_01) || + ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_02) || + ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_03)) { + /* FPGA SPEC 4.3.1.34, First i2c channel mapped to vector 8 */ + switch (irq_num_id) { + case FPGA_MSI_VECTOR_ID_4: + err = request_irq(dev->irq + irq_num_id, fpgaport_1_32_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, dev); + PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_5: + err = request_irq(dev->irq + irq_num_id, fpgaport_33_64_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, dev); + PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_8: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[0]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_9: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[1]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_10: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[2]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_11: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[3]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_12: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[4]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_13: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_5) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[5]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_14: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_5) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[6]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_15: + /*it is an external interrupt number. Ignore this case */ + break; + case FPGA_MSI_VECTOR_ID_16: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_7) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[7]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_17: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_8) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[8]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_18: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_8) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[9]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_19: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_10) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[10]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_20: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_10) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[11]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_21: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[12]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_22: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[13]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_23: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[14]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_24: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[15]); + fpgapci->irq_assigned++; + } + break; + + default: + PRINT("No more interrupt handler for number (%d)\n", + dev->irq + irq_num_id); + break; + } + } + + return err; +} +/* Mask for MSI Multi message enable bits */ +#define MSI_MME 0x70 +/** + * These enums define the type of interrupt scheme that the overall + * system uses. + */ +enum fpga_irq_type { + INT_MSI_SINGLE, + INT_MSI_MULTI, + INT_MSIX, + INT_NONE, + INT_FENCE /* Last item to guard from loop run-overs */ +}; +/** + * @def PCI_DEVICE_STATUS + * define the offset for STS register + * from the start of PCI config space as specified in the + * NVME_Comliance 1.0b. offset 06h:STS - Device status. + * This register has error status for NVME PCI Exress + * Card. After reading data from this reagister, the driver + * will identify if any error is set during the operation and + * report as kernel alert message. + */ +#define PCI_DEVICE_STATUS 0x6 +/** + * @def NEXT_MASK + * This indicates the location of the next capability item + * in the list. + */ +#define NEXT_MASK 0xFF00 +/** + * @def MSIXCAP_ID + * This bit indicates if the pointer leading to this position + * is a capability. + */ +#define MSIXCAP_ID 0x11 +/** + * @def MSICAP_ID + * This bit indicates if the pointer leading to this position + * is a capability. + */ +#define MSICAP_ID 0x5 + +/** + * @def CL_MASK + * This bit position indicates Capabilities List of the controller + * The controller should support the PCI Power Management cap as a + * minimum. + */ +#define CL_MASK 0x0010 + +/** + * @def CAP_REG + * Set to offset defined in NVME Spec 1.0b. + */ +#define CAP_REG 0x34 +static void msi_set_enable(struct pci_dev *dev, int enable) +{ + int pos,maxvec; + u16 control; + int request_private_bits = 4; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + + if (pos) { + pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); + maxvec = 1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1); + PRINT("control = 0x%x maxvec = 0x%x\n", control, maxvec); + control &= ~PCI_MSI_FLAGS_ENABLE; + + + /* + * The PCI 2.3 spec mandates that there are at most 32 + * interrupts. If this device asks for more, only give it one. + */ + if (request_private_bits > 5) { + request_private_bits = 0; + } + + /* Update the number of IRQs the device has available to it */ + control &= ~PCI_MSI_FLAGS_QSIZE; + control |= (request_private_bits << 4); + + pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); + } +} +/** + * @brief Enables pcie-device and claims/remaps neccessary bar resources + * @param dev Pointer to pci-device, which should be allocated + * @return Returns error code or zero if success + * */ +static int fpgapci_setup_device(struct fpgapci_dev *fpgapci,struct pci_dev *dev) +{ + int err = 0; + + /* wake up the pci device */ + err = pci_enable_device(dev); + if(err) { + PRINT("failed to enable pci device %d\n", err); + goto error_pci_en; + } + + /* on platforms with buggy ACPI, pdev->msi_enabled may be set to + * allow pci_enable_device to work. This indicates INTx was not routed + * and only MSI should be used + */ + + pci_set_master(dev); + + /* Setup the BAR memory regions */ + err = pci_request_regions(dev, DRIVER_NAME); + if (err) { + PRINT("failed to enable pci device %d\n", err); + goto error_pci_req; + } + + scan_bars(fpgapci, dev); + + if (map_bars(fpgapci, dev)) { + goto fail_map_bars; + } + + i2c_pci_init(); + + return 0; + /* ERROR HANDLING */ +fail_map_bars: + pci_release_regions(dev); +error_pci_req: + pci_disable_device(dev); +error_pci_en: + return -ENODEV; +} + +static int fpgapci_configure_msi(struct fpgapci_dev *fpgapci,struct pci_dev *dev) +{ + int err = 0, i; + int request_vec; + + msi_set_enable(dev,1); + PRINT("Check MSI capability after msi_set_enable\n"); + + + /*Above 4.1.12*/ + request_vec = total_i2c_pci_bus; + err = pci_alloc_irq_vectors(dev, request_vec, pci_msi_vec_count(dev), + PCI_IRQ_MSI);//PCI_IRQ_AFFINITY | PCI_IRQ_MSI); + + if (err <= 0) { + PRINT("Cannot set MSI vector (%d)\n", err); + goto error_no_msi; + } else { + PRINT("Got %d MSI vectors starting at %d\n", err, dev->irq); + if ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_00) { + if (err < MSI_VECTOR_REV_00) { + goto error_disable_msi; + } + } else if (((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_01) || + ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_02) || + ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_03)) { + if (err < MSI_VECTOR_REV_01) { + goto error_disable_msi; + } + } + } + fpgapci->irq_first = dev->irq; + fpgapci->irq_length = err; + fpgapci->irq_assigned = 0; + + + for(i = 0; i < fpgapci->irq_length; i++) { + err = register_intr_handler(dev, i); + if (err) { + PRINT("Cannot request Interrupt number %d\n", i); + goto error_pci_req_irq; + } + } + + return 0; + +error_pci_req_irq: + for(i = 0; i < fpgapci->irq_assigned; i++) + { + PRINT("free_irq %d i =%d\n",fpgapci->irq_first + i,i); + if (i < 7) + free_irq(fpgapci->irq_first + 8 + i, &fpgalogic_i2c[i]); + else + free_irq(fpgapci->irq_first + 8 + i + 1, &fpgalogic_i2c[i]); + } +error_disable_msi: + pci_disable_msi(fpgapci->pci_dev); +error_no_msi: + return -ENOSPC; +} + +static int fpgapci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct fpgapci_dev *fpgapci = 0; + int status = 0; + +#ifdef TEST + PRINT ( " vendor = 0x%x, device = 0x%x, class = 0x%x, bus:slot.func = %02x:%02x.%02x\n", + dev->vendor, dev->device, dev->class, + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); +#endif + fpgapci = kzalloc(sizeof(struct fpgapci_dev), GFP_KERNEL); + + if (!fpgapci) { + PRINT( "Couldn't allocate memory!\n"); + goto fail_kzalloc; + } + + fpgapci->pci_dev = dev; + dev_set_drvdata(&dev->dev, (void*)fpgapci); + + status = sysfs_create_group(&dev->dev.kobj, &port_attr_grp); + if (status) { + printk(KERN_INFO "%s:Cannot create sysfs\n", __FUNCTION__); + } + + fpgapci->upstream = find_upstream_dev (dev); + + if(fpgapci_setup_device(fpgapci,dev)) { + goto error_no_device; + } + + if (use_irq) { + if(fpgapci_configure_msi(fpgapci,dev)) { + goto error_cannot_configure; + } + } + + + return 0; + /* ERROR HANDLING */ +error_cannot_configure: + printk("error_cannot_configure\n"); + free_bars (fpgapci, dev); + pci_release_regions(dev); + pci_disable_device(dev); +error_no_device: + i2c_pci_deinit(); + printk("error_no_device\n"); +fail_kzalloc: + return -1; + + +} + +static void fpgapci_remove(struct pci_dev *dev) +{ + struct fpgapci_dev *fpgapci = 0; + int i; + PRINT (": dev is %p\n", dev); + + if (dev == 0) { + PRINT ( ": dev is 0\n"); + return; + } + + fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&dev->dev); + if (fpgapci == 0) { + PRINT ( ": fpgapci_dev is 0\n"); + return; + } + i2c_pci_deinit(); + // + if (use_irq) + { + for(i = 0; i < fpgapci->irq_assigned; i++) + { + PRINT("free_irq %d i =%d\n",fpgapci->irq_first + i,i); + if (i < 7) + free_irq(fpgapci->irq_first + 8 + i, &fpgalogic_i2c[i]); + else + free_irq(fpgapci->irq_first + 8 + i + 1, &fpgalogic_i2c[i]); + } + } + pci_disable_msi(fpgapci->pci_dev); + free_bars (fpgapci, dev); + pci_disable_device(dev); + pci_release_regions(dev); + + kfree (fpgapci); +} + +static const struct pci_device_id fpgapci_ids[] = { + {PCI_DEVICE(PCI_VENDOR_ID_XILINX, DEVICE)}, + {0, }, +}; + +MODULE_DEVICE_TABLE(pci, fpgapci_ids); + +static struct pci_driver fpgapci_driver = { + .name = DRIVER_NAME, + .id_table = fpgapci_ids, + .probe = fpgapci_probe, + .remove = fpgapci_remove, + /* resume, suspend are optional */ +}; + +/* Initialize the driver module (but not any device) and register + * the module with the kernel PCI subsystem. */ +static int __init fpgapci_init(void) +{ + + if (pci_register_driver(&fpgapci_driver)) { + PRINT("pci_unregister_driver\n"); + pci_unregister_driver(&fpgapci_driver); + return -ENODEV; + } + + return 0; +} + +static void __exit fpgapci_exit(void) +{ + PRINT ("fpgapci_exit"); + + /* unregister this driver from the PCI bus driver */ + pci_unregister_driver(&fpgapci_driver); + +} + + +module_init (fpgapci_init); +module_exit (fpgapci_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("joyce_yu@dell.com"); +MODULE_DESCRIPTION ("Driver for FPGA Logic I2C bus"); +MODULE_SUPPORTED_DEVICE ("FPGA Logic I2C bus"); diff --git a/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/check_qsfp.sh b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/check_qsfp.sh new file mode 100755 index 000000000000..2028b8e65946 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/check_qsfp.sh @@ -0,0 +1,3 @@ +# Temporary dummy file for s5248f. +# Will be updated soon. + diff --git a/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/pcisysfs.py b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/pcisysfs.py new file mode 100755 index 000000000000..047618e057c8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/pcisysfs.py @@ -0,0 +1,102 @@ +#!/usr/bin/python +# Copyright (c) 2015 Dell Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. + +import struct +import sys +import getopt +from os import * +from mmap import * + +def usage(): + ''' This is the Usage Method ''' + + print '\t\t pcisysfs.py --get --offset --res ' + print '\t\t pcisysfs.py --set --val --offset --res ' + sys.exit(1) + +def pci_mem_read(mm,offset): + mm.seek(offset) + read_data_stream=mm.read(4) + print "" + reg_val=struct.unpack('I',read_data_stream) + print "reg_val read:%x"%reg_val + return reg_val + +def pci_mem_write(mm,offset,data): + mm.seek(offset) + print "data to write:%x"%data + mm.write(struct.pack('I',data)) + +def pci_set_value(resource,val,offset): + fd=open(resource,O_RDWR) + mm=mmap(fd,0) + pci_mem_write(mm,offset,val) + +def pci_get_value(resource,offset): + fd=open(resource,O_RDWR) + mm=mmap(fd,0) + pci_mem_read(mm,offset) + +def main(argv): + + ''' The main function will read the user input from the + command line argument and process the request ''' + + opts = '' + val = '' + choice = '' + resource = '' + offset = '' + + try: + opts, args = getopt.getopt(argv, "hgsv:" , \ + ["val=","res=","offset=","help", "get", "set"]) + + except getopt.GetoptError: + usage() + + for opt,arg in opts: + + if opt in ('-h','--help'): + choice = 'help' + + elif opt in ('-g', '--get'): + choice = 'get' + + elif opt in ('-s', '--set'): + choice = 'set' + + elif opt == '--res': + resource = arg + + elif opt == '--val': + val = int(arg,16) + + elif opt == '--offset': + offset = int(arg,16) + + if choice == 'set' and val != '' and offset !='' and resource !='': + pci_set_value(resource,val,offset) + + elif choice == 'get' and offset != '' and resource !='': + pci_get_value(resource,offset) + + else: + usage() + +#Calling the main method +if __name__ == "__main__": + main(sys.argv[1:]) + diff --git a/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/platform_sensors.py new file mode 100755 index 000000000000..6f7ba9b55b09 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/platform_sensors.py @@ -0,0 +1,277 @@ +#!/usr/bin/python +# On S5248F, the BaseBoard Management Controller is an +# autonomous subsystem provides monitoring and management +# facility independent of the host CPU. IPMI standard +# protocol is used with ipmitool to fetch sensor details. +# Current script support X00 board only. X01 support will +# be added soon. This provies support for the +# following objects: +# * Onboard temperature sensors +# * FAN trays +# * PSU + + +import os +import sys +import logging +import subprocess +import commands + +S5248F_MAX_FAN_TRAYS = 4 +S5248F_MAX_PSUS = 2 +IPMI_SENSOR_DATA = "ipmitool sdr list" +IPMI_SENSOR_DUMP = "/tmp/sdr" + +FAN_PRESENCE = "FAN{0}_prsnt" +PSU_PRESENCE = "PSU{0}_stat" +# Use this for older firmware +# PSU_PRESENCE="PSU{0}_prsnt" + +IPMI_PSU1_DATA_DOCKER = "ipmitool raw 0x04 0x2d 0x31 | awk '{print substr($0,9,1)}'" +IPMI_PSU2_DATA_DOCKER = "ipmitool raw 0x04 0x2d 0x32 | awk '{print substr($0,9,1)}'" +ipmi_sdr_list = "" + +# Dump sensor registers + + +def ipmi_sensor_dump(): + + status = 1 + global ipmi_sdr_list + ipmi_cmd = IPMI_SENSOR_DATA + status, ipmi_sdr_list = commands.getstatusoutput(ipmi_cmd) + + if status: + logging.error('Failed to execute:' + ipmi_sdr_list) + sys.exit(0) + +# Fetch a BMC register + + +def get_pmc_register(reg_name): + + output = None + for item in ipmi_sdr_list.split("\n"): + if reg_name in item: + output = item.strip() + + if output is None: + print('\nFailed to fetch: ' + reg_name + ' sensor ') + sys.exit(0) + + output = output.split('|')[1] + + logging.basicConfig(level=logging.DEBUG) + return output + + +# Print the information for temperature sensors + + +def print_temperature_sensors(): + + print("\nOnboard Temperature Sensors:") + + print ' PT_Left_temp: ',\ + (get_pmc_register('PT_Left_temp')) + print ' PT_Mid_temp: ',\ + (get_pmc_register('PT_Mid_temp')) + print ' PT_Right_temp: ',\ + (get_pmc_register('PT_Right_temp')) + print ' Broadcom Temp: ',\ + (get_pmc_register('NPU_Near_temp')) + print ' Inlet Airflow Temp: ',\ + (get_pmc_register('ILET_AF_temp')) + print ' CPU Temp: ',\ + (get_pmc_register('CPU_temp')) + +ipmi_sensor_dump() + +print_temperature_sensors() + +# Print the information for 1 Fan Tray + + +def print_fan_tray(tray): + + Fan_Status = [' Normal', ' Abnormal'] + Airflow_Direction = ['B2F', 'F2B'] + + print ' Fan Tray ' + str(tray) + ':' + + if (tray == 1): + + fan1_status = int(get_pmc_register('FAN1_Front_stat'), 16) + fan2_status = int(get_pmc_register('FAN1_Rear_stat'), 16) + + print ' Fan1 Speed: ',\ + get_pmc_register('FAN1_Front_rpm') + print ' Fan2 Speed: ',\ + get_pmc_register('FAN1_Rear_rpm') + print ' Fan1 State: ',\ + Fan_Status[fan1_status] + print ' Fan2 State: ',\ + Fan_Status[fan2_status] + + elif (tray == 2): + + fan1_status = int(get_pmc_register('FAN2_Front_stat'), 16) + fan2_status = int(get_pmc_register('FAN2_Rear_stat'), 16) + + print ' Fan1 Speed: ',\ + get_pmc_register('FAN2_Front_rpm') + print ' Fan2 Speed: ',\ + get_pmc_register('FAN2_Rear_rpm') + print ' Fan1 State: ',\ + Fan_Status[fan1_status] + print ' Fan2 State: ',\ + Fan_Status[fan2_status] + + elif (tray == 3): + + fan1_status = int(get_pmc_register('FAN3_Front_stat'), 16) + fan2_status = int(get_pmc_register('FAN3_Rear_stat'), 16) + + print ' Fan1 Speed: ',\ + get_pmc_register('FAN3_Front_rpm') + print ' Fan2 Speed: ',\ + get_pmc_register('FAN3_Rear_rpm') + print ' Fan1 State: ',\ + Fan_Status[fan1_status] + print ' Fan2 State: ',\ + Fan_Status[fan2_status] + + elif (tray == 4): + + fan1_status = int(get_pmc_register('FAN4_Front_stat'), 16) + fan2_status = int(get_pmc_register('FAN4_Rear_stat'), 16) + + print ' Fan1 Speed: ',\ + get_pmc_register('FAN4_Front_rpm') + print ' Fan2 Speed: ',\ + get_pmc_register('FAN4_Rear_rpm') + print ' Fan1 State: ',\ + Fan_Status[fan1_status] + print ' Fan2 State: ',\ + Fan_Status[fan2_status] + + +print('\nFan Trays:') + +for tray in range(1, S5248F_MAX_FAN_TRAYS + 1): + fan_presence = FAN_PRESENCE.format(tray) + if (get_pmc_register(fan_presence)): + print_fan_tray(tray) + else: + print '\n Fan Tray ' + str(tray + 1) + ': Not present' + + def get_psu_presence(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 + ret_status = 1 + + if index == 1: + status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_PSU1_DATA_DOCKER) + elif index == 2: + ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_PSU2_DATA_DOCKER) + + #if ret_status: + # print ipmi_cmd_ret + # logging.error('Failed to execute ipmitool') + # sys.exit(0) + + psu_status = ipmi_cmd_ret + + if psu_status == '1': + status = 1 + + return status + + +# Print the information for PSU1, PSU2 +def print_psu(psu): + Psu_Type = ['Normal', 'Mismatch'] + Psu_Input_Type = ['AC', 'DC'] + PSU_STATUS_TYPE_BIT = 4 + PSU_STATUS_INPUT_TYPE_BIT = 1 + PSU_FAN_PRESENT_BIT = 2 + PSU_FAN_STATUS_BIT = 1 + PSU_FAN_AIR_FLOW_BIT = 0 + Psu_Fan_Presence = ['Present', 'Absent'] + Psu_Fan_Status = ['Normal', 'Abnormal'] + Psu_Fan_Airflow = ['B2F', 'F2B'] + + # print ' Input: ', Psu_Input_Type[psu_input_type] + # print ' Type: ', Psu_Type[psu_type] + + # PSU FAN details + if (psu == 1): + + # psu1_fan_status = int(get_pmc_register('PSU1_status'),16) + + print ' PSU1:' + print ' FAN Normal Temperature: ',\ + get_pmc_register('PSU1_temp') + print ' FAN AirFlow Temperature: ',\ + get_pmc_register('PSU1_AF_temp') + print ' FAN RPM: ',\ + get_pmc_register('PSU1_rpm') + # print ' FAN Status: ', Psu_Fan_Status[psu1_fan_status] + + # PSU input & output monitors + print ' Input Voltage: ',\ + get_pmc_register('PSU1_In_volt') + print ' Output Voltage: ',\ + get_pmc_register('PSU1_Out_volt') + print ' Input Power: ',\ + get_pmc_register('PSU1_In_watt') + print ' Output Power: ',\ + get_pmc_register('PSU1_Out_watt') + print ' Input Current: ',\ + get_pmc_register('PSU1_In_amp') + print ' Output Current: ',\ + get_pmc_register('PSU1_Out_amp') + + else: + + # psu2_fan_status = int(get_pmc_register('PSU1_status'),16) + print ' PSU2:' + print ' FAN Normal Temperature: ',\ + get_pmc_register('PSU2_temp') + print ' FAN AirFlow Temperature: ',\ + get_pmc_register('PSU2_AF_temp') + print ' FAN RPM: ',\ + get_pmc_register('PSU2_rpm') + # print ' FAN Status: ', Psu_Fan_Status[psu2_fan_status] + + # PSU input & output monitors + print ' Input Voltage: ',\ + get_pmc_register('PSU2_In_volt') + print ' Output Voltage: ',\ + get_pmc_register('PSU2_Out_volt') + print ' Input Power: ',\ + get_pmc_register('PSU2_In_watt') + print ' Output Power: ',\ + get_pmc_register('PSU2_Out_watt') + print ' Input Current: ',\ + get_pmc_register('PSU2_In_amp') + print ' Output Current: ',\ + get_pmc_register('PSU2_Out_amp') + + +print('\nPSUs:') +for psu in range(1, S5248F_MAX_PSUS + 1): + #psu_presence = PSU_PRESENCE.format(psu) + if (get_psu_presence(psu)): + print_psu(psu) + else: + print '\n PSU ', psu, 'Not present' + +print '\n Total Power: ',\ + get_pmc_register('PSU_Total_watt') + diff --git a/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/qsfp_irq_enable.py b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/qsfp_irq_enable.py new file mode 100755 index 000000000000..5050475f987e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/qsfp_irq_enable.py @@ -0,0 +1,32 @@ +#!/usr/bin/python + +try: + import struct + import sys + from os import * + from mmap import * + +except ImportError as e: + raise ImportError("%s - required module no found" % str(e)) + +BASE_RES_PATH = "/sys/bus/pci/devices/0000:04:00.0/resource0" +PORT_START = 0 +PORT_END = 32 + + +def pci_mem_write(mm, offset, data): + mm.seek(offset) + mm.write(struct.pack('I', data)) + + +def pci_set_value(resource, val, offset): + fd = open(resource, O_RDWR) + mm = mmap(fd, 0) + val = pci_mem_write(mm, offset, val) + mm.close() + close(fd) + return val + +for port_num in range(PORT_START, PORT_END+1): + port_offset = 0x400c + ((port_num) * 16) + pci_set_value(BASE_RES_PATH, 0x30, port_offset) diff --git a/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/s5248f_platform.sh b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/s5248f_platform.sh new file mode 100755 index 000000000000..e74a3d6c40de --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/s5248f_platform.sh @@ -0,0 +1,161 @@ +#!/bin/bash + +init_devnum() { + found=0 + for devnum in 0 1; do + devname=`cat /sys/bus/i2c/devices/i2c-${devnum}/name` + # iSMT adapter can be at either dffd0000 or dfff0000 + if [[ $devname == 'SMBus iSMT adapter at '* ]]; then + found=1 + break + fi + done + + [ $found -eq 0 ] && echo "cannot find iSMT" && exit 1 +} + +# Attach/Detach syseeprom on CPU board +sys_eeprom() { + case $1 in + "new_device") echo 24c16 0x50 > /sys/bus/i2c/devices/i2c-0/$1 + ;; + "delete_device") echo 0x50 > /sys/bus/i2c/devices/i2c-0/$1 + ;; + *) echo "s5248f_platform: sys_eeprom : invalid command !" + ;; + esac +} + +#Attach/Detach the MUX connecting all QSFPs +switch_board_qsfp_mux() { + case $1 in + "new_device") + for ((i=603;i<=610;i++)); + do + echo "Attaching PCA9548 @ 0x74" + echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-$i/$1 + done + + ;; + "delete_device") + for ((i=603;i<=610;i++)); + do + echo "Detaching PCA9548 @ 0x74" + echo 0x74 > /sys/bus/i2c/devices/i2c-$i/$1 + done + + ;; + *) echo "s5248f_platform: switch_board_qsfp_mux: invalid command !" + ;; + esac + sleep 2 +} + +#Attach/Detach 64 instances of EEPROM driver QSFP ports +#eeprom can dump data using below command +switch_board_qsfp() { + case $1 in + "new_device") + for ((i=2;i<=57;i++)); + do + echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + done + ;; + + "delete_device") + for ((i=2;i<=57;i++)); + do + echo 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + done + ;; + + *) echo "s5248f_platform: switch_board_qsfp: invalid command !" + ;; + esac +} + +#Modsel 64 ports to applicable QSFP type modules +#This enables the adapter to respond for i2c commands +switch_board_modsel() { + resource="/sys/bus/pci/devices/0000:04:00.0/resource0" + for ((i=1;i<=64;i++)); + do + port_addr=$(( 16384 + ((i - 1) * 16))) + hex=$( printf "0x%x" $port_addr ) + python /usr/bin/pcisysfs.py --set --offset $hex --val 0x10 --res $resource > /dev/null 2>&1 + done +} + +platform_firmware_versions() { + FIRMWARE_VERSION_FILE=/var/log/firmware_versions + rm -rf ${FIRMWARE_VERSION_FILE} + echo "BIOS: `dmidecode -s system-version `" > $FIRMWARE_VERSION_FILE + ## Get FPGA version + r=`/usr/bin/pcisysfs.py --get --offset 0x00 --res /sys/bus/pci/devices/0000\:04\:00.0/resource0 | sed '1d; s/.*\(....\)$/\1/; s/\(..\{1\}\)/\1./'` + r_min=$(echo $r | sed 's/.*\(..\)$/0x\1/') + r_maj=$(echo $r | sed 's/^\(..\).*/0x\1/') + echo "FPGA: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE + + ## Get BMC Firmware Revision + r=`cat /sys/class/ipmi/ipmi0/device/bmc/firmware_revision` + echo "BMC: $r" >> $FIRMWARE_VERSION_FILE + + #System CPLD 0x31 on i2c bus 601 ( physical FPGA I2C-2) + r_min=`/usr/sbin/i2cget -y 601 0x31 0x0 | sed ' s/.*\(0x..\)$/\1/'` + r_maj=`/usr/sbin/i2cget -y 601 0x31 0x1 | sed ' s/.*\(0x..\)$/\1/'` + echo "System CPLD: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE + + #Slave CPLD 1 0x30 on i2c bus 600 ( physical FPGA I2C-1) + r_min=`/usr/sbin/i2cget -y 600 0x30 0x0 | sed ' s/.*\(0x..\)$/\1/'` + r_maj=`/usr/sbin/i2cget -y 600 0x30 0x1 | sed ' s/.*\(0x..\)$/\1/'` + echo "Slave CPLD 1: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE + + #Slave CPLD 2 0x31 on i2c bus 600 ( physical FPGA I2C-1) + r_min=`/usr/sbin/i2cget -y 600 0x31 0x0 | sed ' s/.*\(0x..\)$/\1/'` + r_maj=`/usr/sbin/i2cget -y 600 0x31 0x1 | sed ' s/.*\(0x..\)$/\1/'` + echo "Slave CPLD 2: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE + + #Slave CPLD 3 0x32 on i2c bus 600 ( physical FPGA I2C-1) + r_min=`/usr/sbin/i2cget -y 600 0x32 0x0 | sed ' s/.*\(0x..\)$/\1/'` + r_maj=`/usr/sbin/i2cget -y 600 0x32 0x1 | sed ' s/.*\(0x..\)$/\1/'` + echo "Slave CPLD 3: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE + + #Slave CPLD 3 0x32 on i2c bus 600 ( physical FPGA I2C-1) + r_min=`/usr/sbin/i2cget -y 600 0x33 0x0 | sed ' s/.*\(0x..\)$/\1/'` + r_maj=`/usr/sbin/i2cget -y 600 0x33 0x1 | sed ' s/.*\(0x..\)$/\1/'` + echo "Slave CPLD 4: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE +} + +#This enables the led control for CPU and default states +switch_board_led_default() { + resource="/sys/bus/pci/devices/0000:04:00.0/resource0" + python /usr/bin/pcisysfs.py --set --offset 0x24 --val 0x194 --res $resource > /dev/null 2>&1 +} +init_devnum + +if [ "$1" == "init" ]; then + modprobe i2c-dev + modprobe i2c-mux-pca954x force_deselect_on_exit=1 + modprobe ipmi_devintf + modprobe ipmi_si + modprobe i2c_ocores + modprobe dell_s5248f_fpga_ocores + sys_eeprom "new_device" + switch_board_qsfp_mux "new_device" + switch_board_qsfp "new_device" + switch_board_modsel + switch_board_led_default + #python /usr/bin/qsfp_irq_enable.py + platform_firmware_versions + +elif [ "$1" == "deinit" ]; then + sys_eeprom "delete_device" + switch_board_qsfp "delete_device" + switch_board_qsfp_mux "delete_device" + + modprobe -r i2c-mux-pca954x + modprobe -r i2c-dev +else + echo "s5248f_platform : Invalid option !" +fi + diff --git a/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/sensors b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/sensors new file mode 100755 index 000000000000..ee53f2b0f325 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/sensors @@ -0,0 +1,8 @@ +#!/bin/bash +docker exec -i pmon sensors "$@" +docker exec -i pmon /usr/bin/platform_sensors.py "$@" + +#To probe sensors not part of lm-sensors +#if [ -r /usr/local/bin/platform_sensors.py ]; then +# python /usr/local/bin/platform_sensors.py +#fi diff --git a/platform/broadcom/sonic-platform-modules-dell/s5248f/systemd/platform-modules-s5248f.service b/platform/broadcom/sonic-platform-modules-dell/s5248f/systemd/platform-modules-s5248f.service new file mode 100644 index 000000000000..ec3ea09f00ae --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5248f/systemd/platform-modules-s5248f.service @@ -0,0 +1,13 @@ +[Unit] +Description=Dell S5248f Platform modules +Before=pmon.service +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/s5248f_platform.sh init +ExecStop=/usr/local/bin/s5248f_platform.sh deinit +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/src/sonic-device-data/tests/permitted_list b/src/sonic-device-data/tests/permitted_list index bba14e99db3e..370a920d2187 100644 --- a/src/sonic-device-data/tests/permitted_list +++ b/src/sonic-device-data/tests/permitted_list @@ -202,3 +202,10 @@ tm_port_header_type_out trunk_group_max_members ucode_port led_fw_path +l2xlrn_thread_interval +l2xlrn_intr_en +serdes_lane_config_media_type +sai_preinit_cmd_file +sai_preinit_warmboot_cmd_file +sai_postinit_cmd_file +sai_postinit_warmboot_cmd_file From be52977aca8e8c318c972cbe92d5de8bcfaf2c32 Mon Sep 17 00:00:00 2001 From: Wenda Ni Date: Fri, 18 Oct 2019 09:14:39 -0700 Subject: [PATCH 090/278] Revert "Configure buffer profile to all ports (#3561)" (#3628) This reverts commit 8861cbe98edbe513aac5d1ee2c5943bf6179c905. --- files/build_templates/buffers_config.j2 | 8 +- .../tests/sample_output/buffers-dell6100.json | 240 ------------------ 2 files changed, 4 insertions(+), 244 deletions(-) diff --git a/files/build_templates/buffers_config.j2 b/files/build_templates/buffers_config.j2 index bf74b2dcf52c..a5212d979fcb 100644 --- a/files/build_templates/buffers_config.j2 +++ b/files/build_templates/buffers_config.j2 @@ -131,7 +131,7 @@ def {{ defs.generate_pg_profils(port_names_active) }} {% else %} "BUFFER_PG": { -{% for port in PORT_ALL %} +{% for port in PORT_ACTIVE %} "{{ port }}|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }{% if not loop.last %},{% endif %} @@ -144,17 +144,17 @@ def {{ defs.generate_queue_buffers(port_names_active) }} {% else %} "BUFFER_QUEUE": { -{% for port in PORT_ALL %} +{% for port in PORT_ACTIVE %} "{{ port }}|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, {% endfor %} -{% for port in PORT_ALL %} +{% for port in PORT_ACTIVE %} "{{ port }}|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, {% endfor %} -{% for port in PORT_ALL %} +{% for port in PORT_ACTIVE %} "{{ port }}|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }{% if not loop.last %},{% endif %} diff --git a/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json b/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json index 38e2b8313eb4..5cf0472f3f11 100644 --- a/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json +++ b/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json @@ -111,12 +111,6 @@ "Ethernet1|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, - "Ethernet2|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet3|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, "Ethernet4|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, @@ -159,12 +153,6 @@ "Ethernet17|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, - "Ethernet18|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet19|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, "Ethernet20|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, @@ -204,15 +192,6 @@ "Ethernet32|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, - "Ethernet33|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet34|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet35|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, "Ethernet36|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, @@ -234,33 +213,9 @@ "Ethernet42|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, - "Ethernet43|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet44|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet45|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet46|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet47|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, "Ethernet48|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, - "Ethernet49|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet50|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet51|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, "Ethernet52|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" }, @@ -281,21 +236,6 @@ }, "Ethernet58|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet59|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet60|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet61|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet62|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - }, - "Ethernet63|0": { - "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" } }, @@ -306,12 +246,6 @@ "Ethernet1|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, - "Ethernet2|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet3|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, "Ethernet4|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, @@ -354,12 +288,6 @@ "Ethernet17|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, - "Ethernet18|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet19|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, "Ethernet20|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, @@ -399,15 +327,6 @@ "Ethernet32|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, - "Ethernet33|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet34|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet35|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, "Ethernet36|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, @@ -429,33 +348,9 @@ "Ethernet42|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, - "Ethernet43|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet44|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet45|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet46|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet47|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, "Ethernet48|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, - "Ethernet49|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet50|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet51|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, "Ethernet52|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, @@ -477,33 +372,12 @@ "Ethernet58|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, - "Ethernet59|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet60|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet61|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet62|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, - "Ethernet63|3-4": { - "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" - }, "Ethernet0|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, "Ethernet1|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, - "Ethernet2|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet3|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, "Ethernet4|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -546,12 +420,6 @@ "Ethernet17|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, - "Ethernet18|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet19|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, "Ethernet20|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -591,15 +459,6 @@ "Ethernet32|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, - "Ethernet33|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet34|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet35|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, "Ethernet36|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -621,33 +480,9 @@ "Ethernet42|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, - "Ethernet43|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet44|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet45|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet46|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet47|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, "Ethernet48|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, - "Ethernet49|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet50|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet51|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, "Ethernet52|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -669,33 +504,12 @@ "Ethernet58|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, - "Ethernet59|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet60|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet61|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet62|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet63|0-2": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, "Ethernet0|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, "Ethernet1|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, - "Ethernet2|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet3|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, "Ethernet4|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -738,12 +552,6 @@ "Ethernet17|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, - "Ethernet18|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet19|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, "Ethernet20|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -783,15 +591,6 @@ "Ethernet32|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, - "Ethernet33|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet34|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet35|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, "Ethernet36|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -813,33 +612,9 @@ "Ethernet42|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, - "Ethernet43|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet44|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet45|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet46|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet47|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, "Ethernet48|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, - "Ethernet49|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet50|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet51|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, "Ethernet52|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, @@ -860,21 +635,6 @@ }, "Ethernet58|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet59|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet60|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet61|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet62|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - }, - "Ethernet63|5-6": { - "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" } } } From 37ba921449166a5bb27d2067d1af1b9f563ead6e Mon Sep 17 00:00:00 2001 From: Nazarii Hnydyn Date: Sat, 19 Oct 2019 12:11:58 +0300 Subject: [PATCH 091/278] [mellanox] Update SN3800 device configs. (#3633) Signed-off-by: Nazarii Hnydyn --- device/mellanox/x86_64-mlnx_msn3800-r0/pmon_daemon_control.json | 1 + 1 file changed, 1 insertion(+) create mode 120000 device/mellanox/x86_64-mlnx_msn3800-r0/pmon_daemon_control.json diff --git a/device/mellanox/x86_64-mlnx_msn3800-r0/pmon_daemon_control.json b/device/mellanox/x86_64-mlnx_msn3800-r0/pmon_daemon_control.json new file mode 120000 index 000000000000..435a2ce7c0ba --- /dev/null +++ b/device/mellanox/x86_64-mlnx_msn3800-r0/pmon_daemon_control.json @@ -0,0 +1 @@ +../x86_64-mlnx_msn2700-r0/pmon_daemon_control.json \ No newline at end of file From 9d7199ac936a001867ac9aeea698e4348d3b2c20 Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Sat, 19 Oct 2019 11:00:37 -0700 Subject: [PATCH 092/278] [dox]: Add SONiC management docker image (#3636) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 315652e81af3..08375dce678b 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,7 @@ This may take a while, but it is a one-time action, so please be patient. - docker-syncd-nephos.gz: docker image for the daemon to sync database and Nephos switch ASIC (gzip tar archive) - docker-sonic-p4.gz: docker image for all-in-one for p4 software switch (gzip tar archive) - docker-sonic-vs.gz: docker image for all-in-one for software virtual switch (gzip tar archive) + - docker-sonic-mgmt.gz: docker image for [managing, configuring and monitoring SONiC](https://github.com/Azure/sonic-mgmt) (gzip tar archive) ## Contribution Guide From 3b63f6f9d7b618eb890f71dc9cdbe4fdb53802fa Mon Sep 17 00:00:00 2001 From: lguohan Date: Sat, 19 Oct 2019 20:43:03 -0700 Subject: [PATCH 093/278] [kvm]: add eeprom.py for kvm image (#3637) --- .../x86_64-kvm_x86_64-r0/plugins/eeprom.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 device/virtual/x86_64-kvm_x86_64-r0/plugins/eeprom.py diff --git a/device/virtual/x86_64-kvm_x86_64-r0/plugins/eeprom.py b/device/virtual/x86_64-kvm_x86_64-r0/plugins/eeprom.py new file mode 100644 index 000000000000..5cc8cb68018f --- /dev/null +++ b/device/virtual/x86_64-kvm_x86_64-r0/plugins/eeprom.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +############################################################################# +# SONiC Virtual switch platform +# +############################################################################# + +class board(): + + def __init__(self, name, path, cpld_root, ro): + return + + def check_status(self): + return "ok" + + def is_checksum_valid(self, e): + return (True, 0) + + def read_eeprom(self): + return \ +""" +TLV Name Code Len Value +-------------------- ---- --- ----- +Product Name 0x21 5 SONiC +Part Number 0x22 6 000000 +Serial Number 0x23 20 0000000000000000000 +Base MAC Address 0x24 6 00:00:00:00:00:01 +Manufacture Date 0x25 19 10/19/2019 00:00:03 +Device Version 0x26 1 1 +Label Revision 0x27 3 A01 +Platform Name 0x28 20 x86_64-kvm_x86_64-r0 +ONIE Version 0x29 19 master-201811170418 +MAC Addresses 0x2A 2 16 +Vendor Name 0x2D 5 SONiC +""" + + def decode_eeprom(self, e): + print e + + def serial_number_str(self, e): + """Return service tag instead of serial number""" + return "000000" From 07235d01d90d4bf54126c60ad5f478567dadface Mon Sep 17 00:00:00 2001 From: Prince Sunny Date: Sat, 19 Oct 2019 20:44:17 -0700 Subject: [PATCH 094/278] [Submodule] Update sonic-swss-common and sonic-swss (#3626) Sonic-swss-common: aaa8133 - 2019-10-12 : Add VRF object table in state_db (#312) [Tyler Li] 91aceb1 - 2019-10-11 : [schema] Update schema to support debug counters (#308) [Danny Allen] 9bcd5ca - 2019-09-28 : [multi-DB] fix vs test, should NOT replace old DBConnector API with new DBConnector API since vs test docker has no database_config.josn (#311) [Dong Zhang] 599155a - 2019-09-25 : [multi-DB] Part 2: C++ interface API changes / swsscommon unit test / LOGLEVEL_DB apply new API (#301) [Dong Zhang] 379ac73 - 2019-09-20 : add bulkremove for consumer_table_pops.lua (#306) [Dong Zhang] 6b805d3 - 2019-09-19 : timerfd return 0 with errno =0 - handle as False alarm. (#302) [Renuka Manavalan] e455891 - 2019-09-03 : Add VLAN_SUB_INTERFACE in CONFIG_DB schema (#284) [Wenda Ni] Sonic-swss 731a8f5 - 2019-10-17 : [copporch]: fix the endless loop problem when removing copp table group. (#1038) [wangshengjun] 1623219 - 2019-10-14 : Enable C++ unit test during build (#1092) [Qi Luo] 629c9d3 - 2019-10-14 : [vstest]: Revert back to 2 sec, and check if we got more than expected number of syslogs (#1091) [Prince Sunny] 80b2ace - 2019-10-11 : sonic-swss/orchagent: Add new protocol trap name support (#1087) [jpxjlrldgit] 9f765f7 - 2019-10-11 : [aclorch]: Check for existing mirror table only when creating a new table (#1089) [Danny Allen] 4c10260 - 2019-10-11 : [vstest]: Update Route test to check for added entry (#1088) [Prince Sunny] e658b64 - 2019-10-11 : [chassisorch]: Add everflow feature for chassis (#1024) [Ze Gan] 5b13387 - 2019-10-10 : [changelog]: Revert changelog that was done for passing VS test. (#1080) [Prince Sunny] 90a690d - 2019-10-10 : [aclorch]: Simplify the TCP flags matching code and support exact value match (#1072) [Shuotian Cheng] 3461710 - 2019-10-09 : Single VRF for ingress and egress flows, skip route replication (#1045) [Prince Sunny] 953474a - 2019-10-03 : [swss]: Do not use namespace in header files (#1081) [Wenda Ni] bd36751 - 2019-10-03 : Change nexthop key to ip & ifname (#977) [tylerlinp] fee1aaa - 2019-10-02 : [teamsyncd]: Check if LAG exists before removing (#1069) [Shuotian Cheng] 175f3de - 2019-09-30 : Update ECMP NHopGroup for Port Channel oper down (#1030) [Sumukha Tumkur Vani] 182940d - 2019-09-26 : [mirrororch]: Remove mirror session state after it is remvoed (#1066) [Shuotian Cheng] d823dd1 - 2019-09-20 : [MirrorOrch]: Mirror Session Retention across Warm Reboot (#1054) [Shuotian Cheng] a5b6e7c - 2019-09-19 : Ignore link local neighbors (#1065) [Prince Sunny] 0ddaba3 - 2019-09-19 : Adopt to signature change of Selectable::readData, which switched (#1061) [Renuka Manavalan] 543bd98 - 2019-09-18 : [aclorch]: Fix table name in counter table for mirror rules (#1060) [Shuotian Cheng] 12c29b4 - 2019-09-19 : Cannot ping to link-local ipv6 interface address of the switch. (#774) [Kiran Kumar Kella] 4d8e08d - 2019-09-18 : change in fpmsyncd to skip the lookup for the Master device name if the route object table value is zero (#1048) [Arvindsrinivasan Lakshmi narasimhan] da514f5 - 2019-09-18 : Do not update lag mtu from teamsyncd (netlink) (#1053) [Prince Sunny] 3fb22e1 - 2019-09-16 : Check warmboot flag during initialization (#1057) [Prince Sunny] d98d1e9 - 2019-09-16 : [aclorch]: Egress mirror action support and action ASIC support check (#963) [Stepan Blyshchak] 313ef5c - 2019-09-09 : Warmboot Vlan neigh restore fix (#1040) [Prince Sunny] 5841e06 - 2019-09-06 : Add dot1p to tc mapping support (#871) [Wenda Ni] 39fe568 - 2019-08-30 : [aclorch]: Revise ACL rule creation/removal logs (#1042) [Shuotian Cheng] c461911 - 2019-08-27 : [copporch]: Fix the typo - mld_v1_done (#1037) [wangshengjun] 34915de - 2019-08-22 : [portsyncd]: Add default catch block in portsyncd (#1033) [SuvarnaMeenakshi] dc81a21 - 2019-08-20 : [vnet]: Fix FDB related failure in "vnet_bitmap" virtual switch test (#1034) [Volodymyr Samotiy] 5ae4226 - 2019-08-19 : [test]: Adjust stale timer for warm-reboot neighborsync test cases (#1031) [zhenggen-xu] 65cbd55 - 2019-08-16 : [build]: Fix compiling warnings using ARM 32 bit compiler (#1015) [arheneus@marvell.com] b611808 - 2019-08-16 : [Orchagent]: Fixbug segmentfault at routeorch (#1025) [Ze Gan] --- src/sonic-swss | 2 +- src/sonic-swss-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sonic-swss b/src/sonic-swss index 252e12cf3a59..731a8f57119d 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit 252e12cf3a592a287a102a3b74ad2152b36781f6 +Subproject commit 731a8f57119d79e6d7ba6196f026a9e24664e074 diff --git a/src/sonic-swss-common b/src/sonic-swss-common index 036a5d36ad30..aaa8133e8be9 160000 --- a/src/sonic-swss-common +++ b/src/sonic-swss-common @@ -1 +1 @@ -Subproject commit 036a5d36ad307303fdd9315bb06f2240842e5999 +Subproject commit aaa8133e8be9eb2a2f924c9eec997a502b795544 From 6cb445cb9e6fbcc7382d57b507183849e3ce7c2c Mon Sep 17 00:00:00 2001 From: ciju-juniper <53076238+ciju-juniper@users.noreply.github.com> Date: Sun, 20 Oct 2019 09:16:32 +0530 Subject: [PATCH 095/278] [Juniper][QFX5210]Adding the system reboot handler (#3599) The following changes are done as part of this commit: - Adding the system reboot handler - Adding swizzle reset case for the reboot reason - Workaround for the boot problem from Golden bios - Adding the logging messages for platform scripts - EEPROM parsing and library routines --- .../sonic-platform-juniper-qfx5210.postinst | 20 +++ .../modules/x86-64-juniper-qfx5210-64x-psu.c | 84 +++++++-- .../service/qfx5210-platform-init.service | 2 + .../qfx5210/sonic_platform/chassis.py | 138 +++++++++++++- .../qfx5210/utils/juniper_qfx5210_monitor.py | 54 +++++- .../qfx5210/utils/juniper_qfx5210_util.py | 170 ++++++++++++++++-- 6 files changed, 429 insertions(+), 39 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.postinst b/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.postinst index 1b00ceb568e6..dcff39f53799 100644 --- a/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.postinst +++ b/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.postinst @@ -1,2 +1,22 @@ systemctl enable qfx5210-platform-init.service systemctl start qfx5210-platform-init.service + +# There are primary and secondary bios in qfx5210 platform. +# There is a problem with bios which prevents the OS booting from the +# secondary bios when the OS was installed using primary bios. +# Secondary bios fails to detect the UEFI partition. Right now +# the workaround is to have a folder structure /EFI/BOOT/BOOT64x.efi + +SONIC_VERSION=$(sonic-cfggen -y /etc/sonic/sonic_version.yml -v build_version) +FIRST_BOOT_FILE="/host/image-${SONIC_VERSION}/platform/firsttime" + +if [ -f $FIRST_BOOT_FILE ]; then + mkdir /tmp/sda1 + mount /dev/sda1 /tmp/sda1 + cd /tmp/sda1/EFI + mkdir BOOT > /dev/null 2>&1 + cp SONiC-OS/grubx64.efi BOOT/BOOTX64.EFI + cd /tmp + umount sda1 + efibootmgr -c -L "SONiC" -l "\EFI\BOOT\BOOTX64.EFI" > /dev/null 2>&1 +fi diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-psu.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-psu.c index d42e61b3c51b..cb283d2d4a1c 100644 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-psu.c +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-psu.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include #define PSU_STATUS_I2C_ADDR 0x60 #define PSU_STATUS_I2C_REG_OFFSET 0x03 @@ -46,6 +48,10 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); static struct qfx5210_64x_psu_data *qfx5210_64x_psu_update_device(struct device *dev); extern int juniper_i2c_cpld_read (u8 cpld_addr, u8 reg); +/* + * This function is defined in juniper_i2c_cpld.c + */ +extern int juniper_i2c_cpld_write(unsigned short, u8, u8); /* Addresses scanned */ @@ -78,6 +84,36 @@ static struct attribute *qfx5210_64x_psu_attributes[] = { NULL }; +static int qfx5210_cpld_soft_reset(struct notifier_block *nb, + unsigned long action, + void *data) +{ + int ret = 0; + + switch (action) { + case SYS_POWER_OFF: + case SYS_HALT: + printk(KERN_CRIT "System halt/power_off\n"); + break; + case SYS_RESTART: + printk(KERN_CRIT "System restart: qfx5210_cpld_soft_reset\n"); + ret = juniper_i2c_cpld_write(0x65, 0x04, 0x01); + if (ret) { + printk(KERN_CRIT "qfx5210_cpld_soft_reset failed\n"); + } + msleep(100); + break; + default: + /* Do Nothing */ + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block qfx5210_nb = { + .notifier_call = qfx5210_cpld_soft_reset, +}; + static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf) { @@ -103,11 +139,6 @@ static const struct attribute_group qfx5210_64x_psu_group = { .attrs = qfx5210_64x_psu_attributes, }; -/* - * This function is defined in juniper_i2c_cpld.c - */ -extern int juniper_i2c_cpld_write(unsigned short, u8, u8); - /* * QFX5210 power off sequence */ @@ -126,7 +157,6 @@ static void qfx5210_cpld_power_off(void) */ static void (*default_pm_power_off)(void); - static int qfx5210_64x_psu_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) { @@ -165,12 +195,7 @@ static int qfx5210_64x_psu_probe(struct i2c_client *client, dev_info(&client->dev, "%s: psu '%s'\n", dev_name(data->hwmon_dev), client->name); - /* - * Store the default poweroff handler for later usage - */ - default_pm_power_off = pm_power_off; - pm_power_off = qfx5210_cpld_power_off; - + return 0; exit_remove: @@ -189,19 +214,14 @@ static int qfx5210_64x_psu_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &qfx5210_64x_psu_group); kfree(data); - - /* - * Restore the poweroff handler - */ - pm_power_off = default_pm_power_off; - + return 0; } enum psu_index { qfx5210_64x_psu1, - qfx5210_64x_psu2 + qfx5210_64x_psu2 }; static const struct i2c_device_id qfx5210_64x_psu_id[] = { @@ -259,11 +279,37 @@ static struct qfx5210_64x_psu_data *qfx5210_64x_psu_update_device(struct device static int __init qfx5210_64x_psu_init(void) { + /* + * Store the default poweroff handler for later usage + */ + default_pm_power_off = pm_power_off; + /* + * Register the cpld poweroff handler + */ + pm_power_off = qfx5210_cpld_power_off; + /* + * Register the cpld soft reset handler + */ + if(register_reboot_notifier(&qfx5210_nb)) { + printk(KERN_ALERT "Restart handler registration failed\n"); + } + return i2c_add_driver(&qfx5210_64x_psu_driver); } static void __exit qfx5210_64x_psu_exit(void) { + /* + * Restore the poweroff handler + */ + pm_power_off = default_pm_power_off; + /* + * Unregister the cpld soft reset handler + */ + if (!unregister_restart_handler(&qfx5210_nb)) { + printk(KERN_CRIT "Failed to uregister restart handler\n"); + } + i2c_del_driver(&qfx5210_64x_psu_driver); } diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/service/qfx5210-platform-init.service b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/service/qfx5210-platform-init.service index b6a446ec1752..46377aa9fdc8 100755 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/service/qfx5210-platform-init.service +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/service/qfx5210-platform-init.service @@ -8,6 +8,8 @@ DefaultDependencies=no ExecStartPre=/usr/local/bin/juniper_qfx5210_util.py install ExecStart=/usr/local/bin/juniper_qfx5210_monitor.py RemainAfterExit=yes +StandardOutput=syslog+console +StandardError=syslog+console [Install] WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/chassis.py index 5d56ef3a0cde..674d9184df3c 100755 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/chassis.py @@ -60,7 +60,7 @@ def __init__(self): def get_qfx5210_parameter_value(self,parameter_name): try: - with open("/var/run/qfx5210_eeprom", "r") as file: + with open("/var/run/eeprom", "r") as file: for item in file: content = item.split('=') if content[0] == parameter_name: @@ -71,29 +71,32 @@ def get_qfx5210_parameter_value(self,parameter_name): return "False" def get_product_name(self): - product_name_list = self.get_qfx5210_parameter_value('ProductName') + product_name_list = self.get_qfx5210_parameter_value('Product Name') if product_name_list: product_name = ''.join(product_name_list) return product_name else: return False + def get_part_number(self): - part_number_list = self.get_qfx5210_parameter_value('PartNumber') + part_number_list = self.get_qfx5210_parameter_value('Part Number') if part_number_list: part_number = ''.join(part_number_list) return part_number else: return False + def get_serial_number(self): - serial_number_list = self.get_qfx5210_parameter_value('SerialNumber') + serial_number_list = self.get_qfx5210_parameter_value('Serial Number') if serial_number_list: serial_number = ''.join(serial_number_list) return serial_number else: return False + def get_base_mac(self): mac_list = self.get_qfx5210_parameter_value('MAC') if mac_list: @@ -102,13 +105,134 @@ def get_base_mac(self): else: return False + + def get_mfg_date(self): + mfgdate_list = self.get_qfx5210_parameter_value('Manufacture Date') + if mfgdate_list: + mfgdate = ''.join(mfgdate_list) + return mfgdate + else: + return False + + def get_deviceversion_name(self): + device_version_list = self.get_qfx5210_parameter_value('Device Version') + if device_version_list: + deviceversion_name = ''.join(device_version_list) + return deviceversion_name + else: + return False + def get_platform_name(self): - platform_name_list = self.get_qfx5210_parameter_value('PlatformName') + platform_name_list = self.get_qfx5210_parameter_value('Platform Name') if platform_name_list: platform_name = ''.join(platform_name_list) return platform_name else: return False + + def get_MACnumber_name(self): + MACnumber_name_list = self.get_qfx5210_parameter_value('Number of MAC Addresses') + if MACnumber_name_list: + MACnumber_name = ''.join(MACnumber_name_list) + return MACnumber_name + else: + return False + + def get_vendor_name(self): + vendor_name_list = self.get_qfx5210_parameter_value('Vendor Name') + if vendor_name_list: + vendor_name = ''.join(vendor_name_list) + return vendor_name + else: + return False + + def get_mfg_name(self): + mfg_name_list = self.get_qfx5210_parameter_value('Manufacture Name') + if mfg_name_list: + mfg_name = ''.join(mfg_name_list) + return mfg_name + else: + return False + + def get_vendorext_name(self): + vendorext_list = self.get_qfx5210_parameter_value('Vendor Extension') + if vendorext_list: + vendorext = ''.join(vendorext_list) + return vendorext + else: + return False + + def get_vendorextIANA_name(self): + vendorext_list = self.get_qfx5210_parameter_value('IANA') + if vendorext_list: + vendorext = ''.join(vendorext_list) + return vendorext + else: + return False + + def get_vendorextASMREV_name(self): + vendorext_list = self.get_qfx5210_parameter_value('Assembly Part Number Rev') + if vendorext_list: + vendorext = ''.join(vendorext_list) + return vendorext + else: + return False + + def get_vendorextASMPartNum_name(self): + vendorext_list = self.get_qfx5210_parameter_value('Assembly Part Number') + if vendorext_list: + vendorext = ''.join(vendorext_list) + return vendorext + else: + return False + + def get_vendorextASMID_name(self): + vendorext_list = self.get_qfx5210_parameter_value('Assembly ID') + if vendorext_list: + vendorext = ''.join(vendorext_list) + return vendorext + else: + return False + + def get_vendorextASMMajNum_name(self): + vendorext_list = self.get_qfx5210_parameter_value('Assembly Major Revision') + if vendorext_list: + vendorext = ''.join(vendorext_list) + return vendorext + else: + return False + + def get_vendorextASMMinNum_name(self): + vendorext_list = self.get_qfx5210_parameter_value('Assembly Minor Revision') + if vendorext_list: + vendorext = ''.join(vendorext_list) + return vendorext + else: + return False + + def get_vendorextCLEI_name(self): + vendorext_list = self.get_qfx5210_parameter_value('CLEI code') + if vendorext_list: + vendorext = ''.join(vendorext_list) + return vendorext + else: + return False + + def get_onieversion_name(self): + onieversion_name_list = self.get_qfx5210_parameter_value('ONIE Version') + if onieversion_name_list: + onieversion_name = ''.join(onieversion_name_list) + return onieversion_name + else: + return False + + def get_crc_name(self): + crc_list = self.get_qfx5210_parameter_value('CRC') + if crc_list: + crc_name = ''.join(crc_list) + return crc_name + else: + return False def get_fan_type(self, fantype_path): try: @@ -134,6 +258,8 @@ def get_reboot_cause(self): return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None) elif last_reboot_reason == "0x20": return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) + elif last_reboot_reason == "0x10": + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset") else: return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason") else: @@ -145,5 +271,7 @@ def get_reboot_cause(self): return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None) elif last_reboot_reason == "0x20": return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) + elif last_reboot_reason == "0x10": + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset") else: return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason") diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py index a74bce042ac3..d225400121b8 100755 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py @@ -53,10 +53,16 @@ # Deafults VERSION = '1.0' -FUNCTION_NAME = '/usr/local/bin/juniper_qfx5210_monitor' +FUNCTION_NAME = '/var/log/juniper_qfx5210_monitor' + + +global log_file +global log_level global isPlatformAFI +global isFireThresholdReached +FireThresholdSecsRemaining = 120 temp_policy_AFI = { 0: [[70, 0, 48000], [70, 48000, 53000], [80, 53000, 0], [80, 53000, 58000], [100, 58000, 0], ['Yellow Alarm', 64000, 70000], ['Red Alarm', 70000, 75000], ['Fire Shut Alarm', 75000, 0]], @@ -268,6 +274,8 @@ def set_alarm_led_brightness(self, val): def getSensorTemp(self): sum = 0 global isPlatformAFI + global isFireThresholdReached + global FireThresholdSecsRemaining #AFI if (isPlatformAFI == True): temp_policy = temp_policy_AFI @@ -287,6 +295,17 @@ def getSensorTemp(self): 5: [0,0,0,0,0,0,0,0], 6: [0,0,0,0,0,0,0,0], } + # if the Firethreshold Flag is set and 120 seconds have elapsed, invoking the "poweroff" to shutdown the box + if (isFireThresholdReached == True): + firethr = FireThresholdSecsRemaining - 20 + logging.critical('CRITICAL: Fire Threshold reached: System is going to shutdown in %s seconds', firethr) + print "Fire Threshold reached: System is going to shutdown in %s seconds\n" % firethr + FireThresholdSecsRemaining = FireThresholdSecsRemaining - 20 + if (FireThresholdSecsRemaining == 20): + isFireThresholdReached == False + time.sleep(20) + cmd = "poweroff" + returned_value = os.system(cmd) for x in range(self.SENSOR_CORETEMP_NUM_ON_MAIN_BOARD): if x < self.SENSOR_NUM_ON_MAIN_BOARD: @@ -332,6 +351,9 @@ def getSensorTemp(self): fan = QFX5210_FanUtil() # CHECK IF ANY TEMPERATURE SENSORS HAS SET FIRE SHUTDOWN FLAG if SensorFlag[0][7] or SensorFlag[1][7] or SensorFlag[2][7] or SensorFlag[3][7] or SensorFlag[4][7] or SensorFlag[5][7] or SensorFlag[6][7]: + isFireThresholdReached = True + logging.critical('CRITICAL: Fire Threshold reached: System is going to shutdown in 120 seconds') + print "CRITICAL: Fire Threshold reached: System is going to shutdown in 120 seconds\n" value = self.get_alarm_led_brightness() if ( value > 0): self.set_alarm_led_brightness(0) @@ -399,12 +421,32 @@ def getSensorTemp(self): class device_monitor(object): - def __init__(self): + def __init__(self, log_file, log_level): + global isPlatformAFI + global isFireThresholdReached MASTER_LED_PATH = '/sys/class/leds/master/brightness' SYSTEM_LED_PATH = '/sys/class/leds/system/brightness' FANTYPE_PATH = '/sys/bus/i2c/devices/17-0068/fan1_direction' + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + import sonic_platform platform = sonic_platform.platform.Platform() chassis = platform.get_chassis() @@ -418,7 +460,8 @@ def __init__(self): isPlatformAFI = False else: isPlatformAFI = True - + + isFireThresholdReached = False master_led_value = 1 try: @@ -444,7 +487,10 @@ def manage_device(self): thermal.getSensorTemp() def main(): - monitor = device_monitor() + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.DEBUG + + monitor = device_monitor(log_file, log_level) while True: monitor.manage_device() time.sleep(20) diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_util.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_util.py index ccb32a3a894a..b3f130af41c0 100755 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_util.py +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_util.py @@ -56,7 +56,7 @@ ALL_DEVICE = {} DEVICE_NO = {'led':4, 'fan':4,'thermal':6, 'psu':2, 'sfp':64} FORCE = 0 - +FUNCTION_NAME = '/var/log/juniper_qfx5210_util' if DEBUG == True: print sys.argv[0] @@ -67,6 +67,9 @@ def main(): global DEBUG global args global FORCE + + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.DEBUG if len(sys.argv)<2: show_help() @@ -75,11 +78,25 @@ def main(): 'debug', 'force', ]) + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S') + if DEBUG == True: print options print args print len(sys.argv) - + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + for opt, arg in options: if opt in ('-h', '--help'): show_help() @@ -114,7 +131,7 @@ def main(): else: show_help() - DisableWatchDogCmd = '/usr/sbin/i2cset -y 0 0x65 0x3 0x04' + DisableWatchDogCmd = '/usr/sbin/i2cset -f -y 0 0x65 0x3 0x04' # Disable watchdog try: os.system(DisableWatchDogCmd) @@ -131,6 +148,135 @@ def main(): print 'Error: Execution of "%s" failed', CPUeepromFileCmd return False + eeprom_ascii = '/etc/init.d/eeprom_qfx5210_ascii' + # Read file contents in Hex format + with open(eeprom_ascii, 'rb') as Hexformat: + content = Hexformat.read() + Hexformatoutput = binascii.hexlify(content) + + eeprom_hex = '/etc/init.d/eeprom_qfx5210_hex' + #Write contents of CPU EEPROM to new file in hexa format + with open(eeprom_hex, 'wb+') as Hexfile: + Hexfile.write(Hexformatoutput) + + # Read from EEPROM Hex file and extract the different fields like Product name, + # Part Number, Serial Number MAC Address, Mfg Date ... etc and store in /var/run/eeprom file + with open(eeprom_hex, 'rb') as eeprom_hexfile: + # moving the file pointer to required position where product name is stored in EEPROM file and reading the required bytes from this position + + product_position = eeprom_hexfile.seek(26, 0) + product_read = eeprom_hexfile.read(36) + product_name = binascii.unhexlify(product_read) + + # creating the "/var/run/eeprom" file and storing all the values of different fields in this file. + eeprom_file = open ("/var/run/eeprom", "a+") + eeprom_file.write("Product Name=%s\r\n" % str(product_name)) + + # like wise we are moving the file pointer to respective position where other fields are stored and extract these fields and store in /var/run/eeprom file + partnumber_position = eeprom_hexfile.seek(66, 0) + partnumber_read = eeprom_hexfile.read(20) + partnumber_name = binascii.unhexlify(partnumber_read) + eeprom_file.write("Part Number=%s\r\n" % str(partnumber_name)) + + serialnumber_position = eeprom_hexfile.seek(90, 0) + serialnumber_read = eeprom_hexfile.read(24) + serialnumber_name = binascii.unhexlify(serialnumber_read) + eeprom_file.write("Serial Number=%s\r\n" % str(serialnumber_name)) + + macaddress_position = eeprom_hexfile.seek(118, 0) + macaddress_read = eeprom_hexfile.read(12) + macaddress_name="" + for i in range(0,12,2): + macaddress_name += macaddress_read[i:i+2] + ":" + macaddress_name=macaddress_name[:-1] + eeprom_file.write("MAC Address=%s\r\n" % str(macaddress_name)) + + mfgdate_position = eeprom_hexfile.seek(132, 0) + mfgdate_read = eeprom_hexfile.read(40) + mfgdate_name = binascii.unhexlify(mfgdate_read) + eeprom_file.write("Manufacture Date=%s\r\n" % str(mfgdate_name)) + + devversion_position = eeprom_hexfile.seek(176, 0) + devversion_read = eeprom_hexfile.read(2) + eeprom_file.write("Device Version=%s\r\n" % str(devversion_read)) + + platform_position = eeprom_hexfile.seek(182, 0) + platform_read = eeprom_hexfile.read(68) + platform_name = binascii.unhexlify(platform_read) + eeprom_file.write("Platform Name=%s\r\n" % str(platform_name)) + + MACnumber_position = eeprom_hexfile.seek(254, 0) + MACnumber_read = eeprom_hexfile.read(4) + MACnumber = int(MACnumber_read, 16) + eeprom_file.write("Number of MAC Addresses=%s\r\n" % str(MACnumber)) + + vendorName_position = eeprom_hexfile.seek(262, 0) + vendorName_read = eeprom_hexfile.read(40) + vendorName = binascii.unhexlify(vendorName_read) + eeprom_file.write("Vendor Name=%s\r\n" % str(vendorName)) + + mfgname_position = eeprom_hexfile.seek(306, 0) + mfgname_read = eeprom_hexfile.read(40) + mfgname = binascii.unhexlify(mfgname_read) + eeprom_file.write("Manufacture Name=%s\r\n" % str(mfgname)) + + vendorext_position = eeprom_hexfile.seek(350, 0) + vendorext_read = eeprom_hexfile.read(124) + vendorext="" + vendorext += "0x" + vendorext_read[0:2] + for i in range(2,124,2): + vendorext += " 0x" + vendorext_read[i:i+2] + eeprom_file.write("Vendor Extension=%s\r\n" % str(vendorext)) + + IANA_position = eeprom_hexfile.seek(350, 0) + IANA_read = eeprom_hexfile.read(8) + IANAName = binascii.unhexlify(IANA_read) + eeprom_file.write("IANA=%s\r\n" % str(IANAName)) + + ASMpartrev_position = eeprom_hexfile.seek(358, 0) + ASMpartrev_read = eeprom_hexfile.read(4) + ASMpartrev = binascii.unhexlify(ASMpartrev_read) + eeprom_file.write("Assembly Part Number Rev=%s\r\n" % str(ASMpartrev)) + + ASMpartnum_position = eeprom_hexfile.seek(374, 0) + ASMpartnum_read = eeprom_hexfile.read(20) + ASMpartnum_read = binascii.unhexlify(ASMpartnum_read) + eeprom_file.write("Assembly Part Number=%s\r\n" % str(ASMpartnum_read)) + + ASMID_position = eeprom_hexfile.seek(402, 0) + ASMID_read = eeprom_hexfile.read(4) + ASMID_read_upper = ASMID_read.upper() + eeprom_file.write("Assembly ID=0x%s\r\n" % str(ASMID_read_upper)) + + ASMHWMajRev_position = eeprom_hexfile.seek(410, 0) + ASMHWMajRev_read = eeprom_hexfile.read(2) + eeprom_file.write("Assembly Major Revision=0x%s\r\n" % str(ASMHWMajRev_read)) + + ASMHWMinRev_position = eeprom_hexfile.seek(416, 0) + ASMHWMinRev_read = eeprom_hexfile.read(2) + eeprom_file.write("Assembly Minor Revision=0x%s\r\n" % str(ASMHWMinRev_read)) + + Deviation_position = eeprom_hexfile.seek(422, 0) + Deviation_read = eeprom_hexfile.read(28) + Deviation_read_upper = Deviation_read.upper() + eeprom_file.write("Deviation=0x%s\r\n" % str(Deviation_read_upper)) + + CLEI_position = eeprom_hexfile.seek(450, 0) + CLEI_read = eeprom_hexfile.read(20) + CLEI_name = binascii.unhexlify(CLEI_read) + eeprom_file.write("CLEI code=%s\r\n" % str(CLEI_name)) + + ONIEversion_position = eeprom_hexfile.seek(478, 0) + ONIEversion_read = eeprom_hexfile.read(22) + ONIEversion = binascii.unhexlify(ONIEversion_read) + eeprom_file.write("ONIE Version=%s\r\n" % str(ONIEversion)) + + CRC_position = eeprom_hexfile.seek(504, 0) + CRC = eeprom_hexfile.read(8) + eeprom_file.write("CRC=%s\r\n" % str(CRC)) + + eeprom_file.close() + return True def show_help(): @@ -152,7 +298,7 @@ def show_eeprom_help(): def my_log(txt): if DEBUG == True: - print "[ROY]"+txt + print txt return def log_os_system(cmd, show): @@ -253,7 +399,9 @@ def driver_uninstall(): 'echo cpld_qfx5210 0x60 > /sys/bus/i2c/devices/i2c-19/new_device', 'echo cpld_plain 0x62 > /sys/bus/i2c/devices/i2c-20/new_device', 'echo cpld_plain 0x64 > /sys/bus/i2c/devices/i2c-21/new_device', -'echo cpld_plain 0x66 > /sys/bus/i2c/devices/i2c-22/new_device'] +'echo cpld_plain 0x66 > /sys/bus/i2c/devices/i2c-22/new_device', +'echo cpld_plain 0x65 > /sys/bus/i2c/devices/i2c-0/new_device 2>/dev/null' +] def i2c_order_check(): return 0 @@ -322,9 +470,9 @@ def system_ready(): return True def do_install(): - print "Checking system...." + logging.info('Checking system....') if driver_check() == False: - print "No driver, installing...." + logging.info('No driver, installing....') status = driver_install() if status: if FORCE == 0: @@ -332,7 +480,7 @@ def do_install(): else: print PROJECT_NAME.upper()+" drivers detected...." if not device_exist(): - print "No device, installing...." + logging.info('No device, installing....') status = device_install() if status: if FORCE == 0: @@ -342,11 +490,11 @@ def do_install(): return def do_uninstall(): - print "Checking system...." + logging.info('Checking system....') if not device_exist(): print PROJECT_NAME.upper() +" has no device installed...." else: - print "Removing device...." + logging.info('Removing device....') status = device_uninstall() if status: if FORCE == 0: @@ -355,7 +503,7 @@ def do_uninstall(): if driver_check()== False : print PROJECT_NAME.upper() +" has no driver installed...." else: - print "Removing installed driver...." + logging.info('Removing installed driver....') status = driver_uninstall() if status: if FORCE == 0: From 206df4327f07faeff97fd432d5c8e3228ca48a31 Mon Sep 17 00:00:00 2001 From: Wenda Ni Date: Tue, 22 Oct 2019 09:37:45 -0700 Subject: [PATCH 096/278] Adopt per-port buffer & qos profile apply on mellanox (#3543) Signed-off-by: Wenda Ni --- .../ACS-MSN2700/buffers_defaults_t0.j2 | 29 ++++++++++++++----- .../ACS-MSN2700/buffers_defaults_t1.j2 | 29 ++++++++++++++----- .../ACS-MSN3700/buffers_defaults_t0.j2 | 29 ++++++++++++++----- .../ACS-MSN3700/buffers_defaults_t1.j2 | 29 ++++++++++++++----- 4 files changed, 84 insertions(+), 32 deletions(-) diff --git a/device/mellanox/x86_64-mlnx_msn2700-r0/ACS-MSN2700/buffers_defaults_t0.j2 b/device/mellanox/x86_64-mlnx_msn2700-r0/ACS-MSN2700/buffers_defaults_t0.j2 index 018c2f96bc1b..8c3cac4b80b8 100644 --- a/device/mellanox/x86_64-mlnx_msn2700-r0/ACS-MSN2700/buffers_defaults_t0.j2 +++ b/device/mellanox/x86_64-mlnx_msn2700-r0/ACS-MSN2700/buffers_defaults_t0.j2 @@ -65,28 +65,41 @@ {%- macro generate_profile_lists(port_names) %} "BUFFER_PORT_INGRESS_PROFILE_LIST": { - "{{ port_names }}": { +{% for port in port_names.split(',') %} + "{{ port }}": { "profile_list" : "[BUFFER_PROFILE|ingress_lossless_profile],[BUFFER_PROFILE|ingress_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} }, "BUFFER_PORT_EGRESS_PROFILE_LIST": { - "{{ port_names }}": { +{% for port in port_names.split(',') %} + "{{ port }}": { "profile_list" : "[BUFFER_PROFILE|egress_lossless_profile],[BUFFER_PROFILE|egress_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} } {%- endmacro %} {%- macro generate_queue_buffers(port_names) %} "BUFFER_QUEUE": { - "{{ port_names }}|3-4": { +{% for port in port_names.split(',') %} + "{{ port }}|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, - "{{ port_names }}|0-1": { +{% endfor %} +{% for port in port_names.split(',') %} + "{{ port }}|0-2": { "profile" : "[BUFFER_PROFILE|q_lossy_profile]" }, - "{{ port_names }}|5": { +{% endfor %} +{% for port in port_names.split(',') %} + "{{ port }}|5-6": { "profile" : "[BUFFER_PROFILE|q_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} } {%- endmacro %} diff --git a/device/mellanox/x86_64-mlnx_msn2700-r0/ACS-MSN2700/buffers_defaults_t1.j2 b/device/mellanox/x86_64-mlnx_msn2700-r0/ACS-MSN2700/buffers_defaults_t1.j2 index c315ccf59547..45433b1b2641 100644 --- a/device/mellanox/x86_64-mlnx_msn2700-r0/ACS-MSN2700/buffers_defaults_t1.j2 +++ b/device/mellanox/x86_64-mlnx_msn2700-r0/ACS-MSN2700/buffers_defaults_t1.j2 @@ -65,28 +65,41 @@ {%- macro generate_profile_lists(port_names) %} "BUFFER_PORT_INGRESS_PROFILE_LIST": { - "{{ port_names }}": { +{% for port in port_names.split(',') %} + "{{ port }}": { "profile_list" : "[BUFFER_PROFILE|ingress_lossless_profile],[BUFFER_PROFILE|ingress_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} }, "BUFFER_PORT_EGRESS_PROFILE_LIST": { - "{{ port_names }}": { +{% for port in port_names.split(',') %} + "{{ port }}": { "profile_list" : "[BUFFER_PROFILE|egress_lossless_profile],[BUFFER_PROFILE|egress_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} } {%- endmacro %} {%- macro generate_queue_buffers(port_names) %} "BUFFER_QUEUE": { - "{{ port_names }}|3-4": { +{% for port in port_names.split(',') %} + "{{ port }}|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, - "{{ port_names }}|0-1": { +{% endfor %} +{% for port in port_names.split(',') %} + "{{ port }}|0-2": { "profile" : "[BUFFER_PROFILE|q_lossy_profile]" }, - "{{ port_names }}|5": { +{% endfor %} +{% for port in port_names.split(',') %} + "{{ port }}|5-6": { "profile" : "[BUFFER_PROFILE|q_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} } {%- endmacro %} diff --git a/device/mellanox/x86_64-mlnx_msn3700-r0/ACS-MSN3700/buffers_defaults_t0.j2 b/device/mellanox/x86_64-mlnx_msn3700-r0/ACS-MSN3700/buffers_defaults_t0.j2 index 89b269456458..d40bc03fbb59 100644 --- a/device/mellanox/x86_64-mlnx_msn3700-r0/ACS-MSN3700/buffers_defaults_t0.j2 +++ b/device/mellanox/x86_64-mlnx_msn3700-r0/ACS-MSN3700/buffers_defaults_t0.j2 @@ -65,27 +65,40 @@ {%- macro generate_profile_lists(port_names) %} "BUFFER_PORT_INGRESS_PROFILE_LIST": { - "{{ port_names }}": { +{% for port in port_names.split(',') %} + "{{ port }}": { "profile_list" : "[BUFFER_PROFILE|ingress_lossless_profile],[BUFFER_PROFILE|ingress_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} }, "BUFFER_PORT_EGRESS_PROFILE_LIST": { - "{{ port_names }}": { +{% for port in port_names.split(',') %} + "{{ port }}": { "profile_list" : "[BUFFER_PROFILE|egress_lossless_profile],[BUFFER_PROFILE|egress_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} } {%- endmacro %} {%- macro generate_queue_buffers(port_names) %} "BUFFER_QUEUE": { - "{{ port_names }}|3-4": { +{% for port in port_names.split(',') %} + "{{ port }}|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, - "{{ port_names }}|0-1": { +{% endfor %} +{% for port in port_names.split(',') %} + "{{ port }}|0-2": { "profile" : "[BUFFER_PROFILE|q_lossy_profile]" }, - "{{ port_names }}|5": { +{% endfor %} +{% for port in port_names.split(',') %} + "{{ port }}|5-6": { "profile" : "[BUFFER_PROFILE|q_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} } {%- endmacro %} diff --git a/device/mellanox/x86_64-mlnx_msn3700-r0/ACS-MSN3700/buffers_defaults_t1.j2 b/device/mellanox/x86_64-mlnx_msn3700-r0/ACS-MSN3700/buffers_defaults_t1.j2 index d9db9c2d255e..fe8c27b9d364 100644 --- a/device/mellanox/x86_64-mlnx_msn3700-r0/ACS-MSN3700/buffers_defaults_t1.j2 +++ b/device/mellanox/x86_64-mlnx_msn3700-r0/ACS-MSN3700/buffers_defaults_t1.j2 @@ -65,27 +65,40 @@ {%- macro generate_profile_lists(port_names) %} "BUFFER_PORT_INGRESS_PROFILE_LIST": { - "{{ port_names }}": { +{% for port in port_names.split(',') %} + "{{ port }}": { "profile_list" : "[BUFFER_PROFILE|ingress_lossless_profile],[BUFFER_PROFILE|ingress_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} }, "BUFFER_PORT_EGRESS_PROFILE_LIST": { - "{{ port_names }}": { +{% for port in port_names.split(',') %} + "{{ port }}": { "profile_list" : "[BUFFER_PROFILE|egress_lossless_profile],[BUFFER_PROFILE|egress_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} } {%- endmacro %} {%- macro generate_queue_buffers(port_names) %} "BUFFER_QUEUE": { - "{{ port_names }}|3-4": { +{% for port in port_names.split(',') %} + "{{ port }}|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, - "{{ port_names }}|0-1": { +{% endfor %} +{% for port in port_names.split(',') %} + "{{ port }}|0-2": { "profile" : "[BUFFER_PROFILE|q_lossy_profile]" }, - "{{ port_names }}|5": { +{% endfor %} +{% for port in port_names.split(',') %} + "{{ port }}|5-6": { "profile" : "[BUFFER_PROFILE|q_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} } {%- endmacro %} From a0fbeeaca5e8e1d8d0f1a3e2e33001cf52863783 Mon Sep 17 00:00:00 2001 From: yozhao101 <56170650+yozhao101@users.noreply.github.com> Date: Tue, 22 Oct 2019 14:41:12 -0700 Subject: [PATCH 097/278] [Services] Restart SNMP service upon unexpected critical process exit. (#3650) Signed-off-by: Yong Zhao --- dockers/docker-snmp-sv2/Dockerfile.j2 | 2 ++ dockers/docker-snmp-sv2/critical_processes | 2 ++ dockers/docker-snmp-sv2/supervisord.conf | 8 +++++++- files/build_templates/snmp.service.j2 | 4 ++++ rules/docker-snmp-sv2.mk | 1 + 5 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 dockers/docker-snmp-sv2/critical_processes diff --git a/dockers/docker-snmp-sv2/Dockerfile.j2 b/dockers/docker-snmp-sv2/Dockerfile.j2 index 9905e7eee2de..b62ff61eaf95 100644 --- a/dockers/docker-snmp-sv2/Dockerfile.j2 +++ b/dockers/docker-snmp-sv2/Dockerfile.j2 @@ -84,6 +84,8 @@ RUN apt-get -y purge \ COPY ["start.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] COPY ["*.j2", "/usr/share/sonic/templates/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor"] # Although exposing ports is not needed for host net mode, keep it for possible bridge mode EXPOSE 161/udp 162/udp diff --git a/dockers/docker-snmp-sv2/critical_processes b/dockers/docker-snmp-sv2/critical_processes new file mode 100644 index 000000000000..e6039c5b9840 --- /dev/null +++ b/dockers/docker-snmp-sv2/critical_processes @@ -0,0 +1,2 @@ +snmpd +snmp-subagent diff --git a/dockers/docker-snmp-sv2/supervisord.conf b/dockers/docker-snmp-sv2/supervisord.conf index d80579506100..7fd16eec5bbe 100644 --- a/dockers/docker-snmp-sv2/supervisord.conf +++ b/dockers/docker-snmp-sv2/supervisord.conf @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 @@ -15,7 +21,7 @@ stderr_logfile=syslog command=/usr/sbin/rsyslogd -n priority=2 autostart=false -autorestart=false +autorestart=unexpected stdout_logfile=syslog stderr_logfile=syslog diff --git a/files/build_templates/snmp.service.j2 b/files/build_templates/snmp.service.j2 index 43f46bd2b9c0..a05c5fbe1d09 100644 --- a/files/build_templates/snmp.service.j2 +++ b/files/build_templates/snmp.service.j2 @@ -4,11 +4,15 @@ Requires=updategraph.service Requisite=swss.service After=updategraph.service swss.service Before=ntp-config.service +StartLimitIntervalSec=1200 +StartLimitBurst=3 [Service] ExecStartPre=/usr/bin/{{docker_container_name}}.sh start ExecStart=/usr/bin/{{docker_container_name}}.sh wait ExecStop=/usr/bin/{{docker_container_name}}.sh stop +Restart=always +RestartSec=30 [Install] WantedBy=multi-user.target swss.service diff --git a/rules/docker-snmp-sv2.mk b/rules/docker-snmp-sv2.mk index 2a533b436191..bd34f271b861 100644 --- a/rules/docker-snmp-sv2.mk +++ b/rules/docker-snmp-sv2.mk @@ -30,3 +30,4 @@ $(DOCKER_SNMP_SV2)_RUN_OPT += --net=host --privileged -t $(DOCKER_SNMP_SV2)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro # mount Arista platform python libraries to support corresponding platforms SNMP power status query $(DOCKER_SNMP_SV2)_RUN_OPT += -v /usr/lib/python3/dist-packages/arista:/usr/lib/python3/dist-packages/arista:ro +$(DOCKER_SNMP_SV2)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) From 9fb18604251551aa60310122060a7ac029bc5fb0 Mon Sep 17 00:00:00 2001 From: Ying Xie Date: Tue, 22 Oct 2019 19:02:08 -0700 Subject: [PATCH 098/278] [file permission] explicitly set file permission on passwd, group, shadow (#3652) Signed-off-by: Ying Xie --- build_debian.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build_debian.sh b/build_debian.sh index c1a13d1ae7d3..d1e5273b1c71 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -282,6 +282,13 @@ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y in mcelog fi +## Set /etc/shadow permissions to -rw-------. +sudo LANG=c chroot $FILESYSTEM_ROOT chmod 600 /etc/shadow + +## Set /etc/passwd, /etc/group permissions to -rw-r--r--. +sudo LANG=c chroot $FILESYSTEM_ROOT chmod 644 /etc/passwd +sudo LANG=c chroot $FILESYSTEM_ROOT chmod 644 /etc/group + #Adds a locale to a debian system in non-interactive mode sudo sed -i '/^#.* en_US.* /s/^#//' $FILESYSTEM_ROOT/etc/locale.gen && \ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT locale-gen "en_US.UTF-8" From 8d162ae70a6df3feb61b63e4d421eb4e22494ef7 Mon Sep 17 00:00:00 2001 From: Michel Moriniaux Date: Wed, 23 Oct 2019 09:36:10 -0700 Subject: [PATCH 099/278] [doc]: Added branch 201904 to the build status icons (#3642) Somehow this was missed in april, I added the icons for 201904 so that the branch is not forgotten Signed-off-by: Michel Moriniaux --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 08375dce678b..129af89f05d4 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,15 @@ Nephos: [![Nephos](https://sonic-jenkins.westus2.cloudapp.azure.com/job/nephos/j P4: [![P4](https://sonic-jenkins.westus2.cloudapp.azure.com/job/p4/job/buildimage-p4-all/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/p4/job/buildimage-p4-all) VS: [![VS](https://sonic-jenkins.westus2.cloudapp.azure.com/job/vs/job/buildimage-vs-all/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/vs/job/buildimage-vs-all) +*201904*: +Broadcom: [![Broadcom](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201904/) +Barefoot: [![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201904/) +Centec: [![Centec](https://sonic-jenkins.westus2.cloudapp.azure.com/job/centec/job/buildimage-centec-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/centec/job/buildimage-centec-201904/) +Nephos: [![Nephos](https://sonic-jenkins.westus2.cloudapp.azure.com/job/nephos/job/buildimage-nephos-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/nephos/job/buildimage-nephos-201904/) +Marvell: [![Marvell](https://sonic-jenkins.westus2.cloudapp.azure.com/job/marvell/job/buildimage-mrvl-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/marvell/job/buildimage-mrvl-201904/) +Mellanox: [![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-201904/) +VS: [![VS](https://sonic-jenkins.westus2.cloudapp.azure.com/job/vs/job/buildimage-vs-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/vs/job/buildimage-vs-201904) + *201811*: Broadcom: [![Broadcom](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201811/) Barefoot: [![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201811/) From 63328814fc786d04eddabb544edad60235867977 Mon Sep 17 00:00:00 2001 From: Danny Allen <52468448+daall@users.noreply.github.com> Date: Wed, 23 Oct 2019 15:55:47 -0700 Subject: [PATCH 100/278] [core_cleanup] Fix issue where core_cleanup job runs too frequently (#3659) Signed-off-by: Danny Allen --- files/image_config/cron.d/core_cleanup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/image_config/cron.d/core_cleanup b/files/image_config/cron.d/core_cleanup index b1c379da9ebb..8db064ea57d6 100644 --- a/files/image_config/cron.d/core_cleanup +++ b/files/image_config/cron.d/core_cleanup @@ -1,3 +1,3 @@ # Attempts to clean up core files every 2 hours -* */2 * * * root /usr/bin/core_cleanup.py > /dev/null 2>&1 +0 */2 * * * root /usr/bin/core_cleanup.py > /dev/null 2>&1 From 74a28bf062321bf23c9d42286acb9aa32c8e31ac Mon Sep 17 00:00:00 2001 From: Prince Sunny Date: Wed, 23 Oct 2019 21:39:48 -0700 Subject: [PATCH 101/278] [Submodule] Update sonic-utilities (#3660) c12c443 - 2019-10-22 : [command reference] add warm reboot command document (#704) [Ying Xie] e25cf29 - 2019-10-22 : [PR template] Add reminder to add/modify/remove unit tests as appropriate (#708) [Joe LeVeque] 66eafce - 2019-10-19 : [Command Reference] Unify style and formatting; Fix organization; Other fixes (#707) [Joe LeVeque] f32a450 - 2019-10-19 : [generate_dump] Make regex more specific for disabling/enabling logrotate (#701) [Kalimuthu-Velappan] d77c411 - 2019-10-18 : [netstat]: Fix for negative output values of counters after clear counters operation (#697) [lyndonsiao] fc324f2 - 2019-10-18 : [neighbor_advertiser]: Adapt to different mirror ACL table names (#703) [Shuotian Cheng] 342f3a1 - 2019-10-08 : [intfstat,portstat] fix table_as_json (#691) [Mykola F] 5564d87 - 2019-10-07 : [acl-loader] egress mirror action support and action ASIC support check (#575) [Stepan Blyshchak] --- src/sonic-utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-utilities b/src/sonic-utilities index 02375e195394..c12c4434fa24 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit 02375e195394cd84fb2e7639f953a72b894ed000 +Subproject commit c12c4434fa2440914a705b9b15d142012eac4ce0 From e883d35ce1eb00aa1ee1dd99b28ef29e7fb23abe Mon Sep 17 00:00:00 2001 From: InventecJamesHuang <45092023+InventecJamesHuang@users.noreply.github.com> Date: Thu, 24 Oct 2019 12:40:43 +0800 Subject: [PATCH 102/278] [devices]: Adding pre-emphasis for Inventec d6356 platform (#3643) Added pre-emphasis values for the Inventec d6356 platform using media_settings.json. --- .../media_settings.json | 707 ++++++++++++++++++ 1 file changed, 707 insertions(+) create mode 100644 device/inventec/x86_64-inventec_d6356-r0/media_settings.json diff --git a/device/inventec/x86_64-inventec_d6356-r0/media_settings.json b/device/inventec/x86_64-inventec_d6356-r0/media_settings.json new file mode 100644 index 000000000000..f688fcb48a08 --- /dev/null +++ b/device/inventec/x86_64-inventec_d6356-r0/media_settings.json @@ -0,0 +1,707 @@ +{ + "PORT_MEDIA_SETTINGS": { + "0": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x0B3D01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0F4B0A" + } + } + }, + "1": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x0A3C01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x104A0A" + } + } + }, + "2": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x0B3D01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0E4C0A" + } + } + }, + "3": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x083200" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0E4C0A" + } + } + }, + "4": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x0A3D01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0D4D0A" + } + } + }, + "5": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x083400" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0D4D0A" + } + } + }, + "6": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x0A3801" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0D4D0A" + } + } + }, + "7": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x083400" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0D4D0A" + } + } + }, + "8": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x093801" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0C4E0A" + } + } + }, + "9": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x083400" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0D4D0A" + } + } + }, + "10": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x083601" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0B4F0A" + } + } + }, + "11": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x083400" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0C4E0A" + } + } + }, + "12": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x083401" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0A500A" + } + } + }, + "13": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x073200" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0A500A" + } + } + }, + "14": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x083401" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x09510A" + } + } + }, + "15": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x063101" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x09510A" + } + } + }, + "16": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x063401" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x08520A" + } + } + }, + "17": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x063201" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x08520A" + } + } + }, + "18": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x063001" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x07530A" + } + } + }, + "19": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052E00" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x07530A" + } + } + }, + "20": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x063001" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x06540A" + } + } + }, + "21": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052E00" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x07530A" + } + } + }, + "22": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052E01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x05550A" + } + } + }, + "23": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x062D01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x06540A" + } + } + }, + "24": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x063000" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x05550A" + } + } + }, + "25": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x062D01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x06540A" + } + } + }, + "26": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052C00" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x05550A" + } + } + }, + "27": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052C01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x05550A" + } + } + }, + "28": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052C00" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x04560A" + } + } + }, + "29": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052C00" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x05550A" + } + } + }, + "30": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052C00" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x05550A" + } + } + }, + "31": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x062E01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x06540A" + } + } + }, + "32": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052D00" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x06540A" + } + } + }, + "33": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x062E01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x07530A" + } + } + }, + "34": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052D00" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x06540A" + } + } + }, + "35": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052D00" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x07530A" + } + } + }, + "36": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052E00" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x06540A" + } + } + }, + "37": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052C01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x08520A" + } + } + }, + "38": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x082E00" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x08520A" + } + } + }, + "39": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x062D01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x09510A" + } + } + }, + "40": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x072C01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x06540A" + } + } + }, + "41": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052D00" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x06540A" + } + } + }, + "42": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x063001" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x06540A" + } + } + }, + "43": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052D01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x08520A" + } + } + }, + "44": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x083401" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x09510A" + } + } + }, + "45": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x052D01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x09510A" + } + } + }, + "46": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x093901" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x09510A" + } + } + }, + "47": { + "FINISAR CORP.-FTLX8571D3BCL": { + "preemphasis": { + "lane0":"0x072D01" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0A500A" + } + } + }, + "48": { + "FINISAR CORP-FTL410QE2C": { + "preemphasis": { + "lane0":"0x083101", + "lane1":"0x083201", + "lane2":"0x083001", + "lane3":"0x093001" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x07530A", + "lane1":"0x05550A", + "lane2":"0x07530A", + "lane3":"0x05550A" + } + } + }, + "49": { + "FINISAR CORP-FTL410QE2C": { + "preemphasis": { + "lane0":"0x082E01", + "lane1":"0x083301", + "lane2":"0x083101", + "lane3":"0x093102" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x05550A" + } + } + }, + "50": { + "FINISAR CORP-FTL410QE2C": { + "preemphasis": { + "lane0":"0x082F01", + "lane1":"0x083001", + "lane2":"0x083201", + "lane3":"0x093202" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x07530A" + } + } + }, + "51": { + "FINISAR CORP-FTL410QE2C": { + "preemphasis": { + "lane0":"0x083001", + "lane1":"0x0A3101", + "lane2":"0x083301", + "lane3":"0x093302" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x085309", + "lane1":"0x0B4F0A", + "lane2":"0x085309", + "lane3":"0x0B4F0A" + } + } + }, + "52": { + "FINISAR CORP-FTL410QE2C": { + "preemphasis": { + "lane0":"0x093101", + "lane1":"0x0A3201", + "lane2":"0x0A3402", + "lane3":"0x093402" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0B4F0A" + } + } + }, + "53": { + "FINISAR CORP-FTL410QE2C": { + "preemphasis": { + "lane0":"0x093201", + "lane1":"0x0A3301", + "lane2":"0x093401", + "lane3":"0x093502" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0B4F0A" + } + } + }, + "54": { + "FINISAR CORP-FTL410QE2C": { + "preemphasis": { + "lane0":"0x093101", + "lane1":"0x0A3401", + "lane2":"0x0A3501", + "lane3":"0x093602" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0B4F0A" + } + } + }, + "55": { + "FINISAR CORP-FTL410QE2C": { + "preemphasis": { + "lane0":"0x093201", + "lane1":"0x0A3501", + "lane2":"0x0A3601", + "lane3":"0x093701" + } + }, + "Default": { + "preemphasis": { + "lane0":"0x0D4E09" + } + } + } + } +} + From 8457248d01e21662821bf3e8268a6335032052b7 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Thu, 24 Oct 2019 07:35:14 -0700 Subject: [PATCH 103/278] [bgpcfgd]: Split default bgp config into main config and peer template (#3627) Now it's possible to add and remove peers based on ConfigDB - What I did Fixed functionality for dynamically adding/removing static bgp peers. - How I did it Split the bgp default template on bgp part and bgp peer part Changed bgpcfgd to use 1. - How to verify it Build an image and run on your DUT --- dockers/docker-fpm-frr/bgpcfgd | 252 +++++++++++++----- dockers/docker-fpm-frr/bgpd.conf.default.j2 | 79 ++---- dockers/docker-fpm-frr/bgpd.conf.j2 | 21 +- ...bgpd.conf.spine_chassis_frontend_router.j2 | 67 +---- dockers/docker-fpm-frr/bgpd.peer.conf.j2 | 30 +++ dockers/docker-fpm-frr/daemons.common.conf.j2 | 12 + dockers/docker-fpm-frr/frr.conf.j2 | 202 +------------- dockers/docker-fpm-frr/start.sh | 4 +- dockers/docker-fpm-frr/staticd.conf.j2 | 21 +- .../staticd.default_route.conf.j2 | 10 + dockers/docker-fpm-frr/zebra.conf.j2 | 71 +---- .../docker-fpm-frr/zebra.interfaces.conf.j2 | 60 +++++ src/sonic-config-engine/sonic-cfggen | 9 + .../tests/sample_output/bgpd_frr.conf | 101 ++----- .../tests/sample_output/frr.conf | 125 ++++----- .../tests/sample_output/staticd_frr.conf | 9 +- .../sample_output/t2-chassis-fe-bgpd.conf | 67 ++--- .../t2-chassis-fe-vni-zebra.conf | 11 +- .../sample_output/t2-chassis-fe-zebra.conf | 11 +- .../tests/sample_output/zebra_frr.conf | 11 +- src/sonic-config-engine/tests/test_frr.py | 62 +++++ src/sonic-config-engine/tests/test_j2files.py | 28 -- .../tests/test_j2files_t2_chassis_fe.py | 49 ++-- 23 files changed, 572 insertions(+), 740 deletions(-) create mode 100644 dockers/docker-fpm-frr/bgpd.peer.conf.j2 create mode 100644 dockers/docker-fpm-frr/daemons.common.conf.j2 create mode 100644 dockers/docker-fpm-frr/staticd.default_route.conf.j2 create mode 100644 dockers/docker-fpm-frr/zebra.interfaces.conf.j2 create mode 100644 src/sonic-config-engine/tests/test_frr.py diff --git a/dockers/docker-fpm-frr/bgpcfgd b/dockers/docker-fpm-frr/bgpcfgd index f6d0b86385b5..4ba8977fddfa 100755 --- a/dockers/docker-fpm-frr/bgpcfgd +++ b/dockers/docker-fpm-frr/bgpcfgd @@ -1,124 +1,250 @@ #!/usr/bin/env python import sys -import copy -import Queue -import redis import subprocess +import datetime +import time import syslog +import signal +import traceback import os +import shutil +import tempfile +import json +from collections import defaultdict +from pprint import pprint + +import jinja2 +import netaddr from swsscommon import swsscommon -def run_command(command): - syslog.syslog(syslog.LOG_DEBUG, "execute command {}.".format(command)) - p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) - stdout = p.communicate()[0] - p.wait() +g_run = True +g_debug = False + + +def run_command(command, shell=False): + str_cmd = " ".join(command) + if g_debug: + syslog.syslog(syslog.LOG_DEBUG, "execute command {}.".format(str_cmd)) + p = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = p.communicate() if p.returncode != 0: - syslog.syslog(syslog.LOG_ERR, 'command execution returned {}. Command: "{}", stdout: "{}"'.format(p.returncode, command, stdout)) + syslog.syslog(syslog.LOG_ERR, 'command execution returned {}. Command: "{}", stdout: "{}", stderr: "{}"'.format(p.returncode, str_cmd, stdout, stderr)) + + return p.returncode, stdout, stderr + +class TemplateFabric(object): + def __init__(self): + j2_template_paths = ['/usr/share/sonic/templates'] + j2_loader = jinja2.FileSystemLoader(j2_template_paths) + j2_env = jinja2.Environment(loader=j2_loader, trim_blocks=True) + j2_env.filters['ipv4'] = self.is_ipv4 + j2_env.filters['ipv6'] = self.is_ipv6 + self.env = j2_env + + def from_file(self, filename): + return self.env.get_template(filename) + + def from_string(self, tmpl): + return self.env.from_string(tmpl) + + @staticmethod + def is_ipv4(value): + if not value: + return False + if isinstance(value, netaddr.IPNetwork): + addr = value + else: + try: + addr = netaddr.IPNetwork(str(value)) + except: + return False + return addr.version == 4 + + @staticmethod + def is_ipv6(value): + if not value: + return False + if isinstance(value, netaddr.IPNetwork): + addr = value + else: + try: + addr = netaddr.IPNetwork(str(value)) + except: + return False + return addr.version == 6 class BGPConfigManager(object): def __init__(self, daemon): - self.daemon = daemon self.bgp_asn = None - self.bgp_message = Queue.Queue(0) + self.meta = None + self.bgp_messages = [] + self.peers = self.load_peers() # we can have bgp monitors peers here. it could be fixed by adding support for it here + fabric = TemplateFabric() + self.bgp_peer_add_template = fabric.from_file('bgpd.peer.conf.j2') + self.bgp_peer_del_template = fabric.from_string('no neighbor {{ neighbor_addr }}') + self.bgp_peer_shutdown = fabric.from_string('neighbor {{ neighbor_addr }} shutdown') + self.bgp_peer_no_shutdown = fabric.from_string('no neighbor {{ neighbor_addr }} shutdown') daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, self.__metadata_handler) daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_BGP_NEIGHBOR_TABLE_NAME, self.__bgp_handler) + def load_peers(self): + peers = set() + command = ["vtysh", "-c", "show bgp neighbors json"] + rc, out, err = run_command(command) + if rc == 0: + js_bgp = json.loads(out) + peers = set(js_bgp.keys()) + return peers + def __metadata_handler(self, key, op, data): if key != "localhost" \ or "bgp_asn" not in data \ or self.bgp_asn == data["bgp_asn"]: return - # TODO add ASN update commands + # TODO add ASN update commands + self.meta = { 'localhost': data } self.bgp_asn = data["bgp_asn"] self.__update_bgp() def __update_bgp(self): - while not self.bgp_message.empty(): - key, op, data = self.bgp_message.get() - syslog.syslog(syslog.LOG_INFO, 'value for {} changed to {}'.format(key, data)) + cmds = [] + for key, op, data in self.bgp_messages: if op == swsscommon.SET_COMMAND: - command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'neighbor {} remote-as {}'".format(self.bgp_asn, key, data['asn']) - run_command(command) - if "name" in data: - command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'neighbor {} description {}'".format(self.bgp_asn, key, data['name']) - run_command(command) - if "admin_status" in data: - command_mod = "no " if data["admin_status"] == "up" else "" - command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c '{}neighbor {} shutdown'".format(self.bgp_asn, command_mod, key) - run_command(command) + if key not in self.peers: + cmds.append(self.bgp_peer_add_template.render(DEVICE_METADATA=self.meta, neighbor_addr=key, bgp_session=data)) + syslog.syslog(syslog.LOG_INFO, 'Peer {} added with attributes {}'.format(key, data)) + self.peers.add(key) + else: + # when the peer is already configured we support "shutdown/no shutdown" + # commands for the peers only + if "admin_status" in data: + if data['admin_status'] == 'up': + cmds.append(self.bgp_peer_no_shutdown.render(neighbor_addr=key)) + syslog.syslog(syslog.LOG_INFO, 'Peer {} admin state is set to "up"'.format(key)) + elif data['admin_status'] == 'down': + cmds.append(self.bgp_peer_shutdown.render(neighbor_addr=key)) + syslog.syslog(syslog.LOG_INFO, 'Peer {} admin state is set to "down"'.format(key)) + else: + syslog.syslog(syslog.LOG_ERR, "Peer {}: Can't update the peer. has wrong attribute value attr['admin_status'] = '{}'".format(key, data['admin_status'])) + else: + syslog.syslog(syslog.LOG_INFO, "Peer {}: Can't update the peer. No 'admin_status' attribute in the request".format(key)) elif op == swsscommon.DEL_COMMAND: - # Neighbor is deleted - command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'no neighbor {}'".format(self.bgp_asn, key) - run_command(command) + if key in self.peers: + cmds.append(self.bgp_peer_del_template.render(neighbor_addr=key)) + syslog.syslog(syslog.LOG_INFO, 'Peer {} has been removed'.format(key)) + self.peers.remove(key) + else: + syslog.syslog(syslog.LOG_WARNING, 'Peer {} is not found'.format(key)) + self.bgp_messages = [] + + if len(cmds) == 0: + return + + fd, tmp_filename = tempfile.mkstemp(dir='/tmp') + os.close(fd) + with open (tmp_filename, 'w') as fp: + fp.write('router bgp %s\n' % self.bgp_asn) + for cmd in cmds: + fp.write("%s\n" % cmd) + + command = ["vtysh", "-f", tmp_filename] + run_command(command) #FIXME + os.remove(tmp_filename) def __bgp_handler(self, key, op, data): - self.bgp_message.put((key, op, data)) + self.bgp_messages.append((key, op, data)) # If ASN is not set, we just cache this message until the ASN is set. - if self.bgp_asn == None: - return - self.__update_bgp() + if self.bgp_asn is not None: + self.__update_bgp() class Daemon(object): - SELECT_TIMEOUT = 1000 - SUPPORT_DATABASE_LIST = (swsscommon.APPL_DB, swsscommon.CONFIG_DB) + DATABASE_LIST = [ swsscommon.CONFIG_DB ] def __init__(self): - self.appl_db = swsscommon.DBConnector(swsscommon.APPL_DB, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) - self.conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) + self.db_connectors = { db : swsscommon.DBConnector(db, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) for db in Daemon.DATABASE_LIST } self.selector = swsscommon.Select() - self.db_connectors = {} - self.callbacks = {} + self.callbacks = defaultdict(lambda : defaultdict(list)) # db -> table -> [] self.subscribers = set() - def get_db_connector(self, db): - if db not in Daemon.SUPPORT_DATABASE_LIST: - raise ValueError("database {} not Daemon support list {}.".format(db, SUPPORT_DATABASE_LIST)) - # if this database connector has been initialized - if db not in self.db_connectors: - self.db_connectors[db] = swsscommon.DBConnector(db, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) - return self.db_connectors[db] - def add_manager(self, db, table_name, callback): - if db not in self.callbacks: - self.callbacks[db] = {} + if db not in Daemon.DATABASE_LIST: + raise ValueError("database {} isn't supported. Supported '{}' only.".format(db, ",".join(Daemon.DATABASE_LIST))) + if table_name not in self.callbacks[db]: - self.callbacks[db][table_name] = [] - conn = self.get_db_connector(db) + conn = self.db_connectors[db] subscriber = swsscommon.SubscriberStateTable(conn, table_name) self.subscribers.add(subscriber) self.selector.addSelectable(subscriber) self.callbacks[db][table_name].append(callback) - def start(self): - while True: - state, selectable = self.selector.select(Daemon.SELECT_TIMEOUT) - if not selectable: + def run(self): + while g_run: + state, _ = self.selector.select(Daemon.SELECT_TIMEOUT) + if state == self.selector.TIMEOUT: continue + elif state == self.selector.ERROR: + raise Exception("Received error from select") + for subscriber in self.subscribers: key, op, fvs = subscriber.pop() - # if no new message if not key: continue - data = dict(fvs) - syslog.syslog(syslog.LOG_DEBUG, "Receive message : {}".format((key, op, fvs))) + if g_debug: + syslog.syslog(syslog.LOG_DEBUG, "Received message : {}".format((key, op, fvs))) for callback in self.callbacks[subscriber.getDbConnector().getDbId()][subscriber.getTableName()]: - callback(key, op, data) + callback(key, op, dict(fvs)) + + +def wait_for_bgpd(): + # wait for 20 seconds + stop_time = datetime.datetime.now() + datetime.timedelta(seconds=20) + syslog.syslog(syslog.LOG_INFO, "Start waiting for bgpd: %s" % str(datetime.datetime.now())) + while datetime.datetime.now() < stop_time: + rc, out, err = run_command(["vtysh", "-c", "show daemons"]) + if rc == 0 and "bgpd" in out: + syslog.syslog(syslog.LOG_INFO, "bgpd connected to vtysh: %s" % str(datetime.datetime.now())) + return + time.sleep(0.1) # sleep 100 ms + raise RuntimeError("bgpd hasn't been started in 20 seconds") def main(): - syslog.openlog("bgpcfgd") + wait_for_bgpd() daemon = Daemon() bgp_manager = BGPConfigManager(daemon) - daemon.start() - syslog.closelog() - -if __name__ == "__main__": - main() + daemon.run() + + +def signal_handler(signum, frame): + global g_run + g_run = False + + +if __name__ == '__main__': + rc = 0 + try: + syslog.openlog('bgpcfgd') + signal.signal(signal.SIGTERM, signal_handler) + signal.signal(signal.SIGINT, signal_handler) + main() + except KeyboardInterrupt: + syslog.syslog(syslog.LOG_NOTICE, "Keyboard interrupt") + except RuntimeError as e: + syslog.syslog(syslog.LOG_CRIT, "%s" % str(e)) + rc = -2 + except Exception as e: + syslog.syslog(syslog.LOG_CRIT, "Got an exception %s: Traceback: %s" % (str(e), traceback.format_exc())) + rc = -1 + finally: + syslog.closelog() + try: + sys.exit(rc) + except SystemExit: + os._exit(rc) diff --git a/dockers/docker-fpm-frr/bgpd.conf.default.j2 b/dockers/docker-fpm-frr/bgpd.conf.default.j2 index 72779ac53d52..957c2792435f 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.default.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.default.j2 @@ -1,3 +1,4 @@ +! {% if DEVICE_METADATA['localhost'].has_key('bgp_asn') %} {% block bgp_init %} ! @@ -12,7 +13,7 @@ route-map TO_BGP_SPEAKER_V4 deny 10 {% if prefix | ipv4 and name == 'Loopback0' %} ip prefix-list PL_LoopbackV4 permit {{ prefix | ip }}/32 {% elif prefix | ipv6 and name == 'Loopback0' %} -ipv6 prefix-list PL_LoopbackV6 permit {{ prefix | ip }}/64 +ipv6 prefix-list PL_LoopbackV6 permit {{ prefix | replace('/128', '/64') | ip_network }}/64 {% endif %} {% endfor %} ! @@ -28,6 +29,13 @@ route-map FROM_BGPMON_V4 deny 10 route-map TO_BGPMON_V4 permit 10 ! {% endif %} +! +route-map ISOLATE permit 10 + set as-path prepend {{ DEVICE_METADATA['localhost']['bgp_asn'] }} +! +route-map set-next-hop-global-v6 permit 10 + set ipv6 next-hop prefer-global +! router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} bgp log-neighbor-changes bgp bestpath as-path multipath-relax @@ -65,63 +73,32 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% endif %} {% endfor %} {% endblock vlan_advertisement %} -{% block bgp_sessions %} -{% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %} -{% if bgp_session['asn'] | int != 0 %} - neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} - neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} -{# set the bgp neighbor timers if they have not default values #} -{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60) - or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %} - neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }} -{% endif %} -{% if bgp_session.has_key('admin_status') and bgp_session['admin_status'] == 'down' or not bgp_session.has_key('admin_status') and DEVICE_METADATA['localhost'].has_key('default_bgp_status') and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %} - neighbor {{ neighbor_addr }} shutdown -{% endif %} -{# Apply default route-map for v4 peers #} -{% if neighbor_addr | ipv4 %} - neighbor {{ neighbor_addr }} route-map TO_BGP_PEER_V4 out -{% endif %} -{% if neighbor_addr | ipv4 %} +{% block maximum_paths %} address-family ipv4 -{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} - neighbor {{ neighbor_addr }} allowas-in 1 -{% endif %} - neighbor {{ neighbor_addr }} activate - neighbor {{ neighbor_addr }} soft-reconfiguration inbound -{% if bgp_session['rrclient'] | int != 0 %} - neighbor {{ neighbor_addr }} route-reflector-client -{% endif %} -{% if bgp_session['nhopself'] | int != 0 %} - neighbor {{ neighbor_addr }} next-hop-self -{% endif %} maximum-paths 64 exit-address-family -{% endif %} -{% if neighbor_addr | ipv6 %} address-family ipv6 -{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} - neighbor {{ neighbor_addr }} allowas-in 1 -{% endif %} - neighbor {{ neighbor_addr }} activate - neighbor {{ neighbor_addr }} soft-reconfiguration inbound -{% if bgp_session['rrclient'] | int != 0 %} - neighbor {{ neighbor_addr }} route-reflector-client -{% endif %} -{% if bgp_session['nhopself'] | int != 0 %} - neighbor {{ neighbor_addr }} next-hop-self -{% endif %} -{% if bgp_session['asn'] != DEVICE_METADATA['localhost']['bgp_asn'] %} - neighbor {{ neighbor_addr }} route-map set-next-hop-global-v6 in -{% endif %} -{# Apply default route-map for v6 peers #} - neighbor {{ neighbor_addr }} route-map TO_BGP_PEER_V6 out maximum-paths 64 exit-address-family +{% endblock maximum_paths %} +{% block peers_peer_group %} + neighbor PEER_V4 peer-group + neighbor PEER_V6 peer-group + address-family ipv4 +{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} + neighbor PEER_V4 allowas-in 1 {% endif %} + neighbor PEER_V4 soft-reconfiguration inbound + neighbor PEER_V4 route-map TO_BGP_PEER_V4 out + exit-address-family + address-family ipv6 +{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} + neighbor PEER_V6 allowas-in 1 {% endif %} -{% endfor %} -{% endblock bgp_sessions %} + neighbor PEER_V6 soft-reconfiguration inbound + neighbor PEER_V6 route-map TO_BGP_PEER_V6 out + exit-address-family +{% endblock peers_peer_group %} {% block bgp_peers_with_range %} {% if BGP_PEER_RANGE %} {% for bgp_peer in BGP_PEER_RANGE.values() %} @@ -150,11 +127,9 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% endfor %} address-family ipv4 neighbor {{ bgp_peer['name'] }} activate - maximum-paths 64 exit-address-family address-family ipv6 neighbor {{ bgp_peer['name'] }} activate - maximum-paths 64 exit-address-family {% endfor %} {% endif %} diff --git a/dockers/docker-fpm-frr/bgpd.conf.j2 b/dockers/docker-fpm-frr/bgpd.conf.j2 index e9554806b64a..b4b2cd59c9b9 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.j2 @@ -6,28 +6,13 @@ ! {% endblock banner %} ! -{% block system_init %} -hostname {{ DEVICE_METADATA['localhost']['hostname'] }} -password zebra -log syslog informational -log facility local4 +{% include "daemons.common.conf.j2" %} +! agentx -! enable password {# {{ en_passwd }} TODO: param needed #} -{% endblock system_init %} ! {% if DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" %} {% include "bgpd.conf.spine_chassis_frontend_router.j2" %} -{% else%} -{% include "bgpd.conf.default.j2" %} -{% endif %} -! -{% if DEVICE_METADATA['localhost'].has_key('bgp_asn') %} -maximum-paths 64 -! -route-map ISOLATE permit 10 -set as-path prepend {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% endif %} ! -route-map set-next-hop-global-v6 permit 10 -set ipv6 next-hop prefer-global +{% include "bgpd.conf.default.j2" %} ! diff --git a/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 b/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 index 9bd5ef1947c3..afb621b0bf61 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 @@ -1,3 +1,4 @@ +! {# VNET BGP Instance #} ! Vnet BGP instance {% set interfaces_in_vnets = [] %} @@ -59,70 +60,4 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} vrf {{ vnet_name }} {% endfor %} {% endfor %} {% endblock vnet_bgp_instance %} - -{# default bgp #} -{% block default_bgp_instance %} -{% block bgp_init %} -! -! bgp multiple-instance -! -route-map FROM_BGP_SPEAKER_V4 permit 10 -! -route-map TO_BGP_SPEAKER_V4 deny 10 ! -router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} - bgp log-neighbor-changes - bgp bestpath as-path multipath-relax - no bgp default ipv4-unicast - bgp graceful-restart restart-time 240 - bgp graceful-restart -{% for (name, prefix) in LOOPBACK_INTERFACE | pfx_filter %} -{% if prefix | ipv4 and name == 'Loopback0' %} - bgp router-id {{ prefix | ip }} -{% endif %} -{% endfor %} -{# advertise loopback #} -{% for (name, prefix) in LOOPBACK_INTERFACE | pfx_filter %} -{% if prefix | ipv4 and name == 'Loopback0' %} - network {{ prefix | ip }}/32 -{% elif prefix | ipv6 and name == 'Loopback0' %} - address-family ipv6 - network {{ prefix | ip }}/64 - exit-address-family -{% endif %} -{% endfor %} -{% endblock bgp_init %} -{% block bgp_sessions %} -{% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %} -{% if not bgp_session.has_key("local_addr") or bgp_session["local_addr"] not in interfaces_in_vnets %} -{% if bgp_session['asn'] | int != 0 %} - neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} - neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} -{# set the bgp neighbor timers if they have not default values #} -{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60) - or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %} - neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }} -{% endif %} -{% if bgp_session.has_key('admin_status') and bgp_session['admin_status'] == 'down' or not bgp_session.has_key('admin_status') and DEVICE_METADATA['localhost'].has_key('default_bgp_status') and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %} - neighbor {{ neighbor_addr }} shutdown -{% endif %} -{% if bgp_session["asn"] != DEVICE_METADATA['localhost']['bgp_asn'] %} -{% if neighbor_addr | ipv4 %} - address-family ipv4 unicast - neighbor {{ neighbor_addr }} allowas-in 1 - neighbor {{ neighbor_addr }} activate - neighbor {{ neighbor_addr }} soft-reconfiguration inbound - maximum-paths 64 - exit-address-family -{% endif %} -{% else %} - address-family l2vpn evpn - neighbor {{ neighbor_addr }} activate - advertise-all-vni - exit-address-family -{% endif %} -{% endif %} -{% endif %} -{% endfor %} -{% endblock bgp_sessions %} -{% endblock default_bgp_instance %} diff --git a/dockers/docker-fpm-frr/bgpd.peer.conf.j2 b/dockers/docker-fpm-frr/bgpd.peer.conf.j2 new file mode 100644 index 000000000000..7dfdd50ea2c0 --- /dev/null +++ b/dockers/docker-fpm-frr/bgpd.peer.conf.j2 @@ -0,0 +1,30 @@ +{% block bgp_peer %} + neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} + neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} +{# set the bgp neighbor timers if they have not default values #} +{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60) + or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %} + neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }} +{% endif %} +{% if bgp_session.has_key('admin_status') and bgp_session['admin_status'] == 'down' or not bgp_session.has_key('admin_status') and DEVICE_METADATA['localhost'].has_key('default_bgp_status') and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %} + neighbor {{ neighbor_addr }} shutdown +{% endif %} +{% if neighbor_addr | ipv4 %} + address-family ipv4 + neighbor {{ neighbor_addr }} peer-group PEER_V4 +{% elif neighbor_addr | ipv6 %} + address-family ipv6 +{% if bgp_session['asn'] != DEVICE_METADATA['localhost']['bgp_asn'] %} + neighbor {{ neighbor_addr }} route-map set-next-hop-global-v6 in +{% endif %} + neighbor {{ neighbor_addr }} peer-group PEER_V6 +{% endif %} +{% if bgp_session['rrclient'] | int != 0 %} + neighbor {{ neighbor_addr }} route-reflector-client +{% endif %} +{% if bgp_session['nhopself'] | int != 0 %} + neighbor {{ neighbor_addr }} next-hop-self +{% endif %} + neighbor {{ neighbor_addr }} activate + exit-address-family +{% endblock bgp_peer %} diff --git a/dockers/docker-fpm-frr/daemons.common.conf.j2 b/dockers/docker-fpm-frr/daemons.common.conf.j2 new file mode 100644 index 000000000000..23eb5184f5e0 --- /dev/null +++ b/dockers/docker-fpm-frr/daemons.common.conf.j2 @@ -0,0 +1,12 @@ +! +{% block sys_init %} +hostname {{ DEVICE_METADATA['localhost']['hostname'] }} +password zebra +enable password zebra +{% endblock sys_init %} +! +{% block logging %} +log syslog informational +log facility local4 +{% endblock logging %} +! diff --git a/dockers/docker-fpm-frr/frr.conf.j2 b/dockers/docker-fpm-frr/frr.conf.j2 index d9dd6bf05633..afa40ad8ba75 100644 --- a/dockers/docker-fpm-frr/frr.conf.j2 +++ b/dockers/docker-fpm-frr/frr.conf.j2 @@ -6,205 +6,13 @@ ! {% endblock banner %} ! -{% block system_init %} -hostname {{ DEVICE_METADATA['localhost']['hostname'] }} -password zebra -log syslog informational -log facility local4 -agentx -! enable password {# {{ en_passwd }} TODO: param needed #} -{% endblock system_init %} -! -{% block interfaces %} -! Enable link-detect (default disabled) -{% for (name, prefix) in INTERFACE|pfx_filter %} -interface {{ name }} -link-detect -! -{% endfor %} -{% for pc in PORTCHANNEL %} -interface {{ pc }} -link-detect -! -{% endfor %} -{% endblock interfaces %} -! -{% block default_route %} -! set static default route to mgmt gateway as a backup to learned default -{% for (name, prefix) in MGMT_INTERFACE|pfx_filter %} -{% if prefix | ipv4 %} -ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200 -{% endif %} -{% endfor %} -{% endblock default_route %} -! -{% block source_loopback %} -{% set lo_ipv4_addrs = [] %} -{% set lo_ipv6_addrs = [] %} -{% if LOOPBACK_INTERFACE %} -{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %} -{% if name == 'Loopback0' %} -{% if prefix | ipv6 %} -{% if lo_ipv6_addrs.append(prefix) %} -{% endif %} -{% else %} -{% if lo_ipv4_addrs.append(prefix) %} -{% endif %} -{% endif %} -{% endif %} -{% endfor %} -{% endif %} -! Set ip source to loopback for bgp learned routes -route-map RM_SET_SRC permit 10 - set src {{ lo_ipv4_addrs[0] | ip }} -! -{% if lo_ipv6_addrs|length > 0 %} -route-map RM_SET_SRC6 permit 10 - set src {{ lo_ipv6_addrs[0] | ip }} -! -{% endif %} -ip protocol bgp route-map RM_SET_SRC +{% include "daemons.common.conf.j2" %} ! -{% if lo_ipv6_addrs|length > 0 %} -ipv6 protocol bgp route-map RM_SET_SRC6 -! -{% endif %} -{% endblock source_loopback %} -! -{% if DEVICE_METADATA['localhost'].has_key('bgp_asn') %} -{% block bgp_init %} -! -! bgp multiple-instance -! -route-map FROM_BGP_SPEAKER_V4 permit 10 -! -route-map TO_BGP_SPEAKER_V4 deny 10 -! -router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} - bgp log-neighbor-changes - bgp bestpath as-path multipath-relax - no bgp default ipv4-unicast -{# Advertise graceful restart capability for ToR #} -{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} - bgp graceful-restart -{% endif %} -{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %} -{% if prefix | ipv4 and name == 'Loopback0' %} - bgp router-id {{ prefix | ip }} -{% endif %} -{% endfor %} -{# advertise loopback #} -{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %} -{% if prefix | ipv4 and name == 'Loopback0' %} - network {{ prefix | ip }}/32 -{% elif prefix | ipv6 and name == 'Loopback0' %} - address-family ipv6 - network {{ prefix | ip }}/64 - exit-address-family -{% endif %} -{% endfor %} -{% endblock bgp_init %} -{% endif %} -{% block vlan_advertisement %} -{% for (name, prefix) in VLAN_INTERFACE|pfx_filter %} -{% if prefix | ipv4 %} - network {{ prefix }} -{% elif prefix | ipv6 %} - address-family ipv6 - network {{ prefix }} - exit-address-family -{% endif %} -{% endfor %} -{% endblock vlan_advertisement %} -{% block bgp_sessions %} -{% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %} -{% if bgp_session['asn'] | int != 0 %} - neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} - neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} -{# set the bgp neighbor timers if they have not default values #} -{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60) - or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %} - neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }} -{% endif %} -{% if bgp_session.has_key('admin_status') and bgp_session['admin_status'] == 'down' or not bgp_session.has_key('admin_status') and DEVICE_METADATA['localhost'].has_key('default_bgp_status') and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %} - neighbor {{ neighbor_addr }} shutdown -{% endif %} -{% if neighbor_addr | ipv4 %} - address-family ipv4 -{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} - neighbor {{ neighbor_addr }} allowas-in 1 -{% endif %} - neighbor {{ neighbor_addr }} activate - neighbor {{ neighbor_addr }} soft-reconfiguration inbound -{% if bgp_session['rrclient'] | int != 0 %} - neighbor {{ neighbor_addr }} route-reflector-client -{% endif %} -{% if bgp_session['nhopself'] | int != 0 %} - neighbor {{ neighbor_addr }} next-hop-self -{% endif %} - maximum-paths 64 - exit-address-family -{% endif %} -{% if neighbor_addr | ipv6 %} - address-family ipv6 -{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} - neighbor {{ neighbor_addr }} allowas-in 1 -{% endif %} - neighbor {{ neighbor_addr }} activate - neighbor {{ neighbor_addr }} soft-reconfiguration inbound -{% if bgp_session['rrclient'] | int != 0 %} - neighbor {{ neighbor_addr }} route-reflector-client -{% endif %} -{% if bgp_session['nhopself'] | int != 0 %} - neighbor {{ neighbor_addr }} next-hop-self -{% endif %} -{% if bgp_session['asn'] != DEVICE_METADATA['localhost']['bgp_asn'] %} - neighbor {{ neighbor_addr }} route-map set-next-hop-global-v6 in -{% endif %} - maximum-paths 64 - exit-address-family -{% endif %} -{% endif %} -{% endfor %} -{% endblock bgp_sessions %} -{% block bgp_peers_with_range %} -{% if BGP_PEER_RANGE %} -{% for bgp_peer in BGP_PEER_RANGE.values() %} - neighbor {{ bgp_peer['name'] }} peer-group - neighbor {{ bgp_peer['name'] }} passive - neighbor {{ bgp_peer['name'] }} remote-as {{ deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']] }} - neighbor {{ bgp_peer['name'] }} ebgp-multihop 255 -{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %} -{% if name == 'Loopback1' %} - neighbor {{ bgp_peer['name'] }} update-source {{ prefix | ip }} -{% endif %} -{% endfor %} -{% for ip_range in bgp_peer['ip_range'] %} - bgp listen range {{ip_range}} peer-group {{ bgp_peer['name'] }} -{% endfor %} - address-family ipv4 - neighbor {{ bgp_peer['name'] }} activate - neighbor {{ bgp_peer['name'] }} soft-reconfiguration inbound - neighbor {{ bgp_peer['name'] }} route-map FROM_BGP_SPEAKER_V4 in - neighbor {{ bgp_peer['name'] }} route-map TO_BGP_SPEAKER_V4 out - maximum-paths 64 - exit-address-family - address-family ipv6 - neighbor {{ bgp_peer['name'] }} activate - neighbor {{ bgp_peer['name'] }} soft-reconfiguration inbound - maximum-paths 64 - exit-address-family -{% endfor %} -{% endif %} -{% endblock bgp_peers_with_range %} +agentx ! -{% if DEVICE_METADATA['localhost'].has_key('bgp_asn') %} -maximum-paths 64 +{% include "zebra.interfaces.conf.j2" %} ! -route-map ISOLATE permit 10 -set as-path prepend {{ DEVICE_METADATA['localhost']['bgp_asn'] }} -{% endif %} +{% include "staticd.default_route.conf.j2" %} ! -route-map set-next-hop-global-v6 permit 10 -set ipv6 next-hop prefer-global +{% include "bgpd.conf.default.j2" %} ! diff --git a/dockers/docker-fpm-frr/start.sh b/dockers/docker-fpm-frr/start.sh index 3c732fece943..a1b0c0ea0b08 100755 --- a/dockers/docker-fpm-frr/start.sh +++ b/dockers/docker-fpm-frr/start.sh @@ -33,8 +33,6 @@ rm -f /var/run/rsyslogd.pid supervisorctl start rsyslogd -supervisorctl start bgpcfgd - # Start Quagga processes supervisorctl start zebra supervisorctl start staticd @@ -45,3 +43,5 @@ if [ "$CONFIG_TYPE" == "unified" ]; then fi supervisorctl start fpmsyncd + +supervisorctl start bgpcfgd diff --git a/dockers/docker-fpm-frr/staticd.conf.j2 b/dockers/docker-fpm-frr/staticd.conf.j2 index b3de8c424f12..4e39e17d7dbf 100644 --- a/dockers/docker-fpm-frr/staticd.conf.j2 +++ b/dockers/docker-fpm-frr/staticd.conf.j2 @@ -6,24 +6,7 @@ ! {% endblock banner %} ! -{% block sys_init %} -hostname {{ DEVICE_METADATA['localhost']['hostname'] }} -password zebra -enable password zebra -{% endblock sys_init %} +{% include "daemons.common.conf.j2" %} ! -{% block default_route %} -! set static default route to mgmt gateway as a backup to learned default -{% for (name, prefix) in MGMT_INTERFACE|pfx_filter %} -{% if prefix | ipv4 %} -ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200 -{% endif %} -{% endfor %} -{% endblock default_route %} +{% include "staticd.default_route.conf.j2" %} ! -{% block logging %} -log syslog informational -log facility local4 -{% endblock logging %} -! - diff --git a/dockers/docker-fpm-frr/staticd.default_route.conf.j2 b/dockers/docker-fpm-frr/staticd.default_route.conf.j2 new file mode 100644 index 000000000000..22d61ebbd0ff --- /dev/null +++ b/dockers/docker-fpm-frr/staticd.default_route.conf.j2 @@ -0,0 +1,10 @@ +! +{% block default_route %} +! set static default route to mgmt gateway as a backup to learned default +{% for (name, prefix) in MGMT_INTERFACE|pfx_filter %} +{% if prefix | ipv4 %} +ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200 +{% endif %} +{% endfor %} +{% endblock default_route %} +! diff --git a/dockers/docker-fpm-frr/zebra.conf.j2 b/dockers/docker-fpm-frr/zebra.conf.j2 index 3135a056a656..8c1c6f96484b 100644 --- a/dockers/docker-fpm-frr/zebra.conf.j2 +++ b/dockers/docker-fpm-frr/zebra.conf.j2 @@ -6,74 +6,7 @@ ! {% endblock banner %} ! -{% block sys_init %} -hostname {{ DEVICE_METADATA['localhost']['hostname'] }} -password zebra -enable password zebra -{% endblock sys_init %} +{% include "daemons.common.conf.j2" %} ! -{% block vrf %} -{% if VNET is defined %} -{% for vnet_name, vnet_metadata in VNET.iteritems() %} -vrf {{ vnet_name }} -vni {{ vnet_metadata['vni'] }} +{% include "zebra.interfaces.conf.j2" %} ! -{% endfor %} -{% endif %} -{% endblock vrf %} -! -{% block interfaces %} -! Enable link-detect (default disabled) -{% for (name, prefix) in INTERFACE|pfx_filter %} -interface {{ name }} -link-detect -! -{% endfor %} -{% for pc in PORTCHANNEL %} -interface {{ pc }} -link-detect -! -{% endfor %} -{% endblock interfaces %} -! -{% block source_loopback %} -{% set lo_ipv4_addrs = [] %} -{% set lo_ipv6_addrs = [] %} -{% if LOOPBACK_INTERFACE %} -{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %} -{% if name == 'Loopback0' %} -{% if prefix | ipv6 %} -{% if lo_ipv6_addrs.append(prefix) %} -{% endif %} -{% else %} -{% if lo_ipv4_addrs.append(prefix) %} -{% endif %} -{% endif %} -{% endif %} -{% endfor %} -{% endif %} -! Set ip source to loopback for bgp learned routes -{% if lo_ipv4_addrs|length > 0 -%} -route-map RM_SET_SRC permit 10 - set src {{ lo_ipv4_addrs[0] | ip }} -! -{% endif %} -{% if lo_ipv6_addrs|length > 0 %} -route-map RM_SET_SRC6 permit 10 - set src {{ lo_ipv6_addrs[0] | ip }} -! -{% endif %} -ip protocol bgp route-map RM_SET_SRC -! -{% if lo_ipv6_addrs|length > 0 %} -ipv6 protocol bgp route-map RM_SET_SRC6 -! -{% endif %} -{% endblock source_loopback %} -! -{% block logging %} -log syslog informational -log facility local4 -{% endblock logging %} -! - diff --git a/dockers/docker-fpm-frr/zebra.interfaces.conf.j2 b/dockers/docker-fpm-frr/zebra.interfaces.conf.j2 new file mode 100644 index 000000000000..4a089e4dc726 --- /dev/null +++ b/dockers/docker-fpm-frr/zebra.interfaces.conf.j2 @@ -0,0 +1,60 @@ +! +{% block vrf %} +{% if VNET is defined %} +{% for vnet_name, vnet_metadata in VNET.iteritems() %} +vrf {{ vnet_name }} +vni {{ vnet_metadata['vni'] }} +! +{% endfor %} +{% endif %} +{% endblock vrf %} +! +{% block interfaces %} +! Enable link-detect (default disabled) +{% for (name, prefix) in INTERFACE|pfx_filter %} +interface {{ name }} +link-detect +! +{% endfor %} +{% for pc in PORTCHANNEL %} +interface {{ pc }} +link-detect +! +{% endfor %} +{% endblock interfaces %} +! +{% block source_loopback %} +{% set lo_ipv4_addrs = [] %} +{% set lo_ipv6_addrs = [] %} +{% if LOOPBACK_INTERFACE %} +{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %} +{% if name == 'Loopback0' %} +{% if prefix | ipv6 %} +{% if lo_ipv6_addrs.append(prefix) %} +{% endif %} +{% else %} +{% if lo_ipv4_addrs.append(prefix) %} +{% endif %} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +! Set ip source to loopback for bgp learned routes +{% if lo_ipv4_addrs|length > 0 -%} +route-map RM_SET_SRC permit 10 + set src {{ lo_ipv4_addrs[0] | ip }} +! +{% endif %} +{% if lo_ipv6_addrs|length > 0 %} +route-map RM_SET_SRC6 permit 10 + set src {{ lo_ipv6_addrs[0] | ip }} +! +{% endif %} +ip protocol bgp route-map RM_SET_SRC +! +{% if lo_ipv6_addrs|length > 0 %} +ipv6 protocol bgp route-map RM_SET_SRC6 +! +{% endif %} +{% endblock source_loopback %} +! diff --git a/src/sonic-config-engine/sonic-cfggen b/src/sonic-config-engine/sonic-cfggen index 2f4e9c5eb89b..ca550b49e4bc 100755 --- a/src/sonic-config-engine/sonic-cfggen +++ b/src/sonic-config-engine/sonic-cfggen @@ -103,6 +103,14 @@ def pfx_filter(value): table[key] = val return table +def ip_network(value): + """ Extract network for network prefix """ + try: + r_v = netaddr.IPNetwork(value) + except: + return "Invalid ip address %s" % value + return r_v.network + class FormatConverter: """Convert config DB based schema to legacy minigraph based schema for backward capability. We will move to DB schema and remove this class when the config templates are modified. @@ -265,6 +273,7 @@ def main(): env.filters['ipv6'] = is_ipv6 env.filters['unique_name'] = unique_name env.filters['pfx_filter'] = pfx_filter + env.filters['ip_network'] = ip_network for attr in ['ip', 'network', 'prefixlen', 'netmask']: env.filters[attr] = partial(prefix_attr, attr) template = env.get_template(template_file) diff --git a/src/sonic-config-engine/tests/sample_output/bgpd_frr.conf b/src/sonic-config-engine/tests/sample_output/bgpd_frr.conf index c796ef8c164b..3a8abf050b45 100644 --- a/src/sonic-config-engine/tests/sample_output/bgpd_frr.conf +++ b/src/sonic-config-engine/tests/sample_output/bgpd_frr.conf @@ -4,12 +4,18 @@ ! file: bgpd.conf ! ! +! hostname switch-t0 password zebra +enable password zebra +! log syslog informational log facility local4 +!! agentx -! enable password ! +! +! +! ! ! bgp multiple-instance ! @@ -18,7 +24,7 @@ route-map FROM_BGP_SPEAKER_V4 permit 10 route-map TO_BGP_SPEAKER_V4 deny 10 ! ip prefix-list PL_LoopbackV4 permit 10.1.0.32/32 -ipv6 prefix-list PL_LoopbackV6 permit fc00:1::32/64 +ipv6 prefix-list PL_LoopbackV6 permit fc00:1::/64 ! ! route-map TO_BGP_PEER_V4 permit 100 @@ -29,6 +35,13 @@ route-map FROM_BGPMON_V4 deny 10 ! route-map TO_BGPMON_V4 permit 10 ! +! +route-map ISOLATE permit 10 + set as-path prepend 65100 +! +route-map set-next-hop-global-v6 permit 10 + set ipv6 next-hop prefer-global +! router bgp 65100 bgp log-neighbor-changes bgp bestpath as-path multipath-relax @@ -42,81 +55,23 @@ router bgp 65100 network fc00:1::32/64 exit-address-family network 192.168.0.1/27 - neighbor 10.0.0.57 remote-as 64600 - neighbor 10.0.0.57 description ARISTA01T1 - neighbor 10.0.0.57 route-map TO_BGP_PEER_V4 out - address-family ipv4 - neighbor 10.0.0.57 allowas-in 1 - neighbor 10.0.0.57 activate - neighbor 10.0.0.57 soft-reconfiguration inbound - maximum-paths 64 - exit-address-family - neighbor 10.0.0.59 remote-as 64600 - neighbor 10.0.0.59 description ARISTA02T1 - neighbor 10.0.0.59 route-map TO_BGP_PEER_V4 out - address-family ipv4 - neighbor 10.0.0.59 allowas-in 1 - neighbor 10.0.0.59 activate - neighbor 10.0.0.59 soft-reconfiguration inbound - maximum-paths 64 - exit-address-family - neighbor 10.0.0.61 remote-as 64600 - neighbor 10.0.0.61 description ARISTA03T1 - neighbor 10.0.0.61 route-map TO_BGP_PEER_V4 out - address-family ipv4 - neighbor 10.0.0.61 allowas-in 1 - neighbor 10.0.0.61 activate - neighbor 10.0.0.61 soft-reconfiguration inbound - maximum-paths 64 - exit-address-family - neighbor 10.0.0.63 remote-as 64600 - neighbor 10.0.0.63 description ARISTA04T1 - neighbor 10.0.0.63 route-map TO_BGP_PEER_V4 out address-family ipv4 - neighbor 10.0.0.63 allowas-in 1 - neighbor 10.0.0.63 activate - neighbor 10.0.0.63 soft-reconfiguration inbound maximum-paths 64 exit-address-family - neighbor fc00::7a remote-as 64600 - neighbor fc00::7a description ARISTA03T1 address-family ipv6 - neighbor fc00::7a allowas-in 1 - neighbor fc00::7a activate - neighbor fc00::7a soft-reconfiguration inbound - neighbor fc00::7a route-map set-next-hop-global-v6 in - neighbor fc00::7a route-map TO_BGP_PEER_V6 out maximum-paths 64 exit-address-family - neighbor fc00::7e remote-as 64600 - neighbor fc00::7e description ARISTA04T1 - address-family ipv6 - neighbor fc00::7e allowas-in 1 - neighbor fc00::7e activate - neighbor fc00::7e soft-reconfiguration inbound - neighbor fc00::7e route-map set-next-hop-global-v6 in - neighbor fc00::7e route-map TO_BGP_PEER_V6 out - maximum-paths 64 - exit-address-family - neighbor fc00::72 remote-as 64600 - neighbor fc00::72 description ARISTA01T1 - address-family ipv6 - neighbor fc00::72 allowas-in 1 - neighbor fc00::72 activate - neighbor fc00::72 soft-reconfiguration inbound - neighbor fc00::72 route-map set-next-hop-global-v6 in - neighbor fc00::72 route-map TO_BGP_PEER_V6 out - maximum-paths 64 + neighbor PEER_V4 peer-group + neighbor PEER_V6 peer-group + address-family ipv4 + neighbor PEER_V4 allowas-in 1 + neighbor PEER_V4 soft-reconfiguration inbound + neighbor PEER_V4 route-map TO_BGP_PEER_V4 out exit-address-family - neighbor fc00::76 remote-as 64600 - neighbor fc00::76 description ARISTA02T1 address-family ipv6 - neighbor fc00::76 allowas-in 1 - neighbor fc00::76 activate - neighbor fc00::76 soft-reconfiguration inbound - neighbor fc00::76 route-map set-next-hop-global-v6 in - neighbor fc00::76 route-map TO_BGP_PEER_V6 out - maximum-paths 64 + neighbor PEER_V6 allowas-in 1 + neighbor PEER_V6 soft-reconfiguration inbound + neighbor PEER_V6 route-map TO_BGP_PEER_V6 out exit-address-family neighbor BGPMON_V4 peer-group neighbor BGPMON_V4 update-source 10.1.0.32 @@ -129,11 +84,3 @@ router bgp 65100 neighbor 10.20.30.40 description BGPMonitor neighbor 10.20.30.40 activate !! -maximum-paths 64 -! -route-map ISOLATE permit 10 -set as-path prepend 65100 -! -route-map set-next-hop-global-v6 permit 10 -set ipv6 next-hop prefer-global -! diff --git a/src/sonic-config-engine/tests/sample_output/frr.conf b/src/sonic-config-engine/tests/sample_output/frr.conf index 8e7f97cf8c55..edcf0939a03f 100644 --- a/src/sonic-config-engine/tests/sample_output/frr.conf +++ b/src/sonic-config-engine/tests/sample_output/frr.conf @@ -4,12 +4,18 @@ ! file: frr.conf ! ! +! hostname switch-t0 password zebra +enable password zebra +! log syslog informational log facility local4 +!! agentx -! enable password ! +! +! +! ! Enable link-detect (default disabled) interface PortChannel01 link-detect @@ -24,9 +30,6 @@ interface PortChannel04 link-detect ! ! -! set static default route to mgmt gateway as a backup to learned default -ip route 0.0.0.0/0 10.0.0.1 200 -! ! Set ip source to loopback for bgp learned routes route-map RM_SET_SRC permit 10 set src 10.1.0.32 @@ -39,6 +42,11 @@ ip protocol bgp route-map RM_SET_SRC ! ipv6 protocol bgp route-map RM_SET_SRC6 ! +!! +! +! set static default route to mgmt gateway as a backup to learned default +ip route 0.0.0.0/0 10.0.0.1 200 +!! ! ! ! bgp multiple-instance @@ -47,91 +55,64 @@ route-map FROM_BGP_SPEAKER_V4 permit 10 ! route-map TO_BGP_SPEAKER_V4 deny 10 ! +ip prefix-list PL_LoopbackV4 permit 10.1.0.32/32 +ipv6 prefix-list PL_LoopbackV6 permit fc00:1::/64 +! +! +route-map TO_BGP_PEER_V4 permit 100 +! +route-map TO_BGP_PEER_V6 permit 100 +! +route-map FROM_BGPMON_V4 deny 10 +! +route-map TO_BGPMON_V4 permit 10 +! +! +route-map ISOLATE permit 10 + set as-path prepend 65100 +! +route-map set-next-hop-global-v6 permit 10 + set ipv6 next-hop prefer-global +! router bgp 65100 bgp log-neighbor-changes bgp bestpath as-path multipath-relax no bgp default ipv4-unicast + bgp graceful-restart restart-time 240 bgp graceful-restart + bgp graceful-restart preserve-fw-state bgp router-id 10.1.0.32 network 10.1.0.32/32 address-family ipv6 network fc00:1::32/64 exit-address-family network 192.168.0.1/27 - neighbor 10.0.0.57 remote-as 64600 - neighbor 10.0.0.57 description ARISTA01T1 address-family ipv4 - neighbor 10.0.0.57 allowas-in 1 - neighbor 10.0.0.57 activate - neighbor 10.0.0.57 soft-reconfiguration inbound maximum-paths 64 exit-address-family - neighbor 10.0.0.59 remote-as 64600 - neighbor 10.0.0.59 description ARISTA02T1 - address-family ipv4 - neighbor 10.0.0.59 allowas-in 1 - neighbor 10.0.0.59 activate - neighbor 10.0.0.59 soft-reconfiguration inbound - maximum-paths 64 - exit-address-family - neighbor 10.0.0.61 remote-as 64600 - neighbor 10.0.0.61 description ARISTA03T1 - address-family ipv4 - neighbor 10.0.0.61 allowas-in 1 - neighbor 10.0.0.61 activate - neighbor 10.0.0.61 soft-reconfiguration inbound - maximum-paths 64 - exit-address-family - neighbor 10.0.0.63 remote-as 64600 - neighbor 10.0.0.63 description ARISTA04T1 - address-family ipv4 - neighbor 10.0.0.63 allowas-in 1 - neighbor 10.0.0.63 activate - neighbor 10.0.0.63 soft-reconfiguration inbound - maximum-paths 64 - exit-address-family - neighbor fc00::7a remote-as 64600 - neighbor fc00::7a description ARISTA03T1 - address-family ipv6 - neighbor fc00::7a allowas-in 1 - neighbor fc00::7a activate - neighbor fc00::7a soft-reconfiguration inbound - neighbor fc00::7a route-map set-next-hop-global-v6 in - maximum-paths 64 - exit-address-family - neighbor fc00::7e remote-as 64600 - neighbor fc00::7e description ARISTA04T1 address-family ipv6 - neighbor fc00::7e allowas-in 1 - neighbor fc00::7e activate - neighbor fc00::7e soft-reconfiguration inbound - neighbor fc00::7e route-map set-next-hop-global-v6 in maximum-paths 64 exit-address-family - neighbor fc00::72 remote-as 64600 - neighbor fc00::72 description ARISTA01T1 - address-family ipv6 - neighbor fc00::72 allowas-in 1 - neighbor fc00::72 activate - neighbor fc00::72 soft-reconfiguration inbound - neighbor fc00::72 route-map set-next-hop-global-v6 in - maximum-paths 64 + neighbor PEER_V4 peer-group + neighbor PEER_V6 peer-group + address-family ipv4 + neighbor PEER_V4 allowas-in 1 + neighbor PEER_V4 soft-reconfiguration inbound + neighbor PEER_V4 route-map TO_BGP_PEER_V4 out exit-address-family - neighbor fc00::76 remote-as 64600 - neighbor fc00::76 description ARISTA02T1 address-family ipv6 - neighbor fc00::76 allowas-in 1 - neighbor fc00::76 activate - neighbor fc00::76 soft-reconfiguration inbound - neighbor fc00::76 route-map set-next-hop-global-v6 in - maximum-paths 64 + neighbor PEER_V6 allowas-in 1 + neighbor PEER_V6 soft-reconfiguration inbound + neighbor PEER_V6 route-map TO_BGP_PEER_V6 out exit-address-family -! -maximum-paths 64 -! -route-map ISOLATE permit 10 -set as-path prepend 65100 -! -route-map set-next-hop-global-v6 permit 10 -set ipv6 next-hop prefer-global -! + neighbor BGPMON_V4 peer-group + neighbor BGPMON_V4 update-source 10.1.0.32 + neighbor BGPMON_V4 route-map FROM_BGPMON_V4 in + neighbor BGPMON_V4 route-map TO_BGPMON_V4 out + neighbor BGPMON_V4 send-community + neighbor BGPMON_V4 maximum-prefix 1 + neighbor 10.20.30.40 remote-as 65100 + neighbor 10.20.30.40 peer-group BGPMON_V4 + neighbor 10.20.30.40 description BGPMonitor + neighbor 10.20.30.40 activate +!! diff --git a/src/sonic-config-engine/tests/sample_output/staticd_frr.conf b/src/sonic-config-engine/tests/sample_output/staticd_frr.conf index a1a5fddf322b..12a81de82125 100644 --- a/src/sonic-config-engine/tests/sample_output/staticd_frr.conf +++ b/src/sonic-config-engine/tests/sample_output/staticd_frr.conf @@ -4,14 +4,15 @@ ! file: staticd.conf ! ! +! hostname switch-t0 password zebra enable password zebra ! -! set static default route to mgmt gateway as a backup to learned default -ip route 0.0.0.0/0 10.0.0.1 200 -! log syslog informational log facility local4 +!! ! - +! set static default route to mgmt gateway as a backup to learned default +ip route 0.0.0.0/0 10.0.0.1 200 +!! diff --git a/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-bgpd.conf b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-bgpd.conf index 515e0aba8df2..b0b5e2cb1192 100644 --- a/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-bgpd.conf +++ b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-bgpd.conf @@ -4,12 +4,17 @@ ! file: bgpd.conf ! ! +! hostname SpineFront01 password zebra +enable password zebra +! log syslog informational log facility local4 +!! agentx -! enable password ! +! +! ! Vnet BGP instance router bgp 4000 vrf VnetFE no bgp default ipv4-unicast @@ -30,7 +35,8 @@ router bgp 4000 vrf VnetFE address-family l2vpn evpn advertise ipv4 unicast exit-address-family - +!! +! ! ! bgp multiple-instance ! @@ -38,6 +44,20 @@ route-map FROM_BGP_SPEAKER_V4 permit 10 ! route-map TO_BGP_SPEAKER_V4 deny 10 ! +ip prefix-list PL_LoopbackV4 permit 4.0.0.0/32 +! +! +route-map TO_BGP_PEER_V4 permit 100 +! +route-map TO_BGP_PEER_V6 permit 100 +! +! +route-map ISOLATE permit 10 + set as-path prepend 4000 +! +route-map set-next-hop-global-v6 permit 10 + set ipv6 next-hop prefer-global +! router bgp 4000 bgp log-neighbor-changes bgp bestpath as-path multipath-relax @@ -46,37 +66,20 @@ router bgp 4000 bgp graceful-restart bgp router-id 4.0.0.0 network 4.0.0.0/32 - neighbor 4.0.0.1 remote-as 4000 - neighbor 4.0.0.1 description SpineFront02 - neighbor 4.0.0.1 timers 3 10 - address-family l2vpn evpn - neighbor 4.0.0.1 activate - advertise-all-vni - exit-address-family - neighbor 172.16.0.2 remote-as 5000 - neighbor 172.16.0.2 description SpineBack01 - neighbor 172.16.0.2 timers 3 10 - address-family ipv4 unicast - neighbor 172.16.0.2 allowas-in 1 - neighbor 172.16.0.2 activate - neighbor 172.16.0.2 soft-reconfiguration inbound + address-family ipv4 maximum-paths 64 exit-address-family - neighbor 172.16.0.10 remote-as 5000 - neighbor 172.16.0.10 description SpineBack02 - neighbor 172.16.0.10 timers 3 10 - address-family ipv4 unicast - neighbor 172.16.0.10 allowas-in 1 - neighbor 172.16.0.10 activate - neighbor 172.16.0.10 soft-reconfiguration inbound + address-family ipv6 maximum-paths 64 exit-address-family -! -maximum-paths 64 -! -route-map ISOLATE permit 10 -set as-path prepend 4000 -! -route-map set-next-hop-global-v6 permit 10 -set ipv6 next-hop prefer-global -! + neighbor PEER_V4 peer-group + neighbor PEER_V6 peer-group + address-family ipv4 + neighbor PEER_V4 soft-reconfiguration inbound + neighbor PEER_V4 route-map TO_BGP_PEER_V4 out + exit-address-family + address-family ipv6 + neighbor PEER_V6 soft-reconfiguration inbound + neighbor PEER_V6 route-map TO_BGP_PEER_V6 out + exit-address-family +!! diff --git a/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-vni-zebra.conf b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-vni-zebra.conf index 30571f2082ae..bd2b5c84f471 100644 --- a/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-vni-zebra.conf +++ b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-vni-zebra.conf @@ -4,10 +4,15 @@ ! file: zebra.conf ! ! +! hostname SpineFront01 password zebra enable password zebra ! +log syslog informational +log facility local4 +!! +! vrf VnetFE vni 9000 ! @@ -29,8 +34,4 @@ route-map RM_SET_SRC permit 10 ! ip protocol bgp route-map RM_SET_SRC ! -! -log syslog informational -log facility local4 -! - +!! diff --git a/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-zebra.conf b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-zebra.conf index c8157b0519a4..e047fcd64f29 100644 --- a/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-zebra.conf +++ b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-zebra.conf @@ -4,10 +4,15 @@ ! file: zebra.conf ! ! +! hostname SpineFront01 password zebra enable password zebra ! +log syslog informational +log facility local4 +!! +! vrf VnetFE vni 8000 ! @@ -29,8 +34,4 @@ route-map RM_SET_SRC permit 10 ! ip protocol bgp route-map RM_SET_SRC ! -! -log syslog informational -log facility local4 -! - +!! diff --git a/src/sonic-config-engine/tests/sample_output/zebra_frr.conf b/src/sonic-config-engine/tests/sample_output/zebra_frr.conf index 2b21ea523f7a..690f609dafcf 100644 --- a/src/sonic-config-engine/tests/sample_output/zebra_frr.conf +++ b/src/sonic-config-engine/tests/sample_output/zebra_frr.conf @@ -4,10 +4,15 @@ ! file: zebra.conf ! ! +! hostname switch-t0 password zebra enable password zebra ! +log syslog informational +log facility local4 +!! +! ! ! Enable link-detect (default disabled) interface PortChannel01 @@ -35,8 +40,4 @@ ip protocol bgp route-map RM_SET_SRC ! ipv6 protocol bgp route-map RM_SET_SRC6 ! -! -log syslog informational -log facility local4 -! - +!! diff --git a/src/sonic-config-engine/tests/test_frr.py b/src/sonic-config-engine/tests/test_frr.py new file mode 100644 index 000000000000..fcbff063b13b --- /dev/null +++ b/src/sonic-config-engine/tests/test_frr.py @@ -0,0 +1,62 @@ +from unittest import TestCase +import subprocess +import os +import filecmp + + +class TestCfgGen(TestCase): + def setUp(self): + self.test_dir = os.path.dirname(os.path.realpath(__file__)) + self.script_file = os.path.join(self.test_dir, '..', 'sonic-cfggen') + self.t0_minigraph = os.path.join(self.test_dir, 't0-sample-graph.xml') + self.t0_port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini') + self.output_file = os.path.join(self.test_dir, 'output') + + def tearDown(self): + try: + os.remove(self.output_file) + except OSError: + pass + + + def run_script(self, argument, check_stderr=False): +# print '\n Running sonic-cfggen ' + argument + if check_stderr: + output = subprocess.check_output(self.script_file + ' ' + argument, stderr=subprocess.STDOUT, shell=True) + else: + output = subprocess.check_output(self.script_file + ' ' + argument, shell=True) + + linecount = output.strip().count('\n') + if linecount <= 0: + print ' Output: ' + output.strip() + else: + print ' Output: ({0} lines, {1} bytes)'.format(linecount + 1, len(output)) + return output + + def run_diff(self, file1, file2): + return subprocess.check_output('diff -u {} {} || true'.format(file1, file2), shell=True) + + def run_case(self, template, target): + conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', template) + cmd = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + conf_template + ' > ' + self.output_file + self.run_script(cmd) + + original_filename = os.path.join(self.test_dir, 'sample_output', target) + r = filecmp.cmp(original_filename, self.output_file) + diff_output = self.run_diff(original_filename, self.output_file) if not r else "" + + return r, "Diff:\n" + diff_output + + + def test_config_frr(self): + self.assertTrue(*self.run_case('frr.conf.j2', 'frr.conf')) + + def test_bgpd_frr(self): + self.assertTrue(*self.run_case('bgpd.conf.j2', 'bgpd_frr.conf')) + + def test_zebra_frr(self): + self.assertTrue(*self.run_case('zebra.conf.j2', 'zebra_frr.conf')) + + def test_staticd_frr(self): + self.assertTrue(*self.run_case('staticd.conf.j2', 'staticd_frr.conf')) + diff --git a/src/sonic-config-engine/tests/test_j2files.py b/src/sonic-config-engine/tests/test_j2files.py index 1fd9df37e984..c3585a41d44e 100644 --- a/src/sonic-config-engine/tests/test_j2files.py +++ b/src/sonic-config-engine/tests/test_j2files.py @@ -77,34 +77,6 @@ def test_zebra_quagga(self): self.run_script(argument) self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'zebra_quagga.conf'), self.output_file)) - def test_config_frr(self): - conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'frr.conf.j2') - argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + conf_template + ' > ' + self.output_file - self.run_script(argument) - self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'frr.conf'), self.output_file)) - - - def test_bgpd_frr(self): - conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'bgpd.conf.j2') - argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + conf_template + ' > ' + self.output_file - self.run_script(argument) - original_filename = os.path.join(self.test_dir, 'sample_output', 'bgpd_frr.conf') - r = filecmp.cmp(original_filename, self.output_file) - diff_output = self.run_diff(original_filename, self.output_file) if not r else "" - self.assertTrue(r, "Diff:\n" + diff_output) - - def test_zebra_frr(self): - conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'zebra.conf.j2') - argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + conf_template + ' > ' + self.output_file - self.run_script(argument) - self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'zebra_frr.conf'), self.output_file)) - - def test_staticd_frr(self): - conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'staticd.conf.j2') - argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + conf_template + ' > ' + self.output_file - self.run_script(argument) - self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'staticd_frr.conf'), self.output_file)) - def test_ipinip(self): ipinip_file = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-orchagent', 'ipinip.json.j2') argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + ipinip_file + ' > ' + self.output_file diff --git a/src/sonic-config-engine/tests/test_j2files_t2_chassis_fe.py b/src/sonic-config-engine/tests/test_j2files_t2_chassis_fe.py index 531a9d477a66..41ac347e2b18 100644 --- a/src/sonic-config-engine/tests/test_j2files_t2_chassis_fe.py +++ b/src/sonic-config-engine/tests/test_j2files_t2_chassis_fe.py @@ -16,42 +16,39 @@ def setUp(self): self.t2_chassis_fe_port_config = os.path.join(self.test_dir, 't2-chassis-fe-port-config.ini') self.output_file = os.path.join(self.test_dir, 'output') + def tearDown(self): + try: + os.remove(self.output_file) + except OSError: + pass + def run_script(self, argument): print 'CMD: sonic-cfggen ' + argument return subprocess.check_output(self.script_file + ' ' + argument, shell=True) + def run_diff(self, file1, file2): + return subprocess.check_output('diff -u {} {} || true'.format(file1, file2), shell=True) + + def run_case(self, minigraph, template, target): + conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', template) + cmd = '-m ' + minigraph + ' -p ' + self.t2_chassis_fe_port_config + ' -t ' + conf_template + ' > ' + self.output_file + self.run_script(cmd) + + original_filename = os.path.join(self.test_dir, 'sample_output', target) + r = filecmp.cmp(original_filename, self.output_file) + diff_output = self.run_diff(original_filename, self.output_file) if not r else "" + + return r, "Diff:\n" + diff_output + # Test zebra.conf in FRR docker for a T2 chassis frontend (fe) def test_t2_chassis_fe_zebra_frr(self): - conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'zebra.conf.j2') - argument = '-m ' + self.t2_chassis_fe_minigraph + ' -p ' + self.t2_chassis_fe_port_config + ' -t ' + conf_template + ' > ' + self.output_file - self.run_script(argument) - self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 't2-chassis-fe-zebra.conf'), self.output_file)) - - # Test zebra.conf in FRR docker for a T2 chassis frontend (fe) switch with port channel interfaces - def test_t2_chassis_fe_pc_zebra_frr(self): - conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'zebra.conf.j2') - argument = '-m ' + self.t2_chassis_fe_pc_minigraph + ' -p ' + self.t2_chassis_fe_port_config + ' -t ' + conf_template + ' > ' + self.output_file - self.run_script(argument) - self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 't2-chassis-fe-pc-zebra.conf'), self.output_file)) + self.assertTrue(*self.run_case(self.t2_chassis_fe_minigraph, 'zebra.conf.j2', 't2-chassis-fe-zebra.conf')) # Test zebra.conf in FRR docker for a T2 chassis frontend (fe) switch with specified VNI def test_t2_chassis_fe_vni_zebra_frr(self): - conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'zebra.conf.j2') - argument = '-m ' + self.t2_chassis_fe_vni_minigraph + ' -p ' + self.t2_chassis_fe_port_config + ' -t ' + conf_template + ' > ' + self.output_file - self.run_script(argument) - self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 't2-chassis-fe-vni-zebra.conf'), self.output_file)) + self.assertTrue(*self.run_case(self.t2_chassis_fe_vni_minigraph, 'zebra.conf.j2', 't2-chassis-fe-vni-zebra.conf')) # Test bgpd.conf in FRR docker for a T2 chassis frontend (fe) def test_t2_chassis_frontend_bgpd_frr(self): - conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'bgpd.conf.j2') - argument = '-m ' + self.t2_chassis_fe_minigraph + ' -p ' + self.t2_chassis_fe_port_config + ' -t ' + conf_template + ' > ' + self.output_file - self.run_script(argument) - self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 't2-chassis-fe-bgpd.conf'), self.output_file)) - - def tearDown(self): - try: - os.remove(self.output_file) - except OSError: - pass - + self.assertTrue(*self.run_case(self.t2_chassis_fe_minigraph, 'bgpd.conf.j2', 't2-chassis-fe-bgpd.conf')) From 4d29e611a13f86f877586115c268c0769749db03 Mon Sep 17 00:00:00 2001 From: "arheneus@marvell.com" <51254330+antony-rheneus@users.noreply.github.com> Date: Fri, 25 Oct 2019 02:20:45 +0530 Subject: [PATCH 104/278] [build]: Kill arm march docker service before every run to avoid stale entries (#3644) [Makefile] Kill arm march docker service before every run to avoid stale entries [Platform] Marvell - add dtb deb pkg Signed-off-by: Antony Rheneus --- Makefile.work | 3 ++- platform/marvell-armhf/one-image.mk | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.work b/Makefile.work index e18cabeda9ca..37ee2e11529d 100644 --- a/Makefile.work +++ b/Makefile.work @@ -126,7 +126,8 @@ ifneq (,$(filter $(CONFIGURED_ARCH), armhf arm64)) DOCKER_MULTIARCH_CHECK := docker inspect --type image multiarch/qemu-user-static:register &> /dev/null || (echo "multiarch docker not found ..."; docker run --rm --privileged multiarch/qemu-user-static:register --reset --credential yes) - DOCKER_SERVICE_MULTIARCH_CHECK := docker -H unix:///var/run/march/docker.sock info &> /dev/null || (echo "Docker march service not running..."; sudo rm -fr /var/run/march/; (sudo $(SONIC_NATIVE_DOCKERD_FOR_MUTLIARCH) &) &>/dev/null ; sleep 1; sudo $(SONIC_USERFACL_DOCKERD_FOR_MUTLIARCH);) + DOCKER_SERVICE_SAFE_KILLER := (MARCH_PID=`ps -eo pid,cmd | grep "[0-9] dockerd.*march" | awk '{print $$1}'`; echo "Killing march docker $$MARCH_PID"; [ -z "$$MARCH_PID" ] || sudo kill -9 "$$MARCH_PID";) + DOCKER_SERVICE_MULTIARCH_CHECK := ($(DOCKER_SERVICE_SAFE_KILLER); sudo rm -fr /var/run/march/; (echo "Starting docker march service..."; sudo $(SONIC_NATIVE_DOCKERD_FOR_MUTLIARCH) &) &>/dev/null ; sleep 2; sudo $(SONIC_USERFACL_DOCKERD_FOR_MUTLIARCH);) # Docker service to load the compiled dockers-*.gz SONIC_NATIVE_DOCKERD_FOR_DOCKERFS := rm -fr $(PWD)/dockerfs/; mkdir -p $(PWD)/dockerfs/; sudo dockerd --storage-driver=overlay2 --iptables=false \ diff --git a/platform/marvell-armhf/one-image.mk b/platform/marvell-armhf/one-image.mk index 26ab6fb886a7..bed895d84d86 100644 --- a/platform/marvell-armhf/one-image.mk +++ b/platform/marvell-armhf/one-image.mk @@ -4,6 +4,7 @@ SONIC_ONE_IMAGE = sonic-marvell-armhf.bin $(SONIC_ONE_IMAGE)_MACHINE = marvell-armhf $(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie $(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR) +$(SONIC_ONE_IMAGE)_INSTALLS += $(LINUX_KERNEL_DTB) 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)) From 4026a8bc8d918cd27a079a37527f9242596d8c64 Mon Sep 17 00:00:00 2001 From: zzhiyuan Date: Thu, 24 Oct 2019 16:48:46 -0700 Subject: [PATCH 105/278] Remove macro generate_pg_profils for 7170 buffer (#3635) --- .../Arista-7170-64C/buffers_defaults_t0.j2 | 8 -------- .../Arista-7170-64C/buffers_defaults_t1.j2 | 8 -------- .../Arista-7170-Q59S20/buffers_defaults_t0.j2 | 8 -------- .../Arista-7170-Q59S20/buffers_defaults_t1.j2 | 8 -------- 4 files changed, 32 deletions(-) diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t0.j2 b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t0.j2 index e880e6bc3a9c..35188dbeb382 100644 --- a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t0.j2 +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t0.j2 @@ -59,14 +59,6 @@ }, {%- endmacro %} -{%- macro generate_pg_profils(port_names) %} - "BUFFER_PG": { - "{{ port_names }}|3-4": { - "profile" : "[BUFFER_PROFILE|ingress_lossless_profile]" - } - }, -{%- endmacro %} - {%- macro generate_queue_buffers(port_names) %} "BUFFER_QUEUE": { "{{ port_names }}|3-4": { diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t1.j2 b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t1.j2 index e115dc9f0a1d..eb945c25e636 100644 --- a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t1.j2 +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t1.j2 @@ -59,14 +59,6 @@ }, {%- endmacro %} -{%- macro generate_pg_profils(port_names) %} - "BUFFER_PG": { - "{{ port_names }}|3-4": { - "profile" : "[BUFFER_PROFILE|ingress_lossless_profile]" - } - }, -{%- endmacro %} - {%- macro generate_queue_buffers(port_names) %} "BUFFER_QUEUE": { "{{ port_names }}|3-4": { diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t0.j2 b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t0.j2 index 1f6e3f5ed35d..8cd886c14ffd 100644 --- a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t0.j2 +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t0.j2 @@ -71,14 +71,6 @@ }, {%- endmacro %} -{%- macro generate_pg_profils(port_names) %} - "BUFFER_PG": { - "{{ port_names }}|3-4": { - "profile" : "[BUFFER_PROFILE|ingress_lossless_profile]" - } - }, -{%- endmacro %} - {%- macro generate_queue_buffers(port_names) %} "BUFFER_QUEUE": { "{{ port_names }}|3-4": { diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t1.j2 b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t1.j2 index 7487a1db19ba..e14ad9214743 100644 --- a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t1.j2 +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t1.j2 @@ -71,14 +71,6 @@ }, {%- endmacro %} -{%- macro generate_pg_profils(port_names) %} - "BUFFER_PG": { - "{{ port_names }}|3-4": { - "profile" : "[BUFFER_PROFILE|ingress_lossless_profile]" - } - }, -{%- endmacro %} - {%- macro generate_queue_buffers(port_names) %} "BUFFER_QUEUE": { "{{ port_names }}|3-4": { From 040672c93fc9f6c110800f08562938d2ce1a46ec Mon Sep 17 00:00:00 2001 From: pra-moh <49077256+pra-moh@users.noreply.github.com> Date: Thu, 24 Oct 2019 18:16:06 -0700 Subject: [PATCH 106/278] [minigraph.py] Enable telemetry service by default (#3611) --- src/sonic-config-engine/minigraph.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 37d68bdbfb0c..33736383506b 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -800,8 +800,12 @@ def parse_xml(filename, platform=None, port_config_file=None): results['DHCP_SERVER'] = dict((item, {}) for item in dhcp_servers) results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers) results['TACPLUS_SERVER'] = dict((item, {'priority': '1', 'tcp_port': '49'}) for item in tacacs_servers) - results['ACL_TABLE'] = filter_acl_mirror_table_bindings(acls, neighbors, pcs) + results['FEATURE'] = { + 'telemetry': { + 'status': 'enabled' + } + } # Do not configure the minigraph's mirror session, which is currently unused # mirror_sessions = {} From c23aac1581d4cd59e87294d36854d92e3f98bfbc Mon Sep 17 00:00:00 2001 From: zhenggen-xu Date: Sun, 27 Oct 2019 21:15:39 -0700 Subject: [PATCH 107/278] [swss] Remove "-p port_config.ini" option from the portsyncd (#3671) * [portsyncd] Remove "-p port_config.ini" option from the portsyncd Signed-off-by: Zhenggen Xu --- dockers/docker-orchagent/supervisord.conf | 2 +- platform/p4/docker-sonic-p4/supervisord.conf | 2 +- platform/vs/docker-sonic-vs/supervisord.conf | 2 +- src/sonic-swss | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dockers/docker-orchagent/supervisord.conf b/dockers/docker-orchagent/supervisord.conf index 46b37e77c0e4..9ae2776f6d26 100644 --- a/dockers/docker-orchagent/supervisord.conf +++ b/dockers/docker-orchagent/supervisord.conf @@ -34,7 +34,7 @@ stdout_logfile=syslog stderr_logfile=syslog [program:portsyncd] -command=/usr/bin/portsyncd -p /usr/share/sonic/hwsku/port_config.ini +command=/usr/bin/portsyncd priority=4 autostart=false autorestart=false diff --git a/platform/p4/docker-sonic-p4/supervisord.conf b/platform/p4/docker-sonic-p4/supervisord.conf index 008f4c82d2c9..946e4cb36e3a 100644 --- a/platform/p4/docker-sonic-p4/supervisord.conf +++ b/platform/p4/docker-sonic-p4/supervisord.conf @@ -61,7 +61,7 @@ stdout_logfile=syslog stderr_logfile=syslog [program:portsyncd] -command=/usr/bin/portsyncd -p /port_config.ini +command=/usr/bin/portsyncd priority=6 autostart=false autorestart=false diff --git a/platform/vs/docker-sonic-vs/supervisord.conf b/platform/vs/docker-sonic-vs/supervisord.conf index 2010dc918e0a..65812d81fc93 100644 --- a/platform/vs/docker-sonic-vs/supervisord.conf +++ b/platform/vs/docker-sonic-vs/supervisord.conf @@ -44,7 +44,7 @@ stdout_logfile=syslog stderr_logfile=syslog [program:portsyncd] -command=/usr/bin/portsyncd -p /usr/share/sonic/hwsku/port_config.ini +command=/usr/bin/portsyncd priority=6 autostart=false autorestart=false diff --git a/src/sonic-swss b/src/sonic-swss index 731a8f57119d..2a1ffe8135c6 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit 731a8f57119d79e6d7ba6196f026a9e24664e074 +Subproject commit 2a1ffe8135c618d40dce9e4462a0a5ff604751d8 From dc6625c63f677dbfcba3c44271cbd0d7dd63db22 Mon Sep 17 00:00:00 2001 From: Prince Sunny Date: Mon, 28 Oct 2019 18:26:22 -0700 Subject: [PATCH 108/278] [submodule] update sonic-swss (#3675) --- src/sonic-swss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-swss b/src/sonic-swss index 2a1ffe8135c6..09171575324e 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit 2a1ffe8135c618d40dce9e4462a0a5ff604751d8 +Subproject commit 09171575324ea56f42f18e5203f501f9ccb92309 From 5961e031e11880c2a8ff34ec6c5ec0940e66a8e9 Mon Sep 17 00:00:00 2001 From: Ying Xie Date: Tue, 29 Oct 2019 08:30:27 -0700 Subject: [PATCH 109/278] [hostname-config] improve hostname-config process (#3676) We noticed in tests/production that there is a low probability failure where /etc/hosts could have some garbage characters before the entry for local host name. The consequence is that all sudo command would be very slow. In extreme cases it would prevent some services from starting properly. I suspect that the /etc/hosts file might be opened by some process causing the issue. Editing contents with new file level and replace the whole file should be safer. Signed-off-by: Ying Xie --- files/image_config/hostname/hostname-config.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/files/image_config/hostname/hostname-config.sh b/files/image_config/hostname/hostname-config.sh index 6cb8f73cf4af..e9f7fc122709 100755 --- a/files/image_config/hostname/hostname-config.sh +++ b/files/image_config/hostname/hostname-config.sh @@ -8,9 +8,15 @@ hostname -F /etc/hostname # Remove the old hostname entry from hosts file. # But, 'localhost' entry is used by multiple applications. Don't remove it altogether. +# Edit contents of /etc/hosts and put in /etc/hosts.new if [ $CURRENT_HOSTNAME != "localhost" ] || [ $CURRENT_HOSTNAME == $HOSTNAME ] ; then - sed -i "/\s$CURRENT_HOSTNAME$/d" /etc/hosts + sed "/\s$CURRENT_HOSTNAME$/d" /etc/hosts > /etc/hosts.new +else + cp -f /etc/hosts /etc/hosts.new fi -echo "127.0.0.1 $HOSTNAME" >> /etc/hosts +echo "127.0.0.1 $HOSTNAME" >> /etc/hosts.new +# Swap file: hosts.new and hosts +mv -f /etc/hosts /etc/hosts.old +mv -f /etc/hosts.new /etc/hosts From 3a7870955a94146fe04edbd26222ed3739217c19 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Tue, 29 Oct 2019 09:07:50 -0700 Subject: [PATCH 110/278] [bgpd]: Avoid crashing bgpcfgd when render of bgpd.peer.conf.j2 has issues (#3668) --- dockers/docker-fpm-frr/bgpcfgd | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dockers/docker-fpm-frr/bgpcfgd b/dockers/docker-fpm-frr/bgpcfgd index 4ba8977fddfa..aad3c0c6d627 100755 --- a/dockers/docker-fpm-frr/bgpcfgd +++ b/dockers/docker-fpm-frr/bgpcfgd @@ -116,9 +116,14 @@ class BGPConfigManager(object): for key, op, data in self.bgp_messages: if op == swsscommon.SET_COMMAND: if key not in self.peers: - cmds.append(self.bgp_peer_add_template.render(DEVICE_METADATA=self.meta, neighbor_addr=key, bgp_session=data)) - syslog.syslog(syslog.LOG_INFO, 'Peer {} added with attributes {}'.format(key, data)) - self.peers.add(key) + try: + txt = self.bgp_peer_add_template.render(DEVICE_METADATA=self.meta, neighbor_addr=key, bgp_session=data) + cmds.append(txt) + except: + syslog.syslog(syslog.LOG_ERR, 'Peer {}. Error in rendering the template for "SET" command {}'.format(key, data)) + else: + syslog.syslog(syslog.LOG_INFO, 'Peer {} added with attributes {}'.format(key, data)) + self.peers.add(key) else: # when the peer is already configured we support "shutdown/no shutdown" # commands for the peers only From 0f88137b6d87418a7677360b8650ff988e608ebe Mon Sep 17 00:00:00 2001 From: "Sudharsan D.G" Date: Tue, 29 Oct 2019 16:15:43 -0500 Subject: [PATCH 111/278] Updating the sonic-swss submodule pointer (#3680) --- src/sonic-swss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-swss b/src/sonic-swss index 09171575324e..20747fa63d59 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit 09171575324ea56f42f18e5203f501f9ccb92309 +Subproject commit 20747fa63d59f4aadaa06da282e23d8e1e0b9fdf From 1942e3363bcb841ab0db4f87cdee028e8fad30d4 Mon Sep 17 00:00:00 2001 From: "Sudharsan D.G" Date: Tue, 29 Oct 2019 20:05:55 -0500 Subject: [PATCH 112/278] Enable sflowmgrd in docker-sonic-vs (#3595) --- platform/vs/docker-sonic-vs/start.sh | 2 ++ platform/vs/docker-sonic-vs/supervisord.conf | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/platform/vs/docker-sonic-vs/start.sh b/platform/vs/docker-sonic-vs/start.sh index d99047b7bb25..8770d304fcd8 100755 --- a/platform/vs/docker-sonic-vs/start.sh +++ b/platform/vs/docker-sonic-vs/start.sh @@ -67,6 +67,8 @@ supervisorctl start nbrmgrd supervisorctl start vxlanmgrd +supervisorctl start sflowmgrd + # Start arp_update when VLAN exists VLAN=`sonic-cfggen -d -v 'VLAN.keys() | join(" ") if VLAN'` if [ "$VLAN" != "" ]; then diff --git a/platform/vs/docker-sonic-vs/supervisord.conf b/platform/vs/docker-sonic-vs/supervisord.conf index 65812d81fc93..143fe49d44a9 100644 --- a/platform/vs/docker-sonic-vs/supervisord.conf +++ b/platform/vs/docker-sonic-vs/supervisord.conf @@ -180,3 +180,11 @@ autostart=false autorestart=false stdout_logfile=syslog stderr_logfile=syslog + +[program:sflowmgrd] +command=/usr/bin/sflowmgrd +priority=22 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog From 8db6df508bd7d856393d98547a8d17be171dbbd5 Mon Sep 17 00:00:00 2001 From: Nazarii Hnydyn Date: Wed, 30 Oct 2019 16:33:58 +0200 Subject: [PATCH 113/278] [mellanox] Update FW/SDK: 13/29.2000.2308 and 4.3.2308 (#3666) Signed-off-by: Nazarii Hnydyn --- platform/mellanox/fw.mk | 5 ++--- platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers | 2 +- platform/mellanox/sdk.mk | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/platform/mellanox/fw.mk b/platform/mellanox/fw.mk index 0ad1b05137ae..2df1fd11cd75 100644 --- a/platform/mellanox/fw.mk +++ b/platform/mellanox/fw.mk @@ -11,13 +11,12 @@ else FW_FROM_URL = n endif - -MLNX_SPC_FW_VERSION = 13.2000.2162 +MLNX_SPC_FW_VERSION = 13.2000.2308 MLNX_SPC_FW_FILE = fw-SPC-rel-$(subst .,_,$(MLNX_SPC_FW_VERSION))-EVB.mfa $(MLNX_SPC_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC_FW_FILE) -MLNX_SPC2_FW_VERSION = 29.2000.2162 +MLNX_SPC2_FW_VERSION = 29.2000.2308 MLNX_SPC2_FW_FILE = fw-SPC2-rel-$(subst .,_,$(MLNX_SPC2_FW_VERSION))-EVB.mfa $(MLNX_SPC2_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC2_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC2_FW_FILE) diff --git a/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers b/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers index 3acd88b3e04e..f4df2ccaa534 160000 --- a/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers +++ b/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers @@ -1 +1 @@ -Subproject commit 3acd88b3e04ec09e5fb7e2b74ed94540a9fea21e +Subproject commit f4df2ccaa5342e7f3fa5a45a851ef32ea59c0654 diff --git a/platform/mellanox/sdk.mk b/platform/mellanox/sdk.mk index 779e072e3613..dee478e7d52c 100644 --- a/platform/mellanox/sdk.mk +++ b/platform/mellanox/sdk.mk @@ -1,5 +1,5 @@ MLNX_SDK_BASE_PATH = $(PLATFORM_PATH)/sdk-src/sx-kernel/Switch-SDK-drivers/bin/ -MLNX_SDK_VERSION = 4.3.2104 +MLNX_SDK_VERSION = 4.3.2308 MLNX_SDK_ISSU_VERSION = 101 MLNX_SDK_DEB_VERSION = $(subst _,.,$(MLNX_SDK_VERSION)) From cff30c59d005416b2159b7c2d9197ce89876819b Mon Sep 17 00:00:00 2001 From: yozhao101 <56170650+yozhao101@users.noreply.github.com> Date: Wed, 30 Oct 2019 16:41:55 -0700 Subject: [PATCH 114/278] [Services] Restart Router-advertiser service upon unexpected critical process exit (#3681) Signed-off-by: Yong Zhao --- dockers/docker-router-advertiser/Dockerfile.j2 | 2 ++ dockers/docker-router-advertiser/critical_processes | 1 + .../docker-router-advertiser.supervisord.conf | 6 ++++++ files/build_templates/radv.service.j2 | 4 ++++ rules/docker-router-advertiser.mk | 1 + 5 files changed, 14 insertions(+) create mode 100644 dockers/docker-router-advertiser/critical_processes diff --git a/dockers/docker-router-advertiser/Dockerfile.j2 b/dockers/docker-router-advertiser/Dockerfile.j2 index 1594a59c5e8a..39e7b28effc1 100644 --- a/dockers/docker-router-advertiser/Dockerfile.j2 +++ b/dockers/docker-router-advertiser/Dockerfile.j2 @@ -27,5 +27,7 @@ RUN apt-get clean -y && \ COPY ["start.sh", "/usr/bin/"] COPY ["docker-router-advertiser.supervisord.conf", "/etc/supervisor/conf.d/"] COPY ["radvd.conf.j2", "wait_for_intf.sh.j2", "/usr/share/sonic/templates/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor"] ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-router-advertiser/critical_processes b/dockers/docker-router-advertiser/critical_processes new file mode 100644 index 000000000000..238a0346ac9f --- /dev/null +++ b/dockers/docker-router-advertiser/critical_processes @@ -0,0 +1 @@ +radvd diff --git a/dockers/docker-router-advertiser/docker-router-advertiser.supervisord.conf b/dockers/docker-router-advertiser/docker-router-advertiser.supervisord.conf index f0bb4d5b3bbd..4ea84ab11c92 100644 --- a/dockers/docker-router-advertiser/docker-router-advertiser.supervisord.conf +++ b/dockers/docker-router-advertiser/docker-router-advertiser.supervisord.conf @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-script] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 diff --git a/files/build_templates/radv.service.j2 b/files/build_templates/radv.service.j2 index 3dadc56e46ab..54440241d5f6 100644 --- a/files/build_templates/radv.service.j2 +++ b/files/build_templates/radv.service.j2 @@ -3,12 +3,16 @@ Description=Router advertiser container Requires=updategraph.service After=updategraph.service swss.service Before=ntp-config.service +StartLimitIntervalSec=1200 +StartLimitBurst=3 [Service] User={{ sonicadmin_user }} ExecStartPre=/usr/bin/{{ docker_container_name }}.sh start ExecStart=/usr/bin/{{ docker_container_name }}.sh wait ExecStop=/usr/bin/{{ docker_container_name }}.sh stop +Restart=always +RestartSec=30 [Install] WantedBy=multi-user.target diff --git a/rules/docker-router-advertiser.mk b/rules/docker-router-advertiser.mk index 93dc0285585c..53e0d7600ec9 100644 --- a/rules/docker-router-advertiser.mk +++ b/rules/docker-router-advertiser.mk @@ -25,3 +25,4 @@ SONIC_STRETCH_DBG_DOCKERS += $(DOCKER_ROUTER_ADVERTISER_DBG) $(DOCKER_ROUTER_ADVERTISER)_CONTAINER_NAME = radv $(DOCKER_ROUTER_ADVERTISER)_RUN_OPT += --net=host --privileged -t $(DOCKER_ROUTER_ADVERTISER)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro +$(DOCKER_ROUTER_ADVERTISER)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) From f3c92e7779a1b5db72656358db71409a07543ca2 Mon Sep 17 00:00:00 2001 From: simonJi2018 <37395146+simonJi2018@users.noreply.github.com> Date: Fri, 1 Nov 2019 00:13:35 +0800 Subject: [PATCH 115/278] [nephos] support SAI 1.5.0 and fix docker syncd related makefile error (#3684) - support SAI 1.5.0 - fix docker syncd related makefile error --- platform/nephos/docker-syncd-nephos-rpc.mk | 4 ++- platform/nephos/docker-syncd-nephos.mk | 7 ++++- .../nephos/docker-syncd-nephos/Dockerfile.j2 | 4 ++- platform/nephos/nephos-modules.mk | 16 ++++++++++ platform/nephos/rules.mk | 3 +- platform/nephos/sai.mk | 29 +++++++++++++++++-- 6 files changed, 56 insertions(+), 7 deletions(-) diff --git a/platform/nephos/docker-syncd-nephos-rpc.mk b/platform/nephos/docker-syncd-nephos-rpc.mk index 9ee1aeab090c..dafc43b3e7e3 100644 --- a/platform/nephos/docker-syncd-nephos-rpc.mk +++ b/platform/nephos/docker-syncd-nephos-rpc.mk @@ -10,8 +10,9 @@ $(DOCKER_SYNCD_NEPHOS_RPC)_DEPENDS += $(SYNCD_RPC_DBG) \ $(LIBSAIREDIS_DBG) endif $(DOCKER_SYNCD_NEPHOS_RPC)_FILES += $(DSSERVE) $(NPX_DIAG) -$(DOCKER_SYNCD_NEPHOS_RPC)_LOAD_DOCKERS += $(DOCKER_SYNCD_NEPHOS) +$(DOCKER_SYNCD_NEPHOS_RPC)_LOAD_DOCKERS += $(DOCKER_SYNCD_BASE) SONIC_DOCKER_IMAGES += $(DOCKER_SYNCD_NEPHOS_RPC) +SONIC_STRETCH_DOCKERS += $(DOCKER_SYNCD_NEPHOS_RPC) ifeq ($(ENABLE_SYNCD_RPC),y) SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_SYNCD_NEPHOS_RPC) endif @@ -19,5 +20,6 @@ endif $(DOCKER_SYNCD_NEPHOS_RPC)_CONTAINER_NAME = syncd $(DOCKER_SYNCD_NEPHOS_RPC)_RUN_OPT += --net=host --privileged -t $(DOCKER_SYNCD_NEPHOS_RPC)_RUN_OPT += -v /host/machine.conf:/etc/machine.conf +$(DOCKER_SYNCD_NEPHOS_RPC)_RUN_OPT += -v /host/warmboot:/var/warmboot $(DOCKER_SYNCD_NEPHOS_RPC)_RUN_OPT += -v /var/run/docker-syncd:/var/run/sswsyncd $(DOCKER_SYNCD_NEPHOS_RPC)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro diff --git a/platform/nephos/docker-syncd-nephos.mk b/platform/nephos/docker-syncd-nephos.mk index 4acd688de865..6829c91c67aa 100644 --- a/platform/nephos/docker-syncd-nephos.mk +++ b/platform/nephos/docker-syncd-nephos.mk @@ -3,7 +3,8 @@ DOCKER_SYNCD_PLATFORM_CODE = nephos include $(PLATFORM_PATH)/../template/docker-syncd-base.mk -$(DOCKER_SYNCD_BASE)_DEPENDS += $(SYNCD) $(PYTHON_SDK_API) +$(DOCKER_SYNCD_BASE)_DEPENDS += $(SYNCD) +$(DOCKER_SYNCD_BASE)_FILES += $(DSSERVE) $(NPX_DIAG) $(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $(SYNCD_DBG) \ $(LIBSWSSCOMMON_DBG) \ @@ -11,3 +12,7 @@ $(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $(SYNCD_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 += npx_diag:/usr/bin/npx_diag + diff --git a/platform/nephos/docker-syncd-nephos/Dockerfile.j2 b/platform/nephos/docker-syncd-nephos/Dockerfile.j2 index bb15fdd63bbb..b889200f6ca4 100755 --- a/platform/nephos/docker-syncd-nephos/Dockerfile.j2 +++ b/platform/nephos/docker-syncd-nephos/Dockerfile.j2 @@ -32,7 +32,9 @@ debs/{{ deb }}{{' '}} ##debs/{{ deb }}{{' '}} ##{%- endfor %} -COPY ["start.sh", "/usr/bin/"] +COPY ["files/dsserve", "files/npx_diag", "start.sh", "/usr/bin/"] +RUN chmod +x /usr/bin/npx_diag /usr/bin/dsserve + COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] ## Clean up diff --git a/platform/nephos/nephos-modules.mk b/platform/nephos/nephos-modules.mk index 565e975e0a08..b76141b40663 100644 --- a/platform/nephos/nephos-modules.mk +++ b/platform/nephos/nephos-modules.mk @@ -2,9 +2,25 @@ VERSION = 1.0.0 +ifneq ($(NEPHOS_SAI_DEB_LOCAL_URL), ) +SDK_FROM_LOCAL = y +else +SDK_FROM_LOCAL = n +endif + +SDK_VERSION = 3.0.0 +LINUX_VER = 4.9.0-9-2 +SDK_COMMIT_ID = 529202 + +ifeq ($(SAI_FROM_LOCAL), y) +NEPHOS_MODULE = nps-modules-$(LINUX_VER)_$(SDK_VERSION)_$(SDK_COMMIT_ID)_amd64.deb +$(NEPHOS_MODULE)_PATH = $(NEPHOS_SAI_DEB_LOCAL_URL) +SONIC_COPY_DEBS += $(NEPHOS_MODULE) +else NEPHOS_MODULE = nephos-modules_$(VERSION)_amd64.deb $(NEPHOS_MODULE)_SRC_PATH = $(PLATFORM_PATH)/nephos-modules $(NEPHOS_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) SONIC_DPKG_DEBS += $(NEPHOS_MODULE) +endif SONIC_STRETCH_DEBS += $(NEPHOS_MODULE) diff --git a/platform/nephos/rules.mk b/platform/nephos/rules.mk index 797e2def91ce..5c115eeaf8d0 100644 --- a/platform/nephos/rules.mk +++ b/platform/nephos/rules.mk @@ -14,8 +14,9 @@ $(NPX_DIAG)_URL = "https://github.com/NephosInc/SONiC/raw/master/sdk/npx_diag" WARM_VERIFIER = warm-verifier $(WARM_VERIFIER)_URL = "https://github.com/NephosInc/SONiC/raw/master/sai/warm-verifier" + DSSERVE = dsserve -$(DSSERVE)_URL = "https://sonicstorage.blob.core.windows.net/packages/20170518/dsserve?sv=2015-04-05&sr=b&sig=gyNbgSL%2FvpMXDdpboVkIJcTKMRdGgEaOR9OukHhEsu8%3D&se=2030-03-31T23%3A06%3A35Z&sp=r" +$(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 += $(NPX_DIAG) $(WARM_VERIFIER) $(DSSERVE) diff --git a/platform/nephos/sai.mk b/platform/nephos/sai.mk index 93265dc74c56..edaa245cf5ad 100644 --- a/platform/nephos/sai.mk +++ b/platform/nephos/sai.mk @@ -1,12 +1,35 @@ -SDK_VERSION = 2.0.8 -SAI_VERSION = 1.4.1 -SAI_COMMIT_ID = cbb99f +SDK_VERSION = 3.0.0 +SAI_VERSION = 1.5.0 +SAI_COMMIT_ID = 426624 + +# Place here URL where SAI deb exist +NEPHOS_SAI_DEB_LOCAL_URL = +export NEPHOS_SAI_DEB_LOCAL_URL +# +ifneq ($(NEPHOS_SAI_DEB_LOCAL_URL), ) +SAI_FROM_LOCAL = y +else +SAI_FROM_LOCAL = n +endif + NEPHOS_SAI = libsainps_$(SDK_VERSION)_sai_$(SAI_VERSION)_$(SAI_COMMIT_ID)_amd64.deb +ifeq ($(SAI_FROM_LOCAL), y) +$(NEPHOS_SAI)_PATH = $(NEPHOS_SAI_DEB_LOCAL_URL) +else $(NEPHOS_SAI)_URL = "https://github.com/NephosInc/SONiC/raw/master/sai/libsainps_$(SDK_VERSION)_sai_$(SAI_VERSION)_$(SAI_COMMIT_ID)_amd64.deb" +endif NEPHOS_SAI_DEV = libsainps-dev_$(SDK_VERSION)_sai_$(SAI_VERSION)_$(SAI_COMMIT_ID)_amd64.deb $(eval $(call add_derived_package,$(NEPHOS_SAI),$(NEPHOS_SAI_DEV))) +ifeq ($(SAI_FROM_LOCAL), y) +$(NEPHOS_SAI_DEV)_PATH = $(NEPHOS_SAI_DEB_LOCAL_URL) +else $(NEPHOS_SAI_DEV)_URL = "https://github.com/NephosInc/SONiC/raw/master/sai/libsainps-dev_$(SDK_VERSION)_sai_$(SAI_VERSION)_$(SAI_COMMIT_ID)_amd64.deb" +endif +ifeq ($(SAI_FROM_LOCAL), y) +SONIC_COPY_DEBS += $(NEPHOS_SAI) $(NEPHOS_SAI_DEV) +else SONIC_ONLINE_DEBS += $(NEPHOS_SAI) $(NEPHOS_SAI_DEV) +endif $(NEPHOS_SAI_DEV)_DEPENDS += $(NEPHOS_SAI) From 841949f0994c4a845919e256bbb2989fb3219ff5 Mon Sep 17 00:00:00 2001 From: padmanarayana Date: Thu, 31 Oct 2019 09:15:30 -0700 Subject: [PATCH 116/278] [hsflowd]: Update hsflowd to 2.0.25-4 to take care of admin_state changes (#3683) --- rules/sflow.mk | 4 ++-- src/sflow/hsflowd/Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rules/sflow.mk b/rules/sflow.mk index b03e08446370..4366e3479734 100644 --- a/rules/sflow.mk +++ b/rules/sflow.mk @@ -1,7 +1,7 @@ # host-sflow package -HSFLOWD_VERSION = 2.0.21 -HSFLOWD_SUBVERSION = 8 +HSFLOWD_VERSION = 2.0.25 +HSFLOWD_SUBVERSION = 4 export HSFLOWD_VERSION HSFLOWD_SUBVERSION HSFLOWD = hsflowd_$(HSFLOWD_VERSION)-$(HSFLOWD_SUBVERSION)_$(CONFIGURED_ARCH).deb diff --git a/src/sflow/hsflowd/Makefile b/src/sflow/hsflowd/Makefile index 526e30e0490c..f0ff92a7af62 100644 --- a/src/sflow/hsflowd/Makefile +++ b/src/sflow/hsflowd/Makefile @@ -10,7 +10,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : git clone https://github.com/sflow/host-sflow pushd ./host-sflow - git checkout -b sflow -f 996f5ec + git checkout -b sflow tags/v2.0.25-4 # Apply patch series stg init From 064689d44221452f434d0c7ea5e2ee752999fe83 Mon Sep 17 00:00:00 2001 From: Stepan Blyshchak <38952541+stepanblyschak@users.noreply.github.com> Date: Thu, 31 Oct 2019 18:17:29 +0200 Subject: [PATCH 117/278] [sonic-cfggen] optimize sonic-cfggen startup (#3658) * [sonic-cfggen] optimize execution time a lot of template rendering causes switch to start longer because jinja2 needs to parse them. Introducing RedisBytecodeCache to store parsed buckets of internal template bytecode to speedup same template rendering during start * [sonic-cfggen] do lazy regexp compilation to speedup sonic-cfggen * [sonic-cfggen] address pep8 related comments Signed-off-by: Stepan Blyschak --- src/sonic-config-engine/lazy_re.py | 22 ++++++++++++++++++++++ src/sonic-config-engine/redis_bcc.py | 26 ++++++++++++++++++++++++++ src/sonic-config-engine/setup.py | 2 +- src/sonic-config-engine/sonic-cfggen | 16 ++++++++++++++-- 4 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 src/sonic-config-engine/lazy_re.py create mode 100644 src/sonic-config-engine/redis_bcc.py diff --git a/src/sonic-config-engine/lazy_re.py b/src/sonic-config-engine/lazy_re.py new file mode 100644 index 000000000000..b51c385c1cc6 --- /dev/null +++ b/src/sonic-config-engine/lazy_re.py @@ -0,0 +1,22 @@ +# monkey patch re.compile to improve import time of some packages + +import re + +_orig_re_compile = re.compile + + +def __re_compile(*args, **kwargs): + class __LazyReCompile(object): + def __init__(self, *args, **kwargs): + self.args = args + self.kwargs = kwargs + self.pattern_obj = None + + def __getattr__(self, name): + if self.pattern_obj is None: + self.pattern_obj = _orig_re_compile(*self.args, **self.kwargs) + return getattr(self.pattern_obj, name) + return __LazyReCompile(*args, **kwargs) + +re.compile = __re_compile + diff --git a/src/sonic-config-engine/redis_bcc.py b/src/sonic-config-engine/redis_bcc.py new file mode 100644 index 000000000000..5ab59b6a6959 --- /dev/null +++ b/src/sonic-config-engine/redis_bcc.py @@ -0,0 +1,26 @@ +import jinja2 + +class RedisBytecodeCache(jinja2.BytecodeCache): + """ A bytecode cache for jinja2 template that stores bytecode in Redis """ + + REDIS_HASH = 'JINJA2_CACHE' + + def __init__(self, client): + self._client = client + try: + self._client.connect(self._client.STATE_DB, retry_on=False) + except Exception: + self._client = None + + def load_bytecode(self, bucket): + if self._client is None: + return + code = self._client.get(self._client.STATE_DB, self.REDIS_HASH, bucket.key) + if code is not None: + bucket.bytecode_from_string(code) + + def dump_bytecode(self, bucket): + if self._client is None: + return + self._client.set(self._client.STATE_DB, self.REDIS_HASH, bucket.key, bucket.bytecode_to_string()) + diff --git a/src/sonic-config-engine/setup.py b/src/sonic-config-engine/setup.py index 7ca810ce6a54..c75a5b5a03a6 100755 --- a/src/sonic-config-engine/setup.py +++ b/src/sonic-config-engine/setup.py @@ -16,7 +16,7 @@ def get_test_suite(): author='Taoyu Li', author_email='taoyl@microsoft.com', url='https://github.com/Azure/sonic-buildimage', - py_modules=['portconfig', 'minigraph', 'openconfig_acl', 'sonic_device_util', 'config_samples'], + py_modules=['portconfig', 'minigraph', 'openconfig_acl', 'sonic_device_util', 'config_samples', 'redis_bcc', 'lazy_re'], scripts=['sonic-cfggen'], install_requires=['lxml', 'jinja2>=2.10', 'netaddr', 'ipaddr', 'pyyaml', 'pyangbind==0.6.0'], test_suite='setup.get_test_suite', diff --git a/src/sonic-config-engine/sonic-cfggen b/src/sonic-config-engine/sonic-cfggen index ca550b49e4bc..7cff6c9fb384 100755 --- a/src/sonic-config-engine/sonic-cfggen +++ b/src/sonic-config-engine/sonic-cfggen @@ -16,6 +16,16 @@ See usage string for detail description for arguments. """ from __future__ import print_function + +# monkey patch re.compile to do lazy regular expression compilation. +# This is done to improve import time of jinja2, yaml, natsort modules, because they +# do many regexp compilation at import time, so it will speed up sonic-cfggen invocations +# that do not require template generation or yaml loading. sonic-cfggen is used in so many places +# during system boot up that importing jinja2, yaml, natsort every time +# without lazy regular expression compilation affect boot up time. +# FIXME: remove this once sonic-cfggen and templates dependencies are replaced with a faster approach +import lazy_re + import sys import os.path import argparse @@ -33,7 +43,8 @@ from sonic_device_util import get_platform_info from sonic_device_util import get_system_mac from config_samples import generate_sample_config from config_samples import get_available_config -from swsssdk import ConfigDBConnector +from swsssdk import SonicV2Connector, ConfigDBConnector +from redis_bcc import RedisBytecodeCache from collections import OrderedDict from natsort import natsorted @@ -267,7 +278,8 @@ def main(): paths = ['/', '/usr/share/sonic/templates', os.path.dirname(template_file)] loader = jinja2.FileSystemLoader(paths) - env = jinja2.Environment(loader=loader, trim_blocks=True) + redis_bcc = RedisBytecodeCache(SonicV2Connector(host='127.0.0.1')) + env = jinja2.Environment(loader=loader, trim_blocks=True, bytecode_cache=redis_bcc) env.filters['sort_by_port_index'] = sort_by_port_index env.filters['ipv4'] = is_ipv4 env.filters['ipv6'] = is_ipv6 From 8dbe13c4cccb548903684b13c72847c0e094fd0b Mon Sep 17 00:00:00 2001 From: Stepan Blyshchak <38952541+stepanblyschak@users.noreply.github.com> Date: Thu, 31 Oct 2019 18:18:26 +0200 Subject: [PATCH 118/278] [services] improve startup time by changing startup order (#3656) * [services] improve startup time by given precedence to critical services (syncd.service) Signed-off-by: Stepan Blyschak --- files/build_templates/dhcp_relay.service.j2 | 2 +- files/build_templates/lldp.service.j2 | 2 +- files/build_templates/radv.service.j2 | 2 +- files/build_templates/sflow.service.j2 | 2 +- files/build_templates/snmp.service.j2 | 2 +- files/build_templates/telemetry.service.j2 | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/files/build_templates/dhcp_relay.service.j2 b/files/build_templates/dhcp_relay.service.j2 index 7ec133c87af7..f48217d55567 100644 --- a/files/build_templates/dhcp_relay.service.j2 +++ b/files/build_templates/dhcp_relay.service.j2 @@ -1,7 +1,7 @@ [Unit] Description=DHCP relay container Requires=updategraph.service swss.service teamd.service -After=updategraph.service swss.service teamd.service +After=updategraph.service swss.service syncd.service teamd.service Before=ntp-config.service [Service] diff --git a/files/build_templates/lldp.service.j2 b/files/build_templates/lldp.service.j2 index c317e18efc5c..6f8fc902befc 100644 --- a/files/build_templates/lldp.service.j2 +++ b/files/build_templates/lldp.service.j2 @@ -1,7 +1,7 @@ [Unit] Description=LLDP container Requires=updategraph.service -After=updategraph.service +After=updategraph.service swss.service syncd.service Before=ntp-config.service [Service] diff --git a/files/build_templates/radv.service.j2 b/files/build_templates/radv.service.j2 index 54440241d5f6..b3dd3a8d8bcb 100644 --- a/files/build_templates/radv.service.j2 +++ b/files/build_templates/radv.service.j2 @@ -1,7 +1,7 @@ [Unit] Description=Router advertiser container Requires=updategraph.service -After=updategraph.service swss.service +After=updategraph.service swss.service syncd.service Before=ntp-config.service StartLimitIntervalSec=1200 StartLimitBurst=3 diff --git a/files/build_templates/sflow.service.j2 b/files/build_templates/sflow.service.j2 index d77979bb338d..3a5752412b98 100644 --- a/files/build_templates/sflow.service.j2 +++ b/files/build_templates/sflow.service.j2 @@ -1,7 +1,7 @@ [Unit] Description=sFlow container Requires=swss.service -After=swss.service +After=swss.service syncd.service Before=ntp-config.service [Service] diff --git a/files/build_templates/snmp.service.j2 b/files/build_templates/snmp.service.j2 index a05c5fbe1d09..310048e68beb 100644 --- a/files/build_templates/snmp.service.j2 +++ b/files/build_templates/snmp.service.j2 @@ -2,7 +2,7 @@ Description=SNMP container Requires=updategraph.service Requisite=swss.service -After=updategraph.service swss.service +After=updategraph.service swss.service syncd.service Before=ntp-config.service StartLimitIntervalSec=1200 StartLimitBurst=3 diff --git a/files/build_templates/telemetry.service.j2 b/files/build_templates/telemetry.service.j2 index 8781ce7afb47..2e7e45218df2 100644 --- a/files/build_templates/telemetry.service.j2 +++ b/files/build_templates/telemetry.service.j2 @@ -1,7 +1,7 @@ [Unit] Description=Telemetry container Requires=database.service -After=database.service +After=database.service swss.service syncd.service Before=ntp-config.service [Service] From 6cc1f999759cdddc5af03922834bace17a37f732 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Thu, 31 Oct 2019 18:22:58 -0700 Subject: [PATCH 119/278] Return evpn configuration into bgp templates (#3693) --- dockers/docker-fpm-frr/bgpd.peer.conf.j2 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dockers/docker-fpm-frr/bgpd.peer.conf.j2 b/dockers/docker-fpm-frr/bgpd.peer.conf.j2 index 7dfdd50ea2c0..c3dc50449d35 100644 --- a/dockers/docker-fpm-frr/bgpd.peer.conf.j2 +++ b/dockers/docker-fpm-frr/bgpd.peer.conf.j2 @@ -24,6 +24,14 @@ {% endif %} {% if bgp_session['nhopself'] | int != 0 %} neighbor {{ neighbor_addr }} next-hop-self +{% endif %} +{% if bgp_session["asn"] == DEVICE_METADATA['localhost']['bgp_asn'] + and DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" + and (not bgp_session.has_key("local_addr") or bgp_session["local_addr"] not in interfaces_in_vnets) %} + address-family l2vpn evpn + neighbor {{ neighbor_addr }} activate + advertise-all-vni + exit-address-family {% endif %} neighbor {{ neighbor_addr }} activate exit-address-family From 815e2ef6f47284bff872ca369a229fd8a0d90086 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Fri, 1 Nov 2019 07:36:19 -0700 Subject: [PATCH 120/278] [minigraph.py]: Use default namespace for

(#3695) * [minigraph.py]: Use default namespace for
--- src/sonic-config-engine/minigraph.py | 4 ++-- src/sonic-config-engine/tests/test_cfggen.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 33736383506b..7799f3367d95 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -386,8 +386,8 @@ def parse_cpg(cpg, hname): 'name': name, 'ip_range': ip_range_group } - if bgpPeer.find(str(QName(ns1, "Address"))) is not None: - bgp_peers_with_range[name]['src_address'] = bgpPeer.find(str(QName(ns1, "Address"))).text + if bgpPeer.find(str(QName(ns, "Address"))) is not None: + bgp_peers_with_range[name]['src_address'] = bgpPeer.find(str(QName(ns, "Address"))).text if bgpPeer.find(str(QName(ns1, "PeerAsn"))) is not None: bgp_peers_with_range[name]['peer_asn'] = bgpPeer.find(str(QName(ns1, "PeerAsn"))).text else: diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index 6c9574af3514..8288b729584c 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -194,7 +194,7 @@ def test_minigraph_bgp(self): def test_minigraph_peers_with_range(self): argument = '-m "' + self.sample_graph_bgp_speaker + '" -p "' + self.port_config + '" -v BGP_PEER_RANGE.values\(\)' output = self.run_script(argument) - self.assertEqual(output.strip(), "[{'name': 'BGPSLBPassive', 'ip_range': ['10.10.10.10/26', '100.100.100.100/26']}]") + self.assertEqual(output.strip(), "[{'src_address': '10.1.0.32', 'name': 'BGPSLBPassive', 'ip_range': ['10.10.10.10/26', '100.100.100.100/26']}]") def test_minigraph_deployment_id(self): argument = '-m "' + self.sample_graph_bgp_speaker + '" -p "' + self.port_config + '" -v "DEVICE_METADATA[\'localhost\'][\'deployment_id\']"' From 4b59a430f1a277378d265f58cbb1dea5457d0fe2 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Mon, 4 Nov 2019 09:30:18 -0800 Subject: [PATCH 121/278] [docker-fpm-frr]: Add DEVICE_NEIGHBOR_METADATA into bgpcfgd (#3694) --- dockers/docker-fpm-frr/bgpcfgd | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/dockers/docker-fpm-frr/bgpcfgd b/dockers/docker-fpm-frr/bgpcfgd index aad3c0c6d627..b98a3f7ad45a 100755 --- a/dockers/docker-fpm-frr/bgpcfgd +++ b/dockers/docker-fpm-frr/bgpcfgd @@ -80,6 +80,7 @@ class BGPConfigManager(object): def __init__(self, daemon): self.bgp_asn = None self.meta = None + self.neig_meta = {} self.bgp_messages = [] self.peers = self.load_peers() # we can have bgp monitors peers here. it could be fixed by adding support for it here fabric = TemplateFabric() @@ -88,6 +89,7 @@ class BGPConfigManager(object): self.bgp_peer_shutdown = fabric.from_string('neighbor {{ neighbor_addr }} shutdown') self.bgp_peer_no_shutdown = fabric.from_string('no neighbor {{ neighbor_addr }} shutdown') daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, self.__metadata_handler) + daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_NEIGHBOR_METADATA_TABLE_NAME, self.__neighbor_metadata_handler) daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_BGP_NEIGHBOR_TABLE_NAME, self.__bgp_handler) def load_peers(self): @@ -111,13 +113,30 @@ class BGPConfigManager(object): self.bgp_asn = data["bgp_asn"] self.__update_bgp() + def __neighbor_metadata_handler(self, key, op, data): + if op == swsscommon.SET_COMMAND: + self.neig_meta[key] = data + elif op == swsscommon.DEL_COMMAND: + if key in self.neig_meta: + del self.neig_meta[key] + else: + syslog.syslog(syslog.LOG_ERR,"Can't remove key '%s' from neighbor metadata handler. The key doesn't exist" % key) + else: + syslog.syslog(syslog.LOG_ERR,"Wrong operation '%s' for neighbor metadata handler" % op) + self.__update_bgp() + def __update_bgp(self): cmds = [] + new_bgp_messages = [] for key, op, data in self.bgp_messages: if op == swsscommon.SET_COMMAND: if key not in self.peers: + if 'name' in data and data['name'] not in self.neig_meta: + # DEVICE_NEIGHBOR_METADATA should be populated before the rendering + new_bgp_messages.append((key, op, data)) + continue try: - txt = self.bgp_peer_add_template.render(DEVICE_METADATA=self.meta, neighbor_addr=key, bgp_session=data) + txt = self.bgp_peer_add_template.render(DEVICE_METADATA=self.meta, DEVICE_NEIGHBOR_METADATA=self.neig_meta, neighbor_addr=key, bgp_session=data) cmds.append(txt) except: syslog.syslog(syslog.LOG_ERR, 'Peer {}. Error in rendering the template for "SET" command {}'.format(key, data)) @@ -145,7 +164,7 @@ class BGPConfigManager(object): self.peers.remove(key) else: syslog.syslog(syslog.LOG_WARNING, 'Peer {} is not found'.format(key)) - self.bgp_messages = [] + self.bgp_messages = new_bgp_messages if len(cmds) == 0: return From d85777bb1135290721e297a37cafef362dc75d92 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Mon, 4 Nov 2019 09:36:15 -0800 Subject: [PATCH 122/278] [frr]: Fix the issue 'branch already exist' in frr package rebuilds (#3692) Fixed Makefile of FRR. Before we had issues after #3589: - When you want to rebuild frr with new changes you get error "branch frr/7.1 is already exist". - When your patch list is empty stg undo gives an error --- src/sonic-frr/Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sonic-frr/Makefile b/src/sonic-frr/Makefile index 233696de804a..abd9adc3fc67 100644 --- a/src/sonic-frr/Makefile +++ b/src/sonic-frr/Makefile @@ -4,8 +4,9 @@ SHELL = /bin/bash MAIN_TARGET = $(FRR) DERIVED_TARGET = $(FRR_PYTHONTOOLS) $(FRR_DBG) $(FRR_SNMP) $(FRR_SNMP_DBG) +SUFFIX = $(shell date +%Y%m%d\.%H%M%S) FRR_BRANCH = frr/$(FRR_VERSION) -STG_BRANCH = stg_temp +STG_BRANCH = stg_temp.$(SUFFIX) $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : # Build the package @@ -15,11 +16,12 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : stg import -s ../patch/series tools/tarsource.sh -V -e '-sonic' dpkg-buildpackage -rfakeroot -b -us -uc -Ppkg.frr.nortrlib -j$(SONIC_CONFIG_MAKE_JOBS) - stg undo + stg undo || true git clean -xfdf git checkout $(FRR_BRANCH) stg branch --delete $(STG_BRANCH) git rev-parse --short HEAD | xargs git checkout + git checkout master git branch -D $(FRR_BRANCH) popd mv $(DERIVED_TARGET) $* $(DEST)/ From 4fa3a1e27ec55829197cebe634864be7b1768d7d Mon Sep 17 00:00:00 2001 From: yozhao101 <56170650+yozhao101@users.noreply.github.com> Date: Mon, 4 Nov 2019 17:44:01 -0800 Subject: [PATCH 123/278] [Services] Restart Platform-monitor service upon unexpected critical process exit. (#3689) Signed-off-by: Yong Zhao --- dockers/docker-platform-monitor/Dockerfile.j2 | 2 ++ dockers/docker-platform-monitor/critical_processes | 5 +++++ .../docker-platform-monitor/docker-pmon.supervisord.conf.j2 | 6 ++++++ files/build_templates/pmon.service.j2 | 4 ++++ rules/docker-platform-monitor.mk | 1 + 5 files changed, 18 insertions(+) create mode 100644 dockers/docker-platform-monitor/critical_processes diff --git a/dockers/docker-platform-monitor/Dockerfile.j2 b/dockers/docker-platform-monitor/Dockerfile.j2 index c2e142727b80..fd11f628559c 100755 --- a/dockers/docker-platform-monitor/Dockerfile.j2 +++ b/dockers/docker-platform-monitor/Dockerfile.j2 @@ -57,5 +57,7 @@ RUN apt-get purge -y \ COPY ["docker_init.sh", "lm-sensors.sh", "/usr/bin/"] COPY ["docker-pmon.supervisord.conf.j2", "start.sh.j2", "/usr/share/sonic/templates/"] COPY ["ssd_tools/*", "/usr/bin/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor"] ENTRYPOINT ["/usr/bin/docker_init.sh"] diff --git a/dockers/docker-platform-monitor/critical_processes b/dockers/docker-platform-monitor/critical_processes new file mode 100644 index 000000000000..4233cda34982 --- /dev/null +++ b/dockers/docker-platform-monitor/critical_processes @@ -0,0 +1,5 @@ +fancontrol +ledd +xcvrd +psud +syseepromd diff --git a/dockers/docker-platform-monitor/docker-pmon.supervisord.conf.j2 b/dockers/docker-platform-monitor/docker-pmon.supervisord.conf.j2 index c6a571da9335..9a2414c30d05 100644 --- a/dockers/docker-platform-monitor/docker-pmon.supervisord.conf.j2 +++ b/dockers/docker-platform-monitor/docker-pmon.supervisord.conf.j2 @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 diff --git a/files/build_templates/pmon.service.j2 b/files/build_templates/pmon.service.j2 index 9c4226256818..11dea5d12783 100644 --- a/files/build_templates/pmon.service.j2 +++ b/files/build_templates/pmon.service.j2 @@ -6,12 +6,16 @@ After=updategraph.service After=syncd.service {% endif %} Before=ntp-config.service +StartLimitIntervalSec=1200 +StartLimitBurst=3 [Service] User={{ sonicadmin_user }} ExecStartPre=/usr/bin/{{docker_container_name}}.sh start ExecStart=/usr/bin/{{docker_container_name}}.sh wait ExecStop=/usr/bin/{{docker_container_name}}.sh stop +Restart=always +RestartSec=30 [Install] WantedBy=multi-user.target diff --git a/rules/docker-platform-monitor.mk b/rules/docker-platform-monitor.mk index 5eb26fec2f82..7a319e4bf120 100644 --- a/rules/docker-platform-monitor.mk +++ b/rules/docker-platform-monitor.mk @@ -44,3 +44,4 @@ $(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += cmd_wrapper:/usr/bin/sensors $(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += cmd_wrapper:/usr/sbin/smartctl $(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += cmd_wrapper:/usr/sbin/iSmart $(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += cmd_wrapper:/usr/sbin/SmartCmd +$(DOCKER_PLATFORM_MONITOR)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) From 4c31ef3cd217bc71071eba3b244829a1e72d1234 Mon Sep 17 00:00:00 2001 From: yozhao101 <56170650+yozhao101@users.noreply.github.com> Date: Mon, 4 Nov 2019 17:45:41 -0800 Subject: [PATCH 124/278] [Services] Restart Teamd service upon unexpected critical process exit. (#3703) Signed-off-by: Yong Zhao --- dockers/docker-teamd/Dockerfile.j2 | 2 ++ dockers/docker-teamd/critical_processes | 2 ++ dockers/docker-teamd/supervisord.conf | 8 +++++++- files/build_templates/teamd.service.j2 | 4 ++++ rules/docker-teamd.mk | 1 + 5 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 dockers/docker-teamd/critical_processes diff --git a/dockers/docker-teamd/Dockerfile.j2 b/dockers/docker-teamd/Dockerfile.j2 index 9188b7aaf735..fc8626e77229 100644 --- a/dockers/docker-teamd/Dockerfile.j2 +++ b/dockers/docker-teamd/Dockerfile.j2 @@ -36,5 +36,7 @@ RUN apt-get clean -y && \ COPY ["start.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor"] ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-teamd/critical_processes b/dockers/docker-teamd/critical_processes new file mode 100644 index 000000000000..b5c543df050d --- /dev/null +++ b/dockers/docker-teamd/critical_processes @@ -0,0 +1,2 @@ +teammgrd +teamsyncd diff --git a/dockers/docker-teamd/supervisord.conf b/dockers/docker-teamd/supervisord.conf index 738751d0a59f..3a420e0fcdcf 100644 --- a/dockers/docker-teamd/supervisord.conf +++ b/dockers/docker-teamd/supervisord.conf @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 @@ -15,7 +21,7 @@ stderr_logfile=syslog command=/usr/sbin/rsyslogd -n priority=2 autostart=false -autorestart=false +autorestart=unexpected stdout_logfile=syslog stderr_logfile=syslog diff --git a/files/build_templates/teamd.service.j2 b/files/build_templates/teamd.service.j2 index 8034698ecc07..be0521a4fbec 100644 --- a/files/build_templates/teamd.service.j2 +++ b/files/build_templates/teamd.service.j2 @@ -3,12 +3,16 @@ Description=TEAMD container Requires=updategraph.service After=updategraph.service swss.service Before=ntp-config.service +StartLimitIntervalSec=1200 +StartLimitBurst=3 [Service] User={{ sonicadmin_user }} ExecStartPre=/usr/bin/{{docker_container_name}}.sh start ExecStart=/usr/bin/{{docker_container_name}}.sh wait ExecStop=/usr/bin/{{docker_container_name}}.sh stop +Restart=always +RestartSec=30 [Install] WantedBy=multi-user.target diff --git a/rules/docker-teamd.mk b/rules/docker-teamd.mk index a697ce6b8891..598eff97e8f1 100644 --- a/rules/docker-teamd.mk +++ b/rules/docker-teamd.mk @@ -29,3 +29,4 @@ $(DOCKER_TEAMD)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro $(DOCKER_TEAMD)_RUN_OPT += -v /host/warmboot:/var/warmboot $(DOCKER_TEAMD)_BASE_IMAGE_FILES += teamdctl:/usr/bin/teamdctl +$(DOCKER_TEAMD)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) From d6f3fde8849cb4e8145c83ac27d8a18c82c9e9ff Mon Sep 17 00:00:00 2001 From: Aravind Mani <53524901+aravindmani-1@users.noreply.github.com> Date: Tue, 5 Nov 2019 11:40:20 +0530 Subject: [PATCH 125/278] [devices]: support SFP+ for Z9264F (#3700) - Changed sff8436 to optoe driver for both QSFP and SFP+ - Used optoe1 for QSFP and optoe2 for SFP. --- .../plugins/sfputil.py | 322 +++++++++++++++++- .../z9264f/scripts/z9264f_platform.sh | 28 +- 2 files changed, 346 insertions(+), 4 deletions(-) diff --git a/device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py index 24938a122c0e..df841bf88355 100644 --- a/device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py @@ -4,6 +4,7 @@ # try: + import io import struct import sys import getopt @@ -12,16 +13,46 @@ from sonic_sfp.sfputilbase import SfpUtilBase from os import * from mmap import * + from sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_sfp.sff8436 import sff8436Dom + from sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_sfp.sff8472 import sff8472Dom except ImportError as e: raise ImportError("%s - required module not found" % str(e)) +#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_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNL_THRESHOLD_OFFSET = 176 +QSFP_CHANNL_THRESHOLD_WIDTH = 16 +QSFP_CHANNL_MON_MASK_OFFSET = 242 +QSFP_CHANNL_MON_MASK_WIDTH = 4 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 56 + +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 1 class SfpUtil(SfpUtilBase): """Platform-specific SfpUtil class""" PORT_START = 1 - PORT_END = 64 + PORT_END = 66 PORTS_IN_BLOCK = 64 BASE_RES_PATH = "/sys/bus/pci/devices/0000:04:00.0/resource0" @@ -115,6 +146,9 @@ def get_presence(self, port_num): # Mask off 4th bit for presence mask = (1 << 4) + # Mask off 1st bit for presence 65,66 + if (port_num > 64): + mask = (1 << 0) # ModPrsL is active low if reg_value & mask == 0: return True @@ -300,4 +334,288 @@ def get_transceiver_change_event(self, timeout=0): self.oir_fd = -1 self.epoll = -1 - return False, {} \ No newline at end of file + return False, {} + + 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: + offset = 0 + offset_xcvr = 128 + file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + return None + + try: + sysfsfile_eeprom = io.open(file_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + return None + + # 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(sysfsfile_eeprom, (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_qsfp_dom_capability(qsfp_dom_capability_raw, 0) + else: + return None + + dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) + else: + return None + + dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) + else: + return None + + qsfp_dom_rev_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) + else: + return None + + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['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 = {} + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + 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(sysfsfile_eeprom, (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: + return None + + transceiver_dom_info_dict['tx1power'] = 'N/A' + transceiver_dom_info_dict['tx2power'] = 'N/A' + transceiver_dom_info_dict['tx3power'] = 'N/A' + transceiver_dom_info_dict['tx4power'] = 'N/A' + 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']['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'] + + else: + offset = 0 + 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 = io.open(file_path,"rb",0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8472Dom(None,1) + 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_MODULE_THRESHOLD_OFFSET), + SFP_MODULE_THRESHOLD_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: + file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + return None + + try: + sysfsfile_eeprom = io.open(file_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + # Dom Threshold data starts from offset 384 + # Revert offset back to 0 once data is retrieved + offset = 0 + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + sysfsfile_eeprom, + (offset + QSFP_MODULE_THRESHOLD_OFFSET), + QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + else: + return None + + dom_channel_threshold_raw = self._read_eeprom_specific_bytes( + sysfsfile_eeprom, + (offset + QSFP_CHANNL_THRESHOLD_OFFSET), + QSFP_CHANNL_THRESHOLD_WIDTH) + if dom_channel_threshold_raw is not None: + dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values(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['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] + + else: + offset = 0 + 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 = io.open(file_path,"rb",0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8472Dom(None,1) + 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_alarm_warning_threshold(dom_module_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']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + return transceiver_dom_threshold_info_dict diff --git a/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/z9264f_platform.sh b/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/z9264f_platform.sh index 7a7040cacb6c..3435704a65cb 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/z9264f_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/z9264f_platform.sh @@ -58,7 +58,7 @@ switch_board_qsfp() { "new_device") for ((i=2;i<=65;i++)); do - echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 done ;; @@ -74,6 +74,29 @@ switch_board_qsfp() { esac } +#Attach/Detach 2 instances of EEPROM driver SFP+ ports +#eeprom can dump data using below command +switch_board_sfp() { + case $1 in + "new_device") + for ((i=66;i<=67;i++)); + do + echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + done + ;; + + "delete_device") + for ((i=66;i<=67;i++)); + do + echo 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + done + ;; + + *) echo "z9264f_platform: switch_board_sfp: invalid command !" + ;; + esac +} + #Modsel 64 ports to applicable QSFP type modules #This enables the adapter to respond for i2c commands switch_board_modsel() { @@ -114,6 +137,7 @@ if [ "$1" == "init" ]; then sys_eeprom "new_device" switch_board_qsfp_mux "new_device" switch_board_qsfp "new_device" + switch_board_sfp "new_device" switch_board_modsel init_switch_port_led python /usr/bin/qsfp_irq_enable.py @@ -122,7 +146,7 @@ elif [ "$1" == "deinit" ]; then sys_eeprom "delete_device" switch_board_qsfp "delete_device" switch_board_qsfp_mux "delete_device" - + switch_board_sfp "delete_device" modprobe -r i2c-mux-pca954x modprobe -r i2c-dev else From ebcd2d5252996bbc23ed6fa61945e0f284c3e69f Mon Sep 17 00:00:00 2001 From: rkdevi27 <54701695+rkdevi27@users.noreply.github.com> Date: Wed, 6 Nov 2019 00:56:34 +0530 Subject: [PATCH 126/278] [devices]: Fixed Fpga crash on dell z9264 (#3672) Fixed the fpga crash issue which we see in 15-20 mins time frame after onie-install. Accessing stale i2c transfer message buffer causes this crash. Te message buffer becomes stale due to race between i2c transfer and fpga interrupt handler. This new state STATE_STOP will not be exposed for the wake up call till all the ISR of previous transfer is completed successfully. --- .../z9264f/modules/dell_z9264f_fpga_ocores.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-dell/z9264f/modules/dell_z9264f_fpga_ocores.c b/platform/broadcom/sonic-platform-modules-dell/z9264f/modules/dell_z9264f_fpga_ocores.c index d3a4a51ead72..c1644ecf705d 100644 --- a/platform/broadcom/sonic-platform-modules-dell/z9264f/modules/dell_z9264f_fpga_ocores.c +++ b/platform/broadcom/sonic-platform-modules-dell/z9264f/modules/dell_z9264f_fpga_ocores.c @@ -205,6 +205,7 @@ enum { STATE_START, STATE_WRITE, STATE_READ, + STATE_STOP, STATE_ERROR, }; @@ -591,10 +592,13 @@ static void fpgai2c_process(struct fpgalogic_i2c *i2c) PRINT("fpgai2c_process in. status reg :0x%x\n", stat); - if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) { + if ((i2c->state == STATE_STOP) || (i2c->state == STATE_ERROR)) { /* stop has been sent */ PRINT("fpgai2c_process FPGAI2C_REG_CMD_IACK stat = 0x%x Set FPGAI2C_REG_CMD(0%x) FPGAI2C_REG_CMD_IACK = 0x%x\n",stat, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK); fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK); + if(i2c->state == STATE_STOP) { + i2c->state = STATE_DONE; + } wake_up(&i2c->wait); return; } @@ -648,7 +652,7 @@ static void fpgai2c_process(struct fpgalogic_i2c *i2c) ? STATE_READ : STATE_WRITE; } } else { - i2c->state = STATE_DONE; + i2c->state = STATE_STOP; fpgai2c_stop(i2c); return; } @@ -722,6 +726,7 @@ static int fpgai2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) } else { + ret = -ETIMEDOUT; PRINT("Set FPGAI2C_REG_DATA(0%x) val = 0x%x\n",FPGAI2C_REG_DATA, (i2c->msg->addr << 1) | ((i2c->msg->flags & I2C_M_RD) ? 1:0)); @@ -733,9 +738,8 @@ static int fpgai2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) /* Interrupt mode */ if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || (i2c->state == STATE_DONE), HZ)) - return (i2c->state == STATE_DONE) ? num : -EIO; - else - return -ETIMEDOUT; + ret = (i2c->state == STATE_DONE) ? num : -EIO; + return ret; } } From a4c35b72d8d3ac5ba9cb6375ab2ecf6b54fb400b Mon Sep 17 00:00:00 2001 From: ciju-juniper <53076238+ciju-juniper@users.noreply.github.com> Date: Wed, 6 Nov 2019 01:25:58 +0530 Subject: [PATCH 127/278] [Juniper][QFX5210] Updating preemphasis values for supported optics (#3686) * Preemphasis values for various optics This patch adds the preemphasis values for the various supported optics for qfx5210 platform Signed-off-by: Ciju Rajan K --- .../media_settings.json | 19033 +++++++++++++++- .../qfx5210/utils/README | 34 +- 2 files changed, 18060 insertions(+), 1007 deletions(-) diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/media_settings.json b/device/juniper/x86_64-juniper_qfx5210-r0/media_settings.json index d2b28c0aea8b..22788f3a6f23 100644 --- a/device/juniper/x86_64-juniper_qfx5210-r0/media_settings.json +++ b/device/juniper/x86_64-juniper_qfx5210-r0/media_settings.json @@ -31,12 +31,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-1F3-1F3QAA": { "preemphasis": { - "lane0":"0xd3a02", - "lane1":"0x103f02", - "lane2":"0xd3a02", - "lane3":"0xd3a02" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -44,15 +44,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "1": { - "Default": { + }, + "JUNIPER-INNO-TF-FC030-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -61,7 +59,7 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC020-NJC": { "preemphasis": { "lane0":"0x1c4503", "lane1":"0x1c4503", @@ -75,12 +73,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TF-FC010-NJC": { "preemphasis": { - "lane0":"0xd3a02", - "lane1":"0x113f02", - "lane2":"0xd3a02", - "lane3":"0xd3a02" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -88,15 +86,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "2": { - "Default": { + }, + "JUNIPER-INNO-TF-FC001-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -105,7 +101,7 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC003-NJC": { "preemphasis": { "lane0":"0x1c4503", "lane1":"0x1c4503", @@ -119,12 +115,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TR-FC13R-NJ3": { "preemphasis": { - "lane0":"0xd3a02", - "lane1":"0xf3f02", - "lane2":"0xd3a02", - "lane3":"0xd3a02" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -132,15 +128,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "3": { - "Default": { + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -149,7 +143,7 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTLC9551REPM-J1": { "preemphasis": { "lane0":"0x1c4503", "lane1":"0x1c4503", @@ -163,12 +157,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { "preemphasis": { - "lane0":"0xd3a02", - "lane1":"0xf3f02", - "lane2":"0xd3a02", - "lane3":"0xd3a02" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -176,15 +170,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "4": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -193,12 +185,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { "preemphasis": { - "lane0":"0x1b4603", - "lane1":"0x1b4603", - "lane2":"0x1b4603", - "lane3":"0x1b4603" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -207,12 +199,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { "preemphasis": { - "lane0":"0xd3a02", - "lane1":"0xd3a02", - "lane2":"0xd3a02", - "lane3":"0xd3a02" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -220,15 +212,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "5": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -237,7 +227,7 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { "preemphasis": { "lane0":"0x1c4503", "lane1":"0x1c4503", @@ -251,10 +241,10 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "AVAGO-AFBR-79EQDZ-JU1": { "preemphasis": { "lane0":"0xd3a02", - "lane1":"0xd3a02", + "lane1":"0x103f02", "lane2":"0xd3a02", "lane3":"0xd3a02" }, @@ -264,15 +254,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "6": { - "Default": { + }, + "FINISAR CORP-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0xd3a02", + "lane1":"0x103f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -281,12 +269,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x174a03", - "lane1":"0x174a03", - "lane2":"0x174a03", - "lane3":"0x174a03" + "lane0":"0xd3a02", + "lane1":"0x103f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -298,7 +286,21 @@ "JUNIPER-INNO-TR-IQ13L-NJ3": { "preemphasis": { "lane0":"0xd3a02", - "lane1":"0xd3a02", + "lane1":"0x103f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0x103f02", "lane2":"0xd3a02", "lane3":"0xd3a02" }, @@ -310,7 +312,7 @@ } } }, - "7": { + "1": { "Default": { "preemphasis": { "lane0":"0x14410a", @@ -327,10 +329,10 @@ }, "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { "preemphasis": { - "lane0":"0x194803", - "lane1":"0x1b4603", - "lane2":"0x174a03", - "lane3":"0x174a03" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -339,12 +341,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-1F3-1F3QAA": { "preemphasis": { - "lane0":"0xd3a02", - "lane1":"0xd3a02", - "lane2":"0xd3a02", - "lane3":"0xd3a02" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -352,15 +354,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "8": { - "Default": { + }, + "JUNIPER-INNO-TF-FC030-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -369,7 +369,7 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC020-NJC": { "preemphasis": { "lane0":"0x1c4503", "lane1":"0x1c4503", @@ -383,12 +383,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TF-FC010-NJC": { "preemphasis": { - "lane0":"0xd3a02", - "lane1":"0xd3a02", - "lane2":"0xd3a02", - "lane3":"0xd3a02" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -396,15 +396,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "9": { - "Default": { + }, + "JUNIPER-INNO-TF-FC001-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -413,12 +411,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC003-NJC": { "preemphasis": { "lane0":"0x1c4503", "lane1":"0x1c4503", "lane2":"0x1c4503", - "lane3":"0x1d4403" + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -427,12 +425,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TR-FC13R-NJ3": { "preemphasis": { - "lane0":"0xd3a02", - "lane1":"0xf3f02", - "lane2":"0xd3a02", - "lane3":"0xf3a04" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -440,15 +438,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "10": { - "Default": { + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -457,12 +453,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTLC9551REPM-J1": { "preemphasis": { - "lane0":"0x1a4703", - "lane1":"0x1a4703", - "lane2":"0x1a4703", - "lane3":"0x1a4703" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -471,12 +467,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { "preemphasis": { - "lane0":"0xd3a02", - "lane1":"0xd3a02", - "lane2":"0xd3a02", - "lane3":"0xd3a02" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -484,15 +480,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "11": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -501,12 +495,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { "preemphasis": { - "lane0":"0x1b4603", - "lane1":"0x1b4603", - "lane2":"0x1a4703", - "lane3":"0x1b4603" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -515,12 +509,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { "preemphasis": { - "lane0":"0xd3a02", - "lane1":"0xd3a02", - "lane2":"0xd3a02", - "lane3":"0xd3a02" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -528,15 +522,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "12": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -545,12 +537,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { "preemphasis": { - "lane0":"0x154c03", - "lane1":"0x154c03", - "lane2":"0x154c03", - "lane3":"0x154c03" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -559,12 +551,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "AVAGO-AFBR-79EQDZ-JU1": { "preemphasis": { - "lane0":"0xa3402", - "lane1":"0xa3402", - "lane2":"0xa3402", - "lane3":"0xa3202" + "lane0":"0xd3a02", + "lane1":"0x113f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -572,15 +564,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "13": { - "Default": { + }, + "FINISAR CORP-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0xd3a02", + "lane1":"0x113f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -589,12 +579,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x154c03", - "lane1":"0x154c03", - "lane2":"0x154c03", - "lane3":"0x154c03" + "lane0":"0xd3a02", + "lane1":"0x113f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -605,10 +595,24 @@ }, "JUNIPER-INNO-TR-IQ13L-NJ3": { "preemphasis": { - "lane0":"0xa3402", - "lane1":"0xb3402", - "lane2":"0xa3402", - "lane3":"0xa3202" + "lane0":"0xd3a02", + "lane1":"0x113f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0x113f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -618,7 +622,7 @@ } } }, - "14": { + "2": { "Default": { "preemphasis": { "lane0":"0x14410a", @@ -635,10 +639,10 @@ }, "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { "preemphasis": { - "lane0":"0x154c03", - "lane1":"0x154c03", - "lane2":"0x154c03", - "lane3":"0x154c03" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -647,12 +651,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-1F3-1F3QAA": { "preemphasis": { - "lane0":"0xa3002", - "lane1":"0xa3002", - "lane2":"0xa3002", - "lane3":"0x93002" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -660,15 +664,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "15": { - "Default": { + }, + "JUNIPER-INNO-TF-FC030-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -677,12 +679,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC020-NJC": { "preemphasis": { - "lane0":"0x154c03", - "lane1":"0x154c03", - "lane2":"0x154c03", - "lane3":"0x154c03" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -691,12 +693,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TF-FC010-NJC": { "preemphasis": { - "lane0":"0xa3002", - "lane1":"0xa3002", - "lane2":"0xa3002", - "lane3":"0xa3002" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -704,15 +706,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "16": { - "Default": { + }, + "JUNIPER-INNO-TF-FC001-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -721,12 +721,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC003-NJC": { "preemphasis": { - "lane0":"0x154901", - "lane1":"0x124901", - "lane2":"0x124903", - "lane3":"0x144900" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -735,12 +735,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TR-FC13R-NJ3": { "preemphasis": { - "lane0":"0xa3002", - "lane1":"0xa3002", - "lane2":"0xa3002", - "lane3":"0x82d02" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -748,15 +748,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "17": { - "Default": { + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -765,12 +763,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTLC9551REPM-J1": { "preemphasis": { - "lane0":"0x154900", - "lane1":"0x124904", - "lane2":"0x124901", - "lane3":"0x144902" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -779,12 +777,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { "preemphasis": { - "lane0":"0xa3002", - "lane1":"0xa3002", - "lane2":"0xa3002", - "lane3":"0xa3002" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -792,15 +790,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "18": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -809,12 +805,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { "preemphasis": { - "lane0":"0x154900", - "lane1":"0x124900", - "lane2":"0x124903", - "lane3":"0x144902" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -823,12 +819,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { "preemphasis": { - "lane0":"0xa3002", - "lane1":"0xa3002", - "lane2":"0xa3002", - "lane3":"0xa3002" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -836,15 +832,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "19": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -853,12 +847,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { "preemphasis": { - "lane0":"0x154903", - "lane1":"0x124904", - "lane2":"0x124904", - "lane3":"0x144904" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -867,12 +861,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "AVAGO-AFBR-79EQDZ-JU1": { "preemphasis": { - "lane0":"0xa3002", - "lane1":"0xa3002", - "lane2":"0xa3002", - "lane3":"0xa3002" + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -880,15 +874,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "20": { - "Default": { + }, + "FINISAR CORP-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -897,12 +889,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x194803", - "lane1":"0x194803", - "lane2":"0x194803", - "lane3":"0x194803" + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -913,10 +905,24 @@ }, "JUNIPER-INNO-TR-IQ13L-NJ3": { "preemphasis": { - "lane0":"0xa3002", - "lane1":"0xa3002", - "lane2":"0xa3002", - "lane3":"0xc3002" + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -926,7 +932,7 @@ } } }, - "21": { + "3": { "Default": { "preemphasis": { "lane0":"0x14410a", @@ -943,10 +949,10 @@ }, "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { "preemphasis": { - "lane0":"0x194803", - "lane1":"0x194803", - "lane2":"0x194803", - "lane3":"0x194803" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -955,12 +961,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-1F3-1F3QAA": { "preemphasis": { - "lane0":"0xa3002", - "lane1":"0xa3002", - "lane2":"0xa3002", - "lane3":"0xa3002" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -968,15 +974,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "22": { - "Default": { + }, + "JUNIPER-INNO-TF-FC030-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -985,7 +989,7 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC020-NJC": { "preemphasis": { "lane0":"0x1c4503", "lane1":"0x1c4503", @@ -999,12 +1003,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TF-FC010-NJC": { "preemphasis": { - "lane0":"0xd3402", - "lane1":"0xd3402", - "lane2":"0xd3402", - "lane3":"0xd3402" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1012,15 +1016,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "23": { - "Default": { + }, + "JUNIPER-INNO-TF-FC001-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1029,12 +1031,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC003-NJC": { "preemphasis": { - "lane0":"0x1e4303", - "lane1":"0x1e4303", - "lane2":"0x1d4403", - "lane3":"0x1e4303" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1043,12 +1045,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TR-FC13R-NJ3": { "preemphasis": { - "lane0":"0xe3602", - "lane1":"0xf3a03", - "lane2":"0xf3d03", - "lane3":"0xf3d03" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1056,15 +1058,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "24": { - "Default": { + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1073,12 +1073,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTLC9551REPM-J1": { "preemphasis": { - "lane0":"0x154906", - "lane1":"0x154904", - "lane2":"0x154903", - "lane3":"0x154903" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1087,12 +1087,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { "preemphasis": { - "lane0":"0xa3002", - "lane1":"0xa3002", - "lane2":"0xa3002", - "lane3":"0xa3002" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1100,15 +1100,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "25": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1117,12 +1115,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { "preemphasis": { - "lane0":"0x174902", - "lane1":"0x174902", - "lane2":"0x174902", - "lane3":"0x174904" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1131,12 +1129,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { "preemphasis": { - "lane0":"0xa3002", - "lane1":"0xa3002", - "lane2":"0xa3002", - "lane3":"0xa3002" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1144,15 +1142,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "26": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1161,12 +1157,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { "preemphasis": { - "lane0":"0x1a4703", - "lane1":"0x184903", - "lane2":"0x184903", - "lane3":"0x1a4703" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1175,12 +1171,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "AVAGO-AFBR-79EQDZ-JU1": { "preemphasis": { - "lane0":"0xa3002", - "lane1":"0xa3002", - "lane2":"0xa3002", - "lane3":"0xa3002" + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -1188,15 +1184,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "27": { - "Default": { + }, + "FINISAR CORP-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -1205,14 +1199,14 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x1a4703", - "lane1":"0x1a4703", - "lane2":"0x1a4703", - "lane3":"0x1a4703" - }, - "idriver": { + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { "lane0":"0x8", "lane1":"0x8", "lane2":"0x8", @@ -1221,10 +1215,24 @@ }, "JUNIPER-INNO-TR-IQ13L-NJ3": { "preemphasis": { - "lane0":"0xb3203", - "lane1":"0xc3403", - "lane2":"0xc3403", - "lane3":"0xd3403" + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -1234,7 +1242,7 @@ } } }, - "28": { + "4": { "Default": { "preemphasis": { "lane0":"0x14410a", @@ -1251,10 +1259,10 @@ }, "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { "preemphasis": { - "lane0":"0x1a4505", - "lane1":"0x1a4505", - "lane2":"0x1a4505", - "lane3":"0x1a4505" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1263,12 +1271,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-1F3-1F3QAA": { "preemphasis": { - "lane0":"0xc3402", - "lane1":"0xd3402", - "lane2":"0xc3402", - "lane3":"0xc3402" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1276,15 +1284,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "29": { - "Default": { + }, + "JUNIPER-INNO-TF-FC030-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1293,7 +1299,7 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC020-NJC": { "preemphasis": { "lane0":"0x1b4603", "lane1":"0x1b4603", @@ -1307,12 +1313,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TF-FC010-NJC": { "preemphasis": { - "lane0":"0xc3402", - "lane1":"0xc3402", - "lane2":"0xc3402", - "lane3":"0xc3402" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1320,15 +1326,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "30": { - "Default": { + }, + "JUNIPER-INNO-TF-FC001-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1337,12 +1341,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC003-NJC": { "preemphasis": { - "lane0":"0x1a4604", - "lane1":"0x1a4604", - "lane2":"0x1a4604", - "lane3":"0x1a4604" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1351,12 +1355,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TR-FC13R-NJ3": { "preemphasis": { - "lane0":"0xc3402", - "lane1":"0xd3402", - "lane2":"0xc3402", - "lane3":"0xc3402" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1364,15 +1368,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "31": { - "Default": { + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1381,12 +1383,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTLC9551REPM-J1": { "preemphasis": { - "lane0":"0x1b4504", - "lane1":"0x1b4504", - "lane2":"0x1a4703", - "lane3":"0x1b4504" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1395,12 +1397,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { "preemphasis": { - "lane0":"0xd3602", - "lane1":"0xd3602", - "lane2":"0xd3602", - "lane3":"0xd3602" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1408,15 +1410,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "32": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1425,12 +1425,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { "preemphasis": { - "lane0":"0x1c4503", - "lane1":"0x1c4404", - "lane2":"0x1c4503", - "lane3":"0x1c4404" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1439,12 +1439,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { "preemphasis": { - "lane0":"0xf3a02", - "lane1":"0x113c03", - "lane2":"0xf3a03", - "lane3":"0xf3a03" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1452,15 +1452,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "33": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1469,12 +1467,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { "preemphasis": { - "lane0":"0x1c4503", - "lane1":"0x1c4503", - "lane2":"0x1c4503", - "lane3":"0x1c4503" + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" }, "idriver": { "lane0":"0x8", @@ -1483,12 +1481,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "AVAGO-AFBR-79EQDZ-JU1": { "preemphasis": { - "lane0":"0xf3a03", - "lane1":"0xf3a03", - "lane2":"0xf3a03", - "lane3":"0xf3a03" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -1496,15 +1494,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "34": { - "Default": { + }, + "FINISAR CORP-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -1513,12 +1509,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x1a4703", - "lane1":"0x1a4604", - "lane2":"0x1a4703", - "lane3":"0x1a4703" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -1529,10 +1525,24 @@ }, "JUNIPER-INNO-TR-IQ13L-NJ3": { "preemphasis": { - "lane0":"0xd3803", - "lane1":"0xe3803", - "lane2":"0xd3803", - "lane3":"0xc3403" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -1542,7 +1552,7 @@ } } }, - "35": { + "5": { "Default": { "preemphasis": { "lane0":"0x14410a", @@ -1560,9 +1570,9 @@ "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { "preemphasis": { "lane0":"0x1c4503", - "lane1":"0x1b4603", - "lane2":"0x1b4603", - "lane3":"0x1b4603" + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1571,12 +1581,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-1F3-1F3QAA": { "preemphasis": { - "lane0":"0xe3804", - "lane1":"0xe3803", - "lane2":"0xe3804", - "lane3":"0xe3804" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1584,15 +1594,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "36": { - "Default": { + }, + "JUNIPER-INNO-TF-FC030-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1601,12 +1609,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC020-NJC": { "preemphasis": { - "lane0":"0x1b4603", - "lane1":"0x1b4603", - "lane2":"0x1a4703", - "lane3":"0x1b4603" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1615,12 +1623,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TF-FC010-NJC": { "preemphasis": { - "lane0":"0xd3803", - "lane1":"0xd3803", - "lane2":"0xb3203", - "lane3":"0xc3403" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1628,15 +1636,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "37": { - "Default": { + }, + "JUNIPER-INNO-TF-FC001-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1645,12 +1651,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC003-NJC": { "preemphasis": { - "lane0":"0x194803", - "lane1":"0x194803", - "lane2":"0x194803", - "lane3":"0x194803" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1659,12 +1665,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TR-FC13R-NJ3": { "preemphasis": { - "lane0":"0xb3202", - "lane1":"0xb3202", - "lane2":"0xa3003", - "lane3":"0xb3003" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1672,15 +1678,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "38": { - "Default": { + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1689,12 +1693,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTLC9551REPM-J1": { "preemphasis": { - "lane0":"0x164903", - "lane1":"0x164903", - "lane2":"0x164903", - "lane3":"0x164903" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1703,12 +1707,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { "preemphasis": { - "lane0":"0xa3203", - "lane1":"0xa3203", - "lane2":"0xa3203", - "lane3":"0xa3203" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1716,15 +1720,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "39": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1733,12 +1735,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { "preemphasis": { - "lane0":"0x164901", - "lane1":"0x184901", - "lane2":"0x184901", - "lane3":"0x184901" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1747,12 +1749,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { "preemphasis": { - "lane0":"0xa3202", - "lane1":"0xa3202", - "lane2":"0xa3003", - "lane3":"0xa3003" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1760,15 +1762,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "40": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1777,12 +1777,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { "preemphasis": { "lane0":"0x1c4503", "lane1":"0x1c4503", "lane2":"0x1c4503", - "lane3":"0x1c4404" + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -1791,12 +1791,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "AVAGO-AFBR-79EQDZ-JU1": { "preemphasis": { - "lane0":"0xd3a03", - "lane1":"0xd3a03", - "lane2":"0xd3a03", - "lane3":"0xd3a03" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -1804,15 +1804,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "41": { - "Default": { + }, + "FINISAR CORP-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -1821,12 +1819,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x1b4603", - "lane1":"0x1a4703", - "lane2":"0x1b4603", - "lane3":"0x1c4503" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -1838,7 +1836,21 @@ "JUNIPER-INNO-TR-IQ13L-NJ3": { "preemphasis": { "lane0":"0xd3a02", - "lane1":"0xd3a03", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", "lane2":"0xd3a02", "lane3":"0xd3a02" }, @@ -1850,7 +1862,7 @@ } } }, - "42": { + "6": { "Default": { "preemphasis": { "lane0":"0x14410a", @@ -1867,10 +1879,10 @@ }, "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { "preemphasis": { - "lane0":"0x1a4703", - "lane1":"0x1a4703", - "lane2":"0x1a4703", - "lane3":"0x1a4703" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -1879,12 +1891,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-1F3-1F3QAA": { "preemphasis": { - "lane0":"0xd3a03", - "lane1":"0xd3a03", - "lane2":"0xb3a03", - "lane3":"0xa3803" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -1892,15 +1904,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "43": { - "Default": { + }, + "JUNIPER-INNO-TF-FC030-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -1909,12 +1919,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC020-NJC": { "preemphasis": { - "lane0":"0x1b4603", - "lane1":"0x1b4603", - "lane2":"0x1a4703", - "lane3":"0x1b4603" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -1923,12 +1933,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TF-FC010-NJC": { "preemphasis": { - "lane0":"0xd3a03", - "lane1":"0xd3a03", - "lane2":"0xd3a03", - "lane3":"0xd3a03" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -1936,15 +1946,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "44": { - "Default": { + }, + "JUNIPER-INNO-TF-FC001-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -1953,12 +1961,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC003-NJC": { "preemphasis": { - "lane0":"0x184902", - "lane1":"0x184902", - "lane2":"0x154902", - "lane3":"0x184902" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -1967,12 +1975,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TR-FC13R-NJ3": { "preemphasis": { - "lane0":"0x93003", - "lane1":"0x93003", - "lane2":"0x93003", - "lane3":"0x82f03" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -1980,15 +1988,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "45": { - "Default": { + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -1997,12 +2003,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTLC9551REPM-J1": { "preemphasis": { - "lane0":"0x154900", - "lane1":"0x154900", - "lane2":"0x154900", - "lane3":"0x154900" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2011,12 +2017,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { "preemphasis": { - "lane0":"0x72d03", - "lane1":"0x93003", - "lane2":"0x93003", - "lane3":"0x83003" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2024,15 +2030,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "46": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2041,12 +2045,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { "preemphasis": { - "lane0":"0x174900", - "lane1":"0x174900", - "lane2":"0x154900", - "lane3":"0x174904" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2055,12 +2059,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { "preemphasis": { - "lane0":"0x93003", - "lane1":"0x93003", - "lane2":"0x93003", - "lane3":"0x93003" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2068,15 +2072,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "47": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2085,12 +2087,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { "preemphasis": { - "lane0":"0x154903", - "lane1":"0x154903", - "lane2":"0x154903", - "lane3":"0x154903" + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2099,12 +2101,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "AVAGO-AFBR-79EQDZ-JU1": { "preemphasis": { - "lane0":"0x93003", - "lane1":"0x93003", - "lane2":"0x82e03", - "lane3":"0x83003" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -2112,15 +2114,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "48": { - "Default": { + }, + "FINISAR CORP-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -2129,12 +2129,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x184902", - "lane1":"0x164902", - "lane2":"0x164902", - "lane3":"0x144900" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -2145,10 +2145,24 @@ }, "JUNIPER-INNO-TR-IQ13L-NJ3": { "preemphasis": { - "lane0":"0x93003", - "lane1":"0x93003", - "lane2":"0x93003", - "lane3":"0x93003" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -2158,7 +2172,7 @@ } } }, - "49": { + "7": { "Default": { "preemphasis": { "lane0":"0x14410a", @@ -2175,10 +2189,10 @@ }, "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { "preemphasis": { - "lane0":"0x174901", - "lane1":"0x144902", - "lane2":"0x144902", - "lane3":"0x144903" + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2187,12 +2201,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-1F3-1F3QAA": { "preemphasis": { - "lane0":"0x93003", - "lane1":"0x93003", - "lane2":"0x93003", - "lane3":"0x93003" + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2200,15 +2214,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "50": { - "Default": { + }, + "JUNIPER-INNO-TF-FC030-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2217,12 +2229,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC020-NJC": { "preemphasis": { - "lane0":"0x184901", - "lane1":"0x174901", - "lane2":"0x164903", - "lane3":"0x154904" + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2231,12 +2243,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TF-FC010-NJC": { "preemphasis": { - "lane0":"0x93003", - "lane1":"0x93003", - "lane2":"0x83003", - "lane3":"0x93003" + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2244,15 +2256,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "51": { - "Default": { + }, + "JUNIPER-INNO-TF-FC001-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2261,12 +2271,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC003-NJC": { "preemphasis": { - "lane0":"0x154903", - "lane1":"0x154903", - "lane2":"0x134903", - "lane3":"0x144904" + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2275,12 +2285,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TR-FC13R-NJ3": { "preemphasis": { - "lane0":"0x93003", - "lane1":"0x93002", - "lane2":"0x82f03", - "lane3":"0x82f03" + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2288,15 +2298,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "52": { - "Default": { + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2305,12 +2313,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTLC9551REPM-J1": { "preemphasis": { "lane0":"0x194803", - "lane1":"0x194803", - "lane2":"0x194803", - "lane3":"0x194803" + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2319,12 +2327,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { "preemphasis": { - "lane0":"0xd3a02", - "lane1":"0x103f02", - "lane2":"0xd3a02", - "lane3":"0xd3a02" + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2332,15 +2340,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "53": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" }, "idriver": { "lane0":"0x8", @@ -2349,12 +2355,96 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { "preemphasis": { "lane0":"0x194803", - "lane1":"0x194803", - "lane2":"0x184803", - "lane3":"0x194803" + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -2365,10 +2455,24 @@ }, "JUNIPER-INNO-TR-IQ13L-NJ3": { "preemphasis": { - "lane0":"0xa3403", - "lane1":"0xa3403", - "lane2":"0xa3403", - "lane3":"0xa3403" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -2378,7 +2482,7 @@ } } }, - "54": { + "8": { "Default": { "preemphasis": { "lane0":"0x14410a", @@ -2396,9 +2500,9 @@ "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { "preemphasis": { "lane0":"0x1c4503", - "lane1":"0x1e4204", + "lane1":"0x1c4503", "lane2":"0x1c4503", - "lane3":"0x1d4304" + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -2407,12 +2511,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-1F3-1F3QAA": { "preemphasis": { - "lane0":"0xd3a02", - "lane1":"0xf3d02", - "lane2":"0xd3a03", - "lane3":"0xf3c03" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" }, "idriver": { "lane0":"0x8", @@ -2420,15 +2524,16935 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "55": { - "Default": { + }, + "JUNIPER-INNO-TF-FC030-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "9": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xf3a04" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xf3a04" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xf3a04" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xf3a04" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xf3a04" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "10": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "11": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "12": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3402", + "lane1":"0xa3402", + "lane2":"0xa3402", + "lane3":"0xa3202" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3402", + "lane1":"0xa3402", + "lane2":"0xa3402", + "lane3":"0xa3202" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3402", + "lane1":"0xa3402", + "lane2":"0xa3402", + "lane3":"0xa3202" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3402", + "lane1":"0xa3402", + "lane2":"0xa3402", + "lane3":"0xa3202" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3402", + "lane1":"0xa3402", + "lane2":"0xa3402", + "lane3":"0xa3202" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "13": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3402", + "lane1":"0xb3402", + "lane2":"0xa3402", + "lane3":"0xa3202" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3402", + "lane1":"0xb3402", + "lane2":"0xa3402", + "lane3":"0xa3202" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3402", + "lane1":"0xb3402", + "lane2":"0xa3402", + "lane3":"0xa3202" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3402", + "lane1":"0xb3402", + "lane2":"0xa3402", + "lane3":"0xa3202" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3402", + "lane1":"0xb3402", + "lane2":"0xa3402", + "lane3":"0xa3202" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "14": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0x93002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0x93002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0x93002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0x93002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0x93002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "15": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "16": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0x82d02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0x82d02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0x82d02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0x82d02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0x82d02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "17": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "18": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "19": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "20": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xc3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xc3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xc3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xc3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xc3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "21": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "22": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3402", + "lane1":"0xd3402", + "lane2":"0xd3403", + "lane3":"0xd3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3402", + "lane1":"0xd3402", + "lane2":"0xd3403", + "lane3":"0xd3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3402", + "lane1":"0xd3402", + "lane2":"0xd3403", + "lane3":"0xd3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3402", + "lane1":"0xd3402", + "lane2":"0xd3403", + "lane3":"0xd3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3402", + "lane1":"0xd3402", + "lane2":"0xd3403", + "lane3":"0xd3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "23": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xe3602", + "lane1":"0xf3a03", + "lane2":"0xf3d03", + "lane3":"0xf3d03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xe3602", + "lane1":"0xf3a03", + "lane2":"0xf3d03", + "lane3":"0xf3d03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xe3602", + "lane1":"0xf3a03", + "lane2":"0xf3d03", + "lane3":"0xf3d03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xe3602", + "lane1":"0xf3a03", + "lane2":"0xf3d03", + "lane3":"0xf3d03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xe3602", + "lane1":"0xf3a03", + "lane2":"0xf3d03", + "lane3":"0xf3d03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "24": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "25": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "26": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "27": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xb3203", + "lane1":"0xc3403", + "lane2":"0xc3403", + "lane3":"0xd3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xb3203", + "lane1":"0xc3403", + "lane2":"0xc3403", + "lane3":"0xd3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xb3203", + "lane1":"0xc3403", + "lane2":"0xc3403", + "lane3":"0xd3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xb3203", + "lane1":"0xc3403", + "lane2":"0xc3403", + "lane3":"0xd3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xb3203", + "lane1":"0xc3403", + "lane2":"0xc3403", + "lane3":"0xd3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "28": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xd3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xd3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xd3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xd3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xd3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "29": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xc3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xc3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xc3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xc3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xc3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "30": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xd3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xd3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xd3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xd3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xd3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "31": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3602", + "lane1":"0xd3602", + "lane2":"0xd3602", + "lane3":"0xd3602" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3602", + "lane1":"0xd3602", + "lane2":"0xd3602", + "lane3":"0xd3602" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3602", + "lane1":"0xd3602", + "lane2":"0xd3602", + "lane3":"0xd3602" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3602", + "lane1":"0xd3602", + "lane2":"0xd3602", + "lane3":"0xd3602" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3602", + "lane1":"0xd3602", + "lane2":"0xd3602", + "lane3":"0xd3602" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "32": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xf3a02", + "lane1":"0x113c03", + "lane2":"0xf3a03", + "lane3":"0xf3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xf3a02", + "lane1":"0x113c03", + "lane2":"0xf3a03", + "lane3":"0xf3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xf3a02", + "lane1":"0x113c03", + "lane2":"0xf3a03", + "lane3":"0xf3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xf3a02", + "lane1":"0x113c03", + "lane2":"0xf3a03", + "lane3":"0xf3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xf3a02", + "lane1":"0x113c03", + "lane2":"0xf3a03", + "lane3":"0xf3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "33": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xf3a03", + "lane1":"0xf3a03", + "lane2":"0xf3a03", + "lane3":"0xf3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xf3a03", + "lane1":"0xf3a03", + "lane2":"0xf3a03", + "lane3":"0xf3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xf3a03", + "lane1":"0xf3a03", + "lane2":"0xf3a03", + "lane3":"0xf3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xf3a03", + "lane1":"0xf3a03", + "lane2":"0xf3a03", + "lane3":"0xf3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xf3a03", + "lane1":"0xf3a03", + "lane2":"0xf3a03", + "lane3":"0xf3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "34": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3803", + "lane1":"0xe3803", + "lane2":"0xd3803", + "lane3":"0xc3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3803", + "lane1":"0xe3803", + "lane2":"0xd3803", + "lane3":"0xc3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3803", + "lane1":"0xe3803", + "lane2":"0xd3803", + "lane3":"0xc3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3803", + "lane1":"0xe3803", + "lane2":"0xd3803", + "lane3":"0xc3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3803", + "lane1":"0xe3803", + "lane2":"0xd3803", + "lane3":"0xc3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "35": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xe3804", + "lane1":"0xe3803", + "lane2":"0xe3804", + "lane3":"0xe3804" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xe3804", + "lane1":"0xe3803", + "lane2":"0xe3804", + "lane3":"0xe3804" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xe3804", + "lane1":"0xe3803", + "lane2":"0xe3804", + "lane3":"0xe3804" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xe3804", + "lane1":"0xe3803", + "lane2":"0xe3804", + "lane3":"0xe3804" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xe3804", + "lane1":"0xe3803", + "lane2":"0xe3804", + "lane3":"0xe3804" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "36": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3803", + "lane1":"0xd3803", + "lane2":"0xb3203", + "lane3":"0xc3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3803", + "lane1":"0xd3803", + "lane2":"0xb3203", + "lane3":"0xc3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3803", + "lane1":"0xd3803", + "lane2":"0xb3203", + "lane3":"0xc3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3803", + "lane1":"0xd3803", + "lane2":"0xb3203", + "lane3":"0xc3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3803", + "lane1":"0xd3803", + "lane2":"0xb3203", + "lane3":"0xc3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "37": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xb3202", + "lane1":"0xb3202", + "lane2":"0xa3003", + "lane3":"0xb3003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xb3202", + "lane1":"0xb3202", + "lane2":"0xa3003", + "lane3":"0xb3003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xb3202", + "lane1":"0xb3202", + "lane2":"0xa3003", + "lane3":"0xb3003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xb3202", + "lane1":"0xb3202", + "lane2":"0xa3003", + "lane3":"0xb3003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xb3202", + "lane1":"0xb3202", + "lane2":"0xa3003", + "lane3":"0xb3003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "38": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3203", + "lane1":"0xa3203", + "lane2":"0xa3203", + "lane3":"0xa3203" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3203", + "lane1":"0xa3203", + "lane2":"0xa3203", + "lane3":"0xa3203" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3203", + "lane1":"0xa3203", + "lane2":"0xa3203", + "lane3":"0xa3203" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3203", + "lane1":"0xa3203", + "lane2":"0xa3203", + "lane3":"0xa3203" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3203", + "lane1":"0xa3203", + "lane2":"0xa3203", + "lane3":"0xa3203" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "39": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3202", + "lane1":"0xa3202", + "lane2":"0xa3003", + "lane3":"0xa3003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3202", + "lane1":"0xa3202", + "lane2":"0xa3003", + "lane3":"0xa3003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3202", + "lane1":"0xa3202", + "lane2":"0xa3003", + "lane3":"0xa3003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3202", + "lane1":"0xa3202", + "lane2":"0xa3003", + "lane3":"0xa3003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3202", + "lane1":"0xa3202", + "lane2":"0xa3003", + "lane3":"0xa3003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "40": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "41": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "42": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xb3a03", + "lane3":"0xa3803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xb3a03", + "lane3":"0xa3803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xb3a03", + "lane3":"0xa3803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xb3a03", + "lane3":"0xa3803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xb3a03", + "lane3":"0xa3803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "43": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "44": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x82f03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x82f03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x82f03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x82f03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x82f03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "45": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0x72d03", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x83003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x72d03", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x83003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x72d03", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x83003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x72d03", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x83003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0x72d03", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x83003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "46": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "47": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x82e03", + "lane3":"0x83003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x82e03", + "lane3":"0x83003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x82e03", + "lane3":"0x83003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x82e03", + "lane3":"0x83003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x82e03", + "lane3":"0x83003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "48": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "49": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "50": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x83003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x83003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x83003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x83003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x83003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "51": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93002", + "lane2":"0x82f03", + "lane3":"0x82f03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93002", + "lane2":"0x82f03", + "lane3":"0x82f03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93002", + "lane2":"0x82f03", + "lane3":"0x82f03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93002", + "lane2":"0x82f03", + "lane3":"0x82f03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93002", + "lane2":"0x82f03", + "lane3":"0x82f03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "52": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "53": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "54": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xf3d02", + "lane2":"0xd3a03", + "lane3":"0xf3c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xf3d02", + "lane2":"0xd3a03", + "lane3":"0xf3c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xf3d02", + "lane2":"0xd3a03", + "lane3":"0xf3c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xf3d02", + "lane2":"0xd3a03", + "lane3":"0xf3c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xf3d02", + "lane2":"0xd3a03", + "lane3":"0xf3c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "55": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xb3a03", + "lane1":"0xc3a03", + "lane2":"0xa3403", + "lane3":"0xb3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xb3a03", + "lane1":"0xc3a03", + "lane2":"0xa3403", + "lane3":"0xb3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xb3a03", + "lane1":"0xc3a03", + "lane2":"0xa3403", + "lane3":"0xb3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xb3a03", + "lane1":"0xc3a03", + "lane2":"0xa3403", + "lane3":"0xb3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xb3a03", + "lane1":"0xc3a03", + "lane2":"0xa3403", + "lane3":"0xb3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "56": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "57": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0x93203", + "lane1":"0xa3603", + "lane2":"0x93203", + "lane3":"0x93203" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93203", + "lane1":"0xa3603", + "lane2":"0x93203", + "lane3":"0x93203" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0x93203", + "lane1":"0xa3603", + "lane2":"0x93203", + "lane3":"0x93203" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93203", + "lane1":"0xa3603", + "lane2":"0x93203", + "lane3":"0x93203" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0x93203", + "lane1":"0xa3603", + "lane2":"0x93203", + "lane3":"0x93203" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "58": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xb3403", + "lane3":"0xb3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xb3403", + "lane3":"0xb3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xb3403", + "lane3":"0xb3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xb3403", + "lane3":"0xb3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xb3403", + "lane3":"0xb3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "59": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xb3403", + "lane3":"0xb3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xb3403", + "lane3":"0xb3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xb3403", + "lane3":"0xb3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xb3403", + "lane3":"0xb3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xb3403", + "lane3":"0xb3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "60": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xc3603", + "lane3":"0xc3603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xc3603", + "lane3":"0xc3603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xc3603", + "lane3":"0xc3603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xc3603", + "lane3":"0xc3603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xc3603", + "lane3":"0xc3603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "61": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "AVAGO-AFBR-79EQDZ-JU1": { + "preemphasis": { + "lane0":"0xc3603", + "lane1":"0xd3a03", + "lane2":"0xc3603", + "lane3":"0xc3602" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "FINISAR CORP-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xc3603", + "lane1":"0xd3a03", + "lane2":"0xc3603", + "lane3":"0xc3602" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { + "preemphasis": { + "lane0":"0xc3603", + "lane1":"0xd3a03", + "lane2":"0xc3603", + "lane3":"0xc3602" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xc3603", + "lane1":"0xd3a03", + "lane2":"0xc3603", + "lane3":"0xc3602" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xc3603", + "lane1":"0xd3a03", + "lane2":"0xc3603", + "lane3":"0xc3602" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "62": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-1F3-1F3QAA": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC030-NJC": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC020-NJC": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC010-NJC": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC001-NJC": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TF-FC003-NJC": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13R-NJ3": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC9551REPM-J1": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" }, "idriver": { "lane0":"0x8", @@ -2437,12 +19461,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "AVAGO-AFBR-79EQDZ-JU1": { "preemphasis": { - "lane0":"0x1a4703", - "lane1":"0x1a4703", - "lane2":"0x1a4703", - "lane3":"0x1a4703" + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" }, "idriver": { "lane0":"0x8", @@ -2451,28 +19475,27 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "FINISAR CORP-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0xb3a03", - "lane1":"0xc3a03", - "lane2":"0xa3403", - "lane3":"0xb3a03" + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" }, "idriver": { "lane0":"0x8", "lane1":"0x8", + "lane1":"0x8", "lane2":"0x8", "lane3":"0x8" } - } - }, - "56": { - "Default": { + }, + "JUNIPER-FINISAR-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" }, "idriver": { "lane0":"0x8", @@ -2481,12 +19504,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TR-IQ13L-NJ3": { "preemphasis": { - "lane0":"0x184903", - "lane1":"0x184903", - "lane2":"0x184903", - "lane3":"0x184903" + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" }, "idriver": { "lane0":"0x8", @@ -2495,12 +19518,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TR-IQ13L-NJ5": { "preemphasis": { - "lane0":"0xa3403", - "lane1":"0xa3403", - "lane2":"0xa3403", - "lane3":"0xa3403" + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" }, "idriver": { "lane0":"0x8", @@ -2510,7 +19533,7 @@ } } }, - "57": { + "63": { "Default": { "preemphasis": { "lane0":"0x14410a", @@ -2527,10 +19550,10 @@ }, "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { "preemphasis": { - "lane0":"0x194803", - "lane1":"0x194803", - "lane2":"0x194903", - "lane3":"0x194803" + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2539,12 +19562,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-1F3-1F3QAA": { "preemphasis": { - "lane0":"0x93203", - "lane1":"0xa3603", - "lane2":"0x93203", - "lane3":"0x93203" + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2552,15 +19575,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "58": { - "Default": { + }, + "JUNIPER-INNO-TF-FC030-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2569,12 +19590,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC020-NJC": { "preemphasis": { - "lane0":"0x1a4703", - "lane1":"0x1a4703", + "lane0":"0x1b4504", + "lane1":"0x1b4504", "lane2":"0x1a4703", - "lane3":"0x1a4703" + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2583,12 +19604,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TF-FC010-NJC": { "preemphasis": { - "lane0":"0xb3403", - "lane1":"0xc3603", - "lane2":"0xb3403", - "lane3":"0xb3403" + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2596,15 +19617,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "59": { - "Default": { + }, + "JUNIPER-INNO-TF-FC001-NJC": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2613,12 +19632,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-INNO-TF-FC003-NJC": { "preemphasis": { - "lane0":"0x1a4703", - "lane1":"0x1a4703", + "lane0":"0x1b4504", + "lane1":"0x1b4504", "lane2":"0x1a4703", - "lane3":"0x1a4703" + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2627,12 +19646,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-INNO-TR-FC13R-NJ3": { "preemphasis": { - "lane0":"0xb3403", - "lane1":"0xc3603", - "lane2":"0xb3403", - "lane3":"0xb3403" + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2640,15 +19659,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "60": { - "Default": { + }, + "JUNIPER-INNO-TR-FC13T-NJ3": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2657,12 +19674,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTLC9551REPM-J1": { "preemphasis": { - "lane0":"0x1a4703", - "lane1":"0x1a4703", + "lane0":"0x1b4504", + "lane1":"0x1b4504", "lane2":"0x1a4703", - "lane3":"0x1a4505" + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2671,12 +19688,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FTLC1151RDPL-J1": { "preemphasis": { - "lane0":"0xb3403", - "lane1":"0xc3603", - "lane2":"0xc3603", - "lane3":"0xc3603" + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2684,15 +19701,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "61": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C01-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2701,12 +19716,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C03-J1": { "preemphasis": { - "lane0":"0x1b4603", - "lane1":"0x1b4603", - "lane2":"0x1b4603", - "lane3":"0x1b4603" + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2715,12 +19730,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "JUNIPER-FINISAR-FCBN425QE1C10-J1": { "preemphasis": { - "lane0":"0xc3603", - "lane1":"0xd3a03", - "lane2":"0xc3603", - "lane3":"0xc3602" + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2728,15 +19743,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "62": { - "Default": { + }, + "JUNIPER-FINISAR-FCBN425QE1C20-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2745,12 +19758,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FCBN425QE1C30-J1": { "preemphasis": { - "lane0":"0x1c4404", - "lane1":"0x1c4404", - "lane2":"0x1b4504", - "lane3":"0x1c4404" + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" }, "idriver": { "lane0":"0x8", @@ -2759,12 +19772,12 @@ "lane3":"0x8" } }, - "JUNIPER-INNO-TR-IQ13L-NJ3": { + "AVAGO-AFBR-79EQDZ-JU1": { "preemphasis": { - "lane0":"0xd3a03", - "lane1":"0xd3a03", + "lane0":"0xd3a02", + "lane1":"0xd3a02", "lane2":"0xd3a03", - "lane3":"0xd3a03" + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -2772,15 +19785,13 @@ "lane2":"0x8", "lane3":"0x8" } - } - }, - "63": { - "Default": { + }, + "FINISAR CORP-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x14410a", - "lane1":"0x14410a", - "lane2":"0x14410a", - "lane3":"0x14410a" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a03", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -2789,12 +19800,12 @@ "lane3":"0x8" } }, - "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "JUNIPER-FINISAR-FTL410QE3C-J1": { "preemphasis": { - "lane0":"0x1b4504", - "lane1":"0x1b4504", - "lane2":"0x1a4703", - "lane3":"0x1b4504" + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a03", + "lane3":"0xd3a02" }, "idriver": { "lane0":"0x8", @@ -2816,6 +19827,20 @@ "lane2":"0x8", "lane3":"0x8" } + }, + "JUNIPER-INNO-TR-IQ13L-NJ5": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a03", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } } } } diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/README b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/README index 490844f2137d..a69ac017c6f2 100755 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/README +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/README @@ -62,7 +62,23 @@ The status registers are mapped under /sys/bus/i2c/devices/9-0050 and SFPs ==== There are 64 QSFP+ modules supported in qfx5210 platform. EEPORMs will be -mapped under /sys/bus/i2c/devices/[25-88]-0050/ sysfs directory +mapped under /sys/bus/i2c/devices/[25-88]-0050/ sysfs directory. + +FEC should be turned on for SR4 optics and should be turned off for LR4 +optics. + +As an example, see this configuration for FEC for 100G SR4 optics in +/etc/sonic/config_db.json + +"Ethernet4": { + "admin_status": "up", + "alias": "Ethernet4", + "fec": "rs", + "index": "1", + "lanes": "65,66,67,68", + "mtu": "9100", + "speed": "100000" + } Sensor details ============== @@ -74,8 +90,20 @@ Platform poweroff ================= Linux poweroff commands such as 'poweroff', 'shutdown', 'halt', etc. will not power off qfx5210 platform as there are custom CPLDs control the power off -sequences. Use the command 'sudo platform_poweroff' to power off qfx5210 -platform +sequences. So acpi poweroff hooks are added for powering off the qfx5210. The +following messages are displayed in the console towards end of poweroff +sequence: + + [ 52.500807] System halt/power_off + [ 52.866331] reboot: Power down + [ 52.903257] pm_power_off: qfx5210_cpld_power_off + +Once the above messages are seen, you can safely remove the power to the system. + +Similarly platform reboot sequences are in place for system reboot. The following +messages are displayed in the console when the system is rebooted: + + [ 6053.163363] System restart: qfx5210_cpld_soft_reset Platform monitoring daemon ========================== From 7c5fb775d9d90c8140c8ca8b15ae841546a1ea30 Mon Sep 17 00:00:00 2001 From: Nazarii Hnydyn Date: Wed, 6 Nov 2019 00:27:18 +0200 Subject: [PATCH 128/278] [mellanox] Upgrade HW-MGMT to V.7.0000.2303 (#3707) Signed-off-by: Nazarii Hnydyn --- platform/mellanox/hw-management.mk | 2 +- platform/mellanox/hw-management/hw-mgmt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/mellanox/hw-management.mk b/platform/mellanox/hw-management.mk index 3e7749e11c4e..f41c2b9a25ce 100644 --- a/platform/mellanox/hw-management.mk +++ b/platform/mellanox/hw-management.mk @@ -1,6 +1,6 @@ # Mellanox HW Management -MLNX_HW_MANAGEMENT_VERSION = 7.0000.2300 +MLNX_HW_MANAGEMENT_VERSION = 7.0000.2303 export MLNX_HW_MANAGEMENT_VERSION diff --git a/platform/mellanox/hw-management/hw-mgmt b/platform/mellanox/hw-management/hw-mgmt index a72ba6371380..7c26a8f6a520 160000 --- a/platform/mellanox/hw-management/hw-mgmt +++ b/platform/mellanox/hw-management/hw-mgmt @@ -1 +1 @@ -Subproject commit a72ba6371380b6d97cadf9f57f11b05dd9ae576c +Subproject commit 7c26a8f6a520b06663992afe874bc56b1fcd9311 From ed79f545692d0cab53ef68c40098c6a654eb000f Mon Sep 17 00:00:00 2001 From: yozhao101 <56170650+yozhao101@users.noreply.github.com> Date: Tue, 5 Nov 2019 18:32:14 -0800 Subject: [PATCH 129/278] [Services] Restart DHCP-Relay service upon unexpected critical process exit. (#3667) Signed-off-by: Yong Zhao --- dockers/docker-dhcp-relay/Dockerfile.j2 | 2 ++ dockers/docker-dhcp-relay/critical_processes | 1 + .../docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 | 6 ++++++ files/build_templates/dhcp_relay.service.j2 | 4 ++++ files/scripts/supervisor-proc-exit-listener | 3 ++- rules/docker-dhcp-relay.mk | 1 + .../tests/sample_output/docker-dhcp-relay.supervisord.conf | 6 ++++++ 7 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 dockers/docker-dhcp-relay/critical_processes diff --git a/dockers/docker-dhcp-relay/Dockerfile.j2 b/dockers/docker-dhcp-relay/Dockerfile.j2 index e365adab1716..d3c09f9ba260 100644 --- a/dockers/docker-dhcp-relay/Dockerfile.j2 +++ b/dockers/docker-dhcp-relay/Dockerfile.j2 @@ -26,5 +26,7 @@ RUN apt-get clean -y && \ COPY ["docker_init.sh", "start.sh", "/usr/bin/"] COPY ["docker-dhcp-relay.supervisord.conf.j2", "wait_for_intf.sh.j2", "/usr/share/sonic/templates/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor"] ENTRYPOINT ["/usr/bin/docker_init.sh"] diff --git a/dockers/docker-dhcp-relay/critical_processes b/dockers/docker-dhcp-relay/critical_processes new file mode 100644 index 000000000000..ddb183963a67 --- /dev/null +++ b/dockers/docker-dhcp-relay/critical_processes @@ -0,0 +1 @@ +isc-dhcp-relay diff --git a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 index 4462ff3d7fdc..e738e8699e6c 100644 --- a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 +++ b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 diff --git a/files/build_templates/dhcp_relay.service.j2 b/files/build_templates/dhcp_relay.service.j2 index f48217d55567..9106e29a41e2 100644 --- a/files/build_templates/dhcp_relay.service.j2 +++ b/files/build_templates/dhcp_relay.service.j2 @@ -3,12 +3,16 @@ Description=DHCP relay container Requires=updategraph.service swss.service teamd.service After=updategraph.service swss.service syncd.service teamd.service Before=ntp-config.service +StartLimitIntervalSec=1200 +StartLimitBurst=3 [Service] User={{ sonicadmin_user }} ExecStartPre=/usr/bin/{{ docker_container_name }}.sh start ExecStart=/usr/bin/{{ docker_container_name }}.sh wait ExecStop=/usr/bin/{{ docker_container_name }}.sh stop +Restart=always +RestartSec=30 [Install] WantedBy=multi-user.target swss.service teamd.service diff --git a/files/scripts/supervisor-proc-exit-listener b/files/scripts/supervisor-proc-exit-listener index 6bc62fc400c8..8d1735cd2b0c 100755 --- a/files/scripts/supervisor-proc-exit-listener +++ b/files/scripts/supervisor-proc-exit-listener @@ -33,9 +33,10 @@ def main(): expected = int(payload_headers['expected']) processname = payload_headers['processname'] + groupname = payload_headers['groupname'] # If a critical process exited unexpectedly, terminate supervisor - if expected == 0 and processname in critical_processes: + if expected == 0 and processname in critical_processes or groupname in critical_processes: MSG_FORMAT_STR = "Process {} exited unxepectedly. Terminating supervisor..." msg = MSG_FORMAT_STR.format(payload_headers['processname']) syslog.syslog(syslog.LOG_INFO, msg) diff --git a/rules/docker-dhcp-relay.mk b/rules/docker-dhcp-relay.mk index 6fad19cc1998..5aae24ee33b5 100644 --- a/rules/docker-dhcp-relay.mk +++ b/rules/docker-dhcp-relay.mk @@ -25,3 +25,4 @@ SONIC_STRETCH_DBG_DOCKERS += $(DOCKER_DHCP_RELAY_DBG) $(DOCKER_DHCP_RELAY)_CONTAINER_NAME = dhcp_relay $(DOCKER_DHCP_RELAY)_RUN_OPT += --net=host --privileged -t $(DOCKER_DHCP_RELAY)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro +$(DOCKER_DHCP_RELAY)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) diff --git a/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf b/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf index d285fbfc788c..bae273eeaf81 100644 --- a/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf +++ b/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 From 9f1f61c8214a3a922bf972b6e27122df8e435d20 Mon Sep 17 00:00:00 2001 From: "Sudharsan D.G" Date: Wed, 6 Nov 2019 08:25:47 -0800 Subject: [PATCH 130/278] [submodule]: Updated sonic-utilities pointer (#3715) - [warm/fast reboot] continue executing when killing docker failed (#713) [Ying Xie] - [neighbor_advertiser]: Add sleep in setting mirror session and ACL rules(#714)[Shuotian Cheng] - [config]: Flush the neighbor table when removing the router interface(#606) [Shuotian Cheng] - Add a generic configlet application script (#716) [Renuka Manavalan] - Management vrf snmp cli support (#472) [Harish Venkatraman] - show subinterfaces status (#642) [Wenda Ni] - sonic-utilities: Add support for sFlow (#592) [Garrick He] --- src/sonic-utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-utilities b/src/sonic-utilities index c12c4434fa24..0e23e1cd0a3b 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit c12c4434fa2440914a705b9b15d142012eac4ce0 +Subproject commit 0e23e1cd0a3b3538061c8f971acd579bf2a9e151 From 997ea59ba4ac90981013a16dad1c48a8c14f286f Mon Sep 17 00:00:00 2001 From: Joe LeVeque Date: Wed, 6 Nov 2019 09:24:54 -0800 Subject: [PATCH 131/278] Fix typos and comment alignment in supervisor.conf files (#3714) --- .../etc/supervisor/supervisord.conf | 12 ++++++------ dockers/docker-base/etc/supervisor/supervisord.conf | 12 ++++++------ dockers/docker-ptf/supervisord.conf | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/dockers/docker-base-stretch/etc/supervisor/supervisord.conf b/dockers/docker-base-stretch/etc/supervisor/supervisord.conf index 351cc06fc048..5d1010e8fa4e 100644 --- a/dockers/docker-base-stretch/etc/supervisor/supervisord.conf +++ b/dockers/docker-base-stretch/etc/supervisor/supervisord.conf @@ -1,15 +1,15 @@ ; supervisor config file [unix_http_server] -file=/var/run/supervisor.sock ; (the path to the socket file) -chmod=0700 ; sockef file mode (default 0700) +file=/var/run/supervisor.sock ; (the path to the socket file) +chmod=0700 ; socket file mode (default 0700) username=dummy password=dummy [supervisord] -logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) -pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) -childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) +logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) +pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) +childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) user=root ; the below section must remain in the config file for RPC @@ -19,7 +19,7 @@ user=root supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] -serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket +serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket username=dummy password=dummy diff --git a/dockers/docker-base/etc/supervisor/supervisord.conf b/dockers/docker-base/etc/supervisor/supervisord.conf index 351cc06fc048..5d1010e8fa4e 100644 --- a/dockers/docker-base/etc/supervisor/supervisord.conf +++ b/dockers/docker-base/etc/supervisor/supervisord.conf @@ -1,15 +1,15 @@ ; supervisor config file [unix_http_server] -file=/var/run/supervisor.sock ; (the path to the socket file) -chmod=0700 ; sockef file mode (default 0700) +file=/var/run/supervisor.sock ; (the path to the socket file) +chmod=0700 ; socket file mode (default 0700) username=dummy password=dummy [supervisord] -logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) -pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) -childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) +logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) +pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) +childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) user=root ; the below section must remain in the config file for RPC @@ -19,7 +19,7 @@ user=root supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] -serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket +serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket username=dummy password=dummy diff --git a/dockers/docker-ptf/supervisord.conf b/dockers/docker-ptf/supervisord.conf index 9c236612d25c..be71d20a42d9 100644 --- a/dockers/docker-ptf/supervisord.conf +++ b/dockers/docker-ptf/supervisord.conf @@ -1,13 +1,13 @@ ; supervisor config file [unix_http_server] -file=/var/run/supervisor.sock ; (the path to the socket file) -chmod=0700 ; sockef file mode (default 0700) +file=/var/run/supervisor.sock ; (the path to the socket file) +chmod=0700 ; socket file mode (default 0700) [supervisord] -logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) -pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) -childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) +logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) +pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) +childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be @@ -16,7 +16,7 @@ childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TE supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] -serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket +serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket ; The [include] section can just contain the "files" setting. This ; setting can list multiple files (separated by whitespace or From 05e659901fa48c0691a97a48180d113a2d85e258 Mon Sep 17 00:00:00 2001 From: Samuel Angebault Date: Wed, 6 Nov 2019 10:11:38 -0800 Subject: [PATCH 132/278] [arista] Add support for more 7280CR3 variants (#3711) * Add extra Smartsville hwskus --- device/arista/x86_64-arista_7280cr3k_32p4 | 1 + files/Aboot/boot0.j2 | 10 +++++++++- platform/broadcom/sonic-platform-modules-arista | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 120000 device/arista/x86_64-arista_7280cr3k_32p4 diff --git a/device/arista/x86_64-arista_7280cr3k_32p4 b/device/arista/x86_64-arista_7280cr3k_32p4 new file mode 120000 index 000000000000..d6e2ddbb64bd --- /dev/null +++ b/device/arista/x86_64-arista_7280cr3k_32p4 @@ -0,0 +1 @@ +x86_64-arista_7280cr3_32p4 \ No newline at end of file diff --git a/files/Aboot/boot0.j2 b/files/Aboot/boot0.j2 index 1d8d3547d7ab..2f861bbbd405 100644 --- a/files/Aboot/boot0.j2 +++ b/files/Aboot/boot0.j2 @@ -258,10 +258,18 @@ platform_specific() { aboot_machine=arista_7060dx4_32 flash_size=28000 fi - if [ "$sid" = "Smartsville" ]; then + if [ "$sid" = "Smartsville" ] || [ "$sid" = "SmartsvilleSsd" ]; then aboot_machine=arista_7280cr3_32p4 flash_size=7382 fi + if [ "$sid" = "SmartsvilleBK" ] || [ "$sid" = "SmartsvilleBKSsd" ]; then + aboot_machine=arista_7280cr3k_32p4 + flash_size=7382 + fi + if [ "$sid" = "SmartsvilleDD" ] || [ "$sid" = "SmartsvilleDDSsd" ]; then + aboot_machine=arista_7280cr3_32d4 + flash_size=7382 + fi if [ "$platform" = "rook" ] || [ "$platform" = "magpie" ] || [ "$platform" = "woodpecker" ]; then echo "tsc=reliable pcie_ports=native" >>/tmp/append diff --git a/platform/broadcom/sonic-platform-modules-arista b/platform/broadcom/sonic-platform-modules-arista index 10750325b6cf..390d5e22f9c6 160000 --- a/platform/broadcom/sonic-platform-modules-arista +++ b/platform/broadcom/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit 10750325b6cfc7a1dc1a8b0734008bde1bb3ac06 +Subproject commit 390d5e22f9c6c1a007ed325f6b0bd050a79aa5b1 From a117b25446a97477486143c4a9780d0163c207d7 Mon Sep 17 00:00:00 2001 From: yozhao101 <56170650+yozhao101@users.noreply.github.com> Date: Wed, 6 Nov 2019 11:02:57 -0800 Subject: [PATCH 133/278] [Services] Restart LLDP service upon unexpected critical process exit. (#3713) Signed-off-by: Yong Zhao --- dockers/docker-lldp-sv2/Dockerfile.j2 | 2 ++ dockers/docker-lldp-sv2/critical_processes | 3 +++ dockers/docker-lldp-sv2/supervisord.conf | 6 ++++++ files/build_templates/lldp.service.j2 | 4 ++++ rules/docker-lldp-sv2.mk | 1 + 5 files changed, 16 insertions(+) create mode 100644 dockers/docker-lldp-sv2/critical_processes diff --git a/dockers/docker-lldp-sv2/Dockerfile.j2 b/dockers/docker-lldp-sv2/Dockerfile.j2 index 2a76c2cc6f0b..6a720514ef9b 100644 --- a/dockers/docker-lldp-sv2/Dockerfile.j2 +++ b/dockers/docker-lldp-sv2/Dockerfile.j2 @@ -40,5 +40,7 @@ COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] COPY ["lldpd.conf.j2", "/usr/share/sonic/templates/"] COPY ["lldpd", "/etc/default/"] COPY ["lldpmgrd", "/usr/bin/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor"] ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-lldp-sv2/critical_processes b/dockers/docker-lldp-sv2/critical_processes new file mode 100644 index 000000000000..b845b70bb3f7 --- /dev/null +++ b/dockers/docker-lldp-sv2/critical_processes @@ -0,0 +1,3 @@ +lldpd +lldp-syncd +lldpmgrd diff --git a/dockers/docker-lldp-sv2/supervisord.conf b/dockers/docker-lldp-sv2/supervisord.conf index 5feb3543f1bc..3f3f5beabc8d 100644 --- a/dockers/docker-lldp-sv2/supervisord.conf +++ b/dockers/docker-lldp-sv2/supervisord.conf @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 diff --git a/files/build_templates/lldp.service.j2 b/files/build_templates/lldp.service.j2 index 6f8fc902befc..2599fc5c5bdc 100644 --- a/files/build_templates/lldp.service.j2 +++ b/files/build_templates/lldp.service.j2 @@ -3,12 +3,16 @@ Description=LLDP container Requires=updategraph.service After=updategraph.service swss.service syncd.service Before=ntp-config.service +StartLimitIntervalSec=1200 +StartLimitBurst=3 [Service] User={{ sonicadmin_user }} ExecStartPre=/usr/bin/{{docker_container_name}}.sh start ExecStart=/usr/bin/{{docker_container_name}}.sh wait ExecStop=/usr/bin/{{docker_container_name}}.sh stop +Restart=always +RestartSec=30 [Install] WantedBy=multi-user.target diff --git a/rules/docker-lldp-sv2.mk b/rules/docker-lldp-sv2.mk index 104576f78891..91acbe58ad82 100644 --- a/rules/docker-lldp-sv2.mk +++ b/rules/docker-lldp-sv2.mk @@ -30,3 +30,4 @@ $(DOCKER_LLDP_SV2)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro $(DOCKER_LLDP_SV2)_BASE_IMAGE_FILES += lldpctl:/usr/bin/lldpctl $(DOCKER_LLDP_SV2)_BASE_IMAGE_FILES += lldpcli:/usr/bin/lldpcli +$(DOCKER_LLDP_SV2)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) From aa1a13677d071184abd254be5e63f227a053b713 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Wed, 6 Nov 2019 11:57:23 -0800 Subject: [PATCH 134/278] [frr]: Move to version 7.2 (#3704) * Use 7.2 tree to generate frr packages * Adapt patches for frr/7.2 * Use vrf_id --- rules/frr.mk | 2 +- src/sonic-frr/frr | 2 +- ...01-Add-support-of-bgp-tcp-DSCP-value.patch | 26 +- ...verity-of-Vty-connected-from-message.patch | 8 +- ...003-Use-vrf_id-for-vrf-not-tabled_id.patch | 35 +++ ...EXT_HOP-to-be-0.0.0.0-due-to-allevia.patch | 8 +- src/sonic-frr/patch/0005-Support-VRF.patch | 30 --- ...-dead-fd-poll-data-port-fix-from-frr.patch | 107 --------- ...-zebra-kernel-level-graceful-restart.patch | 227 ------------------ src/sonic-frr/patch/series | 4 +- 10 files changed, 59 insertions(+), 390 deletions(-) create mode 100644 src/sonic-frr/patch/0003-Use-vrf_id-for-vrf-not-tabled_id.patch delete mode 100644 src/sonic-frr/patch/0005-Support-VRF.patch delete mode 100644 src/sonic-frr/patch/0007-prevent-dead-fd-poll-data-port-fix-from-frr.patch delete mode 100644 src/sonic-frr/patch/0008-zebra-kernel-level-graceful-restart.patch diff --git a/rules/frr.mk b/rules/frr.mk index 83c359992ac3..27391ce0cf73 100644 --- a/rules/frr.mk +++ b/rules/frr.mk @@ -1,6 +1,6 @@ # FRRouting (frr) package -FRR_VERSION = 7.1 +FRR_VERSION = 7.2 FRR_SUBVERSION = 0 export FRR_VERSION FRR_SUBVERSION diff --git a/src/sonic-frr/frr b/src/sonic-frr/frr index 8c5e037c4960..514f508fc60e 160000 --- a/src/sonic-frr/frr +++ b/src/sonic-frr/frr @@ -1 +1 @@ -Subproject commit 8c5e037c496025597406f496010d6ef6b1d2e73d +Subproject commit 514f508fc60e0573d9863beaad8924927d373954 diff --git a/src/sonic-frr/patch/0001-Add-support-of-bgp-tcp-DSCP-value.patch b/src/sonic-frr/patch/0001-Add-support-of-bgp-tcp-DSCP-value.patch index c7676fd65cb4..9587231d8870 100644 --- a/src/sonic-frr/patch/0001-Add-support-of-bgp-tcp-DSCP-value.patch +++ b/src/sonic-frr/patch/0001-Add-support-of-bgp-tcp-DSCP-value.patch @@ -1,6 +1,6 @@ -From ab8ae984def8ee5cea22f802b2a60a05214c11d2 Mon Sep 17 00:00:00 2001 +From 3ec4fa4c8377330d4e3bdbdfc453a79a7827d84d Mon Sep 17 00:00:00 2001 From: Pavel Shirshov -Date: Mon, 7 Oct 2019 17:00:15 -0700 +Date: Mon, 4 Nov 2019 18:09:51 -0800 Subject: [PATCH 1/1] Add support of bgp tcp DSCP value --- @@ -11,12 +11,12 @@ Subject: [PATCH 1/1] Add support of bgp tcp DSCP value 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c -index 6a5c2c4b3..9ec162aa4 100644 +index 1394c60b2..a70268b05 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c -@@ -627,11 +627,9 @@ int bgp_connect(struct peer *peer) +@@ -633,11 +633,9 @@ int bgp_connect(struct peer *peer) #ifdef IPTOS_PREC_INTERNETCONTROL - frr_elevate_privs(&bgpd_privs) { + frr_with_privs(&bgpd_privs) { if (sockunion_family(&peer->su) == AF_INET) - setsockopt_ipv4_tos(peer->fd, - IPTOS_PREC_INTERNETCONTROL); @@ -28,7 +28,7 @@ index 6a5c2c4b3..9ec162aa4 100644 } #endif -@@ -707,10 +705,9 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen, +@@ -713,10 +711,9 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen, #ifdef IPTOS_PREC_INTERNETCONTROL if (sa->sa_family == AF_INET) @@ -42,10 +42,10 @@ index 6a5c2c4b3..9ec162aa4 100644 sockopt_v6only(sa->sa_family, sock); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c -index d05432327..a15a0f526 100644 +index 141d5cf30..8faa918d0 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c -@@ -1139,6 +1139,42 @@ DEFUN (no_router_bgp, +@@ -1182,6 +1182,42 @@ DEFUN (no_router_bgp, return CMD_SUCCESS; } @@ -88,7 +88,7 @@ index d05432327..a15a0f526 100644 /* BGP router-id. */ -@@ -12929,6 +12965,10 @@ void bgp_vty_init(void) +@@ -13035,6 +13071,10 @@ void bgp_vty_init(void) /* "no router bgp" commands. */ install_element(CONFIG_NODE, &no_router_bgp_cmd); @@ -100,10 +100,10 @@ index d05432327..a15a0f526 100644 install_element(BGP_NODE, &bgp_router_id_cmd); install_element(BGP_NODE, &no_bgp_router_id_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c -index 8c0b5336e..55aeb2dd8 100644 +index 80c6dd613..87a8ef34f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c -@@ -3040,7 +3040,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, +@@ -3050,7 +3050,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->evpn_info = XCALLOC(MTYPE_BGP_EVPN_INFO, sizeof(struct bgp_evpn_info)); @@ -112,7 +112,7 @@ index 8c0b5336e..55aeb2dd8 100644 bgp_evpn_init(bgp); bgp_pbr_init(bgp); return bgp; -@@ -7629,6 +7629,9 @@ int bgp_config_write(struct vty *vty) +@@ -7564,6 +7564,9 @@ int bgp_config_write(struct vty *vty) if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) vty_out(vty, " no bgp fast-external-failover\n"); @@ -123,7 +123,7 @@ index 8c0b5336e..55aeb2dd8 100644 if (bgp->router_id_static.s_addr != 0) vty_out(vty, " bgp router-id %s\n", diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h -index b0f656753..32983a0a9 100644 +index e4f4dc0b5..4d372c562 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -569,6 +569,9 @@ struct bgp { diff --git a/src/sonic-frr/patch/0002-Reduce-severity-of-Vty-connected-from-message.patch b/src/sonic-frr/patch/0002-Reduce-severity-of-Vty-connected-from-message.patch index 9ec7b980ae84..e47544f79384 100644 --- a/src/sonic-frr/patch/0002-Reduce-severity-of-Vty-connected-from-message.patch +++ b/src/sonic-frr/patch/0002-Reduce-severity-of-Vty-connected-from-message.patch @@ -1,6 +1,6 @@ -From 5a30a4e91a91f8e19c69ef219cd6d8b19e9b6fae Mon Sep 17 00:00:00 2001 +From 63b5b14ad289f18928beac65754e7bb13183b5dc Mon Sep 17 00:00:00 2001 From: Pavel Shirshov -Date: Mon, 7 Oct 2019 17:06:27 -0700 +Date: Mon, 4 Nov 2019 18:12:54 -0800 Subject: [PATCH 1/1] Reduce severity of 'Vty connected from' message --- @@ -8,10 +8,10 @@ Subject: [PATCH 1/1] Reduce severity of 'Vty connected from' message 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vty.c b/lib/vty.c -index b1ed3d63c..5aa4b56cb 100644 +index deb9391bd..743ff1c17 100644 --- a/lib/vty.c +++ b/lib/vty.c -@@ -1870,7 +1870,7 @@ static int vty_accept(struct thread *thread) +@@ -1853,7 +1853,7 @@ static int vty_accept(struct thread *thread) zlog_info("can't set sockopt to vty_sock : %s", safe_strerror(errno)); diff --git a/src/sonic-frr/patch/0003-Use-vrf_id-for-vrf-not-tabled_id.patch b/src/sonic-frr/patch/0003-Use-vrf_id-for-vrf-not-tabled_id.patch new file mode 100644 index 000000000000..c9a8c0081994 --- /dev/null +++ b/src/sonic-frr/patch/0003-Use-vrf_id-for-vrf-not-tabled_id.patch @@ -0,0 +1,35 @@ +From 9e7f1de3b79ca6ada8a3124f4cdc35530284832e Mon Sep 17 00:00:00 2001 +From: Pavel Shirshov +Date: Tue, 5 Nov 2019 06:16:51 -0800 +Subject: [PATCH 1/1] Use vrf_id for vrf, not tabled_id + +--- + zebra/zebra_fpm_netlink.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c +index f347d3955..74aab8228 100644 +--- a/zebra/zebra_fpm_netlink.c ++++ b/zebra/zebra_fpm_netlink.c +@@ -284,7 +284,6 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd, + rib_dest_t *dest, struct route_entry *re) + { + struct nexthop *nexthop; +- struct zebra_vrf *zvrf; + + memset(ri, 0, sizeof(*ri)); + +@@ -292,9 +291,7 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd, + ri->af = rib_dest_af(dest); + + ri->nlmsg_type = cmd; +- zvrf = rib_dest_vrf(dest); +- if (zvrf) +- ri->rtm_table = zvrf->table_id; ++ ri->rtm_table = zvrf_id(rib_dest_vrf(dest)); + ri->rtm_protocol = RTPROT_UNSPEC; + + /* +-- +2.17.1.windows.2 + diff --git a/src/sonic-frr/patch/0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch b/src/sonic-frr/patch/0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch index cb3c30c781d2..b31da0651ae1 100644 --- a/src/sonic-frr/patch/0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch +++ b/src/sonic-frr/patch/0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch @@ -1,6 +1,6 @@ -From 9fa0ffcc8f9ec987af527e911cd748014aeacffe Mon Sep 17 00:00:00 2001 +From fe1e544d46d721798594fcec175665e3754500a6 Mon Sep 17 00:00:00 2001 From: Pavel Shirshov -Date: Mon, 7 Oct 2019 17:15:15 -0700 +Date: Mon, 4 Nov 2019 18:14:12 -0800 Subject: [PATCH 1/1] Allow BGP attr NEXT_HOP to be 0.0.0.0 due to alleviate the vendor bug @@ -9,10 +9,10 @@ Subject: [PATCH 1/1] Allow BGP attr NEXT_HOP to be 0.0.0.0 due to alleviate 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c -index f8eae135e..732115756 100644 +index c122df498..3c7aa3075 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c -@@ -2904,8 +2904,7 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, +@@ -2983,8 +2983,7 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, /* If NEXT_HOP is present, validate it. */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { diff --git a/src/sonic-frr/patch/0005-Support-VRF.patch b/src/sonic-frr/patch/0005-Support-VRF.patch deleted file mode 100644 index 8d6689e5240a..000000000000 --- a/src/sonic-frr/patch/0005-Support-VRF.patch +++ /dev/null @@ -1,30 +0,0 @@ -From b7ae4e11c2dc14f9208b62ea060bb5ecbf4cddb2 Mon Sep 17 00:00:00 2001 -From: Pavel Shirshov -Date: Mon, 7 Oct 2019 17:17:54 -0700 -Subject: [PATCH 1/1] Support VRF - ---- - zebra/zebra_fpm_netlink.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c -index 88f0c3250..29f07f801 100644 ---- a/zebra/zebra_fpm_netlink.c -+++ b/zebra/zebra_fpm_netlink.c -@@ -327,7 +327,12 @@ static int netlink_route_info_encode(netlink_route_info_t *ri, char *in_buf, - req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; - req->n.nlmsg_type = ri->nlmsg_type; - req->r.rtm_family = ri->af; -- req->r.rtm_table = ri->rtm_table; -+ if (ri->rtm_table < 256) -+ req->r.rtm_table = ri->rtm_table; -+ else { -+ req->r.rtm_table = RT_TABLE_COMPAT; -+ addattr32(&req->n, in_buf_len, RTA_TABLE, ri->rtm_table); -+ } - req->r.rtm_dst_len = ri->prefix->prefixlen; - req->r.rtm_protocol = ri->rtm_protocol; - req->r.rtm_scope = RT_SCOPE_UNIVERSE; --- -2.17.1.windows.2 - diff --git a/src/sonic-frr/patch/0007-prevent-dead-fd-poll-data-port-fix-from-frr.patch b/src/sonic-frr/patch/0007-prevent-dead-fd-poll-data-port-fix-from-frr.patch deleted file mode 100644 index 5954e5c7c53d..000000000000 --- a/src/sonic-frr/patch/0007-prevent-dead-fd-poll-data-port-fix-from-frr.patch +++ /dev/null @@ -1,107 +0,0 @@ -From e4225086634fb7ae7fa762f3a45af6ad39e78641 Mon Sep 17 00:00:00 2001 -From: sudhanshukumar22 -Date: Tue, 15 Oct 2019 02:17:00 -0700 -Subject: [PATCH] Port a fix from FRR community - https://github.com/donaldsharp/frr/commit/39c93f379a5b57c56739a339ad75ec06e30daef3 - If we have a case where have created a fd for i/o and we have removed the - handling thread but still have the fd in the poll data structure, there - existed a case where we would get the handle this fd return from poll but we - would immediately do nothing with it because we didn't have a thread to hand - the event to. - -This leads to an infinite loop. Prevent the infinite loop -from happening and log the problem. ---- - lib/lib_errors.c | 6 ++++++ - lib/lib_errors.h | 1 + - lib/thread.c | 25 ++++++++++++++++++------- - 3 files changed, 25 insertions(+), 7 deletions(-) - -diff --git a/lib/lib_errors.c b/lib/lib_errors.c -index b6c764d87..033f27e58 100644 ---- a/lib/lib_errors.c -+++ b/lib/lib_errors.c -@@ -50,6 +50,12 @@ static struct log_ref ferr_lib_warn[] = { - .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug, or some combination therof.", - .suggestion = "Gather log data and open an Issue", - }, -+ { -+ .code = EC_LIB_NO_THREAD, -+ .title = "The Event subsystem has detected an internal FD problem", -+ .description = "The Event subsystem has detected a file descriptor read/write event without an associated handling function. This is a bug, please collect log data and open an issue.", -+ .suggestion = "Gather log data and open an Issue", -+ }, - { - .code = EC_LIB_RMAP_RECURSION_LIMIT, - .title = "Reached the Route-Map Recursion Limit", -diff --git a/lib/lib_errors.h b/lib/lib_errors.h -index 39b39fb06..996a16ba9 100644 ---- a/lib/lib_errors.h -+++ b/lib/lib_errors.h -@@ -45,6 +45,7 @@ enum lib_log_refs { - EC_LIB_STREAM, - EC_LIB_LINUX_NS, - EC_LIB_SLOW_THREAD, -+ EC_LIB_NO_THREAD, - EC_LIB_RMAP_RECURSION_LIMIT, - EC_LIB_BACKUP_CONFIG, - EC_LIB_VRF_LENGTH, -diff --git a/lib/thread.c b/lib/thread.c -index 5ca859a74..82708557d 100644 ---- a/lib/thread.c -+++ b/lib/thread.c -@@ -1235,12 +1235,26 @@ static struct thread *thread_run(struct thread_master *m, struct thread *thread, - } - - static int thread_process_io_helper(struct thread_master *m, -- struct thread *thread, short state, int pos) -+ struct thread *thread, short state, short actual_state, int pos) - { - struct thread **thread_array; - -- if (!thread) -+ /* -+ * If another pthread scheduled this file descriptor for this event -+ * we're responding to, no problem, we're getting to it now. -+ * Additionally if !thread if we don't clear this now we'll -+ * infinaloop( which sucks ) -+ */ -+ m->handler.pfds[pos].events &= ~(state); -+ -+ if (!thread) { -+ if ((actual_state & (POLLHUP | POLLIN)) != POLLHUP) -+ flog_err( EC_LIB_NO_THREAD, -+ "Attempting to process an I/O event but for fd: %d(%d) no thread to handle this!\n", -+ m->handler.pfds[pos].fd, actual_state); - return 0; -+ } -+ - - if (thread->type == THREAD_READ) - thread_array = m->read; -@@ -1250,9 +1264,6 @@ static int thread_process_io_helper(struct thread_master *m, - thread_array[thread->u.fd] = NULL; - thread_list_add_tail(&m->ready, thread); - thread->type = THREAD_READY; -- /* if another pthread scheduled this file descriptor for the event we're -- * responding to, no problem; we're getting to it now */ -- thread->master->handler.pfds[pos].events &= ~(state); - return 1; - } - -@@ -1290,10 +1301,10 @@ static void thread_process_io(struct thread_master *m, unsigned int num) - * should still be a valid index into the master's pfds. */ - if (pfds[i].revents & (POLLIN | POLLHUP)) - thread_process_io_helper(m, m->read[pfds[i].fd], POLLIN, -- i); -+ pfds[i].revents,i); - if (pfds[i].revents & POLLOUT) - thread_process_io_helper(m, m->write[pfds[i].fd], -- POLLOUT, i); -+ POLLOUT, pfds[i].revents, i); - - /* if one of our file descriptors is garbage, remove the same - * from --- -2.18.0 - diff --git a/src/sonic-frr/patch/0008-zebra-kernel-level-graceful-restart.patch b/src/sonic-frr/patch/0008-zebra-kernel-level-graceful-restart.patch deleted file mode 100644 index e2a68a3507b4..000000000000 --- a/src/sonic-frr/patch/0008-zebra-kernel-level-graceful-restart.patch +++ /dev/null @@ -1,227 +0,0 @@ - - zebra: Add kernel level graceful restart - - - - Add the a `--graceful_restart X` flag to zebra start that - now creates a timer that pops in X seconds and will go - through and remove all routes that are older than startup. - - If graceful_restart is not specified then we will just pop - a timer that cleans everything up immediately. - - Signed-off-by: Praveen Chaudhary - Signed-off-by: Donald Sharp - -diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst -index f38db9d24..40d894929 100644 ---- a/doc/user/zebra.rst -+++ b/doc/user/zebra.rst -@@ -23,9 +23,12 @@ Besides the common invocation options (:ref:`common-invocation-options`), the - Runs in batch mode. *zebra* parses configuration file and terminates - immediately. - --.. option:: -k, --keep_kernel -+.. option:: -K TIME, --graceful_restart TIME - -- When zebra starts up, don't delete old self inserted routes. -+ If this option is specified, the graceful restart time is TIME seconds. -+ Zebra, when started, will read in routes. Those routes that Zebra -+ identifies that it was the originator of will be swept in TIME seconds. -+ If no time is specified then we will sweep those routes immediately. - - .. option:: -r, --retain - -diff --git a/zebra/main.c b/zebra/main.c -index 184e798bd..3d1d156ad 100644 ---- a/zebra/main.c -+++ b/zebra/main.c -@@ -74,8 +74,7 @@ int retain_mode = 0; - /* Allow non-quagga entities to delete quagga routes */ - int allow_delete = 0; - --/* Don't delete kernel route. */ --int keep_kernel_mode = 0; -+int graceful_restart; - - bool v6_rr_semantics = false; - -@@ -89,12 +88,12 @@ uint32_t nl_rcvbufsize = 4194304; - struct option longopts[] = { - {"batch", no_argument, NULL, 'b'}, - {"allow_delete", no_argument, NULL, 'a'}, -- {"keep_kernel", no_argument, NULL, 'k'}, - {"socket", required_argument, NULL, 'z'}, - {"ecmp", required_argument, NULL, 'e'}, - {"label_socket", no_argument, NULL, 'l'}, - {"retain", no_argument, NULL, 'r'}, - {"vrfdefaultname", required_argument, NULL, 'o'}, -+ {"graceful_restart", required_argument, NULL, 'K'}, - #ifdef HAVE_NETLINK - {"vrfwnetns", no_argument, NULL, 'n'}, - {"nl-bufsize", required_argument, NULL, 's'}, -@@ -264,13 +263,14 @@ int main(int argc, char **argv) - char *netlink_fuzzing = NULL; - #endif /* HANDLE_NETLINK_FUZZING */ - -+ graceful_restart = 0; - vrf_configure_backend(VRF_BACKEND_VRF_LITE); - logicalrouter_configure_backend(LOGICALROUTER_BACKEND_NETNS); - - frr_preinit(&zebra_di, argc, argv); - - frr_opt_add( -- "bakz:e:l:o:r" -+ "baz:e:l:o:rK:" - #ifdef HAVE_NETLINK - "s:n" - #endif -@@ -282,24 +282,24 @@ int main(int argc, char **argv) - #endif /* HANDLE_NETLINK_FUZZING */ - , - longopts, -- " -b, --batch Runs in batch mode\n" -- " -a, --allow_delete Allow other processes to delete zebra routes\n" -- " -z, --socket Set path of zebra socket\n" -- " -e, --ecmp Specify ECMP to use.\n" -- " -l, --label_socket Socket to external label manager\n" -- " -k, --keep_kernel Don't delete old routes which were installed by zebra.\n" -- " -r, --retain When program terminates, retain added route by zebra.\n" -- " -o, --vrfdefaultname Set default VRF name.\n" -+ " -b, --batch Runs in batch mode\n" -+ " -a, --allow_delete Allow other processes to delete zebra routes\n" -+ " -z, --socket Set path of zebra socket\n" -+ " -e, --ecmp Specify ECMP to use.\n" -+ " -l, --label_socket Socket to external label manager\n" -+ " -r, --retain When program terminates, retain added route by zebra.\n" -+ " -o, --vrfdefaultname Set default VRF name.\n" -+ " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" - #ifdef HAVE_NETLINK -- " -n, --vrfwnetns Use NetNS as VRF backend\n" -- " -s, --nl-bufsize Set netlink receive buffer size\n" -- " --v6-rr-semantics Use v6 RR semantics\n" -+ " -n, --vrfwnetns Use NetNS as VRF backend\n" -+ " -s, --nl-bufsize Set netlink receive buffer size\n" -+ " --v6-rr-semantics Use v6 RR semantics\n" - #endif /* HAVE_NETLINK */ - #if defined(HANDLE_ZAPI_FUZZING) -- " -c Bypass normal startup and use this file for testing of zapi\n" -+ " -c Bypass normal startup and use this file for testing of zapi\n" - #endif /* HANDLE_ZAPI_FUZZING */ - #if defined(HANDLE_NETLINK_FUZZING) -- " -w Bypass normal startup and use this file for testing of netlink input\n" -+ " -w Bypass normal startup and use this file for testing of netlink input\n" - #endif /* HANDLE_NETLINK_FUZZING */ - ); - -@@ -318,9 +318,6 @@ int main(int argc, char **argv) - case 'a': - allow_delete = 1; - break; -- case 'k': -- keep_kernel_mode = 1; -- break; - case 'e': - multipath_num = atoi(optarg); - if (multipath_num > MULTIPATH_NUM -@@ -350,6 +347,9 @@ int main(int argc, char **argv) - case 'r': - retain_mode = 1; - break; -+ case 'K': -+ graceful_restart = atoi(optarg); -+ break; - #ifdef HAVE_NETLINK - case 's': - nl_rcvbufsize = atoi(optarg); -@@ -437,9 +437,9 @@ int main(int argc, char **argv) - * will be equal to the current getpid(). To know about such routes, - * we have to have route_read() called before. - */ -- if (!keep_kernel_mode) -- rib_sweep_route(); -- -+ zrouter.startup_time = monotime(NULL); -+ thread_add_timer(zrouter.master, rib_sweep_route, -+ NULL, graceful_restart, NULL); - /* Needed for BSD routing socket. */ - pid = getpid(); - -diff --git a/zebra/rib.h b/zebra/rib.h -index 9fe42aef3..69850f3a0 100644 ---- a/zebra/rib.h -+++ b/zebra/rib.h -@@ -351,7 +351,7 @@ extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, - extern void rib_update(vrf_id_t vrf_id, rib_update_event_t event); - extern void rib_update_table(struct route_table *table, - rib_update_event_t event); --extern void rib_sweep_route(void); -+extern int rib_sweep_route(struct thread *t); - extern void rib_sweep_table(struct route_table *table); - extern void rib_close_table(struct route_table *table); - extern void rib_init(void); -diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c -index 555127b09..b6afcdc8c 100644 ---- a/zebra/zebra_rib.c -+++ b/zebra/zebra_rib.c -@@ -3145,6 +3145,7 @@ void rib_sweep_table(struct route_table *table) - - for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) { - RNODE_FOREACH_RE_SAFE (rn, re, next) { -+ - if (IS_ZEBRA_DEBUG_RIB) - route_entry_dump(&rn->p, NULL, re); - -@@ -3154,6 +3155,14 @@ void rib_sweep_table(struct route_table *table) - if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELFROUTE)) - continue; - -+ /* -+ * If routes are older than startup_time then -+ * we know we read them in from the kernel. -+ * As such we can safely remove them. -+ */ -+ if (zrouter.startup_time < re->uptime) -+ continue; -+ - /* - * So we are starting up and have received - * routes from the kernel that we have installed -@@ -3183,7 +3192,7 @@ void rib_sweep_table(struct route_table *table) - } - - /* Sweep all RIB tables. */ --void rib_sweep_route(void) -+int rib_sweep_route(struct thread *t) - { - struct vrf *vrf; - struct zebra_vrf *zvrf; -@@ -3197,6 +3206,8 @@ void rib_sweep_route(void) - } - - zebra_router_sweep_route(); -+ -+ return 0; - } - - /* Remove specific by protocol routes from 'table'. */ -diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h -index b316b91d0..b2e92bad0 100644 ---- a/zebra/zebra_router.h -+++ b/zebra/zebra_router.h -@@ -110,8 +110,15 @@ struct zebra_router { - * The EVPN instance, if any - */ - struct zebra_vrf *evpn_vrf; -+ -+ /* -+ * Time for when we sweep the rib from old routes -+ */ -+ time_t startup_time; - }; - -+#define GRACEFUL_RESTART_TIME 60 -+ - extern struct zebra_router zrouter; - - extern void zebra_router_init(void); diff --git a/src/sonic-frr/patch/series b/src/sonic-frr/patch/series index da0ab7ba47c5..233021ace50b 100644 --- a/src/sonic-frr/patch/series +++ b/src/sonic-frr/patch/series @@ -1,7 +1,5 @@ 0001-Add-support-of-bgp-tcp-DSCP-value.patch 0002-Reduce-severity-of-Vty-connected-from-message.patch +0003-Use-vrf_id-for-vrf-not-tabled_id.patch 0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch -0005-Support-VRF.patch 0006-changes-for-making-snmp-socket-non-blocking.patch -0007-prevent-dead-fd-poll-data-port-fix-from-frr.patch -0008-zebra-kernel-level-graceful-restart.patch \ No newline at end of file From d346cb3898d58aeb16c22a66a79b117ab267d4b8 Mon Sep 17 00:00:00 2001 From: Stepan Blyshchak <38952541+stepanblyschak@users.noreply.github.com> Date: Wed, 6 Nov 2019 22:12:31 +0200 Subject: [PATCH 135/278] [services] make snmp.timer work again and delay telemetry.service (#3657) Signed-off-by: Stepan Blyschak --- files/build_templates/snmp.service.j2 | 2 -- files/build_templates/sonic_debian_extension.j2 | 6 ++++-- files/build_templates/telemetry.service.j2 | 2 -- files/build_templates/telemetry.timer | 9 +++++++++ 4 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 files/build_templates/telemetry.timer diff --git a/files/build_templates/snmp.service.j2 b/files/build_templates/snmp.service.j2 index 310048e68beb..9d419b8e0dfd 100644 --- a/files/build_templates/snmp.service.j2 +++ b/files/build_templates/snmp.service.j2 @@ -14,5 +14,3 @@ ExecStop=/usr/bin/{{docker_container_name}}.sh stop Restart=always RestartSec=30 -[Install] -WantedBy=multi-user.target swss.service diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index d08aa7b6f1cc..9e8d4eb16a3e 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -317,7 +317,7 @@ EOF ## Bind docker path if [[ $CONFIGURED_ARCH == armhf || $CONFIGURED_ARCH == arm64 ]]; then sudo mkdir -p $FILESYSTEM_ROOT/dockerfs - sudo mount --bind dockerfs $FILESYSTEM_ROOT/dockerfs + sudo mount --bind dockerfs $FILESYSTEM_ROOT/dockerfs fi {% if installer_images.strip() -%} @@ -334,7 +334,7 @@ sudo LANG=C chroot $FILESYSTEM_ROOT docker $SONIC_NATIVE_DOCKERD_FOR_DOCKERFS ta {% endif %} {% endfor %} if [[ $CONFIGURED_ARCH == armhf || $CONFIGURED_ARCH == arm64 ]]; then - sudo umount $FILESYSTEM_ROOT/dockerfs + sudo umount $FILESYSTEM_ROOT/dockerfs sudo rm -fr $FILESYSTEM_ROOT/dockerfs sudo kill -9 `sudo $SONIC_NATIVE_DOCKERD_FOR_DOCKERFS_PID` || true else @@ -362,6 +362,8 @@ sudo LANG=C cp $SCRIPTS_DIR/syncd.sh $FILESYSTEM_ROOT/usr/local/bin/syncd.sh # It implements delayed start of services sudo cp $BUILD_TEMPLATES/snmp.timer $FILESYSTEM_ROOT/etc/systemd/system/ sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable snmp.timer +sudo cp $BUILD_TEMPLATES/telemetry.timer $FILESYSTEM_ROOT/etc/systemd/system/ +sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable telemetry.timer sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get purge -y python-dev sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get clean -y diff --git a/files/build_templates/telemetry.service.j2 b/files/build_templates/telemetry.service.j2 index 2e7e45218df2..4d653e42327d 100644 --- a/files/build_templates/telemetry.service.j2 +++ b/files/build_templates/telemetry.service.j2 @@ -10,5 +10,3 @@ ExecStartPre=/usr/bin/{{docker_container_name}}.sh start ExecStart=/usr/bin/{{docker_container_name}}.sh wait ExecStop=/usr/bin/{{docker_container_name}}.sh stop -[Install] -WantedBy=multi-user.target diff --git a/files/build_templates/telemetry.timer b/files/build_templates/telemetry.timer new file mode 100644 index 000000000000..e08f1c09eac6 --- /dev/null +++ b/files/build_templates/telemetry.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Delays telemetry container until SONiC has started + +[Timer] +OnBootSec=3min 30 sec +Unit=telemetry.service + +[Install] +WantedBy=timers.target From d5af096f417a1111bdfce09f939e0c00cfe43558 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Wed, 6 Nov 2019 16:07:28 -0800 Subject: [PATCH 136/278] [TSA]: Add community to the loopback prefix, when isolated (#3708) * Rename asn/deployment_id_asn_map.yaml to constants/constants.yaml * Fix bgp templates * Add community for loopback when bgpd is isolated * Use correct community value --- dockers/docker-fpm-frr/TSA | 16 ++++++++-------- dockers/docker-fpm-frr/TSB | 17 ++++++++--------- dockers/docker-fpm-frr/TSC | 8 ++++---- dockers/docker-fpm-frr/bgpd.conf.default.j2 | 2 +- dockers/docker-fpm-frr/bgpd.tsa.isolate.conf.j2 | 10 ++++++++++ .../docker-fpm-frr/bgpd.tsa.unisolate.conf.j2 | 6 ++++++ dockers/docker-fpm-frr/start.sh | 4 ++-- dockers/docker-fpm-quagga/bgpd.conf.j2 | 2 +- dockers/docker-fpm-quagga/start.sh | 2 +- files/build_templates/sonic_debian_extension.j2 | 2 +- .../image_config/asn/deployment_id_asn_map.yml | 2 -- files/image_config/constants/constants.yml | 4 ++++ 12 files changed, 46 insertions(+), 29 deletions(-) create mode 100644 dockers/docker-fpm-frr/bgpd.tsa.isolate.conf.j2 create mode 100644 dockers/docker-fpm-frr/bgpd.tsa.unisolate.conf.j2 delete mode 100644 files/image_config/asn/deployment_id_asn_map.yml create mode 100644 files/image_config/constants/constants.yml diff --git a/dockers/docker-fpm-frr/TSA b/dockers/docker-fpm-frr/TSA index abd629157901..1d74757b2d5f 100755 --- a/dockers/docker-fpm-frr/TSA +++ b/dockers/docker-fpm-frr/TSA @@ -3,20 +3,20 @@ c=0 config=$(vtysh -c "show run") echo "$config" | grep -q "route-map TO_BGP_PEER_V4 permit 2" -c=$(($c+$?)) +c=$((c+$?)) echo "$config" | grep -q "route-map TO_BGP_PEER_V4 deny 3" -c=$(($c+$?)) +c=$((c+$?)) echo "$config" | grep -q "route-map TO_BGP_PEER_V6 permit 2" -c=$(($c+$?)) +c=$((c+$?)) echo "$config" | grep -q "route-map TO_BGP_PEER_V6 deny 3" -c=$(($c+$?)) +c=$((c+$?)) if [[ $c -eq 4 ]]; then - vtysh -c "configure terminal" -c "route-map TO_BGP_PEER_V4 permit 2" -c "match ip address prefix-list PL_LoopbackV4" - vtysh -c "configure terminal" -c "route-map TO_BGP_PEER_V4 deny 3" - vtysh -c "configure terminal" -c "route-map TO_BGP_PEER_V6 permit 2" -c "match ipv6 address prefix-list PL_LoopbackV6" - vtysh -c "configure terminal" -c "route-map TO_BGP_PEER_V6 deny 3" + TSA_FILE=$(mktemp) + sonic-cfggen -d -y /etc/sonic/constants.yml -t /usr/share/sonic/templates/bgpd.tsa.isolate.conf.j2 > "$TSA_FILE" + vtysh -f "$TSA_FILE" + rm -f "$TSA_FILE" echo "System Mode: Normal -> Maintenance" else echo "System is already in Maintenance mode" diff --git a/dockers/docker-fpm-frr/TSB b/dockers/docker-fpm-frr/TSB index beb246bfc7f1..83ead86952c3 100755 --- a/dockers/docker-fpm-frr/TSB +++ b/dockers/docker-fpm-frr/TSB @@ -3,21 +3,20 @@ c=0 config=$(vtysh -c "show run") echo "$config" | grep -q "route-map TO_BGP_PEER_V4 permit 2" -c=$(($c+$?)) +c=$((c+$?)) echo "$config" | grep -q "route-map TO_BGP_PEER_V4 deny 3" -c=$(($c+$?)) +c=$((c+$?)) echo "$config" | grep -q "route-map TO_BGP_PEER_V6 permit 2" -c=$(($c+$?)) +c=$((c+$?)) echo "$config" | grep -q "route-map TO_BGP_PEER_V6 deny 3" -c=$(($c+$?)) +c=$((c+$?)) if [[ $c -eq 0 ]]; then - vtysh -c "configure terminal" -c "no route-map TO_BGP_PEER_V4 deny 3" - vtysh -c "configure terminal" -c "no route-map TO_BGP_PEER_V4 permit 2" - vtysh -c "configure terminal" -c "no route-map TO_BGP_PEER_V6 deny 3" - vtysh -c "configure terminal" -c "no route-map TO_BGP_PEER_V6 permit 2" - + TSB_FILE=$(mktemp) + sonic-cfggen -d -y /etc/sonic/constants.yml -t /usr/share/sonic/templates/bgpd.tsa.unisolate.conf.j2 > "$TSB_FILE" + vtysh -f "$TSB_FILE" + rm -f "$TSB_FILE" echo "System Mode: Maintenance -> Normal" else echo "System is already in Normal mode" diff --git a/dockers/docker-fpm-frr/TSC b/dockers/docker-fpm-frr/TSC index 7d0fb1004a7d..c79f4bb2a41b 100755 --- a/dockers/docker-fpm-frr/TSC +++ b/dockers/docker-fpm-frr/TSC @@ -4,13 +4,13 @@ echo "Traffic Shift Check:" c=0 config=$(vtysh -c "show run") echo "$config" | grep -q "route-map TO_BGP_PEER_V4 permit 2" -c=$(($c+$?)) +c=$((c+$?)) echo "$config" | grep -q "route-map TO_BGP_PEER_V4 deny 3" -c=$(($c+$?)) +c=$((c+$?)) echo "$config" | grep -q "route-map TO_BGP_PEER_V6 permit 2" -c=$(($c+$?)) +c=$((c+$?)) echo "$config" | grep -q "route-map TO_BGP_PEER_V6 deny 3" -c=$(($c+$?)) +c=$((c+$?)) if [[ $c -eq 4 ]]; then diff --git a/dockers/docker-fpm-frr/bgpd.conf.default.j2 b/dockers/docker-fpm-frr/bgpd.conf.default.j2 index 957c2792435f..b53e5dff6762 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.default.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.default.j2 @@ -107,7 +107,7 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% if bgp_peer['peer_asn'] is defined %} neighbor {{ bgp_peer['name'] }} remote-as {{ bgp_peer['peer_asn'] }} {% else %} - neighbor {{ bgp_peer['name'] }} remote-as {{ deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']] }} + neighbor {{ bgp_peer['name'] }} remote-as {{ constants.deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']] }} {% endif %} neighbor {{ bgp_peer['name'] }} ebgp-multihop 255 neighbor {{ bgp_peer['name'] }} soft-reconfiguration inbound diff --git a/dockers/docker-fpm-frr/bgpd.tsa.isolate.conf.j2 b/dockers/docker-fpm-frr/bgpd.tsa.isolate.conf.j2 new file mode 100644 index 000000000000..9cd61b899071 --- /dev/null +++ b/dockers/docker-fpm-frr/bgpd.tsa.isolate.conf.j2 @@ -0,0 +1,10 @@ +route-map TO_BGP_PEER_V4 permit 2 + match ip address prefix-list PL_LoopbackV4 + set community {{ constants.traffic_shift_community }} +route-map TO_BGP_PEER_V4 deny 3 +! +route-map TO_BGP_PEER_V6 permit 2 + match ipv6 address prefix-list PL_LoopbackV6 + set community {{ constants.traffic_shift_community }} +route-map TO_BGP_PEER_V6 deny 3 +! diff --git a/dockers/docker-fpm-frr/bgpd.tsa.unisolate.conf.j2 b/dockers/docker-fpm-frr/bgpd.tsa.unisolate.conf.j2 new file mode 100644 index 000000000000..25d7c49125e1 --- /dev/null +++ b/dockers/docker-fpm-frr/bgpd.tsa.unisolate.conf.j2 @@ -0,0 +1,6 @@ +no route-map TO_BGP_PEER_V4 permit 2 +no route-map TO_BGP_PEER_V4 deny 3 +! +no route-map TO_BGP_PEER_V6 permit 2 +no route-map TO_BGP_PEER_V6 deny 3 +! diff --git a/dockers/docker-fpm-frr/start.sh b/dockers/docker-fpm-frr/start.sh index a1b0c0ea0b08..ad9beec766d3 100755 --- a/dockers/docker-fpm-frr/start.sh +++ b/dockers/docker-fpm-frr/start.sh @@ -5,13 +5,13 @@ mkdir -p /etc/frr CONFIG_TYPE=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["docker_routing_config_mode"]'` if [ -z "$CONFIG_TYPE" ] || [ "$CONFIG_TYPE" == "separated" ]; then - sonic-cfggen -d -y /etc/sonic/deployment_id_asn_map.yml -t /usr/share/sonic/templates/bgpd.conf.j2 > /etc/frr/bgpd.conf + sonic-cfggen -d -y /etc/sonic/constants.yml -t /usr/share/sonic/templates/bgpd.conf.j2 > /etc/frr/bgpd.conf sonic-cfggen -d -t /usr/share/sonic/templates/zebra.conf.j2 > /etc/frr/zebra.conf sonic-cfggen -d -t /usr/share/sonic/templates/staticd.conf.j2 > /etc/frr/staticd.conf echo "no service integrated-vtysh-config" > /etc/frr/vtysh.conf rm -f /etc/frr/frr.conf elif [ "$CONFIG_TYPE" == "unified" ]; then - sonic-cfggen -d -y /etc/sonic/deployment_id_asn_map.yml -t /usr/share/sonic/templates/frr.conf.j2 >/etc/frr/frr.conf + sonic-cfggen -d -y /etc/sonic/constants.yml -t /usr/share/sonic/templates/frr.conf.j2 >/etc/frr/frr.conf echo "service integrated-vtysh-config" > /etc/frr/vtysh.conf rm -f /etc/frr/bgpd.conf /etc/frr/zebra.conf /etc/frr/staticd.conf fi diff --git a/dockers/docker-fpm-quagga/bgpd.conf.j2 b/dockers/docker-fpm-quagga/bgpd.conf.j2 index b69f895ccbed..2f4c741303a4 100644 --- a/dockers/docker-fpm-quagga/bgpd.conf.j2 +++ b/dockers/docker-fpm-quagga/bgpd.conf.j2 @@ -101,7 +101,7 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% if bgp_peer['peer_asn'] is defined %} neighbor {{ bgp_peer['name'] }} remote-as {{ bgp_peer['peer_asn'] }} {% else %} - neighbor {{ bgp_peer['name'] }} remote-as {{ deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']] }} + neighbor {{ bgp_peer['name'] }} remote-as {{ constants.deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']] }} {% endif %} neighbor {{ bgp_peer['name'] }} ebgp-multihop 255 neighbor {{ bgp_peer['name'] }} soft-reconfiguration inbound diff --git a/dockers/docker-fpm-quagga/start.sh b/dockers/docker-fpm-quagga/start.sh index 06fdd3bb3961..1ffda3d17732 100755 --- a/dockers/docker-fpm-quagga/start.sh +++ b/dockers/docker-fpm-quagga/start.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash mkdir -p /etc/quagga -sonic-cfggen -d -y /etc/sonic/deployment_id_asn_map.yml -t /usr/share/sonic/templates/bgpd.conf.j2 > /etc/quagga/bgpd.conf +sonic-cfggen -d -y /etc/sonic/constants.yml -t /usr/share/sonic/templates/bgpd.conf.j2 > /etc/quagga/bgpd.conf sonic-cfggen -d -t /usr/share/sonic/templates/zebra.conf.j2 > /etc/quagga/zebra.conf diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index 9e8d4eb16a3e..bd1dfccd28dc 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -235,7 +235,7 @@ sudo bash -c "echo '{ \"DEVICE_METADATA\": { \"localhost\": { \"default_bgp_stat sudo cp $IMAGE_CONFIGS/snmp/snmp.yml $FILESYSTEM_ROOT/etc/sonic/ # Copy ASN configuration files -sudo cp $IMAGE_CONFIGS/asn/deployment_id_asn_map.yml $FILESYSTEM_ROOT/etc/sonic/ +sudo cp $IMAGE_CONFIGS/constants/constants.yml $FILESYSTEM_ROOT/etc/sonic/ # Copy sudoers configuration file sudo cp $IMAGE_CONFIGS/sudoers/sudoers $FILESYSTEM_ROOT/etc/ diff --git a/files/image_config/asn/deployment_id_asn_map.yml b/files/image_config/asn/deployment_id_asn_map.yml deleted file mode 100644 index 36168f828954..000000000000 --- a/files/image_config/asn/deployment_id_asn_map.yml +++ /dev/null @@ -1,2 +0,0 @@ -deployment_id_asn_map: - "1" : 65432 diff --git a/files/image_config/constants/constants.yml b/files/image_config/constants/constants.yml new file mode 100644 index 000000000000..3834717a8bfc --- /dev/null +++ b/files/image_config/constants/constants.yml @@ -0,0 +1,4 @@ +constants: + deployment_id_asn_map: + "1" : 65432 + traffic_shift_community: 12345:12345 From 95466c3ab74784f62e42a83ea7157c7957347b72 Mon Sep 17 00:00:00 2001 From: Neetha John Date: Wed, 6 Nov 2019 18:51:02 -0800 Subject: [PATCH 137/278] [pfcwd]: Do not start pfc watchdog on Management Tor (#3719) Signed-off-by: Neetha John --- files/image_config/updategraph/updategraph | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/files/image_config/updategraph/updategraph b/files/image_config/updategraph/updategraph index dd8314b01221..2eb510afa4e1 100755 --- a/files/image_config/updategraph/updategraph +++ b/files/image_config/updategraph/updategraph @@ -15,7 +15,10 @@ reload_minigraph() acl-loader update full /etc/sonic/acl.json fi config qos reload - pfcwd start_default + DEVICE_TYPE=`sonic-cfggen -m -v DEVICE_METADATA.localhost.type` + if [ "${DEVICE_TYPE}" != "MgmtToRRouter" ]; then + pfcwd start_default + fi if [[ -x /usr/bin/db_migrator.py ]]; then # Set latest version number From 3b51cec9a38d964b1c9fbd67d44932f2714fd98f Mon Sep 17 00:00:00 2001 From: Andriy Kokhan <43479230+akokhan@users.noreply.github.com> Date: Thu, 7 Nov 2019 04:54:05 +0200 Subject: [PATCH 138/278] [barefoot] Added Newport platform support (#3709) [barefoot] Added Newport platform support Signed-off-by: Andriy Kokhan --- .../x86_64-accton_as9516bf_32d-r0/default_sku | 1 + .../installer.conf | 1 + .../newport/buffers.json.j2 | 2 + .../newport/buffers_defaults_t0.j2 | 71 + .../newport/buffers_defaults_t1.j2 | 71 + .../newport/pg_profile_lookup.ini | 20 + .../newport/port_config.ini | 33 + .../newport/qos.json.j2 | 10 + .../newport/sai.profile | 3 + .../newport/switch-tna-sai.conf | 40 + .../x86_64-accton_as9516bf_32d-r0/plugins | 1 + .../pmon_daemon_control.json | 6 + platform/barefoot/one-image.mk | 1 + .../barefoot/platform-modules-bfn-newport.mk | 13 + platform/barefoot/rules.mk | 1 + .../LICENSE | 15 + .../MAINTAINERS | 3 + .../README.md | 2 + .../configs/network/interfaces.d/usb0 | 5 + .../debian/changelog | 5 + .../debian/compat | 1 + .../debian/control | 12 + .../debian/copyright | 15 + .../debian/rules | 35 + .../modules/Makefile | 2 + .../modules/bf_fpga_ioctl.c | 196 +++ .../modules/bf_fpga_ioctl.h | 131 ++ .../modules/bf_fpga_main.c | 1294 +++++++++++++++++ .../modules/bf_fpga_priv.h | 141 ++ .../modules/bf_fpga_sysfs.c | 335 +++++ .../modules/i2c/bf_fpga_i2c.c | 516 +++++++ .../modules/i2c/bf_fpga_i2c.h | 55 + .../modules/i2c/bf_fpga_i2c_ctrl.c | 397 +++++ .../modules/i2c/bf_fpga_i2c_porting.c | 150 ++ .../modules/i2c/bf_fpga_i2c_priv.h | 104 ++ .../modules/i2c/bf_fpga_i2c_priv_porting.h | 93 ++ .../modules/i2c/bf_fpga_i2c_reg.h | 116 ++ .../scripts/bf-sfputil | 10 + .../scripts/eeprom | 10 + .../scripts/fancontrol | 11 + .../scripts/ps_info | 10 + .../scripts/sensors | 12 + .../scripts/test | 1 + 43 files changed, 3951 insertions(+) create mode 100644 device/barefoot/x86_64-accton_as9516bf_32d-r0/default_sku create mode 100644 device/barefoot/x86_64-accton_as9516bf_32d-r0/installer.conf create mode 100644 device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers.json.j2 create mode 100644 device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t0.j2 create mode 100644 device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t1.j2 create mode 100644 device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/pg_profile_lookup.ini create mode 100644 device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/port_config.ini create mode 100644 device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/qos.json.j2 create mode 100644 device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/sai.profile create mode 100644 device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/switch-tna-sai.conf create mode 120000 device/barefoot/x86_64-accton_as9516bf_32d-r0/plugins create mode 100644 device/barefoot/x86_64-accton_as9516bf_32d-r0/pmon_daemon_control.json create mode 100644 platform/barefoot/platform-modules-bfn-newport.mk create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/LICENSE create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/MAINTAINERS create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/README.md create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/configs/network/interfaces.d/usb0 create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/debian/changelog create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/debian/compat create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/debian/control create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/debian/copyright create mode 100755 platform/barefoot/sonic-platform-modules-bfn-newport/debian/rules create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/modules/Makefile create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_ioctl.c create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_ioctl.h create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_main.c create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_priv.h create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_sysfs.c create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c.c create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c.h create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_ctrl.c create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_porting.c create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_priv.h create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_priv_porting.h create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_reg.h create mode 100755 platform/barefoot/sonic-platform-modules-bfn-newport/scripts/bf-sfputil create mode 100755 platform/barefoot/sonic-platform-modules-bfn-newport/scripts/eeprom create mode 100755 platform/barefoot/sonic-platform-modules-bfn-newport/scripts/fancontrol create mode 100755 platform/barefoot/sonic-platform-modules-bfn-newport/scripts/ps_info create mode 100755 platform/barefoot/sonic-platform-modules-bfn-newport/scripts/sensors create mode 100755 platform/barefoot/sonic-platform-modules-bfn-newport/scripts/test diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/default_sku b/device/barefoot/x86_64-accton_as9516bf_32d-r0/default_sku new file mode 100644 index 000000000000..517fa893ae11 --- /dev/null +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/default_sku @@ -0,0 +1 @@ +newport t1 diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/installer.conf b/device/barefoot/x86_64-accton_as9516bf_32d-r0/installer.conf new file mode 100644 index 000000000000..3714ff053bb0 --- /dev/null +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/installer.conf @@ -0,0 +1 @@ +CONSOLE_SPEED=57600 diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers.json.j2 b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers.json.j2 new file mode 100644 index 000000000000..1083a6210fc9 --- /dev/null +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers.json.j2 @@ -0,0 +1,2 @@ +{%- set default_topo = 't0' %} +{%- include 'buffers_config.j2' %} diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t0.j2 b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t0.j2 new file mode 100644 index 000000000000..199f4ad135fb --- /dev/null +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t0.j2 @@ -0,0 +1,71 @@ +{% set default_cable = '5m' %} +{% set ingress_lossless_pool_size = '4194304' %} +{% set ingress_lossy_pool_size = '7340032' %} +{% set egress_lossless_pool_size = '16777152' %} +{% set egress_lossy_pool_size = '7340032' %} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {%- for port_idx in range(0,32) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %} + {%- endfor %} +{%- endmacro %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "{{ ingress_lossless_pool_size }}", + "type": "ingress", + "mode": "dynamic", + "xoff": "2867200" + }, + "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_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"0", + "dynamic_th":"7" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + }, + "q_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + } + }, +{%- endmacro %} + +{%- macro generate_queue_buffers(port_names) %} + "BUFFER_QUEUE": { + "{{ port_names }}|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "{{ port_names }}|0-1": { + "profile" : "[BUFFER_PROFILE|q_lossy_profile]" + } + } +{%- endmacro %} diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t1.j2 b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t1.j2 new file mode 100644 index 000000000000..01f50a4419e9 --- /dev/null +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t1.j2 @@ -0,0 +1,71 @@ +{% set default_cable = '5m' %} +{% set ingress_lossless_pool_size = '2097152' %} +{% set ingress_lossy_pool_size = '5242880' %} +{% set egress_lossless_pool_size = '16777152' %} +{% set egress_lossy_pool_size = '5242880' %} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {%- for port_idx in range(0,32) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %} + {%- endfor %} +{%- endmacro %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "{{ ingress_lossless_pool_size }}", + "type": "ingress", + "mode": "dynamic", + "xoff": "2867200" + }, + "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_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"0", + "dynamic_th":"7" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + }, + "q_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + } + }, +{%- endmacro %} + +{%- macro generate_queue_buffers(port_names) %} + "BUFFER_QUEUE": { + "{{ port_names }}|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "{{ port_names }}|0-1": { + "profile" : "[BUFFER_PROFILE|q_lossy_profile]" + } + } +{%- endmacro %} diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/pg_profile_lookup.ini b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/pg_profile_lookup.ini new file mode 100644 index 000000000000..602400325be0 --- /dev/null +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/pg_profile_lookup.ini @@ -0,0 +1,20 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold + 10000 5m 34816 18432 16384 7 + 25000 5m 34816 18432 16384 7 + 40000 5m 34816 18432 16384 7 + 50000 5m 34816 18432 16384 7 + 100000 5m 36864 18432 18432 7 + 400000 5m 36864 18432 18432 7 + 10000 40m 36864 18432 18432 7 + 25000 40m 39936 18432 21504 7 + 40000 40m 41984 18432 23552 7 + 50000 40m 41984 18432 23552 7 + 100000 40m 54272 18432 35840 7 + 400000 40m 54272 18432 35840 7 + 10000 300m 49152 18432 30720 7 + 25000 300m 71680 18432 53248 7 + 40000 300m 94208 18432 75776 7 + 50000 300m 94208 18432 75776 7 + 100000 300m 184320 18432 165888 7 + 400000 300m 184320 18432 165888 7 diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/port_config.ini b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/port_config.ini new file mode 100644 index 000000000000..3a3be79dc675 --- /dev/null +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/port_config.ini @@ -0,0 +1,33 @@ +# name lanes alias index speed autoneg fec +Ethernet0 0,1,2,3,4,5,6,7 Ethernet0 1 400000 0 rs +Ethernet8 8,9,10,11,12,13,14,15 Ethernet8 2 400000 0 rs +Ethernet16 16,17,18,19,20,21,22,23 Ethernet16 3 400000 0 rs +Ethernet24 24,25,26,27,28,29,30,31 Ethernet24 4 400000 0 rs +Ethernet32 32,33,34,35,36,37,38,39 Ethernet32 5 400000 0 rs +Ethernet40 40,41,42,43,44,45,46,47 Ethernet40 6 400000 0 rs +Ethernet48 48,49,50,51,52,53,54,55 Ethernet48 7 400000 0 rs +Ethernet56 56,57,58,59,60,61,62,63 Ethernet56 8 400000 0 rs +Ethernet64 64,65,66,67,68,69,70,71 Ethernet64 9 400000 0 rs +Ethernet72 72,73,74,75,76,77,78,79 Ethernet72 10 400000 0 rs +Ethernet80 80,81,82,83,84,85,86,87 Ethernet80 11 400000 0 rs +Ethernet88 88,89,90,91,92,93,94,95 Ethernet88 12 400000 0 rs +Ethernet96 96,97,98,99,100,101,102,103 Ethernet96 13 400000 0 rs +Ethernet104 104,105,106,107,108,109,110,111 Ethernet104 14 400000 0 rs +Ethernet112 112,113,114,115,116,117,118,119 Ethernet112 15 400000 0 rs +Ethernet120 120,121,122,123,124,125,126,127 Ethernet120 16 400000 0 rs +Ethernet128 128,129,130,131,132,133,134,135 Ethernet128 17 400000 0 rs +Ethernet136 136,137,138,139,140,141,142,143 Ethernet136 18 400000 0 rs +Ethernet144 144,145,146,147,148,149,150,151 Ethernet144 19 400000 0 rs +Ethernet152 152,153,154,155,156,157,158,159 Ethernet152 20 400000 0 rs +Ethernet160 160,161,162,163,164,165,166,167 Ethernet160 21 400000 0 rs +Ethernet168 168,169,170,171,172,173,174,175 Ethernet168 22 400000 0 rs +Ethernet176 176,177,178,179,180,181,182,183 Ethernet176 23 400000 0 rs +Ethernet184 184,185,186,187,188,189,190,191 Ethernet184 24 400000 0 rs +Ethernet192 192,193,194,195,196,197,198,199 Ethernet192 25 400000 0 rs +Ethernet200 200,201,202,203,204,205,206,207 Ethernet200 26 400000 0 rs +Ethernet208 208,209,210,211,212,213,214,215 Ethernet208 27 400000 0 rs +Ethernet216 216,217,218,219,220,221,222,223 Ethernet216 28 400000 0 rs +Ethernet224 224,225,226,227,228,229,230,231 Ethernet224 29 400000 0 rs +Ethernet232 232,233,234,235,236,237,238,239 Ethernet232 30 400000 0 rs +Ethernet240 240,241,242,243,244,245,246,247 Ethernet240 31 400000 0 rs +Ethernet248 248,249,250,251,252,253,254,255 Ethernet248 32 400000 0 rs diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/qos.json.j2 b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/qos.json.j2 new file mode 100644 index 000000000000..a685277448f1 --- /dev/null +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/qos.json.j2 @@ -0,0 +1,10 @@ +{%- macro generate_tc_to_pg_map() %} + "TC_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "3": "3", + "4": "4" + } + }, +{%- endmacro %} + +{%- include 'qos_config.j2' %} diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/sai.profile b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/sai.profile new file mode 100644 index 000000000000..037b5c135370 --- /dev/null +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/sai.profile @@ -0,0 +1,3 @@ +SAI_KEY_WARM_BOOT_WRITE_FILE=/var/warmboot/sai-warmboot.bin +SAI_KEY_WARM_BOOT_READ_FILE=/var/warmboot/sai-warmboot.bin + diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/switch-tna-sai.conf b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/switch-tna-sai.conf new file mode 100644 index 000000000000..a1ee06da879c --- /dev/null +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/switch-tna-sai.conf @@ -0,0 +1,40 @@ +{ + "instance": 0, + "chip_list": [ + { + "id": "asic-0", + "chip_family": "Tofino2", + "instance": 0, + "pcie_sysfs_prefix": "/sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0", + "pcie_domain": 0, + "pcie_bus": 5, + "pcie_fn": 0, + "pcie_dev": 0, + "pcie_int_mode": 1, + "sds_fw_path": "share/tofino_sds_fw/avago/firmware" + } + ], + "p4_devices": [ + { + "device-id": 0, + "agent0": "lib/platform/x86_64-accton_as9516bf_32d-r0/libpltfm_mgr.so", + "p4_programs": [ + { + "p4_pipelines": [ + { + "p4_pipeline_name": "pipe", + "config": "share/switch/pipe/tofino2.bin", + "context": "share/switch/pipe/context.json" + } + ], + "program-name": "switch", + "switchsai": "lib/libswitchsai.so", + "bfrt-config": "share/switch/bf-rt.json", + "model_json_path" : "share/switch/aug_model.json", + "switchapi_port_add": false, + "non_default_port_ppgs": 5 + } + ] + } + ] +} diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/plugins b/device/barefoot/x86_64-accton_as9516bf_32d-r0/plugins new file mode 120000 index 000000000000..a8464d1ec2b6 --- /dev/null +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/plugins @@ -0,0 +1 @@ +../x86_64-accton_wedge100bf_32x-r0/plugins/ \ No newline at end of file diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/pmon_daemon_control.json b/device/barefoot/x86_64-accton_as9516bf_32d-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..3a76f2fdd0e4 --- /dev/null +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/pmon_daemon_control.json @@ -0,0 +1,6 @@ +{ + "skip_ledd": true, + "skip_xcvrd": false, + "skip_psud": false, + "skip_syseepromd": false +} diff --git a/platform/barefoot/one-image.mk b/platform/barefoot/one-image.mk index 36823baa8781..0147b62d00a1 100644 --- a/platform/barefoot/one-image.mk +++ b/platform/barefoot/one-image.mk @@ -7,6 +7,7 @@ $(SONIC_ONE_IMAGE)_INSTALLS += $(BFN_MODULE) $(PYTHON_THRIFT) $(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(BFN_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(BFN_MONTARA_PLATFORM_MODULE) +$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(BFN_NEWPORT_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(WNC_OSW1800_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(INGRASYS_S9180_32X_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(INGRASYS_S9280_64X_PLATFORM_MODULE) diff --git a/platform/barefoot/platform-modules-bfn-newport.mk b/platform/barefoot/platform-modules-bfn-newport.mk new file mode 100644 index 000000000000..ff251ed1ddd7 --- /dev/null +++ b/platform/barefoot/platform-modules-bfn-newport.mk @@ -0,0 +1,13 @@ +# BFN Platform modules + +BFN_NEWPORT_PLATFORM_MODULE_VERSION = 1.0 + +export BFN_NEWPORT_PLATFORM_MODULE_VERSION + +BFN_NEWPORT_PLATFORM_MODULE = sonic-platform-modules-bfn-newport_$(BFN_NEWPORT_PLATFORM_MODULE_VERSION)_amd64.deb +$(BFN_NEWPORT_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-bfn-newport +$(BFN_NEWPORT_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) +$(BFN_NEWPORT_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as9516bf_32d-r0 +SONIC_DPKG_DEBS += $(BFN_NEWPORT_PLATFORM_MODULE) + +SONIC_STRETCH_DEBS += $(BFN_NEWPORT_PLATFORM_MODULE) diff --git a/platform/barefoot/rules.mk b/platform/barefoot/rules.mk index ea718d10fc96..8a218b3ff169 100644 --- a/platform/barefoot/rules.mk +++ b/platform/barefoot/rules.mk @@ -1,6 +1,7 @@ include $(PLATFORM_PATH)/platform-modules-arista.mk include $(PLATFORM_PATH)/platform-modules-bfn.mk include $(PLATFORM_PATH)/platform-modules-bfn-montara.mk +include $(PLATFORM_PATH)/platform-modules-bfn-newport.mk include $(PLATFORM_PATH)/platform-modules-wnc-osw1800.mk include $(PLATFORM_PATH)/platform-modules-ingrasys.mk include $(PLATFORM_PATH)/bfn-sai.mk diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/LICENSE b/platform/barefoot/sonic-platform-modules-bfn-newport/LICENSE new file mode 100644 index 000000000000..676cdeec726b --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/LICENSE @@ -0,0 +1,15 @@ +Copyright (C) 2016 Microsoft, Inc + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/MAINTAINERS b/platform/barefoot/sonic-platform-modules-bfn-newport/MAINTAINERS new file mode 100644 index 000000000000..85aa0cd77d72 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/MAINTAINERS @@ -0,0 +1,3 @@ +# This file describes the maintainers for sonic-platform-modules-bfn-newport +# See the SONiC project governance document for more information +Mailinglist = sonicproject@googlegroups.com diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/README.md b/platform/barefoot/sonic-platform-modules-bfn-newport/README.md new file mode 100644 index 000000000000..028adef715f3 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/README.md @@ -0,0 +1,2 @@ +# sonic-platform-modules-bfn-newport +Device drivers for support of BFN platform for the SONiC project diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/configs/network/interfaces.d/usb0 b/platform/barefoot/sonic-platform-modules-bfn-newport/configs/network/interfaces.d/usb0 new file mode 100644 index 000000000000..f1dd054cc6f6 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/configs/network/interfaces.d/usb0 @@ -0,0 +1,5 @@ +# BMC interface +auto usb0 +allow-hotplug usb0 +iface usb0 inet6 +up ifconfig usb0 txqueuelen 64 diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/debian/changelog b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/changelog new file mode 100644 index 000000000000..98ecad42ac90 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/changelog @@ -0,0 +1,5 @@ +sonic-platform-modules-bfn-newport (1.0) unstable; urgency=low + + * Initial release + + -- Support Mon, 27 Sep 2019 18:00:00 -0800 diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/debian/compat b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/compat new file mode 100644 index 000000000000..45a4fb75db86 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/compat @@ -0,0 +1 @@ +8 diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/debian/control b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/control new file mode 100644 index 000000000000..edbc5b890c58 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/control @@ -0,0 +1,12 @@ +Source: sonic-platform-modules-bfn-newport +Section: main +Priority: extra +Maintainer: Support +Build-Depends: debhelper (>= 8.0.0), bzip2 +Standards-Version: 3.9.3 + +Package: sonic-platform-modules-bfn-newport +Architecture: amd64 +Depends: linux-image-4.9.0-9-2-amd64 +Description: kernel module for bfn platform fpga and scripts for the devices such as fan, led, sfp + diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/debian/copyright b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/copyright new file mode 100644 index 000000000000..ade42b7aa75a --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/copyright @@ -0,0 +1,15 @@ +Provides linux kernel driver for BF PCIe devices + +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/barefoot/sonic-platform-modules-bfn-newport/debian/rules b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/rules new file mode 100755 index 000000000000..951069a6016a --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/rules @@ -0,0 +1,35 @@ +#!/usr/bin/make -f + +export INSTALL_MOD_DIR:=extra + +PACKAGE_NAME := sonic-platform-modules-bfn-newport +KVERSION ?= $(shell uname -r) +KERNEL_SRC := /lib/modules/$(KVERSION) +MODULE_SRC := $(shell pwd)/modules +SCRIPT_SRC := $(shell pwd)/scripts +CONFIGS_SRC := $(shell pwd)/configs + +%: + dh $@ + +override_dh_auto_build: + make -C $(KERNEL_SRC)/build M=$(MODULE_SRC) + +override_dh_auto_install: + dh_installdirs -p$(PACKAGE_NAME) $(KERNEL_SRC)/$(INSTALL_MOD_DIR) + cp $(MODULE_SRC)/*.ko debian/$(PACKAGE_NAME)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR) + dh_installdirs -p$(PACKAGE_NAME) usr/local/bin + cp -r $(SCRIPT_SRC)/* debian/$(PACKAGE_NAME)/usr/local/bin + dh_installdirs -p$(PACKAGE_NAME) etc/network/interfaces.d/ + cp -r $(CONFIGS_SRC)/network/interfaces.d/* debian/$(PACKAGE_NAME)/etc/network/interfaces.d/ + +override_dh_usrlocal: + +override_dh_pysupport: + +override_dh_clean: + dh_clean + rm -f $(MODULE_SRC)/*.o $(MODULE_SRC)/*.ko $(MODULE_SRC)/*.mod.c $(MODULE_SRC)/.*.cmd + rm -f $(MODULE_SRC)/Module.markers $(MODULE_SRC)/Module.symvers $(MODULE_SRC)/modules.order + rm -rf $(MODULE_SRC)/.tmp_versions + diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/modules/Makefile b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/Makefile new file mode 100644 index 000000000000..732ffb1f3f6c --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/Makefile @@ -0,0 +1,2 @@ +obj-m := bf_fpga.o +bf_fpga-y := bf_fpga_main.o bf_fpga_ioctl.o bf_fpga_sysfs.o i2c/bf_fpga_i2c.o i2c/bf_fpga_i2c_ctrl.o i2c/bf_fpga_i2c_porting.o diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_ioctl.c b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_ioctl.c new file mode 100644 index 000000000000..b0792556caf6 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_ioctl.c @@ -0,0 +1,196 @@ +/******************************************************************************* + Barefoot Networks FPGA Linux driver + Copyright(c) 2018 - 2019 Barefoot Networks, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + info@barefootnetworks.com + Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054 + +*******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include "bf_fpga_priv.h" +#include "bf_fpga_ioctl.h" +#include "i2c/bf_fpga_i2c.h" + +int bf_fpga_ioctl(struct bf_pci_dev *bfdev, + unsigned int cmd, + unsigned long arg) { + void *addr = (void __user *)arg; + int ret = -1; + + if (!bfdev || !addr) { + return -EFAULT; + } + + switch (cmd) { + case BF_FPGA_IOCTL_I2C_CTL: { + bf_fpga_i2c_ctl_t i2c_ctl; + bool busy; + + if (copy_from_user(&i2c_ctl, addr, sizeof(bf_fpga_i2c_ctl_t))) { + return -EFAULT; + } + switch (i2c_ctl.control_type) { + case BF_FPGA_I2C_START: + ret = fpga_i2c_start(i2c_ctl.inst_hndl.bus_id); + break; + case BF_FPGA_I2C_STOP: + ret = fpga_i2c_stop(i2c_ctl.inst_hndl.bus_id); + break; + case BF_FPGA_I2C_RESET: + ret = fpga_i2c_reset(i2c_ctl.inst_hndl.bus_id); + break; + case BF_FPGA_I2C_BUSY: + ret = fpga_i2c_is_busy(i2c_ctl.inst_hndl.bus_id, &busy); + if (ret == 0) { + if (copy_to_user(&(((bf_fpga_i2c_ctl_t *)addr)->is_busy), + &busy, + sizeof(busy))) { + return -EFAULT; + } + } + break; + case BF_FPGA_I2C_INST_EN: + ret = fpga_i2c_inst_en( + i2c_ctl.inst_hndl.bus_id, i2c_ctl.inst_hndl.inst_id, true); + break; + case BF_FPGA_I2C_INST_DIS: + ret = fpga_i2c_inst_en( + i2c_ctl.inst_hndl.bus_id, i2c_ctl.inst_hndl.inst_id, false); + break; + case BF_FPGA_I2C_INST_PMT: + break; + case BF_FPGA_I2C_INST_STOP_ON_ERR: + break; + case BF_FPGA_I2C_INST_INT_EN: + break; + default: + break; + } + break; + } + case BF_FPGA_IOCTL_I2C_SET_CLK: { + bf_fpga_i2c_set_clk_t i2c_clk; + if (copy_from_user(&i2c_clk, addr, sizeof(bf_fpga_i2c_set_clk_t))) { + return -EFAULT; + } + ret = fpga_i2c_set_clk(i2c_clk.bus_id, i2c_clk.clock_div); + break; + } + case BF_FPGA_IOCTL_I2C_ONETIME: { + bf_fpga_i2c_t i2c_op; + int i; + + if (copy_from_user(&i2c_op, addr, sizeof(bf_fpga_i2c_t))) { + return -EFAULT; + } + ret = fpga_i2c_oneshot(&i2c_op); + if (ret == 0) { + /* copy read data to user area */ + for (i = 0; i < i2c_op.num_i2c; i++) { + if (i2c_op.i2c_inst[i].rd_cnt) { + if (copy_to_user(&(((bf_fpga_i2c_t *)addr)->i2c_inst[i].rd_buf), + &i2c_op.i2c_inst[i].rd_buf, + i2c_op.i2c_inst[i].rd_cnt)) { + return -EFAULT; + } + } + } + } else { + printk(KERN_ERR + "fpga i2c ioctl oneshot bus %d error %d i2c_addr 0x%hhx:0x%hhx " + "i2c_status 0x%hhx:0x%hhx\n", + i2c_op.inst_hndl.bus_id, + ret, + i2c_op.i2c_inst[0].i2c_addr, + i2c_op.i2c_inst[1].i2c_addr, + i2c_op.i2c_inst[0].status, + i2c_op.i2c_inst[1].status); + } + break; + } + case BF_FPGA_IOCTL_I2C_ADD_PR: { + bf_fpga_i2c_t i2c_op; + if (copy_from_user(&i2c_op, addr, sizeof(bf_fpga_i2c_t))) { + return -EFAULT; + } + ret = fpga_i2c_pr_add(&i2c_op); + if (ret == 0) { + /* copy read data to user area */ + if (copy_to_user(&((bf_fpga_i2c_t *)addr)->inst_hndl.inst_id, + &i2c_op.inst_hndl.inst_id, + sizeof(i2c_op.inst_hndl.inst_id))) { + return -EFAULT; + } + } else { + printk(KERN_ERR "fpga i2c ioctl add-pr error %d on bus %d\n", + ret, + i2c_op.inst_hndl.bus_id); + } + break; + } + case BF_FPGA_IOCTL_I2C_DEL_PR: { + bf_fpga_i2c_t i2c_op; + if (copy_from_user(&i2c_op, addr, sizeof(bf_fpga_i2c_t))) { + return -EFAULT; + } + ret = fpga_i2c_del(&i2c_op); + if (ret != 0) { + printk(KERN_ERR "fpga i2c ioctl del-pr error %d on bus %d\n", + ret, + i2c_op.inst_hndl.bus_id); + } + break; + } + case BF_FPGA_IOCTL_I2C_RD_DATA: { + bf_fpga_i2c_rd_data_t i2c_rd_data; + /* get user supplied offset and rd_cnt */ + if (copy_from_user( + &i2c_rd_data, addr, offsetof(bf_fpga_i2c_rd_data_t, rd_buf))) { + return -EFAULT; + } + ret = fpga_i2c_data_read(i2c_rd_data.inst_hndl.bus_id, + i2c_rd_data.inst_hndl.inst_id, + i2c_rd_data.offset, + i2c_rd_data.rd_cnt, + i2c_rd_data.rd_buf); + if (ret == 0) { + if (copy_to_user(&(((bf_fpga_i2c_rd_data_t *)addr)->rd_buf), + &i2c_rd_data.rd_buf, + i2c_rd_data.rd_cnt)) { + return -EFAULT; + } + } else { + printk(KERN_ERR "fpga i2c ioctl rd-data error %d on bus %d inst %d\n", + ret, + i2c_rd_data.inst_hndl.bus_id, + i2c_rd_data.inst_hndl.inst_id); + } + break; + } + default: + return -EINVAL; + } + return ret; +} diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_ioctl.h b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_ioctl.h new file mode 100644 index 000000000000..4c5eb7bf0386 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_ioctl.h @@ -0,0 +1,131 @@ +/******************************************************************************* + Barefoot Networks FPGA Linux driver + Copyright(c) 2018 - 2019 Barefoot Networks, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + info@barefootnetworks.com + Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054 + +*******************************************************************************/ +#ifndef _BF_FPGA_IOCTL_H_ +#define _BF_FPGA_IOCTL_H_ + +#ifdef __KERNEL__ +#include +#else +#include + +#endif /* __KERNEL__ */ + +#define BF_FPGA_IOC_MAGIC 'f' +#define BF_I2C_FPGA_NUM_CTRL 34 +#define BF_FPGA_MAX_I2C_RD_DATA 128 +#define BF_FPGA_MAX_I2C_WR_DATA 129 + +/* i2c control types */ +#define BF_FPGA_I2C_START 1 +#define BF_FPGA_I2C_STOP 2 +#define BF_FPGA_I2C_BUSY 3 +#define BF_FPGA_I2C_INST_EN 4 +#define BF_FPGA_I2C_INST_DIS 5 +#define BF_FPGA_I2C_INST_PMT 6 +#define BF_FPGA_I2C_INST_STOP_ON_ERR 7 +#define BF_FPGA_I2C_INST_INT_EN 8 +#define BF_FPGA_I2C_RESET 9 + +/* i2c operation types */ +#define BF_FPGA_I2C_NOP 0 +#define BF_FPGA_I2C_WRITE \ + 1 /* / ..[max 129 bytes] */ +#define BF_FPGA_I2C_READ \ + 2 /* / ..[max 128 bytes] */ +#define BF_FPGA_I2C_ADDR_READ \ + 3 /* / / \ + */ + +#define FPGA_I2c_ONESHOT_BEGIN_INDEX 0 +#define FPGA_I2C_ONESHOT_NUM_INST 15 +#define FPGA_I2C_PERIODIC_BEGIN_INDEX (FPGA_I2C_ONESHOT_NUM_INST) +#define FPGA_I2C_PERIODIC_NUM_INST 16 +#define FPGA_I2C_NUM_INST \ + (FPGA_I2C_ONESHOT_NUM_INST + FPGA_I2C_PERIODIC_NUM_INST) +/* maximum i2c instructions that can be handled in one system call */ +#define BF_FPGA_I2C_MAX_NUM_INST 3 + +typedef struct bf_fpga_i2c_set_clk_s { + /* 0:100k, 1:400k, 2:1M, or: 125e6//3 */ + int clock_div; /* clock divider */ + unsigned char bus_id; /* controller index */ +} bf_fpga_i2c_set_clk_t; + +typedef struct bf_fpga_inst_hndl_s { + int inst_id; /* instruction index within the controller memory space */ + unsigned char bus_id; /* controller index */ + unsigned char status; +} bf_fpga_inst_hndl_t; + +typedef struct bf_fpga_i2c_inst_s { + bool preemt; + bool en; + unsigned char i2c_addr; /* i2c device address in 7 bit format */ + unsigned char i2c_type; /* type of i2c cycle */ + unsigned char delay; /* delay in TBD - microseconds before i2c transaction */ + unsigned char ctrl; + unsigned char wr_cnt; /* number of bytes to write (after i2c address) */ + unsigned char rd_cnt; /* number of bytes to read */ + union { + unsigned char + wr_buf[BF_FPGA_MAX_I2C_WR_DATA]; /* write data source buffer */ + unsigned char rd_buf[BF_FPGA_MAX_I2C_RD_DATA]; /* read data dest buffer */ + }; + unsigned char status; + unsigned char retry_cnt; /* if fpga maintains retry count */ + unsigned char mux; /* if fpga maintains internal MUX */ +} bf_fpga_i2c_inst_t; + +typedef struct bf_fpga_i2c_s { + unsigned char num_i2c; /* number of i2c operations */ + unsigned char one_time; /* one time or periodic */ + bf_fpga_inst_hndl_t inst_hndl; + bf_fpga_i2c_inst_t i2c_inst[BF_FPGA_I2C_MAX_NUM_INST]; +} bf_fpga_i2c_t; + +typedef struct bf_fpga_i2c_rd_data_s { + bf_fpga_inst_hndl_t inst_hndl; + unsigned char offset; + unsigned char rd_cnt; + unsigned char rd_buf[BF_FPGA_MAX_I2C_RD_DATA]; +} bf_fpga_i2c_rd_data_t; + +typedef struct bf_fpga_i2c_ctl_s { + bf_fpga_inst_hndl_t inst_hndl; + unsigned char control_type; /* start, stop, reset, enable, disable or busy */ + bool is_busy; +} bf_fpga_i2c_ctl_t; + +#define BF_FPGA_IOCTL_I2C_CTL _IOWR(BF_FPGA_IOC_MAGIC, 0, bf_fpga_i2c_ctl_t) +#define BF_FPGA_IOCTL_I2C_ONETIME _IOWR(BF_FPGA_IOC_MAGIC, 1, bf_fpga_i2c_t) +#define BF_FPGA_IOCTL_I2C_ADD_PR _IOWR(BF_FPGA_IOC_MAGIC, 2, bf_fpga_i2c_t) +#define BF_FPGA_IOCTL_I2C_DEL_PR _IOWR(BF_FPGA_IOC_MAGIC, 3, bf_fpga_i2c_t) +#define BF_FPGA_IOCTL_I2C_RD_DATA \ + _IOWR(BF_FPGA_IOC_MAGIC, 4, bf_fpga_i2c_rd_data_t) +#define BF_FPGA_IOCTL_I2C_SET_CLK \ + _IOW(BF_FPGA_IOC_MAGIC, 5, bf_fpga_i2c_set_clk_t) + +#endif /* _BF_FPGA_IOCTL_H_ */ diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_main.c b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_main.c new file mode 100644 index 000000000000..563cc5120df1 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_main.c @@ -0,0 +1,1294 @@ +/******************************************************************************* + Barefoot Networks FPGA Linux driver + Copyright(c) 2018 - 2019 Barefoot Networks, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + info@barefootnetworks.com + Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054 + +*******************************************************************************/ +/* bf_fpga kernel module + * + * This is kernel mode driver for BF FPGA chip. + * Provides user space mmap service and user space "wait for interrupt", + * "enable interrupt" and i2c services + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bf_fpga_ioctl.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +#include +#else +#include +#endif +#include +#include +#include +#include "bf_fpga_priv.h" +#include "i2c/bf_fpga_i2c_reg.h" +#include "i2c/bf_fpga_i2c.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) +//#error unsupported linux kernel version +#endif + +/* TBD: Need to build with CONFIG_PCI_MSI */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) +#if defined(RHEL_RELEASE_CODE) +#else +extern int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec); +#endif /* defined(RHEL_RELEASE_CODE) */ +extern int pci_enable_msix(struct pci_dev *dev, + struct msix_entry *entries, + int nvec); +#else +extern int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec); +extern int pci_enable_msix_range(struct pci_dev *dev, + struct msix_entry *entries, + int minvec, + int maxvec); +#endif + +/* Keep any global information here that must survive even after the + * bf_pci_dev is free-ed up. + */ +struct bf_global { + struct bf_pci_dev *bfdev; + struct cdev *bf_cdev; + struct fasync_struct *async_queue; +}; + +static int bf_major; +static int bf_minor[BF_FPGA_MAX_DEVICE_CNT] = {0}; +static struct class *bf_class = NULL; +static char *intr_mode = NULL; + +static enum bf_intr_mode bf_intr_mode_default = BF_INTR_MODE_NONE; +static spinlock_t bf_nonisr_lock; + +/* dev->minor should index into this array */ +static struct bf_global bf_global[BF_FPGA_MAX_DEVICE_CNT]; + +static void bf_add_listener(struct bf_pci_dev *bfdev, + struct bf_listener *listener) { + struct bf_listener **cur_listener = &bfdev->listener_head; + + if (!listener) { + return; + } + spin_lock(&bf_nonisr_lock); + + while (*cur_listener) { + cur_listener = &((*cur_listener)->next); + } + *cur_listener = listener; + listener->next = NULL; + + spin_unlock(&bf_nonisr_lock); +} + +static void bf_remove_listener(struct bf_pci_dev *bfdev, + struct bf_listener *listener) { + struct bf_listener **cur_listener = &bfdev->listener_head; + + /* in case of certain error conditions, this function might be called after + * bf_pci_remove() + */ + if (!bfdev || !listener) { + return; + } + spin_lock(&bf_nonisr_lock); + + if (*cur_listener == listener) { + *cur_listener = listener->next; + } else { + while (*cur_listener) { + if ((*cur_listener)->next == listener) { + (*cur_listener)->next = listener->next; + break; + } + cur_listener = &((*cur_listener)->next); + } + listener->next = NULL; + } + + spin_unlock(&bf_nonisr_lock); +} + +/* a pool of minor numbers is maintained */ +/* return the first available minor number */ +static int bf_get_next_minor_no(int *minor) { + int i; + + spin_lock(&bf_nonisr_lock); + for (i = 0; i < BF_FPGA_MAX_DEVICE_CNT; i++) { + if (bf_minor[i] == 0) { + *minor = i; + bf_minor[i] = 1; /* mark it as taken */ + spin_unlock(&bf_nonisr_lock); + return 0; + } + } + *minor = -1; + spin_unlock(&bf_nonisr_lock); + return -1; +} + +/* return a minor number back to the pool for recycling */ +static int bf_return_minor_no(int minor) { + int err; + + spin_lock(&bf_nonisr_lock); + if (bf_minor[minor] == 0) { /* was already returned */ + err = -1; /* don't change anything, but return error */ + } else { + bf_minor[minor] = 0; /* mark it as available */ + err = 0; + } + spin_unlock(&bf_nonisr_lock); + return err; +} + +static inline struct bf_pci_dev *bf_get_pci_dev(struct bf_dev_info *info) { + return container_of(info, struct bf_pci_dev, info); +} + +/* + * It masks the msix on/off of generating MSI-X messages. + */ +static void bf_msix_mask_irq(struct msi_desc *desc, int32_t state) { + u32 mask_bits = desc->masked; + unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_VECTOR_CTRL; + + if (state != 0) { + mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; + } else { + mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT; + } + + if (mask_bits != desc->masked) { + writel(mask_bits, desc->mask_base + offset); + readl(desc->mask_base); + desc->masked = mask_bits; + } +} + +/** + * irqcontrol can be used to disable/enable interrupt from user space processes. + * + * @param bf_dev + * pointer to bf_pci_dev + * @param irq_state + * state value. 1 to enable interrupt, 0 to disable interrupt. + * + * @return + * - On success, 0. + * - On failure, a negative value. + */ +static int bf_pci_irqcontrol(struct bf_pci_dev *bfdev, s32 irq_state) { + struct pci_dev *pdev = bfdev->pdev; + + pci_cfg_access_lock(pdev); + if (bfdev->mode == BF_INTR_MODE_LEGACY) { + pci_intx(pdev, !!irq_state); + } else if (bfdev->mode == BF_INTR_MODE_MSIX) { + struct msi_desc *desc; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) + list_for_each_entry(desc, &pdev->msi_list, list) + bf_msix_mask_irq(desc, irq_state); +#else + for_each_pci_msi_entry(desc, pdev) bf_msix_mask_irq(desc, irq_state); +#endif + } + pci_cfg_access_unlock(pdev); + + return 0; +} + +/** + * interrupt handler which will check if the interrupt is from the right + * device. If so, disable it here and will be enabled later. + */ +static irqreturn_t bf_pci_irqhandler(int irq, struct bf_pci_dev *bfdev) { + /* Legacy mode need to mask in hardware */ + if (bfdev->mode == BF_INTR_MODE_LEGACY && + !pci_check_and_mask_intx(bfdev->pdev)) { + return IRQ_NONE; + } + + /* NOTE : if bfdev->info.pci_error_state == 1, then do not access the + * device and return IRQ_NOTHANDLED. + */ + return IRQ_HANDLED; +} + +/* Remap pci resources described by bar #pci_bar */ +static int bf_pci_setup_iomem(struct pci_dev *dev, + struct bf_dev_info *info, + int n, + int pci_bar, + const char *name) { + unsigned long addr, len; + void *internal_addr; + + if (sizeof(info->mem) / sizeof(info->mem[0]) <= n) { + return -EINVAL; + } + + addr = pci_resource_start(dev, pci_bar); + len = pci_resource_len(dev, pci_bar); + if (addr == 0 || len == 0) { + return -1; + } + internal_addr = pci_ioremap_bar(dev, pci_bar); + if (internal_addr == NULL) { + return -1; + } + info->mem[n].name = name; + info->mem[n].addr = addr; + info->mem[n].internal_addr = internal_addr; + info->mem[n].size = len; + return 0; +} + +/* Unmap previously ioremap'd resources */ +static void bf_pci_release_iomem(struct bf_dev_info *info) { + int i; + + for (i = 0; i < BF_MAX_BAR_MAPS; i++) { + if (info->mem[i].internal_addr) { + iounmap(info->mem[i].internal_addr); + } + } +} + +static int bf_setup_bars(struct pci_dev *dev, struct bf_dev_info *info) { + int i, iom, ret; + unsigned long flags; + static const char *bar_names[BF_MAX_BAR_MAPS] = { + "BAR0", "BAR1", "BAR2", "BAR3", "BAR4", "BAR5", + }; + + iom = 0; + + for (i = 0; i < BF_MAX_BAR_MAPS; i++) { + if (pci_resource_len(dev, i) != 0 && pci_resource_start(dev, i) != 0) { + flags = pci_resource_flags(dev, i); + if (flags & IORESOURCE_MEM) { + ret = bf_pci_setup_iomem(dev, info, iom, i, bar_names[i]); + if (ret != 0) { + return ret; + } + iom++; + } + } + } + return (iom != 0) ? ret : -ENOENT; +} + +static irqreturn_t bf_interrupt(int irq, void *bfdev_id) { + struct bf_pci_dev *bfdev = ((struct bf_int_vector *)bfdev_id)->bf_dev; + int vect_off = ((struct bf_int_vector *)bfdev_id)->int_vec_offset; + + irqreturn_t ret = bf_pci_irqhandler(irq, bfdev); + + if (ret == IRQ_HANDLED) { + atomic_inc(&(bfdev->info.event[vect_off])); + } + return ret; +} + +static unsigned int bf_poll(struct file *filep, poll_table *wait) { + struct bf_listener *listener = (struct bf_listener *)filep->private_data; + struct bf_pci_dev *bfdev = listener->bfdev; + int i; + + if (!bfdev) { + return -ENODEV; + } + if (!bfdev->info.irq) { + return -EIO; + } + + poll_wait(filep, &bfdev->info.wait, wait); + + for (i = 0; i < BF_MSIX_ENTRY_CNT; i++) { + if (listener->event_count[i] != atomic_read(&bfdev->info.event[i])) { + return POLLIN | POLLRDNORM; + } + } + return 0; +} + +static int bf_find_mem_index(struct vm_area_struct *vma) { + struct bf_pci_dev *bfdev = vma->vm_private_data; + if (vma->vm_pgoff < BF_MAX_BAR_MAPS) { + if (bfdev->info.mem[vma->vm_pgoff].size == 0) { + return -1; + } + return (int)vma->vm_pgoff; + } + return -1; +} + +static const struct vm_operations_struct bf_physical_vm_ops = { +#ifdef CONFIG_HAVE_IOREMAP_PROT + .access = generic_access_phys, +#endif +}; + +static int bf_mmap_physical(struct vm_area_struct *vma) { + struct bf_pci_dev *bfdev = vma->vm_private_data; + int bar = bf_find_mem_index(vma); + struct bf_dev_mem *mem; + if (bar < 0) { + return -EINVAL; + } + + mem = bfdev->info.mem + bar; + + if (mem->addr & ~PAGE_MASK) { + return -ENODEV; + } + if (vma->vm_end - vma->vm_start > mem->size) { + return -EINVAL; + } + + vma->vm_ops = &bf_physical_vm_ops; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + /* + * We cannot use the vm_iomap_memory() helper here, + * because vma->vm_pgoff is the map index we looked + * up above in bf_find_mem_index(), rather than an + * actual page offset into the mmap. + * + * So we just do the physical mmap without a page + * offset. + */ + return remap_pfn_range(vma, + vma->vm_start, + mem->addr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); +} + +static int bf_mmap(struct file *filep, struct vm_area_struct *vma) { + struct bf_listener *listener = filep->private_data; + struct bf_pci_dev *bfdev = listener->bfdev; + int bar; + unsigned long requested_pages, actual_pages; + + if (!bfdev) { + return -ENODEV; + } + if (vma->vm_end < vma->vm_start) { + return -EINVAL; + } + + vma->vm_private_data = bfdev; + + bar = bf_find_mem_index(vma); + if (bar < 0) { + return -EINVAL; + } + + requested_pages = vma_pages(vma); + actual_pages = ((bfdev->info.mem[bar].addr & ~PAGE_MASK) + + bfdev->info.mem[bar].size + PAGE_SIZE - 1) >> + PAGE_SHIFT; + if (requested_pages > actual_pages) { + return -EINVAL; + } + + return bf_mmap_physical(vma); +} + +static int bf_fasync(int fd, struct file *filep, int mode) { + int minor; + + if (!filep->private_data) { + return (-EINVAL); + } + minor = ((struct bf_listener *)filep->private_data)->minor; + if (minor >= BF_FPGA_MAX_DEVICE_CNT) { + return (-EINVAL); + } + if (mode == 0 && &bf_global[minor].async_queue == NULL) { + return 0; /* nothing to do */ + } + return (fasync_helper(fd, filep, mode, &bf_global[minor].async_queue)); +} + +static int bf_open(struct inode *inode, struct file *filep) { + struct bf_pci_dev *bfdev; + struct bf_listener *listener; + int i; + + bfdev = bf_global[iminor(inode)].bfdev; + listener = kmalloc(sizeof(*listener), GFP_KERNEL); + if (listener) { + listener->bfdev = bfdev; + listener->minor = bfdev->info.minor; + listener->next = NULL; + bf_add_listener(bfdev, listener); + for (i = 0; i < BF_MSIX_ENTRY_CNT; i++) { + listener->event_count[i] = atomic_read(&bfdev->info.event[i]); + } + filep->private_data = listener; + return 0; + } else { + return (-ENOMEM); + } +} + +static int bf_release(struct inode *inode, struct file *filep) { + struct bf_listener *listener = filep->private_data; + + bf_fasync(-1, filep, 0); /* empty any process id in the notification list */ + if (listener->bfdev) { + bf_remove_listener(listener->bfdev, listener); + } + kfree(listener); + return 0; +} + +/* user space support: make read() system call after poll() of select() */ +static ssize_t bf_read(struct file *filep, + char __user *buf, + size_t count, + loff_t *ppos) { + struct bf_listener *listener = filep->private_data; + struct bf_pci_dev *bfdev = listener->bfdev; + int retval, event_count[BF_MSIX_ENTRY_CNT]; + int i, mismatch_found = 0; /* OR of per vector mismatch */ + unsigned char cnt_match[BF_MSIX_ENTRY_CNT]; /* per vector mismatch */ + + if (!bfdev) { + return -ENODEV; + } + /* irq must be setup for read() to work */ + if (!bfdev->info.irq) { + return -EIO; + } + + /* ensure that there is enough space on user buffer for the given interrupt + * mode */ + if (bfdev->mode == BF_INTR_MODE_MSIX) { + if (count < sizeof(s32) * BF_MSIX_ENTRY_CNT) { + return -EINVAL; + } + count = sizeof(s32) * BF_MSIX_ENTRY_CNT; + } else if (bfdev->mode == BF_INTR_MODE_MSI) { + if (count < sizeof(s32) * BF_MSI_ENTRY_CNT) { + return -EINVAL; + } + count = sizeof(s32) * BF_MSI_ENTRY_CNT; + } else { + if (count < sizeof(s32)) { + return -EINVAL; + } + count = sizeof(s32); + } + + do { + set_current_state(TASK_INTERRUPTIBLE); + + for (i = 0; i < (count / sizeof(s32)); i++) { + event_count[i] = atomic_read(&(bfdev->info.event[i])); + if (event_count[i] != listener->event_count[i]) { + mismatch_found |= 1; + cnt_match[i] = 1; + } else { + event_count[i] = 0; + cnt_match[i] = 0; + } + } + if (mismatch_found) { + __set_current_state(TASK_RUNNING); + if (copy_to_user(buf, &event_count, count)) { + retval = -EFAULT; + } else { /* adjust the listener->event_count; */ + for (i = 0; i < (count / sizeof(s32)); i++) { + if (cnt_match[i]) { + listener->event_count[i] = event_count[i]; + } + } + retval = count; + } + break; + } + + if (filep->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } while (1); + + __set_current_state(TASK_RUNNING); + + return retval; +} + +/* user space is supposed to call this after it is done with interrupt + * processing + */ +static ssize_t bf_write(struct file *filep, + const char __user *buf, + size_t count, + loff_t *ppos) { + struct bf_listener *listener = filep->private_data; + struct bf_pci_dev *bfdev = listener->bfdev; + ssize_t ret; + s32 int_en; + + if (!bfdev || !bfdev->info.irq) { + return -EIO; + } + + if (count != sizeof(s32)) { + return -EINVAL; + } + + if (copy_from_user(&int_en, buf, count)) { + return -EFAULT; + } + + /* clear pci_error_state */ + bfdev->info.pci_error_state = 0; + + ret = bf_pci_irqcontrol(bfdev, int_en); + + return ret ? ret : sizeof(s32); +} + +static long bf_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { + struct bf_listener *listener = filep->private_data; + struct bf_pci_dev *bfdev = listener->bfdev; + + return (bf_fpga_ioctl(bfdev, cmd, arg)); +} + +static const struct file_operations bf_fops = { + .owner = THIS_MODULE, + .open = bf_open, + .release = bf_release, + .unlocked_ioctl = bf_ioctl, + .read = bf_read, + .write = bf_write, + .mmap = bf_mmap, + .poll = bf_poll, + .fasync = bf_fasync, +}; + +static int bf_major_init(struct bf_pci_dev *bfdev, int minor) { + struct cdev *cdev; + static const char name[] = "bf_fpga"; + dev_t bf_dev = 0; + int result; + + result = alloc_chrdev_region(&bf_dev, 0, BF_FPGA_MAX_DEVICE_CNT, name); + if (result) { + return result; + } + + result = -ENOMEM; + cdev = cdev_alloc(); + if (!cdev) { + goto fail_dev_add; + } + cdev->ops = &bf_fops; + cdev->owner = THIS_MODULE; + kobject_set_name(&cdev->kobj, "%s", name); + result = cdev_add(cdev, bf_dev, BF_FPGA_MAX_DEVICE_CNT); + + if (result) { + goto fail_dev_add; + } + + bf_major = MAJOR(bf_dev); + bf_global[minor].bf_cdev = cdev; + return 0; + +fail_dev_add: + unregister_chrdev_region(bf_dev, BF_FPGA_MAX_DEVICE_CNT); + return result; +} + +static void bf_major_cleanup(struct bf_pci_dev *bfdev, int minor) { + unregister_chrdev_region(MKDEV(bf_major, 0), BF_FPGA_MAX_DEVICE_CNT); + cdev_del(bf_global[minor].bf_cdev); +} + +static int bf_init_cdev(struct bf_pci_dev *bfdev, int minor) { + int ret; + ret = bf_major_init(bfdev, minor); + if (ret) return ret; + + bf_class = class_create(THIS_MODULE, BF_CLASS_NAME); + if (!bf_class) { + printk(KERN_ERR "create_class failed for bf_fpga_dev\n"); + ret = -ENODEV; + goto err_class_register; + } + return 0; + +err_class_register: + bf_major_cleanup(bfdev, minor); + return ret; +} + +static void bf_remove_cdev(struct bf_pci_dev *bfdev) { + class_destroy(bf_class); + bf_major_cleanup(bfdev, bfdev->info.minor); +} + +/** + * bf_register_device - register a new userspace mem device + * @parent: parent device + * @bfdev: bf pci device + * + * returns zero on success or a negative error code. + */ +int bf_register_device(struct device *parent, struct bf_pci_dev *bfdev) { + struct bf_dev_info *info = &bfdev->info; + int i, j, ret = 0; + int minor; + + if (!parent || !info || !info->version) { + return -EINVAL; + } + + init_waitqueue_head(&info->wait); + + for (i = 0; i < BF_MSIX_ENTRY_CNT; i++) { + atomic_set(&info->event[i], 0); + } + + if (bf_get_next_minor_no(&minor)) { + return -EINVAL; + } + + ret = bf_init_cdev(bfdev, minor); + if (ret) { + printk(KERN_ERR "BFi_FPGA: device cdev creation failed\n"); + return ret; + } + + info->dev = device_create( + bf_class, parent, MKDEV(bf_major, minor), bfdev, "bf_fpga_%d", minor); + if (!info->dev) { + printk(KERN_ERR "BF_FPGA: device creation failed\n"); + return -ENODEV; + } + + info->minor = minor; + + /* bind ISRs and request interrupts */ + if (info->irq && (bfdev->mode != BF_INTR_MODE_NONE)) { + /* + * Note that we deliberately don't use devm_request_irq + * here. The parent module can unregister the UIO device + * and call pci_disable_msi, which requires that this + * irq has been freed. However, the device may have open + * FDs at the time of unregister and therefore may not be + * freed until they are released. + */ + if (bfdev->mode == BF_INTR_MODE_LEGACY) { + ret = request_irq(info->irq, + bf_interrupt, + info->irq_flags, + bfdev->name, + (void *)&(bfdev->bf_int_vec[0])); + if (ret) { + printk(KERN_ERR "bf_fpga failed to request legacy irq %ld error %d\n", + info->irq, + ret); + return ret; + } + printk(KERN_NOTICE "BF_FPGA allocating legacy int vector %ld\n", + info->irq); + } else if (bfdev->mode == BF_INTR_MODE_MSIX) { + for (i = 0; i < info->num_irq; i++) { + ret = request_irq(info->msix_entries[i].vector, + bf_interrupt, + info->irq_flags, + bfdev->name, + (void *)&(bfdev->bf_int_vec[i])); + if (ret) { + /* undo all other previous bindings */ + printk(KERN_ERR "bf_fpga failed to request MSIX ret %d itr %d\n", + ret, + i); + for (j = i - 1; j >= 0; j--) { + free_irq(info->msix_entries[j].vector, + (void *)&(bfdev->bf_int_vec[j])); + } + return ret; + } + } + printk(KERN_NOTICE "BF_FPGA allocating %d MSIx vectors from %ld\n", + info->num_irq, + info->irq); + } else if (bfdev->mode == BF_INTR_MODE_MSI) { + for (i = 0; i < info->num_irq; i++) { + ret = request_irq(info->irq + i, + bf_interrupt, + info->irq_flags, + bfdev->name, + (void *)&(bfdev->bf_int_vec[i])); + if (ret) { + /* undo all other previous bindings */ + printk( + KERN_ERR "bf_fpga failed to request MSI ret %d itr %d\n", ret, i); + for (j = i - 1; j >= 0; j--) { + free_irq(info->irq + j, (void *)&(bfdev->bf_int_vec[j])); + } + return ret; + } + } + printk(KERN_NOTICE "BF_FPGA allocating %d MSI vectors from %ld\n", + info->num_irq, + info->irq); + } + } + return 0; +} + +/** + * bf_unregister_device - register a new userspace mem device + * @bfdev: bf pci device + * + * returns none + */ +void bf_unregister_device(struct bf_pci_dev *bfdev) { + struct bf_dev_info *info = &bfdev->info; + int i; + + if (info->irq) { + if (bfdev->mode == BF_INTR_MODE_LEGACY) { + free_irq(info->irq, (void *)&(bfdev->bf_int_vec[0])); + } else if (bfdev->mode == BF_INTR_MODE_MSIX) { + for (i = 0; i < info->num_irq; i++) { + free_irq(info->msix_entries[i].vector, (void *)&(bfdev->bf_int_vec[i])); + } + } else if (bfdev->mode == BF_INTR_MODE_MSI) { + for (i = 0; i < info->num_irq; i++) { + free_irq(info->irq + i, (void *)&(bfdev->bf_int_vec[i])); + } + } + } + device_destroy(bf_class, MKDEV(bf_major, info->minor)); + bf_remove_cdev(bfdev); + bf_return_minor_no(info->minor); + return; +} + +static inline struct device *pci_dev_to_dev(struct pci_dev *pdev) { + return &pdev->dev; +} + +static void bf_fpga_disable_int_dma(struct bf_pci_dev *bfdev) { + u8 *bf_base_addr; + + /* maskinterrupts and DMA */ + bf_base_addr = (bfdev->info.mem[0].internal_addr); + /* return if called before mmap */ + if (!bf_base_addr) { + return; + } + /* mask interrupt at shadow level */ + /* TBD */ +} + +static void fpga_print_build_date(u32 build_date) { + char day, month, year, hr, min, sec; + + sec = (char)(build_date & 0x3f); + build_date >>= 6; + min = (char)(build_date & 0x3f); + build_date >>= 6; + hr = (char)(build_date & 0x1f); + build_date >>= 5; + year = (char)(build_date & 0x3f); + build_date >>= 6; + month = (char)(build_date & 0x0f); + build_date >>= 4; + day = (char)(build_date & 0x1f); + printk(KERN_ALERT "fpga version %02d/%02d/%2d %02d:%02d:%02d", + month, + day, + year, + hr, + min, + sec); +} + +static int bf_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct bf_pci_dev *bfdev; + int err, pci_use_highmem; + int i, num_irq; + u32 build_date, build_ver; + + memset(bf_global, 0, sizeof(bf_global)); + + bfdev = kzalloc(sizeof(struct bf_pci_dev), GFP_KERNEL); + if (!bfdev) { + return -ENOMEM; + } + + /* init the cookies to be passed to ISRs */ + for (i = 0; i < BF_MSIX_ENTRY_CNT; i++) { + bfdev->bf_int_vec[i].int_vec_offset = i; + bfdev->bf_int_vec[i].bf_dev = bfdev; + } + + /* initialize intr_mode to none */ + bfdev->mode = BF_INTR_MODE_NONE; + + /* clear pci_error_state */ + bfdev->info.pci_error_state = 0; + + /* + * enable device + */ + err = pci_enable_device(pdev); + if (err != 0) { + printk(KERN_ERR "bf_fpga cannot enable PCI device\n"); + goto fail_free; + } + + /* + * reserve device's PCI memory regions for use by this + * module + */ + err = pci_request_regions(pdev, "bf_fpga_umem"); + if (err != 0) { + printk(KERN_ERR "bf_fpga Cannot request regions\n"); + goto fail_pci_disable; + } + /* remap IO memory */ + err = bf_setup_bars(pdev, &bfdev->info); + if (err != 0) { + printk(KERN_ERR "bf_fpga Cannot setup BARs\n"); + goto fail_release_iomem; + } + + if (!dma_set_mask(pci_dev_to_dev(pdev), DMA_BIT_MASK(64)) && + !dma_set_coherent_mask(pci_dev_to_dev(pdev), DMA_BIT_MASK(64))) { + pci_use_highmem = 1; + } else { + err = dma_set_mask(pci_dev_to_dev(pdev), DMA_BIT_MASK(32)); + if (err) { + err = dma_set_coherent_mask(pci_dev_to_dev(pdev), DMA_BIT_MASK(32)); + if (err) { + printk(KERN_ERR "bf_fpga no usable DMA configuration, aborting\n"); + goto fail_release_iomem; + } + } + pci_use_highmem = 0; + } + + /* enable pci error reporting */ + /* for the current kernel version, kernel config must have set the followings: + * CONFIG_PCIEPORTBUS=y and CONFIG_PCIEAER = y + * we have pci_error_handlers defined that gets invoked by kernel AER module + * upon detecting the pcie error on this device's addresses. + * However, there seems no way that AER would pass the offending addresses + * to the callback functions. AER logs the error messages on the console. + * This driver's calback function send the SIGIO signal to the user space + * to indicate the error condition. + */ + pci_enable_pcie_error_reporting(pdev); + + bf_fpga_disable_int_dma(bfdev); + + /* enable bus mastering on the device */ + pci_set_master(pdev); + + /* fill in bfdev info */ + bfdev->info.version = "0.1"; + bfdev->info.owner = THIS_MODULE; + bfdev->pdev = pdev; + + switch (bf_intr_mode_default) { +#ifdef CONFIG_PCI_MSI + case BF_INTR_MODE_MSIX: + /* Only 1 msi-x vector needed */ + bfdev->info.msix_entries = + kcalloc(BF_MSIX_ENTRY_CNT, sizeof(struct msix_entry), GFP_KERNEL); + if (!bfdev->info.msix_entries) { + err = -ENOMEM; + goto fail_clear_pci_master; + } + for (i = 0; i < BF_MSIX_ENTRY_CNT; i++) { + bfdev->info.msix_entries[i].entry = i; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) + num_irq = + pci_enable_msix(pdev, bfdev->info.msix_entries, BF_MSIX_ENTRY_CNT); + if (num_irq == 0) { + bfdev->info.num_irq = BF_MSIX_ENTRY_CNT; + bfdev->info.irq = bfdev->info.msix_entries[0].vector; + bfdev->mode = BF_INTR_MODE_MSIX; + printk(KERN_DEBUG "bf_fpga using %d MSIX irq from %ld\n", + num_irq, + bfdev->info.irq); + break; + } +#else + num_irq = pci_enable_msix_range( + pdev, bfdev->info.msix_entries, BF_MSIX_ENTRY_CNT, BF_MSIX_ENTRY_CNT); + if (num_irq == BF_MSIX_ENTRY_CNT) { + bfdev->info.num_irq = num_irq; + bfdev->info.irq = bfdev->info.msix_entries[0].vector; + bfdev->mode = BF_INTR_MODE_MSIX; + printk(KERN_DEBUG "bf_fpga using %d MSIX irq from %ld\n", + num_irq, + bfdev->info.irq); + break; + } else { + if (num_irq) pci_disable_msix(pdev); + kfree(bfdev->info.msix_entries); + bfdev->info.msix_entries = NULL; + printk(KERN_ERR + "bf_fpga error allocating MSIX vectors. Trying MSI...\n"); + /* and, fall back to MSI */ + } +#endif /* LINUX_VERSION_CODE */ + /* ** intentional no-break */ + case BF_INTR_MODE_MSI: +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) + num_irq = pci_enable_msi_block(pdev, BF_MSI_ENTRY_CNT); + /* we must get requested number of MSI vectors enabled */ + if (num_irq == 0) { + bfdev->info.num_irq = BF_MSI_ENTRY_CNT; + bfdev->info.irq = pdev->irq; + bfdev->mode = BF_INTR_MODE_MSI; + printk(KERN_DEBUG "bf_fpga using %d MSI irq from %ld\n", + bfdev->info.num_irq, + bfdev->info.irq); + break; + } +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) + num_irq = pci_enable_msi_range(pdev, BF_MSI_ENTRY_CNT, BF_MSI_ENTRY_CNT); + if (num_irq > 0) { + bfdev->info.num_irq = num_irq; + bfdev->info.irq = pdev->irq; + bfdev->mode = BF_INTR_MODE_MSI; + printk(KERN_DEBUG "bf_fpga using %d MSI irq from %ld\n", + bfdev->info.num_irq, + bfdev->info.irq); + break; + } +#else + num_irq = pci_alloc_irq_vectors_affinity(pdev, + BF_MSI_ENTRY_CNT, + BF_MSI_ENTRY_CNT, + PCI_IRQ_MSI | PCI_IRQ_AFFINITY, + NULL); + if (num_irq > 0) { + bfdev->info.num_irq = num_irq; + bfdev->info.irq = pci_irq_vector(pdev, 0); + bfdev->mode = BF_INTR_MODE_MSI; + printk(KERN_DEBUG "bf_fpga using %d MSI irq from %ld\n", + bfdev->info.num_irq, + bfdev->info.irq); + break; + } +#endif /* LINUX_VERSION_CODE */ +#endif /* CONFIG_PCI_MSI */ + /* fall back to Legacy Interrupt, intentional no-break */ + + case BF_INTR_MODE_LEGACY: + if (pci_intx_mask_supported(pdev)) { + bfdev->info.irq_flags = IRQF_SHARED; + bfdev->info.irq = pdev->irq; + bfdev->mode = BF_INTR_MODE_LEGACY; + printk(KERN_DEBUG "bf_fpga using LEGACY irq %ld\n", bfdev->info.irq); + break; + } + printk(KERN_NOTICE "bf_fpga PCI INTx mask not supported\n"); + /* fall back to no Interrupt, intentional no-break */ + case BF_INTR_MODE_NONE: + bfdev->info.irq = 0; + bfdev->info.num_irq = 0; + bfdev->mode = BF_INTR_MODE_NONE; + break; + + default: + printk(KERN_DEBUG "bf_fpga invalid IRQ mode %u", bf_intr_mode_default); + err = -EINVAL; + goto fail_clear_pci_master; + } + + pci_set_drvdata(pdev, bfdev); + sprintf(bfdev->name, "bf_fpga%d", bfdev->info.minor); + /* register bf driver */ + err = bf_register_device(&pdev->dev, bfdev); + if (err != 0) { + goto fail_release_irq; + } + + bf_global[bfdev->info.minor].async_queue = NULL; + bf_global[bfdev->info.minor].bfdev = bfdev; + + dev_info(&pdev->dev, + "bf_fpga device %d registered with irq %ld\n", + bfdev->instance, + bfdev->info.irq); + if (fpga_i2c_init(bfdev->info.mem[0].internal_addr)) { + printk(KERN_ERR "bf_fpga i2c initialization failed\n"); + goto fail_register_device; + } + if (bf_fpga_sysfs_add(bfdev)) { + printk(KERN_ERR "bf_fpga stsfs initialization failed\n"); + goto fail_i2c_init; + } + build_ver = + *((u32 *)(bfdev->info.mem[0].internal_addr) + (BF_FPGA_VER_REG / 4)); + build_date = + *((u32 *)(bfdev->info.mem[0].internal_addr) + (BF_FPGA_BUILD_DATE / 4)); + fpga_print_build_date(build_date); + printk(KERN_ALERT "bf_fpga version %hu:%hu probe ok\n", + (u16)(build_ver >> 16), + (u16)(build_ver)); + return 0; + +fail_i2c_init: + fpga_i2c_deinit(); +fail_register_device: + bf_unregister_device(bfdev); +fail_release_irq: + pci_set_drvdata(pdev, NULL); + if (bfdev->mode == BF_INTR_MODE_MSIX) { + pci_disable_msix(bfdev->pdev); + kfree(bfdev->info.msix_entries); + bfdev->info.msix_entries = NULL; + } else if (bfdev->mode == BF_INTR_MODE_MSI) { + pci_disable_msi(bfdev->pdev); + } +fail_clear_pci_master: + pci_clear_master(pdev); +fail_release_iomem: + bf_pci_release_iomem(&bfdev->info); + pci_release_regions(pdev); +fail_pci_disable: + pci_disable_device(pdev); +fail_free: + kfree(bfdev); + + printk(KERN_ERR "bf_fpga probe failed\n"); + return err; +} + +static void bf_pci_remove(struct pci_dev *pdev) { + struct bf_pci_dev *bfdev = pci_get_drvdata(pdev); + struct bf_listener *cur_listener; + + bf_fpga_disable_int_dma(bfdev); + bf_fpga_sysfs_del(bfdev); + fpga_i2c_deinit(); + bf_unregister_device(bfdev); + if (bfdev->mode == BF_INTR_MODE_MSIX) { + pci_disable_msix(pdev); + kfree(bfdev->info.msix_entries); + bfdev->info.msix_entries = NULL; + } else if (bfdev->mode == BF_INTR_MODE_MSI) { + pci_disable_msi(pdev); + } + pci_clear_master(pdev); + bf_pci_release_iomem(&bfdev->info); + pci_release_regions(pdev); + pci_disable_pcie_error_reporting(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + bf_global[bfdev->info.minor].bfdev = NULL; + /* existing filep structures in open file(s) must be informed that + * bf_pci_dev is no longer valid */ + spin_lock(&bf_nonisr_lock); + cur_listener = bfdev->listener_head; + while (cur_listener) { + cur_listener->bfdev = NULL; + cur_listener = cur_listener->next; + } + spin_unlock(&bf_nonisr_lock); + kfree(bfdev); + printk(KERN_ALERT "bf_fpga removed\n"); +} + +/** + * bf_pci_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * called when root complex detects pci error associated with the device + */ +static pci_ers_result_t bf_pci_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) { + struct bf_pci_dev *bfdev = pci_get_drvdata(pdev); + int minor; + + if (!bfdev) { + return PCI_ERS_RESULT_NONE; + } + printk(KERN_ERR "bf_fpga pci_err_detected state %d\n", state); + if (state == pci_channel_io_perm_failure || state == pci_channel_io_frozen) { + bfdev->info.pci_error_state = 1; + /* send a signal to the user space program of the error */ + minor = bfdev->info.minor; + if (minor < BF_FPGA_MAX_DEVICE_CNT && bf_global[minor].async_queue) { + kill_fasync(&bf_global[minor].async_queue, SIGIO, POLL_ERR); + } + return PCI_ERS_RESULT_DISCONNECT; + } else { + return PCI_ERS_RESULT_NONE; + } +} + +/** + * bf_pci_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + */ +static pci_ers_result_t bf_pci_slot_reset(struct pci_dev *pdev) { + /* nothing to do for now as we do not expect to get backto normal after + * a pcie link reset + * TBD: fill in this function if tofino can recover after an error + */ + return PCI_ERS_RESULT_DISCONNECT; +} + +/** + * bf_pci_resume - called when kernel thinks the device is up on PCIe. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. + */ +static void bf_pci_resume(struct pci_dev *pdev) { + /* this function should never be called for BF FPGA */ + struct bf_pci_dev *bfdev = pci_get_drvdata(pdev); + + printk(KERN_ERR "BF_FPGA io_resume invoked after pci error\n"); + if (bfdev) { + bfdev->info.pci_error_state = 0; + } +} + +static int bf_config_intr_mode(char *intr_str) { + if (!intr_str) { + pr_info("BF_FPGA Use MSI interrupt by default\n"); + return 0; + } + + if (!strcmp(intr_str, BF_INTR_MODE_MSIX_NAME)) { + bf_intr_mode_default = BF_INTR_MODE_MSIX; + pr_info("BF_FPGA Use MSIX interrupt\n"); + } else if (!strcmp(intr_str, BF_INTR_MODE_MSI_NAME)) { + bf_intr_mode_default = BF_INTR_MODE_MSI; + pr_info("BF_FPGA Use MSI interrupt\n"); + } else if (!strcmp(intr_str, BF_INTR_MODE_LEGACY_NAME)) { + bf_intr_mode_default = BF_INTR_MODE_LEGACY; + pr_info("BF_FPGA Use legacy interrupt\n"); + } else if (!strcmp(intr_str, BF_INTR_MODE_NONE_NAME)) { + bf_intr_mode_default = BF_INTR_MODE_NONE; + pr_info("BF_FPGA interrupt disabled\n"); + } else { + pr_info("Error: BF_FPGA bad intr_mode parameter - %s\n", intr_str); + return -EINVAL; + } + + return 0; +} + +static const struct pci_device_id bf_pci_tbl[] = { + {PCI_VDEVICE(BF, BF_FPGA_DEV_ID_JBAY_0), 0}, + /* required last entry */ + {.device = 0}}; + +/* PCI bus error handlers */ +static struct pci_error_handlers bf_pci_err_handler = { + .error_detected = bf_pci_error_detected, + .slot_reset = bf_pci_slot_reset, + .resume = bf_pci_resume, +}; + +static struct pci_driver bf_pci_driver = {.name = "bf_fpga", + .id_table = bf_pci_tbl, + .probe = bf_pci_probe, + .remove = bf_pci_remove, + .err_handler = &bf_pci_err_handler}; + +static int __init bfdrv_init(void) { + int ret; + + ret = bf_config_intr_mode(intr_mode); + if (ret < 0) { + return ret; + } + spin_lock_init(&bf_nonisr_lock); + return pci_register_driver(&bf_pci_driver); +} + +static void __exit bfdrv_exit(void) { + pci_unregister_driver(&bf_pci_driver); + intr_mode = NULL; +} + +module_init(bfdrv_init); +module_exit(bfdrv_exit); + +module_param(intr_mode, charp, S_IRUGO); +MODULE_PARM_DESC(intr_mode, + "bf-fpga interrupt mode (default=none):\n" + " " BF_INTR_MODE_MSIX_NAME + " Use MSIX interrupt\n" + " " BF_INTR_MODE_MSI_NAME + " Use MSI interrupt\n" + " " BF_INTR_MODE_LEGACY_NAME + " Use Legacy interrupt\n" + " " BF_INTR_MODE_NONE_NAME + " Use no interrupt\n" + "\n"); + +MODULE_DEVICE_TABLE(pci, bf_pci_tbl); +MODULE_DESCRIPTION("Barefoot FPGA PCI-I2C device"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.1"); +MODULE_AUTHOR("Barefoot Networks"); diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_priv.h b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_priv.h new file mode 100644 index 000000000000..7515bde7458d --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_priv.h @@ -0,0 +1,141 @@ +/******************************************************************************* + Barefoot Networks FPGA Linux driver + Copyright(c) 2018 - 2019 Barefoot Networks, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + info@barefootnetworks.com + Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054 + +*******************************************************************************/ +#ifndef _BF_FPGA_H_ +#define _BF_FPGA_H_ + +#define PCI_VENDOR_ID_BF 0x1d1c +#define BF_FPGA_DEV_ID_JBAY_0 0x01F0 + +#ifndef PCI_MSIX_ENTRY_SIZE +#define PCI_MSIX_ENTRY_SIZE 16 +#define PCI_MSIX_ENTRY_LOWER_ADDR 0 +#define PCI_MSIX_ENTRY_UPPER_ADDR 4 +#define PCI_MSIX_ENTRY_DATA 8 +#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 +#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 +#endif + +#define BF_CLASS_NAME "bf_fpga" +#define BF_FPGA_MAX_DEVICE_CNT 1 +#define BF_INTR_MODE_NONE_NAME "none" +#define BF_INTR_MODE_LEGACY_NAME "legacy" +#define BF_INTR_MODE_MSI_NAME "msi" +#define BF_INTR_MODE_MSIX_NAME "msix" +#define BF_MAX_BAR_MAPS 6 +#define BF_MSIX_ENTRY_CNT 1 +#define BF_MSI_ENTRY_CNT 1 + +/* sysfs codes */ +#define BF_SYSFS_NEW_DEVICE 1 +#define BF_SYSFS_RM_DEVICE 0 +#define BF_SYSFS_I2C_START 2 + +/* interrupt mode */ +enum bf_intr_mode { + BF_INTR_MODE_NONE = 0, + BF_INTR_MODE_LEGACY, + BF_INTR_MODE_MSI, + BF_INTR_MODE_MSIX +}; + +/* device memory */ +struct bf_dev_mem { + const char *name; + phys_addr_t addr; + resource_size_t size; + void __iomem *internal_addr; +}; + +struct bf_listener { + struct bf_pci_dev *bfdev; + s32 event_count[BF_MSIX_ENTRY_CNT]; + int minor; + struct bf_listener *next; +}; + +/* device information */ +struct bf_dev_info { + struct module *owner; + struct device *dev; + int minor; + atomic_t event[BF_MSIX_ENTRY_CNT]; + wait_queue_head_t wait; + const char *version; + struct bf_dev_mem mem[BF_MAX_BAR_MAPS]; + struct msix_entry *msix_entries; + long irq; /* first irq vector */ + int num_irq; /* number of irq vectors */ + unsigned long irq_flags; /* sharable ?? */ + int pci_error_state; /* was there a pci bus error */ +}; + +/* cookie to be passed to IRQ handler, useful especially with MSIX */ +struct bf_int_vector { + struct bf_pci_dev *bf_dev; + int int_vec_offset; +}; + +/* sysfs related structs */ +#define BF_FPGA_SYSFS_CNT 64 +#define BF_FPGA_SYSFS_NAME_SIZE 32 + +struct bf_fpga_sysfs_buff { + struct device_attribute dev_attr; + char name[BF_FPGA_SYSFS_NAME_SIZE]; + int bus_id; + unsigned char i2c_addr; + size_t i2c_rd_size; /* bytes to read from the device */ + int sysfs_code; /* unique code for each sysfs file */ + struct bf_pci_dev *fpgadev; /* back pointer */ + bool in_use; +}; + +/** + * structure describing the private information for a BF pcie device. + */ +struct bf_pci_dev { + struct bf_dev_info info; + struct pci_dev *pdev; + enum bf_intr_mode mode; + u8 instance; + char name[16]; + struct bf_int_vector bf_int_vec[BF_MSIX_ENTRY_CNT]; + struct bf_listener * + listener_head; /* head of a singly linked list of listeners */ + struct bf_fpga_sysfs_buff fpga_sysfs_buff[BF_FPGA_SYSFS_CNT]; + struct bf_fpga_sysfs_buff fpga_sysfs_new_device; + struct bf_fpga_sysfs_buff fpga_sysfs_rm_device; + struct bf_fpga_sysfs_buff fpga_sysfs_st_i2c; + spinlock_t sysfs_slock; +}; + +int bf_fpga_ioctl(struct bf_pci_dev *bfdev, + unsigned int cmd, + unsigned long arg); +int bf_fpga_sysfs_add(struct bf_pci_dev *fpgadev); +void bf_fpga_sysfs_del(struct bf_pci_dev *fpgadev); + +#endif /* _BF_FPGA_H_ */ diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_sysfs.c b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_sysfs.c new file mode 100644 index 000000000000..6970a7a95985 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_sysfs.c @@ -0,0 +1,335 @@ +/******************************************************************************* + Barefoot Networks FPGA Linux driver + Copyright(c) 2018 - 2019 Barefoot Networks, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + info@barefootnetworks.com + Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054 + +*******************************************************************************/ +#include +#include +#include +#include +#include +#include "bf_fpga_priv.h" +#include "bf_fpga_ioctl.h" +#include "i2c/bf_fpga_i2c.h" + +/* reads 1 byte from the i2c device */ +static ssize_t bf_fpga_sysfs_i2c_get(struct device *dev, + struct device_attribute *attr, + char *buf) { + bf_fpga_i2c_t i2c_op; + ssize_t size, cur_size; + struct bf_fpga_sysfs_buff *sysfs_buf = + container_of(attr, struct bf_fpga_sysfs_buff, dev_attr); + + if (!sysfs_buf) { + printk(KERN_ERR "fpga-i2c bad attr pointer in sysfs_read\n"); + return -ENXIO; /* something not quite right here; but, don't panic */ + } + i2c_op.num_i2c = 1; + i2c_op.one_time = 1; + i2c_op.inst_hndl.bus_id = sysfs_buf->bus_id; + i2c_op.i2c_inst[0].preemt = false; + i2c_op.i2c_inst[0].en = true; + i2c_op.i2c_inst[0].i2c_addr = sysfs_buf->i2c_addr; + i2c_op.i2c_inst[0].i2c_type = BF_FPGA_I2C_READ; + i2c_op.i2c_inst[0].delay = 0; + i2c_op.i2c_inst[0].wr_cnt = 0; + cur_size = sysfs_buf->i2c_rd_size; + /* limit to PAGE_SIZE per the sysfs contract */ + if (cur_size >= PAGE_SIZE) { + cur_size = PAGE_SIZE; + } + size = 0; + while (cur_size > 0) { + unsigned char cur_cnt; + if (cur_size > 64) { + cur_cnt = 64; + } else { + cur_cnt = (unsigned char)cur_size; + } + i2c_op.i2c_inst[0].rd_cnt = cur_cnt; + if (fpga_i2c_oneshot(&i2c_op)) { + printk(KERN_ERR + "fpga-i2c read one-shot error bus %d addr 0x%hhx status 0x%hhx\n", + i2c_op.inst_hndl.bus_id, + i2c_op.i2c_inst[0].i2c_addr, + i2c_op.i2c_inst[0].status); + return -EIO; + } + memcpy(buf, i2c_op.i2c_inst[0].rd_buf, cur_cnt); + buf += cur_cnt; + size += cur_cnt; + cur_size -= cur_cnt; + } + return size; +} + +/* write the number of bytes supplied to the i2c device, 1st byte has to be + the count(max 8) */ +static ssize_t bf_fpga_sysfs_i2c_set(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) { + bf_fpga_i2c_t i2c_op; + size_t size, cur_cnt; + struct bf_fpga_sysfs_buff *sysfs_buf = + container_of(attr, struct bf_fpga_sysfs_buff, dev_attr); + + if (!sysfs_buf || (count == 0)) { + printk(KERN_ERR "fpga-i2c bad attr pointer in sysfs_write\n"); + return -ENXIO; /* something not quite right here; but, don't panic */ + } + size = 0; + while (count > 0) { + if (count > 64) { + cur_cnt = 64; + } else { + cur_cnt = count; + } + i2c_op.i2c_inst[0].wr_cnt = cur_cnt; + i2c_op.i2c_inst[0].rd_cnt = 0; + memcpy(i2c_op.i2c_inst[0].wr_buf, buf, cur_cnt); + i2c_op.num_i2c = 1; + i2c_op.one_time = 1; + i2c_op.inst_hndl.bus_id = sysfs_buf->bus_id; + i2c_op.i2c_inst[0].preemt = false; + i2c_op.i2c_inst[0].en = true; + i2c_op.i2c_inst[0].i2c_addr = sysfs_buf->i2c_addr; + i2c_op.i2c_inst[0].i2c_type = BF_FPGA_I2C_WRITE; + i2c_op.i2c_inst[0].delay = 0; + if (fpga_i2c_oneshot(&i2c_op)) { + printk( + KERN_ERR + "fpga-i2c write one-shot error bus %d addr 0x%hhx status 0x%hhx\n", + i2c_op.inst_hndl.bus_id, + i2c_op.i2c_inst[0].i2c_addr, + i2c_op.i2c_inst[0].status); + return -EIO; + } + buf += cur_cnt; + size += cur_cnt; + count -= cur_cnt; + } + return size; +} + +static int find_matching_sysfs_buf(struct bf_pci_dev *fpgadev, + int bus_id, + unsigned char i2c_addr) { + int i; + + /* check if a sysfs entry already exists */ + for (i = 0; i < BF_FPGA_SYSFS_CNT; i++) { + if (fpgadev->fpga_sysfs_buff[i].bus_id == bus_id && + fpgadev->fpga_sysfs_buff[i].i2c_addr == i2c_addr) { + return i; + } + } + /* could not find a matching sysfs buffer */ + return -1; +} + +static ssize_t bf_fpga_sysfs_fixed_get(struct device *dev, + struct device_attribute *attr, + char *buf) { + (void)dev; + (void)attr; + (void)buf; + return -ENOSYS; +} + +static ssize_t bf_fpga_sysfs_fixed_set(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) { + struct bf_pci_dev *fpgadev; + int i, en, bus_id, ret, rd_size; + char fname[BF_FPGA_SYSFS_NAME_SIZE]; + unsigned char i2c_addr; + struct bf_fpga_sysfs_buff *new_buf; + struct bf_fpga_sysfs_buff *sysfs_buf = + container_of(attr, struct bf_fpga_sysfs_buff, dev_attr); + + if (!sysfs_buf || (count == 0)) { + printk(KERN_ERR "fpga i2c bad attr pointer in fixed_sysfs_write\n"); + return -ENXIO; /* something not quite right here; but, don't panic */ + } + fpgadev = sysfs_buf->fpgadev; + + switch (sysfs_buf->sysfs_code) { + case BF_SYSFS_NEW_DEVICE: /* new_device request */ + ret = sscanf(buf, "%s %d %hhx %d", fname, &bus_id, &i2c_addr, &rd_size); + /* default rd_size to 1 if not supplied or invalid */ + if (ret < 3) { + return -EINVAL; + } + if (ret < 4 || rd_size > PAGE_SIZE) { + rd_size = 1; + } + if (bus_id >= BF_I2C_FPGA_NUM_CTRL || i2c_addr >= 0x80) { + return -EINVAL; + } + /* find out the free sysfs_buffer to use */ + spin_lock(&fpgadev->sysfs_slock); + if (find_matching_sysfs_buf(fpgadev, bus_id, i2c_addr) != -1) { + /* there is already an matching entry */ + spin_unlock(&fpgadev->sysfs_slock); + return -ENOSPC; + } + for (i = 0; i < BF_FPGA_SYSFS_CNT; i++) { + if (!fpgadev->fpga_sysfs_buff[i].in_use) { + fpgadev->fpga_sysfs_buff[i].in_use = true; + new_buf = &fpgadev->fpga_sysfs_buff[i]; + new_buf->i2c_addr = i2c_addr; + new_buf->i2c_rd_size = (size_t)rd_size; + new_buf->bus_id = bus_id; + break; + } + } + spin_unlock(&fpgadev->sysfs_slock); + if (i >= BF_FPGA_SYSFS_CNT) { + /* no free buffer available, return with ERROR */ + return -ENOSPC; + } + /* create a new sysfs entry now */ + new_buf->dev_attr.show = bf_fpga_sysfs_i2c_get; + new_buf->dev_attr.store = bf_fpga_sysfs_i2c_set; + new_buf->fpgadev = fpgadev; + new_buf->dev_attr.attr.mode = S_IWUSR | S_IRUGO; + new_buf->sysfs_code = 0; + snprintf(new_buf->name, BF_FPGA_SYSFS_NAME_SIZE, "%s", fname); + new_buf->dev_attr.attr.name = new_buf->name; + ret = device_create_file(&(fpgadev->pdev->dev), &new_buf->dev_attr); + break; + + case BF_SYSFS_RM_DEVICE: /* remove device request */ + ret = sscanf(buf, "%d %hhx", &bus_id, &i2c_addr); + if (ret < 2) { + return -EINVAL; + } + if (bus_id >= BF_I2C_FPGA_NUM_CTRL || i2c_addr >= 0x80) { + return -EINVAL; + } + /* delete the sysfs file corresponding to the i2c address */ + spin_lock(&fpgadev->sysfs_slock); + i = find_matching_sysfs_buf(fpgadev, bus_id, i2c_addr); + if (i == -1) { + /* there is no matching entry */ + spin_unlock(&fpgadev->sysfs_slock); + return -EINVAL; + } + /* must invalidate bus_id and i2c_addr when marking the buffer + * not-in-use + */ + new_buf = &fpgadev->fpga_sysfs_buff[i]; + new_buf->i2c_addr = 0xff; + new_buf->bus_id = -1; + fpgadev->fpga_sysfs_buff[i].in_use = false; + spin_unlock(&fpgadev->sysfs_slock); + device_remove_file(&fpgadev->pdev->dev, &new_buf->dev_attr); + new_buf->name[0] = 0; /* nullify the name */ + ret = 0; + break; + + case BF_SYSFS_I2C_START: /* start-stop i2c request */ + ret = sscanf(buf, "%d %d", &bus_id, &en); + if (ret < 2) { + return -EINVAL; + } + if (bus_id >= BF_I2C_FPGA_NUM_CTRL) { + return -EINVAL; + } + if (en) { + ret = fpga_i2c_start(bus_id); + } else { + ret = fpga_i2c_stop(bus_id); + } + break; + + default: + ret = -EINVAL; + } + return ((ret == 0) ? count : ret); +} + +int bf_fpga_sysfs_add(struct bf_pci_dev *fpgadev) { + int rc = 0; + u8 *name; + + spin_lock_init(&fpgadev->sysfs_slock); + /* Add two sysfs files statically, new_device and remove_device. + * Handlers of these two fles can dynamically add more sysfs + * files (or remove files) based on the platform. + */ + fpgadev->fpga_sysfs_new_device.dev_attr.show = bf_fpga_sysfs_fixed_get; + fpgadev->fpga_sysfs_new_device.dev_attr.store = bf_fpga_sysfs_fixed_set; + fpgadev->fpga_sysfs_new_device.fpgadev = fpgadev; + fpgadev->fpga_sysfs_new_device.dev_attr.attr.mode = S_IWUSR | S_IRUGO; + fpgadev->fpga_sysfs_new_device.sysfs_code = BF_SYSFS_NEW_DEVICE; + name = fpgadev->fpga_sysfs_new_device.name; + snprintf(name, BF_FPGA_SYSFS_NAME_SIZE, "new_device"); + fpgadev->fpga_sysfs_new_device.dev_attr.attr.name = name; + rc |= device_create_file(&(fpgadev->pdev->dev), + &fpgadev->fpga_sysfs_new_device.dev_attr); + + fpgadev->fpga_sysfs_rm_device.dev_attr.show = bf_fpga_sysfs_fixed_get; + fpgadev->fpga_sysfs_rm_device.dev_attr.store = bf_fpga_sysfs_fixed_set; + fpgadev->fpga_sysfs_rm_device.fpgadev = fpgadev; + fpgadev->fpga_sysfs_rm_device.dev_attr.attr.mode = S_IWUSR | S_IRUGO; + fpgadev->fpga_sysfs_rm_device.sysfs_code = BF_SYSFS_RM_DEVICE; + name = fpgadev->fpga_sysfs_rm_device.name; + snprintf(name, BF_FPGA_SYSFS_NAME_SIZE, "remove_device"); + fpgadev->fpga_sysfs_rm_device.dev_attr.attr.name = name; + rc |= device_create_file(&(fpgadev->pdev->dev), + &fpgadev->fpga_sysfs_rm_device.dev_attr); + + /* sysfs for i2c start-stop control */ + fpgadev->fpga_sysfs_st_i2c.dev_attr.show = bf_fpga_sysfs_fixed_get; + fpgadev->fpga_sysfs_st_i2c.dev_attr.store = bf_fpga_sysfs_fixed_set; + fpgadev->fpga_sysfs_st_i2c.fpgadev = fpgadev; + fpgadev->fpga_sysfs_st_i2c.dev_attr.attr.mode = S_IWUSR | S_IRUGO; + fpgadev->fpga_sysfs_st_i2c.sysfs_code = BF_SYSFS_I2C_START; + name = fpgadev->fpga_sysfs_st_i2c.name; + snprintf(name, BF_FPGA_SYSFS_NAME_SIZE, "i2c_start"); + fpgadev->fpga_sysfs_st_i2c.dev_attr.attr.name = name; + rc |= device_create_file(&(fpgadev->pdev->dev), + &fpgadev->fpga_sysfs_st_i2c.dev_attr); + + return rc; +} + +void bf_fpga_sysfs_del(struct bf_pci_dev *fpgadev) { + int i; + + device_remove_file(&fpgadev->pdev->dev, + &fpgadev->fpga_sysfs_new_device.dev_attr); + device_remove_file(&fpgadev->pdev->dev, + &fpgadev->fpga_sysfs_rm_device.dev_attr); + device_remove_file(&fpgadev->pdev->dev, &fpgadev->fpga_sysfs_st_i2c.dev_attr); + for (i = 0; i < BF_FPGA_SYSFS_CNT; i++) { + if (fpgadev->fpga_sysfs_buff[i].in_use) { + device_remove_file(&fpgadev->pdev->dev, + &fpgadev->fpga_sysfs_buff[i].dev_attr); + } + } +} diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c.c b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c.c new file mode 100644 index 000000000000..1a622e5392d6 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c.c @@ -0,0 +1,516 @@ +/******************************************************************************* + Barefoot Networks FPGA Linux driver + Copyright(c) 2018 - 2019 Barefoot Networks, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + info@barefootnetworks.com + Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054 + +*******************************************************************************/ +#include +#include "bf_fpga_i2c_priv_porting.h" +#include +#include "bf_fpga_i2c_priv.h" +#include "bf_fpga_i2c.h" +#include "bf_fpga_i2c_reg.h" + +/* allocate find physically contiguous free blocks of instructions in one time + * or periodic area and mark them "in-use" */ +static int get_next_free_index(fpga_i2c_controller_t *i2c_ctrl, + int cnt, + bool pr) { + int i, j, begin, end; + + if (pr) { + begin = FPGA_I2C_PERIODIC_BEGIN_INDEX; + end = FPGA_I2C_NUM_INST; + } else { + begin = FPGA_I2c_ONESHOT_BEGIN_INDEX; + end = FPGA_I2C_ONESHOT_NUM_INST; + } + + bf_fpga_fast_lock(&i2c_ctrl->spinlock); + for (i = begin; i < end;) { + /* check if there are cnt number of free slots here */ + for (j = 0; j < cnt; j++) { + if (i2c_ctrl->i2c_inst[i + j].in_use) { + break; + } + } + if (j == cnt) { + /* we found enough free slots, so, return i */ + break; + } else { + /* we did not find enough free slots, continue searching */ + i += (j + 1); + continue; + } + } + if (i < end) { + for (j = 0; j < cnt; j++) { + i2c_ctrl->i2c_inst[i + j].in_use = true; + } + } else { + i = -1; + } + bf_fpga_fast_unlock(&i2c_ctrl->spinlock); + return i; +} + +/* free physically contiguous in-use blocks of instructions */ +static void release_index(fpga_i2c_controller_t *i2c_ctrl, + int inst_id, + int cnt) { + int i; + + if (inst_id < 0 || (inst_id + cnt) >= FPGA_I2C_NUM_INST) { + return; /* invalid id */ + } + bf_fpga_fast_lock(&i2c_ctrl->spinlock); + for (i = inst_id; i < (inst_id + cnt); i++) { + i2c_ctrl->i2c_inst[i].in_use = false; + } + bf_fpga_fast_unlock(&i2c_ctrl->spinlock); +} + +/* convert miroseconds to i2c-instruction delay parameter */ +static int us_to_fpga_delay(int microsec) { + int delay; + + if (microsec < 10) { + delay = 0; + } else if (microsec < 100) { + delay = 1; + } else if (microsec < 1000) { + delay = 2; + } else if (microsec < 10000) { + delay = 3; + } else if (microsec < 100000) { + delay = 4; + } else if (microsec < 1000000) { + delay = 5; + } else { + delay = 6; + } + return delay; +} + +/* populate single i2c_instruction at the given instruction slot */ +static int fpga_i2c_enqueue(int bus_id, + int inst_id, + bf_fpga_i2c_inst_t *i2c_inst) { + fpga_i2c_controller_t *i2c_ctrl = fpga_i2c_ctrl_get(bus_id); + int delay = us_to_fpga_delay(i2c_inst->delay); + uint32_t wd0 = 0, wd1 = 0; + uint32_t i2c_data[2]; + uint8_t i2c_addr, num_wr, num_rd; + + i2c_addr = i2c_inst->i2c_addr; + num_wr = i2c_inst->wr_cnt; + num_rd = i2c_inst->rd_cnt; + if (i2c_addr > 0x7F || num_wr > 129 || num_rd > 128) { + return BF_FPGA_EINVAL; + } + if (i2c_inst->preemt) { + wd0 |= I2C_INST_PMT; + } + if (i2c_inst->en) { + wd0 |= I2C_INST_EN; + } + i2c_data[0] = i2c_data[1] = 0; /* clear on init */ + switch (i2c_inst->i2c_type) { + case BF_FPGA_I2C_NOP: + /* add delay + enable */ + wd0 |= (I2C_NOP | (delay << I2C_DELAY_SHF)); + break; + case BF_FPGA_I2C_WRITE: + if (num_wr == 0) { + return BF_FPGA_EINVAL; + } + wd0 |= (I2C_WR_ADDR_DATA | (delay << I2C_DELAY_SHF)); + wd1 |= (i2c_inst->i2c_addr << I2C_DEV_ADDR_SHF); + /* copy the first byte into register address */ + wd1 |= ((i2c_inst->wr_buf[0]) << I2C_CMD_OFFSET); + wd1 |= ((num_wr - 1) << I2C_WR_CNT_SHF); + if (num_wr <= 9) { + /* copy data into instruction area */ + memcpy(i2c_data, &i2c_inst->wr_buf[1], (num_wr - 1)); + bf_fpga_i2c_reg_write32( + i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0]); + bf_fpga_i2c_reg_write32( + i2c_ctrl, Bf_FPGA_I2C_INST_DATA_HI(inst_id), i2c_data[1]); + } else { + /* copy the data in data area */ + int len = num_wr - 1; + uint32_t addr; + uint8_t *val = (uint8_t *)(&i2c_inst->wr_buf[1]); + /* store the data pointer Note the indexing required by FPGA specs */ + i2c_data[0] = BF_FPGA_I2C_DATA_AREA(inst_id); + addr = i2c_data[0]; + bf_fpga_i2c_reg_write32( + i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0] / 4); + /* do byte write to avoid endianness mismatch */ + while (len--) { + bf_fpga_i2c_reg_write8(i2c_ctrl, addr, *val); + addr++; + val++; + } + } + break; + case BF_FPGA_I2C_READ: + if (num_rd == 0) { + return BF_FPGA_EINVAL; + } + wd0 |= (I2C_RD_DATA | (delay << I2C_DELAY_SHF)); + wd1 |= (i2c_inst->i2c_addr << I2C_DEV_ADDR_SHF); + wd1 |= ((num_rd) << I2C_RD_CNT_SHF); + if (num_rd > 8) { + /* store the data area pointer */ + i2c_data[0] = BF_FPGA_I2C_DATA_AREA(inst_id); + bf_fpga_i2c_reg_write32( + i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0] / 4); + } + break; + case BF_FPGA_I2C_ADDR_READ: + if (num_wr == 0 || num_rd == 0) { + return BF_FPGA_EINVAL; + } + wd0 |= (I2C_RD_ADDR_DATA_BURST | (delay << I2C_DELAY_SHF)); + wd1 |= (i2c_inst->i2c_addr << I2C_DEV_ADDR_SHF); + /* 1st byte of the write buf goes into "register address" field */ + wd1 |= ((num_wr - 1) << I2C_WR_CNT_SHF); + wd1 |= ((i2c_inst->wr_buf[0]) << I2C_CMD_OFFSET); + wd1 |= ((num_rd) << I2C_RD_CNT_SHF); + /* less than 8 bytes data goes to the instruction area */ + if ((num_wr - 1 + num_rd) <= 8) { + memcpy(i2c_data, &i2c_inst->wr_buf[1], (num_wr - 1)); + bf_fpga_i2c_reg_write32( + i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0]); + bf_fpga_i2c_reg_write32( + i2c_ctrl, Bf_FPGA_I2C_INST_DATA_HI(inst_id), i2c_data[1]); + } else { + int len = num_wr - 1; + uint32_t addr; + uint8_t *val = (uint8_t *)(&i2c_inst->wr_buf[1]); + /* store the data area pointer */ + i2c_data[0] = BF_FPGA_I2C_DATA_AREA(inst_id); + addr = i2c_data[0]; + bf_fpga_i2c_reg_write32( + i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0] / 4); + /* copy the data in data area */ + while (len--) { + bf_fpga_i2c_reg_write8(i2c_ctrl, addr, *val); + addr++; + val++; + } + } + break; + default: + return BF_FPGA_EINVAL; + } + bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_PARAM(inst_id), wd1); + bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(inst_id), wd0); + return BF_FPGA_OK; +} + +/* get the i2c completion status of a particular instruction */ +static uint32_t fpga_i2c_get_status(int bus_id, int inst_id) { + fpga_i2c_controller_t *i2c_ctrl = fpga_i2c_ctrl_get(bus_id); + uint32_t addr = Bf_FPGA_I2C_INST_CTRL(inst_id); + return (bf_fpga_i2c_reg_read32(i2c_ctrl, addr) & I2C_STATUS_MASK); +} + +/** FPGA I2C data read (assumes locked by caller and no need to stop i2c) + * + * read the data following a read type i2c operation + * + * @param bus_id + * i2c controller id + * @param inst_id + * instruction id within this controller space + * @param offset + * offset in the data-area where read-data is available + * @param num_rd + * number of bytes to read + * @param rd_buf + * buffer to read into + * @return + * 0 on success and <0 on error + */ +static int fpga_i2c_data_read_locked(fpga_i2c_controller_t *i2c_ctrl, + int inst_id, + uint8_t offset, + uint8_t num_rd, + uint8_t *rd_buf) { + uint8_t i; + uint32_t addr, data_cnt; + + if (!i2c_ctrl || !rd_buf || !num_rd || inst_id < 0 || + inst_id >= FPGA_I2C_NUM_INST) { + return BF_FPGA_EINVAL; + } + /* find out the wr_cnt + rd_cnt from the already executed instruction field */ + data_cnt = bf_fpga_i2c_reg_read32(i2c_ctrl, Bf_FPGA_I2C_INST_PARAM(inst_id)); + /* point to data area if the (wr_cnt + rd_cnt) > 8 */ + data_cnt &= 0xffff; /* retain only the length fields */ + if (((data_cnt & 0xff) + (data_cnt >> 8)) <= 8) { + addr = Bf_FPGA_I2C_INST_DATA_LO(inst_id) + offset; + } else { + addr = BF_FPGA_I2C_DATA_AREA(inst_id) + offset; + } + for (i = 0; i < num_rd; i++) { + *rd_buf = bf_fpga_i2c_reg_read8(i2c_ctrl, addr); + addr++; + rd_buf++; + } + return BF_FPGA_OK; +} + +/** FPGA I2C data read + * + * read the data following a read type i2c operation + * + * @param bus_id + * i2c controller id + * @param inst_id + * instruction id within this controller space + * @param offset + * offset in the data-area where read-data is available + * @param num_rd + * number of bytes to read + * @param rd_buf + * buffer to read into + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_data_read( + int bus_id, int inst_id, uint8_t offset, uint8_t num_rd, uint8_t *rd_buf) { + fpga_i2c_controller_t *i2c_ctrl = fpga_i2c_ctrl_get(bus_id); + int ret; + bool i2c_running; + uint8_t val; + + if (!i2c_ctrl || !rd_buf || !num_rd || inst_id < 0 || + inst_id >= FPGA_I2C_NUM_INST) { + return BF_FPGA_EINVAL; + } + + /* aligned (upto) 4 bytes can be read without stopping the ongoing i2c, + * this is guaranteed by FPGA design. i2c has to be stopped, in all other + * cases, to read a consistent set of read-data. + */ + if ((offset % 4 == 0) && (num_rd <= 4)) { + return ( + fpga_i2c_data_read_locked(i2c_ctrl, inst_id, offset, num_rd, rd_buf)); + } + + /* non-aligned case; stop i2c if running, read data and restart i2c */ + if (bf_fpga_i2c_lock(i2c_ctrl)) { + return BF_FPGA_EAGAIN; + } + /* check if i2c_controller is running */ + val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_TOP_I2C_STATUS); + i2c_running = ((val & I2C_STS_BUSY) ? true : false); + if (i2c_running) { + /* stop ongoing i2c operations */ + fpga_i2c_stop_locked(i2c_ctrl); + } + ret = fpga_i2c_data_read_locked(i2c_ctrl, inst_id, offset, num_rd, rd_buf); + if (i2c_running) { + /* restart ongoing i2c operations */ + fpga_i2c_start_locked(i2c_ctrl); + } + bf_fpga_i2c_unlock(i2c_ctrl); + return ret; +} + +/** FPGA I2C onetime i2c operation + * + * @param i2c_op + * bf_fpga_i2c_t parameters * + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_oneshot(bf_fpga_i2c_t *i2c_op) { + int i, ret; + uint32_t val; + int bus_id; + fpga_i2c_controller_t *i2c_ctrl; + + if (!i2c_op) { + return BF_FPGA_EINVAL; + } + + bus_id = i2c_op->inst_hndl.bus_id; + i2c_ctrl = fpga_i2c_ctrl_get(bus_id); + + if (i2c_op->num_i2c == 0 || i2c_op->num_i2c >= FPGA_I2C_ONESHOT_NUM_INST || + i2c_op->one_time == 0 || bus_id >= BF_I2C_FPGA_NUM_CTRL || !i2c_ctrl) { + return BF_FPGA_EINVAL; + } + if (bf_fpga_i2c_lock(i2c_ctrl)) { + return BF_FPGA_EAGAIN; + } + /* stop ongoing i2c operations */ + ret = fpga_i2c_stop_locked(i2c_ctrl); + if (ret) { + bf_fpga_i2c_unlock(i2c_ctrl); + return ret; + } + /* populate one time i2c operation instruction(s) from offset zero */ + for (i = 0; i < i2c_op->num_i2c; i++) { + ret = fpga_i2c_enqueue(bus_id, i, &i2c_op->i2c_inst[i]); + if (ret) { + goto oneshot_error_exit; + } + } + /* start i2c operations */ + ret = fpga_i2c_start_locked(i2c_ctrl); + if (ret) { + goto oneshot_error_exit; + } + + /* wait until complete and read the data if necessary */ + for (i = 0; i < i2c_op->num_i2c; i++) { + int cnt; + val = 0; + /* cnt is roughly the number of bytes of this i2c cycle + * overhead of 100 bytes for for worst case timeout, one + * should not hit that in normal working case + */ + cnt = i2c_op->i2c_inst[i].wr_cnt + i2c_op->i2c_inst[i].rd_cnt; + /* bump up the cnt for an i2c transaction containing some data + * for computing worst case timeout */ + if (cnt > 0) { + cnt = cnt + 100; + } + while (!(val & I2C_STATUS_COMPLETED) && (cnt-- > 0)) { + /* 1 byte ~= 10 bits takes 25 microsec on i2c cycle at 400khz */ + bf_fpga_us_delay(50); + val = fpga_i2c_get_status(bus_id, i); + } + i2c_op->i2c_inst[i].status = val; /* store the h/w status */ + if (val & I2C_STATUS_ERR_MASK) { + ret = BF_FPGA_EIO; + goto oneshot_error_exit; + } + if (i2c_op->i2c_inst[i].rd_cnt) { + uint8_t offset = 0; + if (i2c_op->i2c_inst[i].wr_cnt > 1) { + offset = i2c_op->i2c_inst[i].wr_cnt - 1; + } + if (fpga_i2c_data_read_locked(i2c_ctrl, + i, + offset, + i2c_op->i2c_inst[i].rd_cnt, + i2c_op->i2c_inst[i].rd_buf)) { + ret = BF_FPGA_EIO; + goto oneshot_error_exit; + } + } + } + ret = BF_FPGA_OK; + +oneshot_error_exit: + for (i = 0; i < i2c_op->num_i2c; i++) { + /* cleanup the enable bit */ + val = bf_fpga_i2c_reg_read32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(i)); + val &= (~I2C_INST_EN); + bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(i), val); + } + bf_fpga_i2c_unlock(i2c_ctrl); + return ret; +} + +/** FPGA I2C insert periodic i2c operation + * + * @param i2c_op + * bf_fpga_i2c_t parameters * + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_pr_add(bf_fpga_i2c_t *i2c_op) { + fpga_i2c_controller_t *i2c_ctrl; + int i, ret, next_id; + bool preemt; + + if (!i2c_op) { + return BF_FPGA_EINVAL; + } + i2c_ctrl = fpga_i2c_ctrl_get(i2c_op->inst_hndl.bus_id); + if (!i2c_ctrl) { + return BF_FPGA_EINVAL; + } + if (bf_fpga_i2c_lock(i2c_ctrl)) { + return BF_FPGA_EAGAIN; + } + /* get the next available free slot */ + next_id = get_next_free_index(i2c_ctrl, i2c_op->num_i2c, true); + if (next_id < 0) { + bf_fpga_i2c_unlock(i2c_ctrl); + return BF_FPGA_EBUSY; + } + /* populate periodic i2c operation instruction(s) */ + for (i = 0; i < i2c_op->num_i2c; i++) { + preemt = ((i == (i2c_op->num_i2c - 1)) ? false : true); + i2c_op->i2c_inst[i].preemt = preemt; + ret = fpga_i2c_enqueue( + i2c_op->inst_hndl.bus_id, next_id + i, &i2c_op->i2c_inst[i]); + + if (ret) { + bf_fpga_i2c_unlock(i2c_ctrl); + return ret; + } + } + bf_fpga_i2c_unlock(i2c_ctrl); + i2c_op->inst_hndl.inst_id = next_id; + return BF_FPGA_OK; +} + +/** FPGA I2C remove periodic i2c operation(s) from instruction memory + * + * @param i2c_op + * bf_fpga_i2c_t parameters * + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_del(bf_fpga_i2c_t *i2c_op) { + fpga_i2c_controller_t *i2c_ctrl; + int i, inst_id; + + if (!i2c_op) { + return BF_FPGA_EINVAL; + } + i2c_ctrl = fpga_i2c_ctrl_get(i2c_op->inst_hndl.bus_id); + if (!i2c_ctrl) { + return BF_FPGA_EINVAL; + } + inst_id = i2c_op->inst_hndl.inst_id; + if (bf_fpga_i2c_lock(i2c_ctrl)) { + return BF_FPGA_EAGAIN; + } + for (i = 0; i < i2c_op->num_i2c; i++) { + /* nullify the instruction */ + bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(inst_id + i), 0); + } + /* reset the in_use flag */ + release_index(i2c_ctrl, inst_id, i2c_op->num_i2c); + bf_fpga_i2c_unlock(i2c_ctrl); + return BF_FPGA_OK; +} diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c.h b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c.h new file mode 100644 index 000000000000..6f56ed270bdd --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c.h @@ -0,0 +1,55 @@ +/******************************************************************************* + Barefoot Networks FPGA Linux driver + Copyright(c) 2018 - 2019 Barefoot Networks, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + info@barefootnetworks.com + Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054 + +*******************************************************************************/ +#ifndef _BF_FPGA_I2C_H +#define _BF_FPGA_I2C_H + +/* Allow the use in C++ code. */ +#ifdef __cplusplus +extern "C" { +#endif + +int fpga_i2c_start(int bus_id); +int fpga_i2c_stop(int bus_id); +int fpga_i2c_reset(int bus_id); +int fpga_i2c_is_busy(int bus_id, bool *is_busy); +int fpga_i2c_inst_en(int bus_id, int inst_id, bool en); +int fpga_i2c_set_clk(int bus_id, int clock_div); +int fpga_i2c_controller_init(int bus_id); +int fpga_i2c_controller_cleanup(int bus_id); +int fpga_i2c_init(uint8_t *base_addr); +void fpga_i2c_deinit(void); +int fpga_i2c_oneshot(bf_fpga_i2c_t *i2c_op); +int fpga_i2c_pr_add(bf_fpga_i2c_t *i2c_op); +int fpga_i2c_del(bf_fpga_i2c_t *i2c_op); +int fpga_i2c_data_read( + int bus_id, int inst_id, uint8_t offset, uint8_t len, uint8_t *buf); +bool fpga_i2c_is_inited(void); + +#ifdef __cplusplus +} +#endif /* C++ */ + +#endif /* _BF_FPGA_I2C_H */ diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_ctrl.c b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_ctrl.c new file mode 100644 index 000000000000..a8837ba3b60c --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_ctrl.c @@ -0,0 +1,397 @@ +/******************************************************************************* + Barefoot Networks FPGA Linux driver + Copyright(c) 2018 - 2019 Barefoot Networks, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + info@barefootnetworks.com + Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054 + +*******************************************************************************/ +#include +#include "bf_fpga_i2c_priv_porting.h" +#include +#include "bf_fpga_i2c.h" +#include "bf_fpga_i2c_priv.h" +#include "bf_fpga_i2c_reg.h" + +/* static i2c controller contents */ +static fpga_i2c_controller_t fpga_i2c_ctrl[BF_I2C_FPGA_NUM_CTRL]; +static bool fpga_i2c_inited = false; + +/* fpga memory space access APIs */ +/* 32 bit write into fpga BAR0 */ +void bf_fpga_reg_write(fpga_i2c_controller_t *i2c_ctrl, + uint32_t offset, + uint32_t val) { + uint8_t *ptr = i2c_ctrl->fpga_base_addr + offset; + bf_fpga_write32(ptr, val); +} + +/* 32 bit read into fpga BAR0 */ +uint32_t bf_fpga_reg_read(fpga_i2c_controller_t *i2c_ctrl, uint32_t offset) { + uint8_t *ptr = i2c_ctrl->fpga_base_addr + offset; + return (bf_fpga_read32(ptr)); +} + +/* 32 bit write into fpga i2c space */ +void bf_fpga_i2c_reg_write32(fpga_i2c_controller_t *i2c_ctrl, + uint32_t offset, + uint32_t val) { + uint8_t *ptr = i2c_ctrl->i2c_base_addr + offset; + bf_fpga_write32(ptr, val); +} + +/* 32 bit read into fpga i2c space */ +uint32_t bf_fpga_i2c_reg_read32(fpga_i2c_controller_t *i2c_ctrl, + uint32_t offset) { + uint8_t *ptr = i2c_ctrl->i2c_base_addr + offset; + return (bf_fpga_read32(ptr)); +} + +/* 8 bit write into fpga i2c space */ +void bf_fpga_i2c_reg_write8(fpga_i2c_controller_t *i2c_ctrl, + uint32_t offset, + uint8_t val) { + uint8_t *ptr = i2c_ctrl->i2c_base_addr + offset; + bf_fpga_write8(ptr, val); +} + +/* 8 bit read into fpga i2c space */ +uint8_t bf_fpga_i2c_reg_read8(fpga_i2c_controller_t *i2c_ctrl, + uint32_t offset) { + uint8_t *ptr = i2c_ctrl->i2c_base_addr + offset; + return (bf_fpga_read8(ptr)); +} + +int bf_fpga_i2c_lock(fpga_i2c_controller_t *i2c_ctrl) { + return (bf_fpga_cr_enter(&i2c_ctrl->fpga_ctrl_lock)); +} + +void bf_fpga_i2c_unlock(fpga_i2c_controller_t *i2c_ctrl) { + return (bf_fpga_cr_leave(&i2c_ctrl->fpga_ctrl_lock)); +} + +/** FPGA return pointer to i2c_controller struct + * + * @param bus_id + * i2c controller id + * @return + * pointer to i2c_controller struct of + */ +fpga_i2c_controller_t *fpga_i2c_ctrl_get(int bus_id) { + if (bus_id >= BF_I2C_FPGA_NUM_CTRL) { + return NULL; + } else { + return &fpga_i2c_ctrl[bus_id]; + } +} + +/* is fpga module is soft inited */ +bool fpga_i2c_is_inited() { return fpga_i2c_inited; } + +/** FPGA I2C set clock: sets clock of i2c operations + * + * controller must be stopped before, if applicable. + * + * @param bus_id + * i2c controller id + * @param clk_div + * clock divider value as per fpga specs + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_set_clk(int bus_id, int clk_div) { + uint32_t val; + fpga_i2c_controller_t *i2c_ctrl; + + if (bus_id >= BF_I2C_FPGA_NUM_CTRL) { + return BF_FPGA_EINVAL; + } + i2c_ctrl = fpga_i2c_ctrl_get(bus_id); + if (bf_fpga_i2c_lock(i2c_ctrl)) { + return BF_FPGA_EAGAIN; + } + clk_div = (clk_div & I2C_CTRL_CLK_DIV_MASK) << I2C_CTRL_CLK_DIV_SHF; + val = bf_fpga_i2c_reg_read32(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP); + val &= ~(I2C_CTRL_CLK_DIV_MASK << I2C_CTRL_CLK_DIV_SHF); + val |= clk_div; + bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP, val); + bf_fpga_i2c_unlock(i2c_ctrl); + return BF_FPGA_OK; +} + +/** FPGA I2C stop : stops ongoing i2c operations without mutex locking + * + * internal function + * + * @param bus_id + * i2c controller struct + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_stop_locked(fpga_i2c_controller_t *i2c_ctrl) { + int to_ms, ret; + uint8_t val; + + val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP); + val &= ~I2C_CTRL_START; + bf_fpga_i2c_reg_write8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP, val); + + to_ms = 100; /* 5 msec converted to multiple of 50 micro sec */ + val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_TOP_I2C_STATUS); + while ((val & I2C_STS_BUSY) && to_ms) { + bf_fpga_us_delay(50); + to_ms--; + val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_TOP_I2C_STATUS); + } + if (to_ms > 0) { + ret = BF_FPGA_OK; + } else { + ret = BF_FPGA_EIO; + } + return ret; +} + +/** FPGA I2C start : starts i2c operations without mutex locking + * + * internal function + * + * @param bus_id + * i2c controller struct + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_start_locked(fpga_i2c_controller_t *i2c_ctrl) { + uint8_t val; + val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP); + bf_fpga_i2c_reg_write8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP, val | I2C_CTRL_START); + return BF_FPGA_OK; +} + +/** FPGA I2C stop : stops ongoing i2c operations + * + * @param bus_id + * i2c controller id + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_stop(int bus_id) { + fpga_i2c_controller_t *i2c_ctrl; + int ret; + + if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) { + return BF_FPGA_EINVAL; + } + i2c_ctrl = fpga_i2c_ctrl_get(bus_id); + if (bf_fpga_i2c_lock(i2c_ctrl)) { + return BF_FPGA_EAGAIN; + } + ret = fpga_i2c_stop_locked(i2c_ctrl); + bf_fpga_i2c_unlock(i2c_ctrl); + return ret; +} + +/** FPGA I2C start : starts i2c operations + * + * @param bus_id + * i2c controller id + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_start(int bus_id) { + fpga_i2c_controller_t *i2c_ctrl; + int ret; + + if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) { + return BF_FPGA_EINVAL; + } + i2c_ctrl = fpga_i2c_ctrl_get(bus_id); + if (bf_fpga_i2c_lock(i2c_ctrl)) { + return BF_FPGA_EAGAIN; + } + ret = fpga_i2c_start_locked(i2c_ctrl); + bf_fpga_i2c_unlock(i2c_ctrl); + return ret; +} + +/** FPGA I2C reset: reset i2c by issuing 9 clocks in a specific way + * + * @param bus_id + * i2c controller id + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_reset(int bus_id) { + fpga_i2c_controller_t *i2c_ctrl; + + if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) { + return BF_FPGA_EINVAL; + } + i2c_ctrl = fpga_i2c_ctrl_get(bus_id); + if (bf_fpga_i2c_lock(i2c_ctrl)) { + return BF_FPGA_EAGAIN; + } + bf_fpga_i2c_reg_write8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP, I2C_CTRL_RESET); + bf_fpga_i2c_unlock(i2c_ctrl); + return BF_FPGA_OK; +} + +/** FPGA I2C is running? + * + * @param bus_id + * i2c controller id + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_is_busy(int bus_id, bool *busy) { + uint8_t val; + fpga_i2c_controller_t *i2c_ctrl; + + if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) { + return BF_FPGA_EINVAL; + } + i2c_ctrl = fpga_i2c_ctrl_get(bus_id); + if (bf_fpga_i2c_lock(i2c_ctrl)) { + return BF_FPGA_EAGAIN; + } + val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_TOP_I2C_STATUS); + *busy = ((val & I2C_STS_BUSY) ? true : false); + bf_fpga_i2c_unlock(i2c_ctrl); + return BF_FPGA_OK; +} + +/** FPGA I2C instruction enable/disable + * + * enable or disable a particular instruction in i2c instruction memory + * @param bus_id + * i2c controller id + * @param inst_id + * instruction id within this controller space + * @param en + * true for enable, false for disable + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_inst_en(int bus_id, int inst_id, bool en) { + uint32_t val; + fpga_i2c_controller_t *i2c_ctrl; + + if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) { + return BF_FPGA_EINVAL; + } + if (inst_id < 0 || inst_id >= FPGA_I2C_NUM_INST) { + return BF_FPGA_EINVAL; + } + i2c_ctrl = fpga_i2c_ctrl_get(bus_id); + if (bf_fpga_i2c_lock(i2c_ctrl)) { + return BF_FPGA_EAGAIN; + } + val = bf_fpga_i2c_reg_read32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(inst_id)); + if (en) { + val |= I2C_INST_EN; + } else { + val &= ~I2C_INST_EN; + } + bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(inst_id), val); + fpga_i2c_ctrl[bus_id].i2c_inst[inst_id].en = en; + bf_fpga_i2c_unlock(i2c_ctrl); + return BF_FPGA_OK; +} + +/** FPGA I2C controller initialization + * + * @param bus_id + * i2c controller id + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_controller_init(int bus_id) { + fpga_i2c_controller_t *i2c_ctrl; + int i, ret; + + if (bus_id >= BF_I2C_FPGA_NUM_CTRL) { + return BF_FPGA_EINVAL; + } + i2c_ctrl = fpga_i2c_ctrl_get(bus_id); + if (!i2c_ctrl) { + return BF_FPGA_EINVAL; + } + bf_fpga_fast_lock_init(&i2c_ctrl->spinlock, 0); + bf_fpga_cr_init(&i2c_ctrl->fpga_ctrl_lock); + bf_fpga_cr_enter(&i2c_ctrl->fpga_ctrl_lock); + for (i = 0; i < FPGA_I2C_NUM_INST; i++) { + fpga_i2c_ctrl[bus_id].i2c_inst[i].inst = (uint32_t)i; + bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(i), 0); + } + bf_fpga_cr_leave(&i2c_ctrl->fpga_ctrl_lock); + ret = fpga_i2c_set_clk(bus_id, 1); /* 400 khz default */ + ret |= fpga_i2c_stop(bus_id); /* just in case */ + return ret; +} + +/** FPGA I2C controller de initialization + * + * @param bus_id + * i2c controller id + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_controller_cleanup(int bus_id) { + int i; + + fpga_i2c_stop(bus_id); + for (i = 0; i < FPGA_I2C_NUM_INST; i++) { + fpga_i2c_ctrl[bus_id].i2c_inst[i].en = false; + } + bf_fpga_cr_destroy(&fpga_i2c_ctrl[bus_id].fpga_ctrl_lock); + bf_fpga_fast_lock_destroy(&fpga_i2c_ctrl[bus_id].spinlock); + return BF_FPGA_OK; +} + +/** FPGA I2C global initialization + * + * @param base_addr + * virtual address of i2c memory relative to BAR0 base + * @return + * 0 on success and <0 on error + */ +int fpga_i2c_init(uint8_t *base_addr) { + int i; + + memset(fpga_i2c_ctrl, 0, sizeof(fpga_i2c_ctrl)); + for (i = 0; i < BF_I2C_FPGA_NUM_CTRL; i++) { + fpga_i2c_ctrl[i].i2c_base_addr = base_addr + BF_FPGA_I2C_CTRL_BASE_ADDR(i); + fpga_i2c_ctrl[i].fpga_base_addr = base_addr; + fpga_i2c_controller_init(i); + } + fpga_i2c_inited = true; + return BF_FPGA_OK; +} + +/** FPGA I2C global de initialization + * + */ +void fpga_i2c_deinit(void) { + int i; + + for (i = 0; i < BF_I2C_FPGA_NUM_CTRL; i++) { + fpga_i2c_controller_cleanup(i); + } + fpga_i2c_inited = false; +} diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_porting.c b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_porting.c new file mode 100644 index 000000000000..8b126c2e6dce --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_porting.c @@ -0,0 +1,150 @@ +/******************************************************************************* + Barefoot Networks FPGA Linux driver + Copyright(c) 2018 - 2019 Barefoot Networks, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + info@barefootnetworks.com + Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054 + +*******************************************************************************/ +#include +#include +#include +#include +#include +#include "bf_fpga_i2c_priv_porting.h" +#include +#include "bf_fpga_i2c.h" +#include "bf_fpga_i2c_priv.h" + +/* This file contains OS and system specific porting functions for i2c APIs. + * Implementation in this file is for porting to linux kernel. + */ +/* mutex APIs are for mutual exclusion with capability to sleep while in + * exclusion mode + */ + +/* sleepable virtual exclusion region */ +typedef struct { + atomic_t lock_state; /* 1: in exclusion mode, 0: not in exclusion mode */ +} sleepable_v_mutex_t; + +int bf_fpga_cr_init(bf_fpga_mutex_t *lock) { + sleepable_v_mutex_t *mtx; + + if (!lock) { + return -1; + } + mtx = vzalloc(sizeof(sleepable_v_mutex_t)); + + if (mtx) { + atomic_set(&mtx->lock_state, 0); + *lock = (bf_fpga_mutex_t *)mtx; + return 0; + } else { + *lock = NULL; + return -1; + } +} + +void bf_fpga_cr_destroy(bf_fpga_mutex_t *lock) { + if (lock && *lock) { + vfree(*lock); + *lock = NULL; + } +} + +void bf_fpga_cr_leave(bf_fpga_mutex_t *lock) { + sleepable_v_mutex_t *mtx; + + if (lock && *lock) { + mtx = (sleepable_v_mutex_t *)*lock; + atomic_xchg(&mtx->lock_state, 0); + } +} + +int bf_fpga_cr_enter(bf_fpga_mutex_t *lock) { + sleepable_v_mutex_t *mtx; + + /* All we do here is: test and set */ + if (lock && *lock) { + int cnt = 10000; /* This will provide maximum of 500-1000 ms timeout */ + mtx = (sleepable_v_mutex_t *)*lock; + while (atomic_cmpxchg(&mtx->lock_state, 0, 1) != 0) { + if (cnt-- <= 0) { + return -1; /* this is a worst case timeout situation */ + } + usleep_range(50, 100); /* 50 us = about 2 bytes at 400Kbs i2c */ + } + return 0; + } else { + return -1; + } +} + +/* **** not implemented in current mode of locking */ +int bf_fpga_mutex_trylock(bf_fpga_mutex_t *lock) { + if (lock && *lock) { + return -1; + } else { + return -1; + } +} + +/* fast lock is a non-blocking busy lock, implemented with spinlock */ +int bf_fpga_fast_lock_init(bf_fpga_fast_lock_t *sl, unsigned int initial) { + spinlock_t *slock; + + (void)initial; + if (!sl) { + return -1; + } + slock = vzalloc(sizeof(spinlock_t)); + + if (slock) { + spin_lock_init(slock); + *sl = (bf_fpga_fast_lock_t *)slock; + return 0; + } else { + *sl = NULL; + return -1; + } +} + +void bf_fpga_fast_lock_destroy(bf_fpga_fast_lock_t *sl) { + if (sl && *sl) { + vfree(*sl); + *sl = NULL; + } +} + +int bf_fpga_fast_lock(bf_fpga_fast_lock_t *sl) { + if (sl && *sl) { + spin_lock(*sl); + return 0; + } else { + return -1; + } +} + +void bf_fpga_fast_unlock(bf_fpga_fast_lock_t *sl) { + if (sl && *sl) { + spin_unlock(*sl); + } +} diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_priv.h b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_priv.h new file mode 100644 index 000000000000..0b3b1e47b015 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_priv.h @@ -0,0 +1,104 @@ +/******************************************************************************* + Barefoot Networks FPGA Linux driver + Copyright(c) 2018 - 2019 Barefoot Networks, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + info@barefootnetworks.com + Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054 + +*******************************************************************************/ +#ifndef _BF_FPGA_I2C_PRIV_H +#define _BF_FPGA_I2C_PRIV_H + +/* Allow the use in C++ code. */ +#ifdef __cplusplus +extern "C" { +#endif + +#define FPGA_I2C_INST_OFFSET(idx) (0x10 + (16 * idx)) + +typedef enum { + FGPA_I2C_NOP = 0x0, + FGPA_I2C_WR_ADDR_DATA = 0x1, /* wr: reg_addr, wr: data */ + FGPA_I2C_WR_ADDR_RD_DATA = 0x2, /* wr: reg_addrss, r/s, rd: data */ + FGPA_I2C_WR_ADDR = 0x3, /* wr: reg_addr */ + FGPA_I2C_RD_DATA = 0x4, /* rd: data */ + FGPA_I2C_MULTI_WR_RD = 0x5 /* wr: n bytes, r/s, rd: m bytes */ +} i2c_cmd_type; + +/* contents of each instruction instance */ +typedef struct i2c_inst_cmd_s { + i2c_cmd_type i2c_cmd; /* i2x cycle type */ + uint32_t data_lo; /* lower 4 bytes of data associated with this inst */ + uint32_t data_hi; /* upper 4 bytes of data associated with this inst */ + uint32_t us_delay; /* delay before i2c cycle */ + uint8_t i2c_addr; /* i2c device address, in 7 bit format */ + uint8_t reg_addr; /* 1st write byte, if present in i2c cycle */ + uint8_t num_read; /* number of bytes to write excluding reg_addr */ + uint8_t num_write; /* number of bytes to read */ +} i2c_inst_cmd_t; + +/* attributes of each instruction instance */ +typedef struct i2c_inst_s { + uint32_t inst; /* index of the instruction within the controller memory */ + bool en; /* is instruction enabled */ + bool preemt; /* atomically execute next instruction */ + bool int_en; /* enable interrupt after execution */ + bool in_use; /* is this instruction currently used */ +} i2c_inst_t; + +typedef struct fpga_i2c_controller_s { + bf_fpga_mutex_t fpga_ctrl_lock; + bf_fpga_fast_lock_t spinlock; + uint8_t *fpga_base_addr; /* virtual address of start of fpga memory */ + uint8_t *i2c_base_addr; /* virtual address of i2c controller memory */ + uint32_t start; /* offset of start of i2c instruction memory */ + uint32_t len; /* number of i2c instructions belonging to this i2c engine */ + uint32_t clk_div; /* clock divider used by this i2c engine */ + bool int_en; + i2c_inst_t i2c_inst[FPGA_I2C_NUM_INST]; +} fpga_i2c_controller_t; + +fpga_i2c_controller_t *fpga_i2c_ctrl_get(int bus_id); +void bf_fpga_reg_write(fpga_i2c_controller_t *i2c_ctrl, + uint32_t offset, + uint32_t val); +uint32_t bf_fpga_reg_read(fpga_i2c_controller_t *i2c_ctrl, uint32_t offset); +void bf_fpga_i2c_reg_write32(fpga_i2c_controller_t *i2c_ctrl, + uint32_t offset, + uint32_t val); +uint32_t bf_fpga_i2c_reg_read32(fpga_i2c_controller_t *i2c_ctrl, + uint32_t offset); +void bf_fpga_i2c_reg_write8(fpga_i2c_controller_t *i2c_ctrl, + uint32_t offset, + uint8_t val); +uint8_t bf_fpga_i2c_reg_read8(fpga_i2c_controller_t *i2c_ctrl, uint32_t offset); + +int bf_fpga_i2c_lock(fpga_i2c_controller_t *i2c_ctrl); + +void bf_fpga_i2c_unlock(fpga_i2c_controller_t *i2c_ctrl); + +int fpga_i2c_start_locked(fpga_i2c_controller_t *i2c_ctrl); +int fpga_i2c_stop_locked(fpga_i2c_controller_t *i2c_ctrl); + +#ifdef __cplusplus +} +#endif /* C++ */ + +#endif /* _BF_FPGA_I2C_PRIV_H */ diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_priv_porting.h b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_priv_porting.h new file mode 100644 index 000000000000..adea5c9311fa --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_priv_porting.h @@ -0,0 +1,93 @@ +/******************************************************************************* + Barefoot Networks FPGA Linux driver + Copyright(c) 2018 - 2019 Barefoot Networks, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + info@barefootnetworks.com + Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054 + +*******************************************************************************/ +#ifndef _BF_FPGA_I2C_PRIV_PORTING_H +#define _BF_FPGA_I2C_PRIV_PORTING_H + +/* Allow the use in C++ code. */ +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* This file contains OS and system specific porting functions declarations. + */ +/* return status compliant with linux system calls */ +#define BF_FPGA_OK 0 +#define BF_FPGA_EINVAL (-EINVAL) +#define BF_FPGA_EIO (-EIO) +#define BF_FPGA_EBUSY (-EBUSY) +#define BF_FPGA_EAGAIN (-EAGAIN) + +/* pci memory access functions */ +static inline void bf_fpga_write32(uint8_t *addr, uint32_t val) { + u8 __iomem *reg_addr = addr; + writel(val, reg_addr); +} + +static inline uint32_t bf_fpga_read32(uint8_t *addr) { + u8 __iomem *reg_addr = addr; + return (readl(reg_addr)); +} + +static inline void bf_fpga_write8(uint8_t *addr, uint8_t val) { + u8 __iomem *reg_addr = addr; + writeb(val, reg_addr); +} + +static inline uint8_t bf_fpga_read8(uint8_t *addr) { + u8 __iomem *reg_addr = addr; + return (readb(reg_addr)); +} + +static inline void bf_fpga_us_delay(unsigned long usecs) { + usleep_range(usecs, usecs + 10); +} + +/* general purpose mutual exclusion lock */ +typedef void *bf_fpga_mutex_t; + +/* fast_lock for locking only non-blocking and quick operations */ +typedef void *bf_fpga_fast_lock_t; + +/* APIs to init/enter/leave critical (exclusive access) regions */ +int bf_fpga_cr_init(bf_fpga_mutex_t *lock); +void bf_fpga_cr_destroy(bf_fpga_mutex_t *lock); +int bf_fpga_cr_enter(bf_fpga_mutex_t *lock); +void bf_fpga_cr_leave(bf_fpga_mutex_t *lock); + +int bf_fpga_fast_lock_init(bf_fpga_fast_lock_t *sl, unsigned int initial); +void bf_fpga_fast_lock_destroy(bf_fpga_fast_lock_t *sl); +int bf_fpga_fast_lock(bf_fpga_fast_lock_t *sl); +void bf_fpga_fast_unlock(bf_fpga_fast_lock_t *sl); + +#ifdef __cplusplus +} +#endif /* C++ */ + +#endif /* _BF_FPGA_I2C_PRIV_PORTING_H */ diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_reg.h b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_reg.h new file mode 100644 index 000000000000..9ad9b31b3b3f --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/modules/i2c/bf_fpga_i2c_reg.h @@ -0,0 +1,116 @@ +/******************************************************************************* + Barefoot Networks FPGA Linux driver + Copyright(c) 2018 - 2019 Barefoot Networks, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + info@barefootnetworks.com + Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054 + +*******************************************************************************/ +#ifndef _BF_FPGA_I2C_REG_H +#define _BF_FPGA_I2C_REG_H + +/* Allow the use in C++ code. */ +#ifdef __cplusplus +extern "C" { +#endif + +/* registers outsize of all i2c controller register space */ +#define BF_FPGA_I2C_BASE_ADDR 0x0 +#define BF_FPGA_I2C_CTRL_BASE_ADDR(i) (BF_FPGA_I2C_BASE_ADDR + (i * 4096)) + +/* per i2c controller register offset relative to BF_FPGA_I2C_CTRL_BASE_ADDR */ +#define Bf_FPGA_I2C_CTRL_TOP 0 +#define I2C_CTRL_START (1 << 0) +#define I2C_CTRL_RESET (1 << 1) +#define I2C_CTRL_CLK_DIV_SHF (8) +#define I2C_CTRL_CLK_DIV_MASK (0x1FF) + +#define Bf_FPGA_TOP_I2C_STATUS 4 +#define I2C_STS_BUSY (1 << 0) +#define I2C_STS_ERR (1 << 3) + +#define Bf_FPGA_I2C_INST_CTRL(i) (0x10 + (16 * i)) +#define I2C_INST_EN (1 << 31) +#define I2C_INST_PMT (1 << 30) +#define I2C_TYPE_SHF (26) +#define I2C_DELAY_SHF (23) +#define I2C_STOP_ON_ERROR (22) +/* various status values */ +#define I2C_STATUS_MASK 0x3F +#define I2C_STATUS_ERR_MASK 0x3C +#define I2C_STATUS_RUNNING 0x1 +#define I2C_STATUS_COMPLETED 0x2 +#define I2C_STATUS_NACK_ADDR 0x4 +#define I2C_STATUS_NACK_CMD 0x8 +#define I2C_STATUS_NACK_WR_DATA 0x10 +#define I2C_STATUS_TOUT 0x20 + +/* i2c instruction types */ +#define I2C_WR_ADDR_DATA (0 << I2C_TYPE_SHF) +#define I2C_RD_DATA (3 << I2C_TYPE_SHF) +#define I2C_WR_ADDR (2 << I2C_TYPE_SHF) +#define I2C_RD_ADDR_DATA (1 << I2C_TYPE_SHF) +#define I2C_RD_ADDR_DATA_BURST (4 << I2C_TYPE_SHF) +#define I2C_NOP (6 << I2C_TYPE_SHF) + +#define Bf_FPGA_I2C_INST_PARAM(i) (0x14 + (16 * i)) +#define I2C_DEV_ADDR_SHF (24) +#define I2C_CMD_OFFSET (16) +#define I2C_WR_CNT_SHF (8) +#define I2C_RD_CNT_SHF (0) + +#define Bf_FPGA_I2C_INST_DATA_LO(i) (0x18 + (16 * i)) +#define Bf_FPGA_I2C_INST_DATA_HI(i) (0x1C + (16 * i)) +/****************** +#define Bf_FPGA_I2C_PR_CTRL(i) (0x100 + (16 * i)) +#define Bf_FPGA_I2C_PR_PARM(i) (0x104 + (16 * i)) +#define Bf_FPGA_I2C_PR_LO(i) (0x108 + (16 * i)) +#define Bf_FPGA_I2C_PR_HI(i) (0x10C + (16 * i)) +******************/ + +/* data area pointers */ +/* the driver makes fixed static allocation of the available memory + * on per instruction basis + * allocate 128 bytes per one time instruction = total 0x780 bytes + * allocate 64 bytes per one periodic instruction = total 0x400 bytes + * FPGA_I2C_ONESHOT_NUM_INST -> comes from a header file that must be included + * before this file. + */ +#define BF_FPGA_ONE_MAX_BURST 128 +#define BF_FPGA_PR_MAX_BURST 64 +#define BF_FPGA_I2C_DATA_AREA(i) \ + ((i < FPGA_I2C_ONESHOT_NUM_INST) \ + ? (0x200 + (i * BF_FPGA_ONE_MAX_BURST)) \ + : (0x980 + ((i - FPGA_I2C_ONESHOT_NUM_INST) * BF_FPGA_PR_MAX_BURST))) + +#if BF_FPGA_I2C_DATA_AREA(FPGA_I2C_PERIODIC_NUM_INST) > 0x1000 +#error erroneous allocation of FPGA memory to i2c data area. Fix it! +#endif + +#define BF_FPGA_VER_REG 0x3F000 +#define BF_FPGA_BUILD_DATE 0x3F004 +#define BF_FPGA_RESET_CTRL_1 0x3F008 +#define BF_FPGA_RESET_CTRL_2 0x3F00C + +#ifdef __cplusplus +} +#endif /* C++ */ + +#endif /* _BF_FPGA_I2C_REG_H */ diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/bf-sfputil b/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/bf-sfputil new file mode 100755 index 000000000000..3df67614e499 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/bf-sfputil @@ -0,0 +1,10 @@ +#!/bin/bash + +DOCKER_EXEC_FLAGS="i" + +# Determine whether stdout is on a terminal +if [ -t 1 ] ; then + DOCKER_EXEC_FLAGS+="t" +fi + +docker exec -$DOCKER_EXEC_FLAGS syncd sfputil "$@" diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/eeprom b/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/eeprom new file mode 100755 index 000000000000..07d98556cbbf --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/eeprom @@ -0,0 +1,10 @@ +#!/bin/bash + +DOCKER_EXEC_FLAGS="i" + +# Determine whether stdout is on a terminal +if [ -t 1 ] ; then + DOCKER_EXEC_FLAGS+="t" +fi + +docker exec -$DOCKER_EXEC_FLAGS syncd eeprom "$@" diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/fancontrol b/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/fancontrol new file mode 100755 index 000000000000..515fcbdd69da --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/fancontrol @@ -0,0 +1,11 @@ +#!/bin/bash + +DOCKER_EXEC_FLAGS="i" + +# Determine whether stdout is on a terminal +if [ -t 1 ] ; then + DOCKER_EXEC_FLAGS+="t" +fi + +docker exec -$DOCKER_EXEC_FLAGS syncd fancontrol "$@" + diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/ps_info b/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/ps_info new file mode 100755 index 000000000000..38c9d3330414 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/ps_info @@ -0,0 +1,10 @@ +#!/bin/bash + +DOCKER_EXEC_FLAGS="i" + +# Determine whether stdout is on a terminal +if [ -t 1 ] ; then + DOCKER_EXEC_FLAGS+="t" +fi + +docker exec -$DOCKER_EXEC_FLAGS syncd ps_info "$@" diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/sensors b/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/sensors new file mode 100755 index 000000000000..07af6955321e --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/sensors @@ -0,0 +1,12 @@ +#!/bin/bash + +DOCKER_EXEC_FLAGS="i" + +# Determine whether stdout is on a terminal +if [ -t 1 ] ; then + DOCKER_EXEC_FLAGS+="t" +fi + +docker exec -$DOCKER_EXEC_FLAGS syncd sensors "$@" + + diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/test b/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/test new file mode 100755 index 000000000000..38327722c91f --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/scripts/test @@ -0,0 +1 @@ +echo "test" From 65fc916dcfcd01ed0f16025de1730f46b8329984 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Thu, 7 Nov 2019 09:56:17 +0700 Subject: [PATCH 139/278] [platform/device] - Implement Silverstone platform API [Chassis/Fan] (#3706) Implement part of the Chassis and Fan related APIs. - Chassis APIs get_base_mac() get_serial_number() get_serial_number() get_system_eeprom_info() get_reboot_cause() - Fan APIs get_direction() get_speed() get_target_speed() get_speed_tolerance() set_speed() set_status_led() get_target_speed() - Fan APIs base on Device API get_name() get_presence() get_model() get_serial() get_status() Signed-off-by: Wirut Getbamrung wgetbumr@celestica.com --- .../sonic_platform/__init__.py | 2 + .../sonic_platform/chassis.py | 114 ++++++++ .../sonic_platform/eeprom.py | 113 +++++++ .../sonic_platform/fan.py | 276 ++++++++++++++++++ .../sonic_platform/helper.py | 56 ++++ .../sonic_platform/platform.py | 23 ++ .../debian/platform-modules-silverstone.init | 2 + .../platform-modules-silverstone.install | 4 +- .../platform-modules-silverstone.postinst | 4 +- .../silverstone/setup.py | 34 +++ 10 files changed, 626 insertions(+), 2 deletions(-) create mode 100644 device/celestica/x86_64-cel_silverstone-r0/sonic_platform/__init__.py create mode 100644 device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py create mode 100644 device/celestica/x86_64-cel_silverstone-r0/sonic_platform/eeprom.py create mode 100644 device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py create mode 100644 device/celestica/x86_64-cel_silverstone-r0/sonic_platform/helper.py create mode 100644 device/celestica/x86_64-cel_silverstone-r0/sonic_platform/platform.py create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone/setup.py diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/__init__.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/__init__.py new file mode 100644 index 000000000000..d82f3749319c --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py new file mode 100644 index 000000000000..dc622016cbb2 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# + +import sys +import re +import os +import subprocess +import json + +try: + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.eeprom import Tlv + from sonic_platform.fan import Fan + from helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN_TRAY = 7 +NUM_FAN = 2 +NUM_PSU = 2 +NUM_THERMAL = 5 +NUM_SFP = 32 +NUM_COMPONENT = 5 + +IPMI_OEM_NETFN = "0x3A" +IPMI_GET_REBOOT_CAUSE = "0x03 0x00 0x01 0x06" + + +class Chassis(ChassisBase): + """Platform-specific Chassis class""" + + def __init__(self): + self.config_data = {} + ChassisBase.__init__(self) + self._eeprom = Tlv() + self._api_helper = APIHelper() + + for fant_index in range(0, NUM_FAN_TRAY): + for fan_index in range(0, NUM_FAN): + fan = Fan(fant_index, fan_index) + self._fan_list.append(fan) + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self._eeprom.get_mac() + + def get_serial_number(self): + """ + Retrieves the hardware serial number for the chassis + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.get_serial() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + """ + return self._eeprom.get_eeprom() + + def get_reboot_cause(self): + """ + Retrieves the cause of the previous reboot + + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + one of the predefined strings in this class. If the first string + is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used + to pass a description of the reboot cause. + """ + + status, raw_cause = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_GET_REBOOT_CAUSE) + hx_cause = raw_cause.split()[0] if status else 00 + reboot_cause = { + "00": self.REBOOT_CAUSE_HARDWARE_OTHER, + "11": self.REBOOT_CAUSE_POWER_LOSS, + "22": self.REBOOT_CAUSE_NON_HARDWARE, + "33": self.REBOOT_CAUSE_HARDWARE_OTHER, + "44": self.REBOOT_CAUSE_NON_HARDWARE, + "55": self.REBOOT_CAUSE_NON_HARDWARE, + "66": self.REBOOT_CAUSE_WATCHDOG, + "77": self.REBOOT_CAUSE_NON_HARDWARE + }.get(hx_cause, self.REBOOT_CAUSE_HARDWARE_OTHER) + + description = { + "00": "Unknown reason", + "11": "The last reset is Power on reset", + "22": "The last reset is soft-set CPU warm reset", + "33": "The last reset is soft-set CPU cold reset", + "44": "The last reset is CPU warm reset", + "55": "The last reset is CPU cold reset", + "66": "The last reset is watchdog reset", + "77": "The last reset is power cycle reset" + }.get(hx_cause, "Unknown reason") + + return (reboot_cause, description) diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/eeprom.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/eeprom.py new file mode 100644 index 000000000000..dd0c9332b54e --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/eeprom.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica Silverstone +# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# + +try: + import glob + import os + import sys + import imp + import re + from array import array + from cStringIO import StringIO + from sonic_platform_base.sonic_eeprom import eeprom_dts + from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo +except ImportError, e: + raise ImportError(str(e) + "- required module not found") + +CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' +CACHE_FILE = 'syseeprom_cache' +TLV_EEPROM_I2C_BUS = 0 +TLV_EEPROM_I2C_ADDR = 56 + +class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + + EEPROM_DECODE_HEADLINES = 6 + + def __init__(self): + self._eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-00{1}/eeprom".format(TLV_EEPROM_I2C_BUS, TLV_EEPROM_I2C_ADDR) + super(Tlv, self).__init__(self._eeprom_path, 0, '', True) + self._eeprom = self._load_eeprom() + + def __parse_output(self, decode_output): + decode_output.replace('\0', '') + lines = decode_output.split('\n') + lines = lines[self.EEPROM_DECODE_HEADLINES:] + _eeprom_info_dict = dict() + + for line in lines: + try: + match = re.search( + '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) + if match is not None: + idx = match.group(1) + value = match.group(3).rstrip('\0') + + _eeprom_info_dict[idx] = value + except: + pass + return _eeprom_info_dict + + def _load_eeprom(self): + original_stdout = sys.stdout + sys.stdout = StringIO() + try: + self.read_eeprom_db() + except: + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + return self.__parse_output(decode_output) + + status = self.check_status() + if 'ok' not in status: + return False + + if not os.path.exists(CACHE_ROOT): + try: + os.makedirs(CACHE_ROOT) + except: + pass + + # + # only the eeprom classes that inherit from eeprom_base + # support caching. Others will work normally + # + try: + self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) + except: + pass + + e = self.read_eeprom() + if e is None: + return 0 + + try: + self.update_cache(e) + except: + pass + + self.decode_eeprom(e) + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + + (is_valid, valid_crc) = self.is_checksum_valid(e) + if not is_valid: + return False + + return self.__parse_output(decode_output) + + def get_eeprom(self): + return self._eeprom + + def get_serial(self): + return self._eeprom.get('0x23', "Undefined.") + + def get_mac(self): + return self._eeprom.get('0x24', "Undefined.") diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py new file mode 100644 index 000000000000..902de261f8cb --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py @@ -0,0 +1,276 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +import json +import math +import os.path + +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") + + +FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", "FAN-3F", "FAN-3R", + "FAN-4F", "FAN-4R", "FAN-5F", "FAN-5R", "FAN-6F", "FAN-6R", "FAN-7F", "FAN-7R"] + +IPMI_OEM_NETFN = "0x3A" +IPMI_SENSOR_NETFN = "0x04" +IPMI_FAN_SPEED_CMD = "0x2D {}" +IPMI_AIR_FLOW_CMD = "0x0A {}" +IPMI_FAN_PRESENT_CMD = "0x06 0x03 {}" +IPMI_SET_FAN_LED_CMD = "0x07 {} {}" +IPMI_GET_FAN_LED_CMD = "0x08 {}" +IPMI_SET_PWM = "0x03 0x01 0x02 {} {}" +IPMI_FRU_PRINT_ID = "ipmitool fru print {}" +IPMI_FRU_MODEL_KEY = "Board Part Number" +IPMI_FRU_SERIAL_KEY = "Board Serial" + +MAX_OUTLET = 24700 +MAX_INLET = 29700 +SPEED_TOLERANCE = 10 + +FAN1_FRONT_SS_ID = "0x0D" +FAN1_REAR_SS_ID = "0x45" +FAN_LED_OFF_CMD = "0x00" +FAN_LED_GREEN_CMD = "0x01" +FAN_LED_RED_CMD = "0x02" +FAN1_LED_CMD = "0x04" +FAN_PWM_REGISTER_START = 0x22 +FAN_PWM_REGISTER_STEP = 0x10 +FAN1_FRU_ID = 6 + + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): + self.fan_index = fan_index + self.fan_tray_index = fan_tray_index + self.is_psu_fan = is_psu_fan + if self.is_psu_fan: + self.psu_index = psu_index + self._api_helper = APIHelper() + self.index = self.fan_tray_index * 2 + self.fan_index + + 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 + status, raw_flow = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_AIR_FLOW_CMD.format(hex(self.fan_tray_index))) + if status and raw_flow == "01": + 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) + + Note: + M = 150 + Max F2B = 24700 RPM + Max B2F = 29700 RPM + """ + # ipmitool raw 0x3a 0x03 0x01 0x01 {register} + # register = 22 32 42 52 62 72 82 + + max_rpm = MAX_OUTLET if self.fan_index % 2 == 0 else MAX_INLET + fan1_ss_start = FAN1_FRONT_SS_ID if self.fan_index % 2 == 0 else FAN1_REAR_SS_ID + + ss_id = hex(int(fan1_ss_start, 16) + self.fan_tray_index) + status, raw_ss_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_FAN_SPEED_CMD.format(ss_id)) + + ss_read = raw_ss_read.split()[0] + rpm_speed = int(ss_read, 16)*150 + speed = int(float(rpm_speed)/max_rpm * 100) + + return speed + + 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) + + Note: + speed_pc = pwm_target/255*100 + + 0 : when PWM mode is use + pwm : when pwm mode is not use + """ + target = 0 + return target + + 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 SPEED_TOLERANCE + + def set_speed(self, speed): + """ + Sets the fan speed + Args: + speed: An integer, the percentage of full fan speed to set fan to, + in the range 0 (off) to 100 (full speed) + Returns: + A boolean, True if speed is set successfully, False if not + Notes: + pwm setting mode must set as Manual + manual: ipmitool raw 0x3a 0x06 0x01 0x0 + auto: ipmitool raw 0x3a 0x06 0x01 0x1 + """ + # ipmitool raw 0x3a 0x03 0x01 0x02 {register} {pwm_speed} + # register = 22 32 42 52 62 72 82 + + speed_hex = hex(int(float(speed)/100 * 255)) + fan_register_hex = hex(FAN_PWM_REGISTER_START + + (self.fan_tray_index*FAN_PWM_REGISTER_STEP)) + + set_speed_cmd = IPMI_SET_PWM.format(fan_register_hex, speed_hex) + status, set_speed_res = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, set_speed_cmd) + + set_speed = False if not status else True + + return set_speed + + 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 + + Note: + LED setting mode must set as Manual + manual: ipmitool raw 0x3A 0x09 0x02 0x00 + auto: ipmitool raw 0x3A 0x09 0x02 0x01 + """ + led_cmd = { + self.STATUS_LED_COLOR_GREEN: FAN_LED_GREEN_CMD, + self.STATUS_LED_COLOR_RED: FAN_LED_RED_CMD, + self.STATUS_LED_COLOR_OFF: FAN_LED_OFF_CMD + }.get(color) + + fan_selector = hex(int(FAN1_LED_CMD, 16) + self.fan_tray_index) + status, set_led = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_SET_FAN_LED_CMD.format(fan_selector, led_cmd)) + set_status_led = False if not status else True + + return set_status_led + + 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 + + Note: + STATUS_LED_COLOR_GREEN = "green" + STATUS_LED_COLOR_AMBER = "amber" + STATUS_LED_COLOR_RED = "red" + STATUS_LED_COLOR_OFF = "off" + """ + fan_selector = hex(int(FAN1_LED_CMD, 16) + self.fan_tray_index) + status, hx_color = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_GET_FAN_LED_CMD.format(fan_selector)) + + status_led = { + "00": self.STATUS_LED_COLOR_OFF, + "01": self.STATUS_LED_COLOR_GREEN, + "02": self.STATUS_LED_COLOR_RED, + }.get(hx_color, self.STATUS_LED_COLOR_OFF) + + return status_led + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] if not self.is_psu_fan else "PSU-{} FAN-{}".format( + self.psu_index+1, self.fan_index+1) + + return fan_name + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + presence = False + status, raw_present = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_FAN_PRESENT_CMD.format(hex(self.index))) + if status and raw_present == "00": + 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 = "Unknown" + ipmi_fru_idx = self.fan_tray_index + FAN1_FRU_ID + status, raw_model = self._api_helper.ipmi_fru_id( + ipmi_fru_idx, IPMI_FRU_MODEL_KEY) + + fru_pn_list = raw_model.split() + if len(fru_pn_list) > 4: + model = fru_pn_list[4] + + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + serial = "Unknown" + ipmi_fru_idx = self.fan_tray_index + FAN1_FRU_ID + status, raw_model = self._api_helper.ipmi_fru_id( + ipmi_fru_idx, IPMI_FRU_SERIAL_KEY) + + fru_sr_list = raw_model.split() + if len(fru_sr_list) > 3: + serial = fru_sr_list[3] + + 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() and self.get_speed() > 0 diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/helper.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/helper.py new file mode 100644 index 000000000000..1132b5b06785 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/helper.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python + +import os +import subprocess + + +HOST_CHK_CMD = "docker > /dev/null 2>&1" +EMPTY_STRING = "" + + +class APIHelper(): + + def __init__(self): + pass + + def is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return 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, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + except: + 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, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + except: + status = False + return status, result diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/platform.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/platform.py new file mode 100644 index 000000000000..a632de87e742 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/platform.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + """Platform-specific Platform class""" + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.init index c1d4c10b48fc..eb003599ec61 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.init @@ -29,6 +29,8 @@ start) fi decode-syseeprom --init 2> /dev/null & + /bin/sh /usr/local/bin/platform_api_mgnt.sh init + echo "done." ;; diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install index a3a8b3d424a1..03e13544b8b1 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install @@ -1,2 +1,4 @@ silverstone/cfg/silverstone-modules.conf etc/modules-load.d -silverstone/systemd/platform-modules-silverstone.service lib/systemd/system \ No newline at end of file +silverstone/systemd/platform-modules-silverstone.service lib/systemd/system +silverstone/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_silverstone-r0 +services/platform_api/platform_api_mgnt.sh usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.postinst index 771057bed0dc..feb9cf45c219 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.postinst +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.postinst @@ -1,3 +1,5 @@ depmod -a systemctl enable platform-modules-silverstone.service -systemctl start platform-modules-silverstone.service \ No newline at end of file +systemctl start platform-modules-silverstone.service + +/usr/local/bin/platform_api_mgnt.sh install diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/setup.py b/platform/broadcom/sonic-platform-modules-cel/silverstone/setup.py new file mode 100644 index 000000000000..20a2b6d1063a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/setup.py @@ -0,0 +1,34 @@ +from setuptools import setup + +DEVICE_NAME = 'celestica' +HW_SKU = 'x86_64-cel_silverstone-r0' + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Celestica Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + maintainer='Wirut Getbamrung', + maintainer_email='wgetbumr@celestica.com', + packages=[ + 'sonic_platform', + ], + package_dir={ + 'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)}, + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 2.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) From 7d4093d6edcb7eea637b920fa96752ac3d1e07e3 Mon Sep 17 00:00:00 2001 From: brandonchuang Date: Thu, 7 Nov 2019 10:57:08 +0800 Subject: [PATCH 140/278] [device/platform] Add reset in sfputil.py for Accton AS7326-56X (#3685) Add reset in sfputil.py for as7326-56x. Signed-off-by: brandon_chuang --- .../plugins/sfputil.py | 24 ++++- .../as7326-56x/modules/accton_i2c_cpld.c | 87 ++++++++++++++++++- 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as7326_56x-r0/plugins/sfputil.py index 330d30b879d7..0292e2d52e1a 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/plugins/sfputil.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/plugins/sfputil.py @@ -219,8 +219,30 @@ def set_low_power_mode(self, port_num, lpmode): time.sleep(0.01) def reset(self, port_num): - raise NotImplementedError + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + cpld_i = self.get_cpld_num(port_num) + cpld_ps = self._cpld_mapping[cpld_i] + path = "/sys/bus/i2c/devices/{0}/module_reset_{1}" + port_ps = path.format(cpld_ps, port_num) + + self.__port_to_mod_rst = port_ps + try: + reg_file = open(self.__port_to_mod_rst, 'r+', buffering=0) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + #toggle reset + reg_file.seek(0) + reg_file.write('1') + time.sleep(1) + reg_file.seek(0) + reg_file.write('0') + reg_file.close() + + return True @property def _get_present_bitmap(self): nodes = [] diff --git a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_i2c_cpld.c b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_i2c_cpld.c index a4ff19fea546..70d9a66affdb 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_i2c_cpld.c +++ b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/modules/accton_i2c_cpld.c @@ -285,6 +285,14 @@ enum as7326_56x_cpld_sysfs_attributes { TRANSCEIVER_TXFAULT_ATTR_ID(48), TRANSCEIVER_TXFAULT_ATTR_ID(57), TRANSCEIVER_TXFAULT_ATTR_ID(58), + TRANSCEIVER_RESET_ATTR_ID(49), + TRANSCEIVER_RESET_ATTR_ID(50), + TRANSCEIVER_RESET_ATTR_ID(51), + TRANSCEIVER_RESET_ATTR_ID(52), + TRANSCEIVER_RESET_ATTR_ID(53), + TRANSCEIVER_RESET_ATTR_ID(54), + TRANSCEIVER_RESET_ATTR_ID(55), + TRANSCEIVER_RESET_ATTR_ID(56), }; /* sysfs attributes for hwmon @@ -297,6 +305,8 @@ static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, char *buf); static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t set_reset(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); static ssize_t access(struct device *dev, struct device_attribute *da, const char *buf, size_t count); static ssize_t show_version(struct device *dev, struct device_attribute *da, @@ -437,6 +447,15 @@ DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(48); DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(57); DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(58); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(49); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(50); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(51); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(52); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(53); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(54); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(55); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(56); + static struct attribute *as7326_56x_cpld3_attributes[] = { &sensor_dev_attr_version.dev_attr.attr, &sensor_dev_attr_access.dev_attr.attr, @@ -507,7 +526,7 @@ static struct attribute *as7326_56x_cpld2_attributes[] = { DECLARE_SFP_TRANSCEIVER_ATTR(22), DECLARE_SFP_TRANSCEIVER_ATTR(23), DECLARE_SFP_TRANSCEIVER_ATTR(24), - DECLARE_SFP_TRANSCEIVER_ATTR(25), + DECLARE_SFP_TRANSCEIVER_ATTR(25), DECLARE_SFP_TRANSCEIVER_ATTR(26), DECLARE_SFP_TRANSCEIVER_ATTR(27), DECLARE_SFP_TRANSCEIVER_ATTR(28), @@ -574,6 +593,14 @@ static struct attribute *as7326_56x_cpld1_attributes[] = { DECLARE_SFP_TRANSCEIVER_ATTR(48), DECLARE_SFP_TRANSCEIVER_ATTR(57), DECLARE_SFP_TRANSCEIVER_ATTR(58), + DECLARE_TRANSCEIVER_RESET_ATTR(49), + DECLARE_TRANSCEIVER_RESET_ATTR(50), + DECLARE_TRANSCEIVER_RESET_ATTR(51), + DECLARE_TRANSCEIVER_RESET_ATTR(52), + DECLARE_TRANSCEIVER_RESET_ATTR(53), + DECLARE_TRANSCEIVER_RESET_ATTR(54), + DECLARE_TRANSCEIVER_RESET_ATTR(55), + DECLARE_TRANSCEIVER_RESET_ATTR(56), NULL }; @@ -724,6 +751,11 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, reg = 0x19; mask = 0x1 << (( attr->index - MODULE_RXLOS_57)+2); break; + case MODULE_RESET_49 ... MODULE_RESET_56: + reg = 0x4; + mask = 0x1 << (attr->index - MODULE_RESET_49); + revert = 1; + break; default: return 0; } @@ -806,6 +838,59 @@ static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, return status; } +static ssize_t set_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); + struct as7326_56x_cpld_data *data = i2c_get_clientdata(client); + long reset; + int status; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &reset); + if (status) { + return status; + } + + switch (attr->index) + { + case MODULE_RESET_49 ... MODULE_RESET_56: + reg = 0x4; + mask = 0x1 << (attr->index - MODULE_RESET_49); + break; + default: + return 0; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as7326_56x_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + /* Update reset status */ + if (!reset) { + status |= mask; + } + else { + status &= ~mask; + } + + status = as7326_56x_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + static ssize_t access(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { From 6d46badbdc6a72e0c923fdae2ab2258011c8bed2 Mon Sep 17 00:00:00 2001 From: lguohan Date: Wed, 6 Nov 2019 20:18:31 -0800 Subject: [PATCH 141/278] [aboot]: preserve snmp.yml and acl.json for eos to sonic fast reboot (#3716) --- files/Aboot/boot0.j2 | 4 +++- files/image_config/platform/rc.local | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/files/Aboot/boot0.j2 b/files/Aboot/boot0.j2 index 2f861bbbd405..66e86774e766 100644 --- a/files/Aboot/boot0.j2 +++ b/files/Aboot/boot0.j2 @@ -94,7 +94,9 @@ clean_flash() { [ $f != "$cmdline_base" ] && [ $f != "aquota.user" ] && [ $f != "old_config" ] && - [ $f != "minigraph.xml" ] + [ $f != "minigraph.xml" ] && + [ $f != "snmp.yml" ] && + [ $f != "acl.json" ] then rm -rf "$target_path/$f" fi diff --git a/files/image_config/platform/rc.local b/files/image_config/platform/rc.local index 190743285644..b74e9f40c4b0 100755 --- a/files/image_config/platform/rc.local +++ b/files/image_config/platform/rc.local @@ -223,6 +223,8 @@ if [ -f $FIRST_BOOT_FILE ]; then elif [ -f /host/minigraph.xml ]; then mkdir -p /etc/sonic/old_config mv /host/minigraph.xml /etc/sonic/old_config/ + [ -f /host/acl.json ] && mv /host/acl.json /etc/sonic/old_config/ + [ -f /host/snmp.yml ] && mv /host/snmp.yml /etc/sonic/old_config/ touch /tmp/pending_config_migration elif [ -n "$migration" ] && [ -f /host/migration/minigraph.xml ]; then mkdir -p /etc/sonic/old_config From 6a76cd2bb68e8ca4b61667e834e6dfed099eb76e Mon Sep 17 00:00:00 2001 From: Vitaliy Senchyshyn <43479243+vsenchyshyn@users.noreply.github.com> Date: Thu, 7 Nov 2019 11:01:54 -0800 Subject: [PATCH 142/278] [build]: Fixed BFN target build (#3721) Signed-off-by: Vitaliy Senchyshyn --- platform/barefoot/bfn-platform.mk | 4 ++-- platform/barefoot/bfn-sai.mk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/barefoot/bfn-platform.mk b/platform/barefoot/bfn-platform.mk index 15fbd80daafd..32ba62e3feb2 100644 --- a/platform/barefoot/bfn-platform.mk +++ b/platform/barefoot/bfn-platform.mk @@ -1,5 +1,5 @@ -BFN_PLATFORM = bfnplatform_9.0.0.e658347_deb9.deb -$(BFN_PLATFORM)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/rel_9_0/bfnplatform_9.0.0.e658347_deb9.deb" +BFN_PLATFORM = bfnplatform_20191107_deb9.deb +$(BFN_PLATFORM)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/dev/bfnplatform_20191107_deb9.deb" SONIC_ONLINE_DEBS += $(BFN_PLATFORM) $(BFN_SAI_DEV)_DEPENDS += $(BFN_PLATFORM) diff --git a/platform/barefoot/bfn-sai.mk b/platform/barefoot/bfn-sai.mk index 2e6b8f711fda..366a7487deb8 100644 --- a/platform/barefoot/bfn-sai.mk +++ b/platform/barefoot/bfn-sai.mk @@ -1,5 +1,5 @@ -BFN_SAI = bfnsdk_9.0.0.e658347_deb9.deb -$(BFN_SAI)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/rel_9_0/bfnsdk_9.0.0.e658347_deb9.deb" +BFN_SAI = bfnsdk_20191107_deb9.deb +$(BFN_SAI)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/dev/bfnsdk_20191107_deb9.deb" SONIC_ONLINE_DEBS += $(BFN_SAI) $(BFN_SAI_DEV)_DEPENDS += $(BFN_SAI) From a5e2799b338df79f38798eef608ad92367efeec0 Mon Sep 17 00:00:00 2001 From: Santhosh Kumar T <53558409+santhosh-kt@users.noreply.github.com> Date: Fri, 8 Nov 2019 02:57:02 +0530 Subject: [PATCH 143/278] [DellEMC] S6100 Watchdog Support (#3698) Implement Watchdog platform2.0 API for DellEMC S6100 platform. - Added new file watchdog.py in sonic_platform directory. - Enabled API support to Enable/disable watchdog. --- .../s6100/sonic_platform/watchdog.py | 227 ++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/watchdog.py diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/watchdog.py new file mode 100644 index 000000000000..207ccb8971bc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/watchdog.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python + +######################################################################## +# +# DELLEMC S6100 +# +# Abstract base class for implementing a platform-specific class with +# which to interact with a hardware watchdog module in SONiC +# +######################################################################## + +try: + import os + import struct + import ctypes + from sonic_platform_base.watchdog_base import WatchdogBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class _timespec(ctypes.Structure): + _fields_ = [ + ('tv_sec', ctypes.c_long), + ('tv_nsec', ctypes.c_long) + ] + +class Watchdog(WatchdogBase): + """ + Abstract base class for interfacing with a hardware watchdog module + """ + + io_resource = '/dev/port' + + WD_STATUS_OFFSET = 0x207 + WD_TIMER_OFFSET = 0x206 + WD_ENABLE = 0 + WD_DISABLE = 1 + + armed_time = 0 + timeout = 0 + CLOCK_MONOTONIC = 1 + + def __init__(self): + self._librt = ctypes.CDLL('librt.so.1', use_errno=True) + self._clock_gettime = self._librt.clock_gettime + self._clock_gettime.argtypes=[ctypes.c_int, ctypes.POINTER(_timespec)] + + def _io_reg_read(self, offset): + """ + Read the resource file + """ + fd = os.open(self.io_resource, os.O_RDONLY) + if fd < 0: + return -1 + + if os.lseek(fd, offset, os.SEEK_SET) != offset: + os.close(fd) + return -1 + + buf = os.read(fd, 1) + reg_value = ord(buf) + + os.close(fd) + return reg_value + + def _io_reg_write(self, offset, val): + """ + Write in the resource file + """ + fd = os.open(self.io_resource, os.O_RDWR) + if fd < 0: + return -1 + + if os.lseek(fd, offset, os.SEEK_SET) != offset: + os.close(fd) + return -1 + + ret = os.write(fd, struct.pack('B', val)) + if ret != 1: + os.close(fd) + return -1 + + os.close(fd) + return ret + + def _read_gpio_file(self, file_path): + """ + Read the GPIO values + """ + fd = os.open(file_path, os.O_RDONLY) + read_str = os.read(fd, os.path.getsize(file_path)) + gpio_val = int(read_str, 16) + os.close(fd) + return gpio_val + + def _write_gpio_file(self, file_path, val): + """ + Write the GPIO values + """ + fd = os.open(file_path, os.O_RDWR) + ret = os.write(fd, val) + if ret < 0: + os.close(fd) + return -1 + + os.close(fd) + return 1 + + def _get_time(self): + """ + To get clock monotonic time + """ + ts = _timespec() + if self._clock_gettime(self.CLOCK_MONOTONIC, ctypes.pointer(ts)) != 0: + errno_ = ctypes.get_errno() + return 0 + return ts.tv_sec + ts.tv_nsec * 1e-9 + + def arm(self, seconds): + """ + Arm the hardware watchdog with a timeout of seconds. + 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. + """ + gpio = "/sys/devices/platform/dell_ich.0/sc_gp_lvl" + timer_offset = -1 + if seconds <= 30: + timer_offset = 1 + seconds = 30 + elif seconds > 30 and seconds <= 60: + timer_offset = 2 + seconds = 60 + elif seconds > 60 and seconds <= 180: + timer_offset = 3 + seconds = 180 + + if timer_offset == -1: + return -1 + if self._io_reg_read(self.WD_TIMER_OFFSET) != timer_offset: + if self._io_reg_write(self.WD_TIMER_OFFSET, timer_offset) == -1: + return -1 + self.disarm() + + if self.is_armed(): + gpio_val = self._read_gpio_file(gpio) + high_val = gpio_val | (1 << 15) + if self._write_gpio_file(gpio, hex(high_val)) != -1: + low_val = high_val & 0xFFFF7FFF + if self._write_gpio_file(gpio, hex(low_val)) != -1: + self.armed_time = self._get_time() + self.timeout = seconds + return seconds + elif self._io_reg_write(self.WD_STATUS_OFFSET, self.WD_ENABLE) != -1: + self.armed_time = self._get_time() + self.timeout = seconds + return seconds + + return -1 + + def disarm(self): + """ + Disarm the hardware watchdog + + Returns: + A boolean, True if watchdog is disarmed successfully, False + if not + """ + if self._io_reg_write(self.WD_STATUS_OFFSET, self.WD_DISABLE) != -1: + self.armed_time = 0 + self.timeout = 0 + return True + + return False + + def is_armed(self): + """ + Retrieves the armed state of the hardware watchdog. + + Returns: + A boolean, True if watchdog is armed, False if not + """ + wd_status = self.WD_DISABLE + wd_status = self._io_reg_read(self.WD_STATUS_OFFSET) + if wd_status == self.WD_ENABLE: + return True + + return False + + def get_remaining_time(self): + """ + If the watchdog is armed, retrieve the number of seconds + remaining on the watchdog timer + + Returns: + An integer specifying the number of seconds remaining on + their watchdog timer. If the watchdog is not armed, returns + -1. + + S6100 doesnot have hardware support to show remaining time. + Due to this limitation, this API is implemented in software. + This API would return correct software time difference if it + is called from the process which armed the watchdog timer. + If this API called from any other process, it would return + 0. If the watchdog is not armed, this API would return -1. + """ + if not self.is_armed(): + return -1 + + if self.armed_time > 0 and self.timeout != 0: + cur_time = self._get_time() + if cur_time <= 0: + return 0 + diff_time = int(cur_time - self.armed_time) + if diff_time > self.timeout: + return self.timeout + else: + return self.timeout - diff_time + + return 0 + From bdf1b7c6074e5e0f34b25786298a5124088db594 Mon Sep 17 00:00:00 2001 From: Ping Mao <41933969+li-pingmao@users.noreply.github.com> Date: Thu, 7 Nov 2019 13:45:39 -0800 Subject: [PATCH 144/278] libyang 1.0.73 (#3710) - build libyang1.0.73 debian pacakge from libyang github source - build libyang python2 and python3 debian packages --- rules/libyang.mk | 21 +++-- src/libyang/Makefile | 25 +++--- src/libyang/patch/libyang.patch | 134 +++++++++++++++++++++++++++++++ src/libyang/patch/series | 2 + src/libyang/patch/swig.patch | 136 ++++++++++++++++++++++++++++++++ 5 files changed, 303 insertions(+), 15 deletions(-) create mode 100644 src/libyang/patch/libyang.patch create mode 100644 src/libyang/patch/series create mode 100644 src/libyang/patch/swig.patch diff --git a/rules/libyang.mk b/rules/libyang.mk index 2561be6b7122..d10c2ea2cc66 100644 --- a/rules/libyang.mk +++ b/rules/libyang.mk @@ -1,23 +1,32 @@ # libyang -LIBYANG_VERSION_BASE = 0.16 -LIBYANG_VERSION = $(LIBYANG_VERSION_BASE).105 +LIBYANG_VERSION_BASE = 1.0 +LIBYANG_VERSION = $(LIBYANG_VERSION_BASE).73 LIBYANG_SUBVERSION = 1 export LIBYANG_VERSION_BASE export LIBYANG_VERSION export LIBYANG_SUBVERSION -LIBYANG = libyang$(LIBYANG_VERSION_BASE)_$(LIBYANG_VERSION)-$(LIBYANG_SUBVERSION)_$(CONFIGURED_ARCH).deb +LIBYANG = libyang_$(LIBYANG_VERSION)_$(CONFIGURED_ARCH).deb $(LIBYANG)_SRC_PATH = $(SRC_PATH)/libyang $(LIBYANG)_DEPENDS += $(SWIG_BASE) $(SWIG) SONIC_MAKE_DEBS += $(LIBYANG) SONIC_STRETCH_DEBS += $(LIBYANG) -LIBYANG_DEV = libyang-dev_$(LIBYANG_VERSION)-$(LIBYANG_SUBVERSION)_$(CONFIGURED_ARCH).deb +LIBYANG_DEV = libyang-dev_$(LIBYANG_VERSION)_$(CONFIGURED_ARCH).deb $(eval $(call add_derived_package,$(LIBYANG),$(LIBYANG_DEV))) -LIBYANG_DBG = libyang$(LIBYANG_VERSION_BASE)-dbgsym_$(LIBYANG_VERSION)-$(LIBYANG_SUBVERSION)_$(CONFIGURED_ARCH).deb +LIBYANG_DBG = libyang-dbg_$(LIBYANG_VERSION)_$(CONFIGURED_ARCH).deb $(eval $(call add_derived_package,$(LIBYANG),$(LIBYANG_DBG))) -export LIBYANG LIBYANG_DEV LIBYANG_DBG +LIBYANG_CPP = libyang-cpp_$(LIBYANG_VERSION)_$(CONFIGURED_ARCH).deb +$(eval $(call add_derived_package,$(LIBYANG),$(LIBYANG_CPP))) + +LIBYANG_PY3 = python3-yang_$(LIBYANG_VERSION)_$(CONFIGURED_ARCH).deb +$(eval $(call add_derived_package,$(LIBYANG),$(LIBYANG_PY3))) + +LIBYANG_PY2 = python2-yang_$(LIBYANG_VERSION)_$(CONFIGURED_ARCH).deb +$(eval $(call add_derived_package,$(LIBYANG),$(LIBYANG_PY2))) + +export LIBYANG LIBYANG_DBG LIBYANG_DEV LIBYANG_CPP LIBYANG_PY3 LIBYANG_PY2 diff --git a/src/libyang/Makefile b/src/libyang/Makefile index cb58f7c5128b..32cabdf13bdf 100644 --- a/src/libyang/Makefile +++ b/src/libyang/Makefile @@ -3,19 +3,26 @@ SHELL = /bin/bash .SHELLFLAGS += -e MAIN_TARGET = $(LIBYANG) -DERIVED_TARGETS = $(LIBYANG_DEV) $(LIBYANG_DBG) +DERIVED_TARGETS = $(LIBYANG_DEV) $(LIBYANG_DBG) $(LIBYANG_PY2) $(LIBYANG_PY3) $(LIBYANG_CPP) $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # Obtaining the libyang rm -fr ./libyang-$(LIBYANG_VERSION) - wget -O libyang_$(LIBYANG_VERSION).orig.tar.gz 'https://sonicstorage.blob.core.windows.net/packages/libyang_0.16.105.orig.tar.gz?sv=2015-04-05&sr=b&sig=yTWDhl6B9TTXWAQ46zpLiNxUib61W7U0%2F%2FGvhRibKOc%3D&se=2046-09-30T22%3A10%3A27Z&sp=r' - wget -O libyang_$(LIBYANG_VERSION).dsc 'https://sonicstorage.blob.core.windows.net/packages/libyang_0.16.105-1.dsc?sv=2015-04-05&sr=b&sig=eLkO5wzB1C5oKNIaUPro4gwrgEC3EygIO6eCyTzHmeI%3D&se=2046-09-30T22%3A10%3A12Z&sp=r' - wget -O libyang_$(LIBYANG_VERSION)-$(LIBYANG_SUBVERSION).debian.tar.xz 'https://sonicstorage.blob.core.windows.net/packages/libyang_0.16.105-1.debian.tar.xz?sv=2015-04-05&sr=b&sig=AH18p7pKK0xIBVxZuA8EMv9%2FhXbCFKmbWAn7Za8%2BZW4%3D&se=2046-09-30T22%3A09%3A36Z&sp=r' - dpkg-source -x libyang_$(LIBYANG_VERSION).dsc + git clone https://github.com/CESNET/libyang.git libyang-$(LIBYANG_VERSION) + pushd libyang-$(LIBYANG_VERSION) + git checkout tags/v1.0-r4 -b libyang + # Apply patch series + stg init + stg import -s ../patch/series - pushd ./libyang-$(LIBYANG_VERSION) - dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) - popd + mkdir build + pushd build + cmake .. + make build-deb - mv $(DERIVED_TARGETS) $* $(DEST)/ + pushd debs + mv $* $(DEST)/ + mv $(DERIVED_TARGETS) $(DEST)/ + popd $(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/src/libyang/patch/libyang.patch b/src/libyang/patch/libyang.patch new file mode 100644 index 000000000000..a950d85086ab --- /dev/null +++ b/src/libyang/patch/libyang.patch @@ -0,0 +1,134 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index fa562dd3..8635ba15 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -33,6 +33,7 @@ set(LIBYANG_MICRO_SOVERSION 2) + set(LIBYANG_SOVERSION_FULL ${LIBYANG_MAJOR_SOVERSION}.${LIBYANG_MINOR_SOVERSION}.${LIBYANG_MICRO_SOVERSION}) + set(LIBYANG_SOVERSION ${LIBYANG_MAJOR_SOVERSION}) + ++set(CMAKE_INSTALL_PREFIX /usr) + # set default build type if not specified by user + if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE debug) +diff --git a/packages/debian.control.in b/packages/debian.control.in +index da6588b9..fb3ede48 100644 +--- a/packages/debian.control.in ++++ b/packages/debian.control.in +@@ -53,3 +53,15 @@ Depends: python3-yang@PACKAGE_PART_NAME@ (=@LIBYANG_VERSION@) + Section: debug + Architecture: any + Description: Debug symbols of python3 bidings of libyang library. ++ ++Package: python2-yang@PACKAGE_PART_NAME@ ++Depends: @PACKAGE_NAME@ (=@LIBYANG_VERSION@), libyang-cpp@PACKAGE_PART_NAME@ (=@LIBYANG_VERSION@) ++Section: libs ++Architecture: any ++Description: Bindings of libyang library to python2 language. ++ ++Package: python2-yang@PACKAGE_PART_NAME@-dbg ++Depends: python2-yang@PACKAGE_PART_NAME@ (=@LIBYANG_VERSION@) ++Section: debug ++Architecture: any ++Description: Debug symbols of python2 bidings of libyang library. +diff --git a/packages/debian.python2-yang.install b/packages/debian.python2-yang.install +new file mode 100644 +index 00000000..14ce2f3c +--- /dev/null ++++ b/packages/debian.python2-yang.install +@@ -0,0 +1 @@ ++usr/lib/python2.7/dist-packages/* +diff --git a/packages/debian.rules.in b/packages/debian.rules.in +index d565819e..e92fe4a1 100644 +--- a/packages/debian.rules.in ++++ b/packages/debian.rules.in +@@ -9,10 +9,14 @@ export DH_VERBOSE=1 + override_dh_strip: + dh_strip -plibyang@PACKAGE_PART_NAME@ --dbg-package=libyang@PACKAGE_PART_NAME@-dbg + dh_strip -plibyang-cpp@PACKAGE_PART_NAME@ --dbg-package=libyang-cpp@PACKAGE_PART_NAME@-dbg ++ dh_strip -ppython2-yang@PACKAGE_PART_NAME@ --dbg-package=python2-yang@PACKAGE_PART_NAME@-dbg + dh_strip -ppython3-yang@PACKAGE_PART_NAME@ --dbg-package=python3-yang@PACKAGE_PART_NAME@-dbg + + override_dh_auto_configure: +- cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_BUILD_TYPE:String="@BUILD_TYPE@" -DGEN_LANGUAGE_BINDINGS=ON . ++ cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_BUILD_TYPE:String="@BUILD_TYPE@" -DENABLE_LYD_PRIV=ON -DGEN_LANGUAGE_BINDINGS=ON -DGEN_PYTHON_VERSION=2 . ++ ++override_dh_makeshlibs: ++ dh_makeshlibs -Xextensions -Xuser_types + + override_dh_auto_test: + ctest --output-on-failure +diff --git a/packages/libyang.dsc.in b/packages/libyang.dsc.in +index fdfa402b..f75ba184 100644 +--- a/packages/libyang.dsc.in ++++ b/packages/libyang.dsc.in +@@ -1,10 +1,10 @@ + Format: 3.0 (quilt) + Source: @PACKAGE_NAME@ +-Binary: @PACKAGE_NAME@, @PACKAGE_NAME@-dbg, @PACKAGE_NAME@-dev, libyang-cpp@PACKAGE_PART_NAME@, libyang-cpp@PACKAGE_PART_NAME@-dev, libyang-cpp@PACKAGE_PART_NAME@-dbg, python3-yang@PACKAGE_PART_NAME@, python3-yang@PACKAGE_PART_NAME@-dbg ++Binary: @PACKAGE_NAME@, @PACKAGE_NAME@-dbg, @PACKAGE_NAME@-dev, libyang-cpp@PACKAGE_PART_NAME@, libyang-cpp@PACKAGE_PART_NAME@-dev, libyang-cpp@PACKAGE_PART_NAME@-dbg, python3-yang@PACKAGE_PART_NAME@, python3-yang@PACKAGE_PART_NAME@-dbg python2-yang@PACKAGE_PART_NAME@, python2-yang@PACKAGE_PART_NAME@-dbg + Maintainer: CESNET + Version: @LIBYANG_VERSION@ + Architecture: any + Standards-Version: 3.8.2 + Homepage: https://github.com/CESNET/libyang + Vcs-Git: https://github.com/CESNET/libyang +-Build-Depends: debhelper (>= 9), make, gcc, doxygen, cmake, pkg-config, libpcre3-dev, libcmocka-dev, python3-dev, g++, swig (>= 3.0.12) ++Build-Depends: debhelper (>= 9), make, gcc, doxygen, cmake, pkg-config, libpcre3-dev, libcmocka-dev, python3-dev, python2-dev, g++, swig (>= 3.0.12) +diff --git a/packages/libyang.spec.in b/packages/libyang.spec.in +index 6a4ac615..6939f028 100644 +--- a/packages/libyang.spec.in ++++ b/packages/libyang.spec.in +@@ -46,6 +46,8 @@ BuildRequires: python3-devel + %else + BuildRequires: python34-devel + %endif ++ ++BuildRequires: python2-devel + %endif + + Conflicts: @CONFLICT_PACKAGE_NAME@ = @LIBYANG_MAJOR_VERSION@.@LIBYANG_MINOR_VERSION@ +@@ -70,6 +72,11 @@ Summary: Binding to python + Requires: libyang-cpp@PACKAGE_PART_NAME@ = %{version}-%{release} + Requires: %{name} = %{version}-%{release} + ++%package -n python2-yang@PACKAGE_PART_NAME@ ++Summary: Binding to python ++Requires: libyang-cpp@PACKAGE_PART_NAME@ = %{version}-%{release} ++Requires: %{name} = %{version}-%{release} ++ + %description -n libyang-cpp@PACKAGE_PART_NAME@ + Bindings of libyang library to C++ language. + +@@ -80,6 +87,10 @@ Headers of bindings to c++ language. + Bindings of libyang library to python language. + %endif + ++%description -n python2-yang@PACKAGE_PART_NAME@ ++Bindings of libyang library to python language. ++%endif ++ + %description devel + Headers of libyang library. + +@@ -167,4 +178,9 @@ make DESTDIR=%{buildroot} install + %{_libdir}/python* + %endif + ++%files -n python2-yang@PACKAGE_PART_NAME@ ++%defattr(-,root,root) ++%{_libdir}/python* ++%endif ++ + %changelog +diff --git a/packages/local-deb.sh.in b/packages/local-deb.sh.in +index 057bbc67..4318a49d 100755 +--- a/packages/local-deb.sh.in ++++ b/packages/local-deb.sh.in +@@ -18,6 +18,7 @@ fi + cp "@PROJECT_SOURCE_DIR@/packages/debian.libyang-dev.install" debian/@PACKAGE_NAME@-dev.install + cp "@PROJECT_SOURCE_DIR@/packages/debian.libyang-cpp.install" debian/libyang-cpp@PACKAGE_PART_NAME@.install + cp "@PROJECT_SOURCE_DIR@/packages/debian.libyang-cpp-dev.install" debian/libyang-cpp@PACKAGE_PART_NAME@-dev.install ++cp "@PROJECT_SOURCE_DIR@/packages/debian.python2-yang.install" debian/python2-yang@PACKAGE_PART_NAME@.install + cp "@PROJECT_SOURCE_DIR@/packages/debian.python3-yang.install" debian/python3-yang@PACKAGE_PART_NAME@.install + echo -e "@PACKAGE_NAME@ (@LIBYANG_VERSION@) stable; urgency=low\n" >debian/changelog + git log -10 --pretty=format:' * %s (%aN)%n' 2>/dev/null >>debian/changelog || echo -e " * unknown changes \n" >>debian/changelog diff --git a/src/libyang/patch/series b/src/libyang/patch/series new file mode 100644 index 000000000000..773245e4eed5 --- /dev/null +++ b/src/libyang/patch/series @@ -0,0 +1,2 @@ +libyang.patch +swig.patch diff --git a/src/libyang/patch/swig.patch b/src/libyang/patch/swig.patch new file mode 100644 index 000000000000..a6f798c18224 --- /dev/null +++ b/src/libyang/patch/swig.patch @@ -0,0 +1,136 @@ +diff --git a/swig/CMakeLists.txt b/swig/CMakeLists.txt +index 4cee36ec..0baa69ab 100644 +--- a/swig/CMakeLists.txt ++++ b/swig/CMakeLists.txt +@@ -20,27 +20,34 @@ endif() + + # find Python package + if(GEN_PYTHON_BINDINGS AND SWIG_FOUND) +- message(STATUS "Python version ${GEN_PYTHON_VERSION} was selected") +- unset(PYTHON_LIBRARY CACHE) +- unset(PYTHON_EXECUTABLE CACHE) +- unset(PYTHON_INCLUDE_DIR CACHE) +- unset(PYTHON_LIBRARY_DEBUG CACHE) +- if(${GEN_PYTHON_VERSION} STREQUAL "2") +- find_package(PythonLibs 2 REQUIRED) +- find_package(PythonInterp 2 REQUIRED) +- if(NOT PYTHONLIBS_FOUND) +- message(WARNING "Did not found Python version 2.x") +- message(STATUS "Sysrepo supports Python 2.x and Python 3.x") +- endif() +- elseif(${GEN_PYTHON_VERSION} STREQUAL "3") +- find_package(PythonLibs 3 REQUIRED) +- find_package(PythonInterp 3 REQUIRED) +- if(NOT PYTHONLIBS_FOUND) +- message(WARNING "Did not found Python version 3.x") +- message(STATUS "Sysrepo supports Python 2.x and Python 3.x") +- endif() ++ if(ENABLE_STATIC) ++ message(WARNING "Can't create a static Python module") + else() +- message(WARNING "Sysrepo supports Python 2.x and Python 3.x") ++ set(GEN_PYTHON_VERSION 2 3) ++ foreach(CUR_PYTHON_VERSION ${GEN_PYTHON_VERSION}) ++ message(STATUS "Python version ${CUR_PYTHON_VERSION} was selected") ++ ++ unset(PYTHON_EXECUTABLE CACHE) ++ unset(PYTHON_INCLUDE_PATH CACHE) ++ unset(PYTHON_EXT_SUFFIX CACHE) ++ unset(PYTHON_MODULE_PATH CACHE) ++ set(PYTHON_EXT_SUFFIX ".so") ++ ++ find_program(PYTHON_EXECUTABLE NAMES python${CUR_PYTHON_VERSION}) ++ execute_process(COMMAND ${PYTHON_EXECUTABLE} -c ++ "from distutils.sysconfig import get_config_var; print(get_config_var('INCLUDEPY'))" ++ OUTPUT_VARIABLE PYTHON_INCLUDE_PATH ++ OUTPUT_STRIP_TRAILING_WHITESPACE ) ++ #execute_process(COMMAND ${PYTHON_EXECUTABLE} -c ++ # "from distutils.sysconfig import get_config_var; print(get_config_var('EXT_SUFFIX'))" ++ # OUTPUT_VARIABLE PYTHON_EXT_SUFFIX ++ # OUTPUT_STRIP_TRAILING_WHITESPACE ) ++ execute_process(COMMAND ${PYTHON_EXECUTABLE} -c ++ "from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific=True))" ++ OUTPUT_VARIABLE PYTHON_MODULE_PATH ++ OUTPUT_STRIP_TRAILING_WHITESPACE ) ++ add_subdirectory(python python${CUR_PYTHON_VERSION}) ++ endforeach(CUR_PYTHON_VERSION) + endif() + endif() + +@@ -99,12 +106,6 @@ if (GEN_CPP_BINDINGS) + endif() + endif() + +-if(ENABLE_STATIC AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND AND (${GEN_PYTHON_VERSION} STREQUAL "2" OR ${GEN_PYTHON_VERSION} STREQUAL "3")) +- message(WARNING "Can't create a static Python module") +-elseif(PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND AND (${GEN_PYTHON_VERSION} STREQUAL "2" OR ${GEN_PYTHON_VERSION} STREQUAL "3")) +- add_subdirectory(python) +-endif() +- + if(NOT ENABLE_STATIC AND GEN_JAVASCRIPT_BINDINGS) + message(WARNING "Can't create Javascript bindings with a shared library, please use -DENABLE_STATIC") + elseif(ENABLE_STATIC AND GEN_JAVASCRIPT_BINDINGS) +diff --git a/swig/python/CMakeLists.txt b/swig/python/CMakeLists.txt +index 994b1234..5d18b8bf 100644 +--- a/swig/python/CMakeLists.txt ++++ b/swig/python/CMakeLists.txt +@@ -1,30 +1,38 @@ + set(PYTHON_SWIG_BINDING yang) ++set(PYTHON_SWIG_TARGET yang${CUR_PYTHON_VERSION}) + include_directories(${PYTHON_INCLUDE_PATH}) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) ++include_directories(${PROJECT_SOURCE_DIR}/cpp/src) + + set(CMAKE_SWIG_FLAGS "-c++") +-set(CMAKE_SWIG_FLAGS "-I${PROJECT_SOURCE_DIR}") ++set(CMAKE_SWIG_FLAGS "-I${PROJECT_SOURCE_DIR}" "-I${PROJECT_SOURCE_DIR}/cpp/src") + set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}) + +-set_source_files_properties(${PYTHON_SWIG_BINDING}.i PROPERTIES CPLUSPLUS ON PREFIX "") ++set_source_files_properties(${PYTHON_SWIG_BINDING}.i PROPERTIES CPLUSPLUS ON PREFIX "" SWIG_MODULE_NAME ${PYTHON_SWIG_BINDING}) + + if(${CMAKE_VERSION} VERSION_LESS "3.8.0") +- swig_add_module(${PYTHON_SWIG_BINDING} python ${PYTHON_SWIG_BINDING}.i) ++ swig_add_module(${PYTHON_SWIG_TARGET} python ${PYTHON_SWIG_BINDING}.i) + else() +- swig_add_library(${PYTHON_SWIG_BINDING} LANGUAGE python SOURCES ${PYTHON_SWIG_BINDING}.i) ++ swig_add_library(${PYTHON_SWIG_TARGET} LANGUAGE python SOURCES ${PYTHON_SWIG_BINDING}.i) + endif() +-swig_link_libraries(${PYTHON_SWIG_BINDING} ${PYTHON_LIBRARIES} libyang-cpp) ++swig_link_libraries(${PYTHON_SWIG_TARGET} ${PYTHON_LIBRARIES} libyang-cpp) ++ ++set_target_properties(_${PYTHON_SWIG_TARGET} PROPERTIES OUTPUT_NAME "_yang${PYTHON_EXT_SUFFIX}" SUFFIX "") + + # Generate header with SWIG run-time functions + execute_process(COMMAND ${SWIG_EXECUTABLE} -python -external-runtime ${CMAKE_CURRENT_BINARY_DIR}/swigpyrun.h) + +-file(COPY "examples" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) ++add_custom_command(TARGET ${PYTHON_SWIG_TARGET}_swig_compilation POST_BUILD ++ COMMAND sed -e "'s/\\(inst =.*tp_new.*\\)Py_None, Py_None);/PyObject *tup = PyTuple_New(0); \\1tup, Py_None); Py_DECREF(tup);/'" < swigpyrun.h > swigpyrun.h.new ++ COMMAND sed -e "'s/\\(inst =.*tp_new.*\\)Py_None, Py_None);/PyObject *tup = PyTuple_New(0); \\1tup, Py_None); Py_DECREF(tup);/'" < yangPYTHON_wrap.cxx > yangPYTHON_wrap.cxx.new ++ COMMAND diff -q swigpyrun.h swigpyrun.h.new || mv swigpyrun.h.new swigpyrun.h ++ COMMAND diff -q yangPYTHON_wrap.cxx yangPYTHON_wrap.cxx.new || mv yangPYTHON_wrap.cxx.new yangPYTHON_wrap.cxx ++ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ++ ) + +-execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific=True))" +- OUTPUT_VARIABLE PYTHON_MODULE_PATH +- OUTPUT_STRIP_TRAILING_WHITESPACE ) ++file(COPY "examples" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + +-install( TARGETS _${PYTHON_SWIG_BINDING} DESTINATION ${PYTHON_MODULE_PATH}) ++install( TARGETS _${PYTHON_SWIG_TARGET} DESTINATION ${PYTHON_MODULE_PATH}) + install( FILES "${CMAKE_CURRENT_BINARY_DIR}/${PYTHON_SWIG_BINDING}.py" DESTINATION ${PYTHON_MODULE_PATH}) + install( FILES "${CMAKE_CURRENT_BINARY_DIR}/swigpyrun.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libyang) + +@@ -51,8 +59,8 @@ if(ENABLE_BUILD_TESTS) + ADD_PYTHON_TEST(test_tree_data) + ADD_PYTHON_TEST(test_tree_schema) + +- add_custom_command(TARGET ${SWIG_MODULE_${PYTHON_SWIG_BINDING}_REAL_NAME} POST_BUILD +- COMMAND cp "${CMAKE_CURRENT_BINARY_DIR}/_${PYTHON_SWIG_BINDING}.so" ${PY2_SWIG_DIR}/tests ++ add_custom_command(TARGET ${SWIG_MODULE_${PYTHON_SWIG_TARGET}_REAL_NAME} POST_BUILD ++ COMMAND cp "${CMAKE_CURRENT_BINARY_DIR}/_yang${PYTHON_EXT_SUFFIX}" ${PY2_SWIG_DIR}/tests/_yang.so + COMMAND cp "${CMAKE_CURRENT_BINARY_DIR}/${PYTHON_SWIG_BINDING}.py" ${PY2_SWIG_DIR}/tests + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) From 6c0ab4b9261e5f3ce7b7a575e79a2b13c5021ea9 Mon Sep 17 00:00:00 2001 From: dereksun01 <52683998+dereksun01@users.noreply.github.com> Date: Fri, 8 Nov 2019 08:24:42 +0800 Subject: [PATCH 145/278] [device] accton device of as5812_54t supports SAI and modify as5812_54t periphery (#3663) - Support as5812_54t SAI. - Modify as5812_54t periphery. Signed-off-by: derek_sun --- .../Accton-AS5812-54T/port_config.ini | 146 +++++------ .../Accton-AS5812-54T/sai.profile | 2 +- .../td2-as5812-72x10G.config.bcm | 148 ------------ .../td2-as5812t-72x10G.config.bcm | 194 +++++++++++++++ .../led_proc_init.soc | 226 ++++++------------ .../as5812-54t/modules/Makefile | 2 +- .../modules/x86-64-accton-as5812-54t-leds.c | 18 +- .../as5812-54t/utils/accton_as5812_util.py | 1 - .../debian/rules | 2 +- 9 files changed, 353 insertions(+), 386 deletions(-) mode change 100755 => 100644 device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/port_config.ini mode change 100755 => 100644 device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/sai.profile delete mode 100644 device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/td2-as5812-72x10G.config.bcm create mode 100644 device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/td2-as5812t-72x10G.config.bcm diff --git a/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/port_config.ini b/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/port_config.ini old mode 100755 new mode 100644 index ee60c526227d..857a8987bc13 --- a/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/port_config.ini +++ b/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/port_config.ini @@ -1,73 +1,73 @@ -# name lanes alias index speed -Ethernet0 13 tenGigE0 1 10000 -Ethernet1 14 tenGigE1 2 10000 -Ethernet2 15 tenGigE2 3 10000 -Ethernet3 16 tenGigE3 4 10000 -Ethernet4 21 tenGigE4 5 10000 -Ethernet5 22 tenGigE5 6 10000 -Ethernet6 23 tenGigE6 7 10000 -Ethernet7 24 tenGigE7 8 10000 -Ethernet8 25 tenGigE8 9 10000 -Ethernet9 26 tenGigE9 10 10000 -Ethernet10 27 tenGigE10 11 10000 -Ethernet11 28 tenGigE11 12 10000 -Ethernet12 29 tenGigE12 13 10000 -Ethernet13 30 tenGigE13 14 10000 -Ethernet14 31 tenGigE14 15 10000 -Ethernet15 32 tenGigE15 16 10000 -Ethernet16 45 tenGigE16 17 10000 -Ethernet17 46 tenGigE17 18 10000 -Ethernet18 47 tenGigE18 19 10000 -Ethernet19 48 tenGigE19 20 10000 -Ethernet20 49 tenGigE20 21 10000 -Ethernet21 50 tenGigE21 22 10000 -Ethernet22 51 tenGigE22 23 10000 -Ethernet23 52 tenGigE23 24 10000 -Ethernet24 53 tenGigE24 25 10000 -Ethernet25 54 tenGigE25 26 10000 -Ethernet26 55 tenGigE26 27 10000 -Ethernet27 56 tenGigE27 28 10000 -Ethernet28 57 tenGigE28 29 10000 -Ethernet29 58 tenGigE29 30 10000 -Ethernet30 59 tenGigE30 31 10000 -Ethernet31 60 tenGigE31 32 10000 -Ethernet32 61 tenGigE32 33 10000 -Ethernet33 62 tenGigE33 34 10000 -Ethernet34 63 tenGigE34 35 10000 -Ethernet35 64 tenGigE35 36 10000 -Ethernet36 65 tenGigE36 37 10000 -Ethernet37 66 tenGigE37 38 10000 -Ethernet38 67 tenGigE38 39 10000 -Ethernet39 68 tenGigE39 40 10000 -Ethernet40 69 tenGigE40 41 10000 -Ethernet41 70 tenGigE41 42 10000 -Ethernet42 71 tenGigE42 43 10000 -Ethernet43 72 tenGigE43 44 10000 -Ethernet44 73 tenGigE44 45 10000 -Ethernet45 74 tenGigE45 46 10000 -Ethernet46 75 tenGigE46 47 10000 -Ethernet47 76 tenGigE47 48 10000 -Ethernet48 97 tenGigE48 49 10000 -Ethernet49 98 tenGigE49 49 10000 -Ethernet50 99 tenGigE50 49 10000 -Ethernet51 100 tenGigE51 49 10000 -Ethernet52 101 tenGigE52 50 10000 -Ethernet53 102 tenGigE53 50 10000 -Ethernet54 103 tenGigE54 50 10000 -Ethernet55 104 tenGigE55 50 10000 -Ethernet56 81 tenGigE56 51 10000 -Ethernet57 82 tenGigE57 51 10000 -Ethernet58 83 tenGigE58 51 10000 -Ethernet59 84 tenGigE59 51 10000 -Ethernet60 105 tenGigE60 52 10000 -Ethernet61 106 tenGigE61 52 10000 -Ethernet62 107 tenGigE62 52 10000 -Ethernet63 108 tenGigE63 52 10000 -Ethernet64 109 tenGigE64 53 10000 -Ethernet65 110 tenGigE65 53 10000 -Ethernet66 111 tenGigE66 53 10000 -Ethernet67 112 tenGigE67 53 10000 -Ethernet68 77 tenGigE68 54 10000 -Ethernet69 78 tenGigE69 54 10000 -Ethernet70 79 tenGigE70 54 10000 -Ethernet71 80 tenGigE71 54 10000 +# name lanes alias index speed autoneg +Ethernet0 14 tenGigE0 1 10000 1 +Ethernet1 13 tenGigE1 2 10000 1 +Ethernet2 16 tenGigE2 3 10000 1 +Ethernet3 15 tenGigE3 4 10000 1 +Ethernet4 22 tenGigE4 5 10000 1 +Ethernet5 21 tenGigE5 6 10000 1 +Ethernet6 24 tenGigE6 7 10000 1 +Ethernet7 23 tenGigE7 8 10000 1 +Ethernet8 26 tenGigE8 9 10000 1 +Ethernet9 25 tenGigE9 10 10000 1 +Ethernet10 28 tenGigE10 11 10000 1 +Ethernet11 27 tenGigE11 12 10000 1 +Ethernet12 30 tenGigE12 13 10000 1 +Ethernet13 29 tenGigE13 14 10000 1 +Ethernet14 32 tenGigE14 15 10000 1 +Ethernet15 31 tenGigE15 16 10000 1 +Ethernet16 46 tenGigE16 17 10000 1 +Ethernet17 45 tenGigE17 18 10000 1 +Ethernet18 48 tenGigE18 19 10000 1 +Ethernet19 47 tenGigE19 20 10000 1 +Ethernet20 50 tenGigE20 21 10000 1 +Ethernet21 49 tenGigE21 22 10000 1 +Ethernet22 52 tenGigE22 23 10000 1 +Ethernet23 51 tenGigE23 24 10000 1 +Ethernet24 54 tenGigE24 25 10000 1 +Ethernet25 53 tenGigE25 26 10000 1 +Ethernet26 56 tenGigE26 27 10000 1 +Ethernet27 55 tenGigE27 28 10000 1 +Ethernet28 58 tenGigE28 29 10000 1 +Ethernet29 57 tenGigE29 30 10000 1 +Ethernet30 60 tenGigE30 31 10000 1 +Ethernet31 59 tenGigE31 32 10000 1 +Ethernet32 62 tenGigE32 33 10000 1 +Ethernet33 61 tenGigE33 34 10000 1 +Ethernet34 64 tenGigE34 35 10000 1 +Ethernet35 63 tenGigE35 36 10000 1 +Ethernet36 66 tenGigE36 37 10000 1 +Ethernet37 65 tenGigE37 38 10000 1 +Ethernet38 68 tenGigE38 39 10000 1 +Ethernet39 67 tenGigE39 40 10000 1 +Ethernet40 70 tenGigE40 41 10000 1 +Ethernet41 69 tenGigE41 42 10000 1 +Ethernet42 72 tenGigE42 43 10000 1 +Ethernet43 71 tenGigE43 44 10000 1 +Ethernet44 74 tenGigE44 45 10000 1 +Ethernet45 73 tenGigE45 46 10000 1 +Ethernet46 76 tenGigE46 47 10000 1 +Ethernet47 75 tenGigE47 48 10000 1 +Ethernet48 97 tenGigE48 49 10000 0 +Ethernet49 98 tenGigE49 49 10000 0 +Ethernet50 99 tenGigE50 49 10000 0 +Ethernet51 100 tenGigE51 49 10000 0 +Ethernet52 101 tenGigE52 50 10000 0 +Ethernet53 102 tenGigE53 50 10000 0 +Ethernet54 103 tenGigE54 50 10000 0 +Ethernet55 104 tenGigE55 50 10000 0 +Ethernet56 77 tenGigE56 51 10000 0 +Ethernet57 78 tenGigE57 51 10000 0 +Ethernet58 79 tenGigE58 51 10000 0 +Ethernet59 80 tenGigE59 51 10000 0 +Ethernet60 105 tenGigE60 52 10000 0 +Ethernet61 106 tenGigE61 52 10000 0 +Ethernet62 107 tenGigE62 52 10000 0 +Ethernet63 108 tenGigE63 52 10000 0 +Ethernet64 109 tenGigE64 53 10000 0 +Ethernet65 110 tenGigE65 53 10000 0 +Ethernet66 111 tenGigE66 53 10000 0 +Ethernet67 112 tenGigE67 53 10000 0 +Ethernet68 81 tenGigE68 54 10000 0 +Ethernet69 82 tenGigE69 54 10000 0 +Ethernet70 83 tenGigE70 54 10000 0 +Ethernet71 84 tenGigE71 54 10000 0 diff --git a/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/sai.profile b/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/sai.profile old mode 100755 new mode 100644 index 063814c1fcb3..dc4f243953bf --- a/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/sai.profile +++ b/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/sai.profile @@ -1 +1 @@ -SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td2-as5812-72x10G.config.bcm +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td2-as5812t-72x10G.config.bcm diff --git a/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/td2-as5812-72x10G.config.bcm b/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/td2-as5812-72x10G.config.bcm deleted file mode 100644 index 4844616d0382..000000000000 --- a/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/td2-as5812-72x10G.config.bcm +++ /dev/null @@ -1,148 +0,0 @@ -os=unix -bcm_stat_flags=0 -parity_enable=0 -parity_correction=0 - -bcm_num_cos=8 -l2_mem_entries=32768 -l3_mem_entries=16384 -l3_alpm_enable=2 -ipv6_lpm_128b_enable=1 - -mmu_lossless=0 -lls_num_l2uc=12 -module_64ports=0 - -#SFI -serdes_if_type=9 - -port_init_cl72=0 -phy_an_c73=5 # TSCMOD_CL73_CL37 - -#sdk6.5.5 only supports 156(default) or 125 -#xgxs_lcpll_xtal_refclk=1 -tslam_dma_enable=1 -table_dma_enable=1 - -#for 72 ports with 48 10G ports and 6 40G ports for breakout mode -pbmp_oversubscribe=0x1fffffffffffffffffe -pbmp_xport_xe=0x1fffffffffffffffffe - -rate_ext_mdio_divisor=96 - -#SFP+ 1-4 from WC3 -portmap_1=13:10 -portmap_2=14:10 -portmap_3=15:10 -portmap_4=16:10 - -#SFP+ 5-8 from WC5 -portmap_5=21:10 -portmap_6=22:10 -portmap_7=23:10 -portmap_8=24:10 - -#SFP+ 9-12 from WC6 -portmap_9=25:10 -portmap_10=26:10 -portmap_11=27:10 -portmap_12=28:10 - -#SFP+ 13-16 from WC7 -portmap_13=29:10 -portmap_14=30:10 -portmap_15=31:10 -portmap_16=32:10 - -#SFP+ 17-20 from WC11 -portmap_17=45:10 -portmap_18=46:10 -portmap_19=47:10 -portmap_20=48:10 - -#SFP+ 21-24 from WC12 -portmap_21=49:10 -portmap_22=50:10 -portmap_23=51:10 -portmap_24=52:10 - -#SFP+ 25-28 from WC13 -portmap_25=53:10 -portmap_26=54:10 -portmap_27=55:10 -portmap_28=56:10 - -#SFP+ 29-32 from WC14 -portmap_29=57:10 -portmap_30=58:10 -portmap_31=59:10 -portmap_32=60:10 - -#SFP+ 33-36 from WC15 -portmap_33=61:10 -portmap_34=62:10 -portmap_35=63:10 -portmap_36=64:10 - -#SFP+ 37-40 from WC16 -portmap_37=65:10 -portmap_38=66:10 -portmap_39=67:10 -portmap_40=68:10 - -#SFP+ 41-44 from WC17 -portmap_41=69:10 -portmap_42=70:10 -portmap_43=71:10 -portmap_44=72:10 - -#SFP+ 45-48 from WC18 -portmap_45=73:10 -portmap_46=74:10 -portmap_47=75:10 -portmap_48=76:10 - -# QSFP+ 49/WC24/port 49 -portmap_49=97:10 -portmap_50=98:10 -portmap_51=99:10 -portmap_52=100:10 - -# QSFP+ 51/WC25/port 50 -portmap_53=101:10 -portmap_54=102:10 -portmap_55=103:10 -portmap_56=104:10 - -# QSFP+ 53/WC20/port 51 -portmap_57=81:10 -portmap_58=82:10 -portmap_59=83:10 -portmap_60=84:10 - -# QSFP+ 50/WC26/port 52 -portmap_61=105:10 -portmap_62=106:10 -portmap_63=107:10 -portmap_64=108:10 - -# QSFP+ 52/WC27/port 53 -portmap_65=109:10 -portmap_66=110:10 -portmap_67=111:10 -portmap_68=112:10 - -# QSFP+ 54/WC19/port 54 -portmap_69=77:10 -portmap_70=78:10 -portmap_71=79:10 -portmap_72=80:10 - -# L3 ECMP -# - In Trident2, VP LAGs share the same table as ECMP group table. -# The first N entries are reserved for VP LAGs, where N is the value of the -# config property "max_vp_lags". By default this was set to 256 -l3_max_ecmp_mode=1 -max_vp_lags=0 - -stable_size=0x2000000 diff --git a/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/td2-as5812t-72x10G.config.bcm b/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/td2-as5812t-72x10G.config.bcm new file mode 100644 index 000000000000..b55558521094 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54t-r0/Accton-AS5812-54T/td2-as5812t-72x10G.config.bcm @@ -0,0 +1,194 @@ +bcm_num_cos=8 +bcm_stat_flags=0 +bcm_stat_interval=2000000 +bcm_tunnel_term_compatible_mode=1 + +cdma_timeout_usec=3000000 + +fpem_mem_entries=16384 + +ipv6_lpm_128b_enable=0x1 +ifp_inports_support_enable=1 + +l2xmsg_mode=1 +l2_mem_entries=32768 + +l3_alpm_enable=2 +l3_max_ecmp_mode=1 +l3_mem_entries=16384 +l3_alpm_ipv6_128b_bkt_rsvd=1 + +load_firmware=0x101 + +max_vp_lags=0 +module_64ports=1 +miim_intr_enable=0 +mem_cache_enable=0 +mdio_output_delay=15 + +os=unix +oversubscribe_mode=1 + +parity_enable=0 +port_flex_enable=1 +parity_correction=0 +phy_ext_rom_boot_xe=0 +phy_aux_voltage_enable=1 + +#for 72 ports with 48 10G ports and 6 40G ports for breakout mode +pbmp_xport_xe=0x7fffffffffffffffffe +pbmp_oversubscribe=0x7fffffffffffffffffe + +rate_ext_mdio_divisor=96 + +schan_intr_enable=0 +skip_L2_USER_ENTRY=0 +stable_size=0x2000000 +stable_size=0x5500000 ;Specify the stable cache size in bytes used for Warm boot operations + +tdma_timeout_usec=3000000 + +#port-lanes configuration +portmap_1=14:10 +portmap_2=13:10 +portmap_3=16:10 +portmap_4=15:10 +port_phy_addr_1=0x1 +port_phy_addr_2=0x0 +port_phy_addr_3=0x3 +port_phy_addr_4=0x2 + +portmap_5=22:10 +portmap_6=21:10 +portmap_7=24:10 +portmap_8=23:10 +port_phy_addr_5=0x5 +port_phy_addr_6=0x4 +port_phy_addr_7=0x7 +port_phy_addr_8=0x6 + +portmap_9=26:10 +portmap_10=25:10 +portmap_11=28:10 +portmap_12=27:10 +port_phy_addr_9=0x9 +port_phy_addr_10=0x8 +port_phy_addr_11=0xb +port_phy_addr_12=0xa + +portmap_13=30:10 +portmap_14=29:10 +portmap_15=32:10 +portmap_16=31:10 +port_phy_addr_13=0x21 +port_phy_addr_14=0x20 +port_phy_addr_15=0x23 +port_phy_addr_16=0x22 + +portmap_17=46:10 +portmap_18=45:10 +portmap_19=48:10 +portmap_20=47:10 +port_phy_addr_17=0x25 +port_phy_addr_18=0x24 +port_phy_addr_19=0x27 +port_phy_addr_20=0x26 + +portmap_21=50:10 +portmap_22=49:10 +portmap_23=52:10 +portmap_24=51:10 +port_phy_addr_21=0x29 +port_phy_addr_22=0x28 +port_phy_addr_23=0x2b +port_phy_addr_24=0x2a + +portmap_25=54:10 +portmap_26=53:10 +portmap_27=56:10 +portmap_28=55:10 +port_phy_addr_25=0x41 +port_phy_addr_26=0x40 +port_phy_addr_27=0x43 +port_phy_addr_28=0x42 + +portmap_29=58:10 +portmap_30=57:10 +portmap_31=60:10 +portmap_32=59:10 +port_phy_addr_29=0x45 +port_phy_addr_30=0x44 +port_phy_addr_31=0x47 +port_phy_addr_32=0x46 + +portmap_33=62:10 +portmap_34=61:10 +portmap_35=64:10 +portmap_36=63:10 +port_phy_addr_33=0x49 +port_phy_addr_34=0x48 +port_phy_addr_35=0x4b +port_phy_addr_36=0x4a + +portmap_37=66:10 +portmap_38=65:10 +portmap_39=68:10 +portmap_40=67:10 +port_phy_addr_37=0x61 +port_phy_addr_38=0x60 +port_phy_addr_39=0x63 +port_phy_addr_40=0x62 + +portmap_41=70:10 +portmap_42=69:10 +portmap_43=72:10 +portmap_44=71:10 +port_phy_addr_41=0x65 +port_phy_addr_42=0x64 +port_phy_addr_43=0x67 +port_phy_addr_44=0x66 + +portmap_45=74:10 +portmap_46=73:10 +portmap_47=76:10 +portmap_48=75:10 +port_phy_addr_45=0x69 +port_phy_addr_46=0x68 +port_phy_addr_47=0x6b +port_phy_addr_48=0x6a + +#port_49 +portmap_49=97:10 +portmap_50=98:10 +portmap_51=99:10 +portmap_52=100:10 + +#port_50 +portmap_53=101:10 +portmap_54=102:10 +portmap_55=103:10 +portmap_56=104:10 + +#port_51 +portmap_57=77:10 +portmap_58=78:10 +portmap_59=79:10 +portmap_60=80:10 + +#port_52 +portmap_61=105:10 +portmap_62=106:10 +portmap_63=107:10 +portmap_64=108:10 + +#port_53 +portmap_65=109:10 +portmap_66=110:10 +portmap_67=111:10 +portmap_68=112:10 + +#port_54 +portmap_69=81:10 +portmap_70=82:10 +portmap_71=83:10 +portmap_72=84:10 \ No newline at end of file diff --git a/device/accton/x86_64-accton_as5812_54t-r0/led_proc_init.soc b/device/accton/x86_64-accton_as5812_54t-r0/led_proc_init.soc index d93e373d0567..954446d4a8ba 100644 --- a/device/accton/x86_64-accton_as5812_54t-r0/led_proc_init.soc +++ b/device/accton/x86_64-accton_as5812_54t-r0/led_proc_init.soc @@ -1,162 +1,94 @@ # LED setting for active # ----------------------------------------------------------------------------- -# for as5812_54x (48xg+6qxg) +# for as5812_54t (48xg+6qxg) # # on green - if link up # off - if link down # blink - if active # ----------------------------------------------------------------------------- -m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0 -m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1 -m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2 -m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 -m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4 -m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5 -m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6 -m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 -m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8 -m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9 -m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10 -m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 -m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12 -m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13 -m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14 -m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 -m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16 -m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17 -m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18 -m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19 -m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20 -m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21 -m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22 -m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23 -m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24 -m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25 -m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26 -m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27 -m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28 -m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29 -m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30 -m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31 -m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32 -m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33 -m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34 -m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 -m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36 -m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37 -m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38 -m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 -m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40 -m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41 -m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42 -m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 -m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44 -m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45 -m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46 -m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 -m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48 -m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49 -m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50 -m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51 -m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52 -m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53 -m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54 -m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55 -m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56 -m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57 -m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58 -m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59 -m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60 -m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61 -m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62 -m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 -m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0 -m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1 -m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2 -m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 -m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4 -m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5 -m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6 -m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 -m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8 -m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9 -m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10 -m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 -m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12 -m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13 -m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14 -m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 -m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16 -m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17 -m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18 -m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19 -m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20 -m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21 -m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22 -m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23 -m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24 -m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25 -m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26 -m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27 -m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28 -m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29 -m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30 -m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31 -m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32 -m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33 -m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34 -m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 -m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36 -m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37 -m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38 -m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 -m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40 -m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41 -m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42 -m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 -m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44 -m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45 -m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46 -m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 -m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48 -m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49 -m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50 -m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51 -m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52 -m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53 -m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54 -m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55 -m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56 -m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57 -m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58 -m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59 -m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60 -m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61 -m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62 -m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 +m xlmac_rx_ctrl.xe0-xe47 STRICT_PREAMBLE=0 + +link on +link off + +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=12 REMAP_PORT_1=13 REMAP_PORT_2=14 REMAP_PORT_3=15 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=8 REMAP_PORT_5=9 REMAP_PORT_6=10 REMAP_PORT_7=11 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=4 REMAP_PORT_9=5 REMAP_PORT_10=6 REMAP_PORT_11=7 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=0 REMAP_PORT_13=1 REMAP_PORT_14=2 REMAP_PORT_15=3 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=16 REMAP_PORT_17=17 REMAP_PORT_18=18 REMAP_PORT_19=19 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=63 REMAP_PORT_21=62 REMAP_PORT_22=61 REMAP_PORT_23=60 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=63 REMAP_PORT_25=62 REMAP_PORT_26=61 REMAP_PORT_27=60 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=63 REMAP_PORT_29=62 REMAP_PORT_30=61 REMAP_PORT_31=60 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=63 REMAP_PORT_33=62 REMAP_PORT_34=61 REMAP_PORT_35=60 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=28 REMAP_PORT_37=29 REMAP_PORT_38=30 REMAP_PORT_39=31 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=24 REMAP_PORT_41=25 REMAP_PORT_42=26 REMAP_PORT_43=27 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=20 REMAP_PORT_45=21 REMAP_PORT_46=22 REMAP_PORT_47=23 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=32 REMAP_PORT_49=33 REMAP_PORT_50=34 REMAP_PORT_51=35 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=63 REMAP_PORT_53=62 REMAP_PORT_54=61 REMAP_PORT_55=60 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=63 REMAP_PORT_57=62 REMAP_PORT_58=61 REMAP_PORT_59=60 +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=63 REMAP_PORT_61=62 REMAP_PORT_62=61 REMAP_PORT_63=60 + +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=63 REMAP_PORT_1=63 REMAP_PORT_2=63 REMAP_PORT_3=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=63 REMAP_PORT_5=63 REMAP_PORT_6=63 REMAP_PORT_7=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=63 REMAP_PORT_9=63 REMAP_PORT_10=63 REMAP_PORT_11=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 REMAP_PORT_13=63 REMAP_PORT_14=63 REMAP_PORT_15=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=19 REMAP_PORT_17=18 REMAP_PORT_18=17 REMAP_PORT_19=16 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=15 REMAP_PORT_21=14 REMAP_PORT_22=13 REMAP_PORT_23=12 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=7 REMAP_PORT_25=6 REMAP_PORT_26=5 REMAP_PORT_27=4 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=3 REMAP_PORT_29=2 REMAP_PORT_30=1 REMAP_PORT_31=0 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=23 REMAP_PORT_33=22 REMAP_PORT_34=21 REMAP_PORT_35=20 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=63 REMAP_PORT_37=63 REMAP_PORT_38=63 REMAP_PORT_39=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=63 REMAP_PORT_41=63 REMAP_PORT_42=63 REMAP_PORT_43=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=63 REMAP_PORT_45=63 REMAP_PORT_46=63 REMAP_PORT_47=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=11 REMAP_PORT_49=10 REMAP_PORT_50=9 REMAP_PORT_51=8 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=24 REMAP_PORT_53=25 REMAP_PORT_54=26 REMAP_PORT_55=27 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=28 REMAP_PORT_57=29 REMAP_PORT_58=30 REMAP_PORT_59=31 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=32 REMAP_PORT_61=33 REMAP_PORT_62=34 REMAP_PORT_63=35 led 0 stop led 0 prog \ - 06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \ - 61 FD 02 3F 60 FF 28 32 0F 87 67 4A 96 FF 06 FF \ - D2 2B 74 16 02 1F 60 FF 28 32 0F 87 67 4A 96 FF \ - 06 FF D2 13 74 28 02 0F 60 FF 28 32 0F 87 67 4A \ - 96 FF 06 FF D2 0B 74 3A 3A 48 32 07 32 08 C7 32 \ - 04 C7 97 71 57 77 69 32 00 32 01 B7 97 71 63 32 \ - 0E 77 6B 26 FD 97 27 77 6B 32 0F 87 57 00 00 00 +02 F9 42 80 02 F7 42 00 02 F8 42 00 02 F4 42 48 \ +02 F3 42 24 06 F5 D2 00 74 1E 02 F5 42 05 67 4B \ +86 F8 06 F3 D6 F8 74 1E 86 F0 3E F4 06 F8 88 4A \ +03 75 3C 4A 04 71 41 67 7D 67 91 57 67 7D 67 91 \ +57 67 91 67 7D 57 67 7D 67 7D 57 06 F8 88 80 4A \ +00 27 97 75 46 90 4A 00 27 4A 01 27 B7 97 71 62 \ +77 2C 06 F5 D6 F0 74 75 02 F5 4A 07 37 4E 07 02 \ +F0 42 00 4E 07 06 F5 0A 07 71 46 77 2C 16 F7 06 \ +F9 17 4D DA 07 74 8E 12 F7 52 00 86 F9 57 86 F7 \ +57 16 F7 06 F9 07 4D DA 07 74 A2 12 F7 52 00 86 \ +F9 57 86 F7 57 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + led 0 start led 1 stop led 1 prog \ - 06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \ - 61 FD 02 20 67 89 02 24 67 89 02 10 67 89 02 28 \ - 67 89 02 2C 67 89 02 0C 67 89 02 2C 67 79 02 28 \ - 67 79 02 24 67 79 02 20 67 79 02 10 67 79 02 0C \ - 67 79 02 0B 60 FF 28 32 0F 87 67 56 96 FF 06 FF \ - D2 FF 74 46 3A 36 32 07 32 08 C7 32 04 C7 97 71 \ - 63 77 75 32 00 32 01 B7 97 71 6F 32 0E 77 77 26 \ - FD 97 27 77 77 32 0F 87 57 12 A0 F8 15 1A 01 75 \ - 85 28 67 56 57 32 0F 87 57 12 A0 F8 15 1A 01 71 \ - A1 28 67 56 80 28 67 56 80 28 67 56 80 28 67 56 \ - 57 32 0F 87 32 0F 87 32 0F 87 32 0F 87 57 00 00 +02 F9 42 80 02 F7 42 00 02 F8 42 00 02 F4 42 36 \ +02 F3 42 24 02 F6 17 4E 01 67 AD 86 F8 67 AD 86 \ +F8 67 AD 86 F8 67 AD 86 F8 06 F8 D2 18 74 19 12 \ +01 02 10 60 F8 67 7E 12 01 02 0C 60 F8 67 7E 12 \ +01 02 04 60 F8 67 7E 12 01 02 00 60 F8 67 7E 12 \ +01 02 08 60 F8 67 7E 12 01 02 14 60 F8 67 7E 02 \ +F6 07 4E 01 02 18 60 F8 67 AD 86 F8 06 F3 D6 F8 \ +74 68 86 F0 3E F4 16 E0 5A 00 71 AD 77 A2 1A 00 \ +75 AD 77 A2 02 F6 4A 01 71 9F 06 F8 88 4A 03 75 \ +95 4A 04 71 9A 67 DF 67 E3 57 67 E3 67 DF 57 67 \ +E3 57 02 F6 4A 01 71 AA 67 DF 67 DF 57 06 F8 88 \ +80 4A 00 27 97 75 A2 90 4A 00 27 4A 01 27 B7 97 \ +71 C4 77 84 06 F5 D6 F0 74 D7 02 F5 4A 07 37 4E \ +07 02 F0 42 00 4E 07 06 F5 0A 07 71 A2 77 84 22 \ +01 77 E5 22 00 16 F7 06 F9 97 4D DA 07 74 F6 12 \ +F7 52 00 86 F9 57 86 F7 57 00 00 00 00 00 00 00 + + led 1 start + +link on +led auto on +set RCError=off + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54t/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as5812-54t/modules/Makefile index 9e338c01f23e..db535d8d6771 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54t/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54t/modules/Makefile @@ -1,4 +1,4 @@ obj-m:= x86-64-accton-as5812-54t-cpld.o x86-64-accton-as5812-54t-fan.o \ - x86-64-accton-as5812-54t-leds.o x86-64-accton-as5812-54t-sfp.o \ + x86-64-accton-as5812-54t-leds.o \ x86-64-accton-as5812-54t-psu.o ym2651y.o cpr_4011_4mxx.o diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54t/modules/x86-64-accton-as5812-54t-leds.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54t/modules/x86-64-accton-as5812-54t-leds.c index 011f62e76c06..39e553d2f544 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54t/modules/x86-64-accton-as5812-54t-leds.c +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54t/modules/x86-64-accton-as5812-54t-leds.c @@ -29,13 +29,8 @@ #include #include -extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); -extern int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); - -extern void led_classdev_unregister(struct led_classdev *led_cdev); -extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev); -extern void led_classdev_resume(struct led_classdev *led_cdev); -extern void led_classdev_suspend(struct led_classdev *led_cdev); +extern int as5812_54t_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as5812_54t_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); #define DRVNAME "as5812_54t_led" @@ -223,12 +218,12 @@ static u8 led_light_mode_to_reg_val(enum led_type type, static int accton_as5812_54t_led_read_value(u8 reg) { - return accton_i2c_cpld_read(0x60, reg); + return as5812_54t_cpld_read(0x60, reg); } static int accton_as5812_54t_led_write_value(u8 reg, u8 value) { - return accton_i2c_cpld_write(0x60, reg, value); + return as5812_54t_cpld_write(0x60, reg, value); } static void accton_as5812_54t_led_update(void) @@ -555,11 +550,6 @@ static int __init accton_as5812_54t_led_init(void) { int ret; - extern int platform_accton_as5812_54t(void); - if (!platform_accton_as5812_54t()) { - return -ENODEV; - } - ret = platform_driver_register(&accton_as5812_54t_led_driver); if (ret < 0) { goto exit; diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54t/utils/accton_as5812_util.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54t/utils/accton_as5812_util.py index 7a2bec3a0199..cad526e17af5 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54t/utils/accton_as5812_util.py +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54t/utils/accton_as5812_util.py @@ -159,7 +159,6 @@ def driver_check(): 'modprobe x86-64-accton-as5812-54t-cpld' , 'modprobe cpr_4011_4mxx' , 'modprobe ym2651y' , -'modprobe x86-64-accton-as5812-54t-sfp' , 'modprobe x86-64-accton-as5812-54t-psu' , 'modprobe x86-64-accton-as5812-54t-fan' , 'modprobe x86-64-accton-as5812-54t-leds' ] diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/rules b/platform/broadcom/sonic-platform-modules-accton/debian/rules index f1d730b577fa..722d4126ad0e 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/rules +++ b/platform/broadcom/sonic-platform-modules-accton/debian/rules @@ -21,7 +21,7 @@ KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) MODULE_DIRS := as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x MODULE_DIRS += as7326-56x as6712-32x as7726-32x as4630-54pe minipack as5812-54x -MODULE_DIRS += as5835-54x as9716-32d as5835-54t as7312-54xs as7315-27xb as5812-54x +MODULE_DIRS += as5835-54x as9716-32d as5835-54t as7312-54xs as7315-27xb as5812-54t MODULE_DIR := modules UTILS_DIR := utils SERVICE_DIR := service From ac2908ef035f2dfc278a61d7bb4c631b92c1aa67 Mon Sep 17 00:00:00 2001 From: jostar-yang Date: Fri, 8 Nov 2019 13:53:21 +0800 Subject: [PATCH 146/278] [devices]: Add thermal plan to as4630_54pe (#3665) --- .../as4630-54pe/classes/fanutil.py | 257 ++++----------- .../as4630-54pe/classes/thermalutil.py | 105 +++---- .../utils/accton_as4630_54pe_monitor.py | 294 +++++++----------- .../debian/control | 1 - 4 files changed, 206 insertions(+), 451 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/fanutil.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/fanutil.py index b6752783dc03..df2e511adef7 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/fanutil.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/fanutil.py @@ -1,223 +1,90 @@ #!/usr/bin/env python +# Copyright (c) 2019 Edgecore Networks Corporation # -# Copyright (C) 2017 Accton Technology Corporation +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # -# This 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 CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. # -# 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. +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - # ------------------------------------------------------------------ # HISTORY: # mm/dd/yyyy (A.D.) -# 11/13/2017: Polly Hsu, Create -# 1/10/2018: Jostar modify for as7716_32 -# 12/03/2018: Jostar modify for as7726_32 +# 10/24/2019:Jostar craete for as4630_54pe # ------------------------------------------------------------------ try: + import os import time import logging + import glob + import commands from collections import namedtuple except ImportError as e: raise ImportError('%s - required module not found' % str(e)) - -class FanUtil(object): - """Platform-specific FanUtil class""" - - FAN_NUM_ON_MAIN_BROAD = 6 - FAN_NUM_1_IDX = 1 - FAN_NUM_2_IDX = 2 - FAN_NUM_3_IDX = 3 - FAN_NUM_4_IDX = 4 - FAN_NUM_5_IDX = 5 - FAN_NUM_6_IDX = 6 - - FAN_NODE_NUM_OF_MAP = 2 - FAN_NODE_FAULT_IDX_OF_MAP = 1 - FAN_NODE_DIR_IDX_OF_MAP = 2 +class ThermalUtil(object): + """Platform-specific ThermalUtil class""" + THERMAL_NUM_MAX = 4 + THERMAL_NUM_1_IDX = 1 + THERMAL_NUM_2_IDX = 2 + THERMAL_NUM_3_IDX = 3 + THERMAL_NUM_4_IDX = 4 - BASE_VAL_PATH = '/sys/bus/i2c/devices/54-0066/{0}' - FAN_DUTY_PATH = '/sys/bus/i2c/devices/54-0066/fan_duty_cycle_percentage' - - #logfile = '' - #loglevel = logging.INFO - """ Dictionary where - key1 = fan id index (integer) starting from 1 - key2 = fan node index (interger) starting from 1 + key1 = thermal id index (integer) starting from 1 value = path to fan device file (string) """ - _fan_to_device_path_mapping = {} - -#fan1_direction -#fan1_fault -#fan1_present - - #(FAN_NUM_2_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan2_duty_cycle_percentage', - _fan_to_device_node_mapping = { - (FAN_NUM_1_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan1_fault', - (FAN_NUM_1_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan1_direction', - - (FAN_NUM_2_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan2_fault', - (FAN_NUM_2_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan2_direction', - - (FAN_NUM_3_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan3_fault', - (FAN_NUM_3_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan3_direction', - - (FAN_NUM_4_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan4_fault', - (FAN_NUM_4_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan4_direction', - - (FAN_NUM_5_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan5_fault', - (FAN_NUM_5_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan5_direction', + + thermal_sysfspath ={ + THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/14-0048/hwmon/hwmon*/temp1_input"], + THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/24-004b/hwmon/hwmon*/temp1_input"], + THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/25-004a/hwmon/hwmon*/temp1_input"], + THERMAL_NUM_4_IDX: ["/sys/class/hwmon/hwmon1/temp1_input"], + } - (FAN_NUM_6_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan6_fault', - (FAN_NUM_6_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan6_direction', - } - - def _get_fan_to_device_node(self, fan_num, node_num): - return self._fan_to_device_node_mapping[(fan_num, node_num)] - - def _get_fan_node_val(self, fan_num, node_num): - if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: - logging.debug('GET. Parameter error. fan_num:%d', fan_num) - return None - - if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP: - logging.debug('GET. Parameter error. node_num:%d', node_num) + def _get_thermal_val(self, thermal_num): + if thermal_num < self.THERMAL_NUM_1_IDX or thermal_num > self.THERMAL_NUM_MAX: + logging.debug('GET. Parameter error. thermal_num, %d', thermal_num) return None - - device_path = self.get_fan_to_device_path(fan_num, node_num) - try: - val_file = open(device_path, 'r') - except IOError as e: - logging.error('GET. unable to open file: %s', str(e)) - return None - - content = val_file.readline().rstrip() - - if content == '': - logging.debug('GET. content is NULL. device_path:%s', device_path) - return None - - try: - val_file.close() - except: - logging.debug('GET. unable to close file. device_path:%s', device_path) - return None - - return int(content) - - def _set_fan_node_val(self, fan_num, node_num, val): - if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: - logging.debug('GET. Parameter error. fan_num:%d', fan_num) - return None - - if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP: - logging.debug('GET. Parameter error. node_num:%d', node_num) - return None - - content = str(val) - if content == '': - logging.debug('GET. content is NULL. device_path:%s', device_path) - return None - - device_path = self.get_fan_to_device_path(fan_num, node_num) - try: - val_file = open(device_path, 'w') - except IOError as e: - logging.error('GET. unable to open file: %s', str(e)) - return None - - val_file.write(content) - - try: - val_file.close() - except: - logging.debug('GET. unable to close file. device_path:%s', device_path) - return None - - return True - - def __init__(self): - fan_path = self.BASE_VAL_PATH - - for fan_num in range(self.FAN_NUM_1_IDX, self.FAN_NUM_ON_MAIN_BROAD+1): - for node_num in range(self.FAN_NODE_FAULT_IDX_OF_MAP, self.FAN_NODE_NUM_OF_MAP+1): - self._fan_to_device_path_mapping[(fan_num, node_num)] = fan_path.format( - self._fan_to_device_node_mapping[(fan_num, node_num)]) - - def get_num_fans(self): - return self.FAN_NUM_ON_MAIN_BROAD - - def get_idx_fan_start(self): - return self.FAN_NUM_1_IDX - - def get_num_nodes(self): - return self.FAN_NODE_NUM_OF_MAP - - def get_idx_node_start(self): - return self.FAN_NODE_FAULT_IDX_OF_MAP + device_path = self.get_thermal_path(thermal_num) + for filename in glob.glob(device_path): + try: + val_file = open(filename, 'r') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + content = val_file.readline().rstrip() + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + try: + val_file.close() + except: + logging.debug('GET. unable to close file. device_path:%s', device_path) + return None + + return int(content) + + return 0 - def get_size_node_map(self): - return len(self._fan_to_device_node_mapping) + def get_num_thermals(self): + return self.THERMAL_NUM_MAX def get_size_path_map(self): - return len(self._fan_to_device_path_mapping) - - def get_fan_to_device_path(self, fan_num, node_num): - return self._fan_to_device_path_mapping[(fan_num, node_num)] - - def get_fan_fault(self, fan_num): - return self._get_fan_node_val(fan_num, self.FAN_NODE_FAULT_IDX_OF_MAP) - - - def get_fan_dir(self, fan_num): - return self._get_fan_node_val(fan_num, self.FAN_NODE_DIR_IDX_OF_MAP) - - def get_fan_duty_cycle(self): - #duty_path = self.FAN_DUTY_PATH - try: - val_file = open(self.FAN_DUTY_PATH) - except IOError as e: - print "Error: unable to open file: %s" % str(e) - return False - - content = val_file.readline().rstrip() - val_file.close() - return int(content) + return len(self.thermal_sysfspath) - def set_fan_duty_cycle(self, val): - try: - fan_file = open(self.FAN_DUTY_PATH, 'r+') - except IOError as e: - print "Error: unable to open file: %s" % str(e) - return False - #val = ((val + 1 ) * 625 +75 ) / 100 - fan_file.write(str(val)) - fan_file.close() - return True - - def get_fanr_speed(self, fan_num): - return self._get_fan_node_val(fan_num, self.FANR_NODE_SPEED_IDX_OF_MAP) - - def get_fan_status(self, fan_num): - if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: - logging.debug('GET. Parameter error. fan_num, %d', fan_num) - return None - - if self.get_fan_fault(fan_num) is not None and self.get_fan_fault(fan_num) > 0: - logging.debug('GET. FAN fault. fan_num, %d', fan_num) - return False - - return True + def get_thermal_path(self, thermal_num): + return self.thermal_sysfspath[thermal_num][0] +def main(): + thermal = ThermalUtil() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/thermalutil.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/thermalutil.py index 3af7b3d7df5f..bd5530fd9035 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/thermalutil.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/thermalutil.py @@ -1,26 +1,22 @@ #!/usr/bin/env python +# Copyright (c) 2019 Edgecore Networks Corporation # -# Copyright (C) 2017 Accton Technology Corporation +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # -# This 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 CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. # -# 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. +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - # ------------------------------------------------------------------ # HISTORY: # mm/dd/yyyy (A.D.) -# 11/13/2017: Polly Hsu, Create -# 1/10/2018:Jostar modify for as7716_32x -# 12/03/2018:Jostar modify for as7726_32x thermal plan +# 10/24/2019:Jostar craete for as4630_54pe # ------------------------------------------------------------------ try: @@ -35,91 +31,60 @@ class ThermalUtil(object): """Platform-specific ThermalUtil class""" - THERMAL_NUM_MAX = 5 - THERMAL_NUM_1_IDX = 1 # 1_ON_MAIN_BROAD. LM75 - THERMAL_NUM_2_IDX = 2 # 2_ON_MAIN_BROAD. LM75 - THERMAL_NUM_3_IDX = 3 # 3_ON_MAIN_BROAD. LM75 - THERMAL_NUM_4_IDX = 4 # 4_ON_MAIN_BROAD. LM75 - THERMAL_NUM_5_IDX = 5 # 5_ON_MAIN_BROAD. LM75 + THERMAL_NUM_MAX = 4 + THERMAL_NUM_1_IDX = 1 + THERMAL_NUM_2_IDX = 2 + THERMAL_NUM_3_IDX = 3 + THERMAL_NUM_4_IDX = 4 """ Dictionary where key1 = thermal id index (integer) starting from 1 value = path to fan device file (string) """ - - _thermal_to_device_node_mapping = { - THERMAL_NUM_1_IDX: ['55', '48'], - THERMAL_NUM_2_IDX: ['55', '49'], - THERMAL_NUM_3_IDX: ['55', '4a'], - THERMAL_NUM_4_IDX: ['55', '4b'], - THERMAL_NUM_5_IDX: ['54', '4c'], - } + thermal_sysfspath ={ - THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/55-0048/hwmon/hwmon4/temp1_input"], - THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/55-0049/hwmon/hwmon5/temp1_input"], - THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/55-004a/hwmon/hwmon6/temp1_input"], - THERMAL_NUM_4_IDX: ["/sys/bus/i2c/devices/55-004b/hwmon/hwmon7/temp1_input"], - THERMAL_NUM_5_IDX: ["/sys/bus/i2c/devices/54-004c/hwmon/hwmon3/temp1_input"], + THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/14-0048/hwmon/hwmon*/temp1_input"], + THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/24-004b/hwmon/hwmon*/temp1_input"], + THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/25-004a/hwmon/hwmon*/temp1_input"], + THERMAL_NUM_4_IDX: ["/sys/class/hwmon/hwmon1/temp1_input"], } - - #def __init__(self): + def _get_thermal_val(self, thermal_num): if thermal_num < self.THERMAL_NUM_1_IDX or thermal_num > self.THERMAL_NUM_MAX: logging.debug('GET. Parameter error. thermal_num, %d', thermal_num) return None - device_path = self.get_thermal_to_device_path(thermal_num) - if(os.path.isfile(device_path)): - for filename in glob.glob(device_path): - try: - val_file = open(filename, 'r') - except IOError as e: - logging.error('GET. unable to open file: %s', str(e)) - return None + device_path = self.get_thermal_path(thermal_num) + for filename in glob.glob(device_path): + try: + val_file = open(filename, 'r') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None content = val_file.readline().rstrip() if content == '': logging.debug('GET. content is NULL. device_path:%s', device_path) return None try: - val_file.close() + val_file.close() except: logging.debug('GET. unable to close file. device_path:%s', device_path) return None + return int(content) - else: - print "No such device_path=%s"%device_path - return 0 + return 0 def get_num_thermals(self): return self.THERMAL_NUM_MAX - def get_idx_thermal_start(self): - return self.THERMAL_NUM_1_IDX - - def get_size_node_map(self): - return len(self._thermal_to_device_node_mapping) - def get_size_path_map(self): return len(self.thermal_sysfspath) - def get_thermal_to_device_path(self, thermal_num): + def get_thermal_path(self, thermal_num): return self.thermal_sysfspath[thermal_num][0] - def get_thermal_1_val(self): - return self._get_thermal_node_val(self.THERMAL_NUM_1_IDX) - - def get_thermal_2_val(self): - return self._get_thermal_node_val(self.THERMAL_NUM_2_IDX) - def get_thermal_temp(self): - return (self._get_thermal_node_val(self.THERMAL_NUM_1_IDX) + self._get_thermal_node_val(self.THERMAL_NUM_2_IDX) +self._get_thermal_node_val(self.THERMAL_NUM_3_IDX)) - def main(): thermal = ThermalUtil() - print "termal1=%d" %thermal._get_thermal_val(1) - print "termal2=%d" %thermal._get_thermal_val(2) - print "termal3=%d" %thermal._get_thermal_val(3) - print "termal4=%d" %thermal._get_thermal_val(4) - print "termal5=%d" %thermal._get_thermal_val(5) - + if __name__ == '__main__': - main() + main() \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_monitor.py index eca1eac6b216..6dbf5c2cc720 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_monitor.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_monitor.py @@ -1,25 +1,22 @@ #!/usr/bin/env python +# -*- coding: utf-8 -* +# Copyright (c) 2019 Edgecore Networks Corporation # -# Copyright (C) 2017 Accton Technology Corporation +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # -# This 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 CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. # -# 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 . - -# ------------------------------------------------------------------ +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +# # HISTORY: # mm/dd/yyyy (A.D.)# -# 4/20/2018: Jostar modify for as7726_32x -# 12/03/2018:Jostar modify for as7726_32x thermal plan +# 10/24/2019:Jostar create for as4630_54pe thermal plan # ------------------------------------------------------------------ try: @@ -32,11 +29,12 @@ import logging.config import logging.handlers import types - import time # this is only being used as part of the example - import traceback + import time + import traceback + import commands from tabulate import tabulate - from as7726_32x.fanutil import FanUtil - from as7726_32x.thermalutil import ThermalUtil + from as4630_54pe.fanutil import FanUtil + from as4630_54pe.thermalutil import ThermalUtil except ImportError as e: raise ImportError('%s - required module not found' % str(e)) @@ -48,25 +46,20 @@ global log_level -# Air Flow Front to Back : -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 <=38C : Keep 37.5%(0x04) Fan speed -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 38C : Change Fan speed from 37.5%(0x04) to 62.5%(0x08) -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 46C : Change Fan speed from 62.5%(0x08) to 100%(0x0E) -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 58C : Send alarm message -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 66C : Shut down system -# One Fan fail : Change Fan speed to 100%(0x0E) -# Air Flow Back to Front : -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 <=34C : Keep 37.5%(0x04) Fan speed -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 34C : Change Fan speed from 37.5%(0x04) to 62.5%(0x08) -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 44C : Change Fan speed from 62.5%(0x08) to 100%(0x0E) -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 59C : Send alarm message -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 67C : Shut down system -# One Fan fail: Change Fan speed to 100%(0x0E) -# sensor_LM75_CPU == sensor_LM75_4B - - + +# Temperature Policy +# If any fan fail , please set fan speed register to 16 +# The max value of fan speed register is 14 +# LM77(48)+LM75(4B)+LM75(4A) > 140, Set 10 +# LM77(48)+LM75(4B)+LM75(4A) > 150, Set 12 +# LM77(48)+LM75(4B)+LM75(4A) > 160, Set 14 +# LM77(48)+LM75(4B)+LM75(4A) < 140, Set 8 +# LM77(48)+LM75(4B)+LM75(4A) < 150, Set 10 +# LM77(48)+LM75(4B)+LM75(4A) < 160, Set 12 +# Reset DUT:LM77(48)>=70C +# class switch(object): def __init__(self, value): self.value = value @@ -87,13 +80,13 @@ def match(self, *args): else: return False - -fan_policy_state=1 +fan_policy_state=0 fan_fail=0 alarm_state = 0 #0->default or clear, 1-->alarm detect test_temp = 0 -test_temp_list = [0, 0, 0, 0, 0, 0] +test_temp_list = [0, 0, 0] temp_test_data=0 +test_temp_revert=0 # Make a class we can use to capture stdout and sterr in the log class device_monitor(object): # static temp var @@ -124,119 +117,71 @@ def __init__(self, log_file, log_level): sys_handler = handler = logging.handlers.SysLogHandler(address = '/dev/log') sys_handler.setLevel(logging.WARNING) logging.getLogger('').addHandler(sys_handler) - - #logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) def get_state_from_fan_policy(self, temp, policy): state=0 - - logging.debug('temp=%d', temp) for i in range(0, len(policy)): - #logging.debug('policy[%d][0]=%d, policy[%d][1]=%d, policy[%d][2]=%d', i,policy[i][0],i, policy[i][1], i, policy[i][2]) - if temp > policy[i][2]: - if temp <= policy[i][3]: + if (temp > policy[i][2]): #temp_down + if temp <= policy[i][3]: #temp_up state =i - logging.debug ('temp=%d >= policy[%d][2]=%d, temp=%d < policy[%d][3]=%d' , temp, i, policy[i][2], temp, i, policy[i][3]) - logging.debug ('fan_state=%d', state) - break - + return state - def manage_fans(self): - global fan_policy_state global fan_fail global test_temp global test_temp_list global alarm_state - global temp_test_data - - LEVEL_FAN_DEF=0 - LEVEL_FAN_MID=1 - LEVEL_FAN_MAX=2 - LEVEL_TEMP_HIGH=3 - LEVEL_TEMP_CRITICAL=4 - - - fan_policy_f2b = { - LEVEL_FAN_DEF: [38, 0x4, 0, 38000], - LEVEL_FAN_MID: [63, 0x6, 38000, 46000], - LEVEL_FAN_MAX: [100, 0xE, 46000, 58000], - LEVEL_TEMP_HIGH: [100, 0xE, 58000, 66000], - LEVEL_TEMP_CRITICAL: [100, 0xE, 58000, 200000], - } - fan_policy_b2f = { - LEVEL_FAN_DEF: [38, 0x4, 0, 34000], - LEVEL_FAN_MID: [63, 0x8, 34000, 44000], - LEVEL_FAN_MAX: [100, 0xE, 44000, 59000], - LEVEL_TEMP_HIGH: [100, 0xE, 59000, 67000], - LEVEL_TEMP_CRITICAL: [100, 0xE, 59000, 200000], + global temp_test_data + global test_temp_revert + LEVEL_FAN_MIN=0 + LEVEL_FAN_NORMAL=1 + LEVEL_FAN_MID=2 + LEVEL_FAN_HIGH=3 + LEVEL_TEMP_CRITICAL=4 + fan_policy = { + LEVEL_FAN_MIN: [50, 8, 0, 140000], + LEVEL_FAN_NORMAL: [62, 10, 140000, 150000], + LEVEL_FAN_MID: [75, 12, 150000, 160000], + LEVEL_FAN_HIGH: [88, 14, 160000, 240000], + LEVEL_TEMP_CRITICAL: [100, 16, 240000, 300000], } - - fan_policy = fan_policy_f2b - + temp = [0, 0 , 0] + temp_fail=0 thermal = ThermalUtil() fan = FanUtil() - fan_dir=fan.get_fan_dir(1) - if fan_dir == 1: - fan_dri=1 #something wrong, set fan_dir to default val - else: - fan_policy = fan_policy_b2f + ori_duty_cycle=fan.get_fan_duty_cycle() + new_duty_cycle=0 - ori_pwm=fan.get_fan_duty_cycle() - new_pwm=0 - logging.debug('fan_dir=%d, ori_pwm=%d', fan_dir, ori_pwm) - logging.debug('test_temp=%d', test_temp) - if test_temp==0: - temp1 = thermal._get_thermal_val(1) - temp2 = thermal._get_thermal_val(2) - temp3 = thermal._get_thermal_val(3) - temp4 = thermal._get_thermal_val(4) - temp5 = thermal._get_thermal_val(5) + if test_temp==0: + for i in range(0,3): + temp[i]=thermal._get_thermal_val(i+1) + if temp[i]==0 or temp[i]==None: + temp_fail=1 + logging.warning("Get temp-%d fail", i); + return False else: - temp1 = test_temp_list[0] - temp2 = test_temp_list[1] - temp3 = test_temp_list[2] - temp4 = test_temp_list[3] - temp5 = test_temp_list[4] + if test_temp_revert==0: + temp_test_data=temp_test_data+2000 + else: + temp_test_data=temp_test_data-2000 + + for i in range(0,3): + temp[i]=test_temp_list[i]+temp_test_data fan_fail=0 - - if temp3==0: - temp_get=50000 # if one detect sensor is fail or zero, assign temp=50000, let fan to 75% - logging.debug('lm75_49 detect fail, so set temp_get=50000, let fan to 75%') - elif temp4==0: - temp_get=50000 # if one detect sensor is fail or zero, assign temp=50000, let fan to 75% - logging.debug('lm75_4b detect fail, so set temp_get=50000, let fan to 75%') - else: - temp_get= (temp3 + temp4)/2 # Use (sensor_LM75_4a + sensor_LM75_4b) /2 - ori_state=fan_policy_state - - #temp_test_data=temp_test_data+1000 - #temp_get = temp_get + temp_test_data - #print "Unit test:temp_get=%d"%temp_get - - fan_policy_state=self.get_state_from_fan_policy(temp_get, fan_policy) - #print "temp3=%d"%temp3 - #print "temp4=%d"%temp4 - #print "temp_get=%d"%temp_get - - logging.debug('lm75_48=%d, lm75_49=%d, lm75_4a=%d, lm_4b=%d, lm_4b=%d', temp1,temp2,temp3,temp4,temp5) - logging.debug('ori_state=%d, fan_policy_state=%d', ori_state, fan_policy_state) - new_pwm = fan_policy[fan_policy_state][0] - if fan_fail==0: - logging.debug('new_fan_cycle=%d', new_pwm) - - if fan_fail==0: - if new_pwm!=ori_pwm: - fan.set_fan_duty_cycle(new_pwm) - logging.info('Set fan speed from %d to %d', ori_pwm, new_pwm) + + temp_val=0 + for i in range(0,3): + if temp[i]==None: + break + temp_val+=temp[i] #Check Fan status for i in range (fan.FAN_NUM_1_IDX, fan.FAN_NUM_ON_MAIN_BROAD+1): if fan.get_fan_status(i)==0: new_pwm=100 - logging.debug('fan_%d fail, set pwm to 100',i) + logging.warning('Fan_%d fail, set pwm to 100',i) if test_temp==0: fan_fail=1 fan.set_fan_duty_cycle(new_pwm) @@ -244,59 +189,38 @@ def manage_fans(self): else: fan_fail=0 - #if fan_policy_state == ori_state: - # return True - #else: - new_state = fan_policy_state + ori_state=fan_policy_state + fan_policy_state=self.get_state_from_fan_policy(temp_val, fan_policy) - #logging.warning('Temperature high alarm testing') - if ori_state==LEVEL_FAN_DEF: - if new_state==LEVEL_TEMP_HIGH: + if fan_policy_state > LEVEL_TEMP_CRITICAL or fan_policy_state < LEVEL_FAN_MIN: + logging.error("Get error fan current_state\n"); + return 0 + + #Decision : Decide new fan pwm percent. + if fan_fail==0 and ori_duty_cycle!=fan_policy[fan_policy_state][0]: + new_duty_cycle = fan_policy[fan_policy_state][0]; + fan.set_fan_duty_cycle(new_duty_cycle) + + if temp[0] >= 70000: #LM75-48 + #critical case*/ + logging.critical('Alarm-Critical for temperature critical is detected, reset DUT') + cmd_str="i2cset -y -f 3 0x60 0x4 0xE4" + time.sleep(2); + status, output = commands.getstatusoutput(cmd_str) + + #logging.debug('ori_state=%d, current_state=%d, temp_val=%d\n\n',ori_state, fan_policy_state, temp_val) + + if ori_state < LEVEL_FAN_HIGH: + if fan_policy_state >= LEVEL_FAN_HIGH: if alarm_state==0: logging.warning('Alarm for temperature high is detected') - alarm_state=1 - if new_state==LEVEL_TEMP_CRITICAL: - logging.critical('Alarm for temperature critical is detected, reboot DUT') - time.sleep(2) - os.system('reboot') - if ori_state==LEVEL_FAN_MID: - if new_state==LEVEL_TEMP_HIGH: - if alarm_state==0: - logging.warning('Alarm for temperature high is detected') - alarm_state=1 - if new_state==LEVEL_TEMP_CRITICAL: - logging.critical('Alarm for temperature critical is detected') - time.sleep(2) - os.system('reboot') - if ori_state==LEVEL_FAN_MAX: - if new_state==LEVEL_TEMP_HIGH: - if alarm_state==0: - logging.warning('Alarm for temperature high is detected') - alarm_state=1 - if new_state==LEVEL_TEMP_CRITICAL: - logging.critical('Alarm for temperature critical is detected') - time.sleep(2) - os.system('reboot') + alarm_state=1 + + if fan_policy_state < LEVEL_FAN_MID: if alarm_state==1: - if temp_get < (fan_policy[3][0] - 5000): #below 65 C, clear alarm - logging.warning('Alarm for temperature high is cleared') - alarm_state=0 - if ori_state==LEVEL_TEMP_HIGH: - if new_state==LEVEL_TEMP_CRITICAL: - logging.critical('Alarm for temperature critical is detected') - time.sleep(2) - os.system('reboot') - if new_state <= LEVEL_FAN_MID: - logging.warning('Alarm for temperature high is cleared') + logging.info('Alarm for temperature high is cleared') alarm_state=0 - if new_state <= LEVEL_FAN_MAX: - if temp_get < (fan_policy[3][0] - 5000): #below 65 C, clear alarm - logging.warning('Alarm for temperature high is cleared') - alarm_state=0 - if ori_state==LEVEL_TEMP_CRITICAL: - if new_state <= LEVEL_FAN_MAX: - logging.warning('Alarm for temperature critical is cleared') - + return True def main(argv): @@ -319,12 +243,12 @@ def main(argv): log_file = arg if sys.argv[1]== '-t': - if len(sys.argv)!=7: - print "temp test, need input six temp" + if len(sys.argv)!=5: + print "temp test, need input three temp" return 0 i=0 - for x in range(2, 7): + for x in range(2, 5): test_temp_list[i]= int(sys.argv[x])*1000 i=i+1 test_temp = 1 @@ -332,14 +256,14 @@ def main(argv): print test_temp_list fan = FanUtil() - fan.set_fan_duty_cycle(38) - print "set default fan speed to 37.5%" + fan.set_fan_duty_cycle(50) + print "set default fan speed to 50%" monitor = device_monitor(log_file, log_level) # Loop forever, doing something useful hopefully: while True: - #monitor.manage_fans() - time.sleep(5) + monitor.manage_fans() + time.sleep(10) #10sec if __name__ == '__main__': main(sys.argv[1:]) - + diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/control b/platform/broadcom/sonic-platform-modules-accton/debian/control index 2b3c1af3d80f..0d333691c017 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/control +++ b/platform/broadcom/sonic-platform-modules-accton/debian/control @@ -68,7 +68,6 @@ Description: kernel modules for platform devices such as fan, led, sfp Package: sonic-platform-accton-as5835-54t Architecture: amd64 Description: kernel modules for platform devices such as fan, led, sfp - Package: sonic-platform-accton-as7312-54xs Architecture: amd64 Description: kernel modules for platform devices such as fan, led, sfp From 2e61e14bb3f39f5d2e58137f697c7a8d55593a16 Mon Sep 17 00:00:00 2001 From: Pradchaya Phucharoen Date: Fri, 8 Nov 2019 13:02:53 +0700 Subject: [PATCH 147/278] [devices] Celeatica Silverstone add IPMI platform sensor read. (#3591) * [platform/broadcom] Celeatica Silverstone add IPMI platform sensor read. * [platform_sensors] Silverstone update temperature sensor description --- .../platform-modules-silverstone.install | 2 + .../silverstone/scripts/platform_sensors.py | 173 ++++++++++++++++++ .../silverstone/scripts/sensors | 11 ++ 3 files changed, 186 insertions(+) create mode 100755 platform/broadcom/sonic-platform-modules-cel/silverstone/scripts/platform_sensors.py create mode 100755 platform/broadcom/sonic-platform-modules-cel/silverstone/scripts/sensors diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install index 03e13544b8b1..67b433ced85f 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone.install @@ -1,3 +1,5 @@ +silverstone/scripts/sensors usr/bin +silverstone/scripts/platform_sensors.py usr/local/bin silverstone/cfg/silverstone-modules.conf etc/modules-load.d silverstone/systemd/platform-modules-silverstone.service lib/systemd/system silverstone/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_silverstone-r0 diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-cel/silverstone/scripts/platform_sensors.py new file mode 100755 index 000000000000..186ee6c5450e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/scripts/platform_sensors.py @@ -0,0 +1,173 @@ +#!/usr/bin/python +# +# Silverstone platform sensors. This script get the sensor data from BMC +# using ipmitool and display them in lm-sensor alike format. +# +# The following data is support: +# 1. Temperature sensors +# 2. PSUs +# 3. Fan trays + +import sys +import logging +import subprocess + +IPMI_SDR_CMD = "ipmitool sdr elist" +MAX_NUM_FANS = 7 +MAX_NUM_PSUS = 2 + + +def ipmi_sensor_dump(cmd): + ''' Execute ipmitool command return dump output + exit if any error occur. + ''' + sensor_dump = '' + try: + sensor_dump = subprocess.check_output(cmd, shell=True) + except subprocess.CalledProcessError as e: + logging.error('Error! Failed to execute: {}'.format(cmd)) + sys.exit(1) + return sensor_dump + +def get_reading_by_name(sensor_name, sdr_elist_dump): + ''' + Search for the match sensor name, return sensor + reading value and unit, return object epmtry string + if search not match. + + The output of sensor dump: + TEMP_FAN_U52 | 00h | ok | 7.1 | 31 degrees C + TEMP_FAN_U17 | 01h | ok | 7.1 | 27 degrees C + TEMP_SW_U52 | 02h | ok | 7.1 | 30 degrees C + Fan2_Status | 07h | ok | 29.2 | Present + Fan2_Front | 0Eh | ok | 29.2 | 12000 RPM + Fan2_Rear | 46h | ok | 29.2 | 14700 RPM + PSU2_Status | 39h | ok | 10.2 | Presence detected + PSU2_Fan | 3Dh | ok | 10.2 | 16000 RPM + PSU2_VIn | 3Ah | ok | 10.2 | 234.30 Volts + PSU2_CIn | 3Bh | ok | 10.2 | 0.80 Amps + ''' + found = '' + + for line in sdr_elist_dump.split("\n"): + if sensor_name in line: + found = line.strip() + break + + if not found: + logging.error('Cannot find sensor name:' + sensor_name) + + else: + try: + found = found.split('|')[4] + except IndexError: + logging.error('Cannot get sensor data of:' + sensor_name) + + logging.basicConfig(level=logging.DEBUG) + return found + + +def read_temperature_sensors(ipmi_sdr_elist): + + sensor_list = [ + ('TEMP_FAN_U52', 'Fan Tray Middle Temp'), + ('TEMP_FAN_U17', 'Fan Tray Right Temp'), + ('TEMP_SW_U52', 'Switchboard Left Inlet Temp'), + ('TEMP_SW_U16', 'Switchboard Right Inlet Temp'), + ('TEMP_BB_U3', 'Baseboard Temp'), + ('TEMP_CPU', 'CPU Internal Temp'), + ('TEMP_SW_Internal', 'ASIC Internal Temp'), + ('SW_U04_Temp', 'IR3595 Chip Left Temp'), + ('SW_U14_Temp', 'IR3595 Chip Right Temp'), + ('SW_U4403_Temp', 'IR3584 Chip Temp'), + ] + + output = '' + sensor_format = '{0:{width}}{1}\n' + # Find max length of sensor calling name + max_name_width = max(len(sensor[1]) for sensor in sensor_list) + + output += "Temperature Sensors\n" + output += "Adapter: IPMI adapter\n" + for sensor in sensor_list: + reading = get_reading_by_name(sensor[0],ipmi_sdr_elist) + output += sensor_format.format('{}:'.format(sensor[1]), + reading, + width=str(max_name_width+1)) + output += '\n' + return output + + +def read_fan_sensors(num_fans, ipmi_sdr_elist): + + sensor_list = [ + ('Fan{}_Status', 'Status'), + ('Fan{}_Front', 'Fan {} front'), + ('Fan{}_Rear', 'Fan {} rear'), + ] + + output = '' + sensor_format = '{0:{width}}{1}\n' + # Find max length of sensor calling name + max_name_width = max(len(sensor[1]) for sensor in sensor_list) + + output += "Fan Trays\n" + output += "Adapter: IPMI adapter\n" + for fan_num in range(1, num_fans+1): + for sensor in sensor_list: + ipmi_sensor_name = sensor[0].format(fan_num) + display_sensor_name = sensor[1].format(fan_num) + reading = get_reading_by_name(ipmi_sensor_name, ipmi_sdr_elist) + output += sensor_format.format('{}:'.format(display_sensor_name), + reading, + width=str(max_name_width+1)) + output += '\n' + return output + + +def read_psu_sensors(num_psus, ipmi_sdr_elist): + + sensor_list = [ + ('PSU{}_Status', 'PSU {} Status'), + ('PSU{}_Fan', 'PSU {} Fan'), + ('PSU{}_VIn', 'PSU {} Input Voltag'), + ('PSU{}_CIn', 'PSU {} Input Current'), + ('PSU{}_PIn', 'PSU {} Input Power'), + ('PSU{}_Temp1', 'PSU {} Temp1'), + ('PSU{}_Temp2', 'PSU {} Temp2'), + ('PSU{}_VOut', 'PSU {} Output Voltag'), + ('PSU{}_COut', 'PSU {} Output Current'), + ('PSU{}_POut', 'PSU {} Output Power'), + ] + + output = '' + sensor_format = '{0:{width}}{1}\n' + # Find max length of sensor calling name + max_name_width = max(len(sensor[1]) for sensor in sensor_list) + + output += "PSU\n" + output += "Adapter: IPMI adapter\n" + for psu_num in range(1, num_psus+1): + for sensor in sensor_list: + ipmi_sensor_name = sensor[0].format(psu_num) + display_sensor_name = sensor[1].format(psu_num) + reading = get_reading_by_name(ipmi_sensor_name, ipmi_sdr_elist) + output += sensor_format.format('{}:'.format(display_sensor_name), + reading, + width=str(max_name_width+1)) + output += '\n' + return output + + +def main(): + output_string = '' + + ipmi_sdr_elist = ipmi_sensor_dump(IPMI_SDR_CMD) + output_string += read_temperature_sensors(ipmi_sdr_elist) + output_string += read_psu_sensors(MAX_NUM_PSUS, ipmi_sdr_elist) + output_string += read_fan_sensors(MAX_NUM_FANS, ipmi_sdr_elist) + print(output_string) + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/scripts/sensors b/platform/broadcom/sonic-platform-modules-cel/silverstone/scripts/sensors new file mode 100755 index 000000000000..405d92c2b3cc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/scripts/sensors @@ -0,0 +1,11 @@ +#!/bin/bash + +DOCKER_EXEC_FLAGS="i" + +# Determine whether stdout is on a terminal +if [ -t 1 ] ; then + DOCKER_EXEC_FLAGS+="t" +fi + +docker exec -$DOCKER_EXEC_FLAGS pmon sensors "$@" +docker exec -$DOCKER_EXEC_FLAGS pmon platform_sensors.py "$@" From e877e471c0ff4145ead779ab0be85ca10b9f3242 Mon Sep 17 00:00:00 2001 From: Guohan Lu Date: Sat, 9 Nov 2019 05:03:07 +0000 Subject: [PATCH 148/278] [devices]: fix debian/control for accton platform modules the bug was introduced by commit ac2908ef035f2dfc278a61d7bb4c631b92c1aa67 Signed-off-by: Guohan Lu --- platform/broadcom/sonic-platform-modules-accton/debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/control b/platform/broadcom/sonic-platform-modules-accton/debian/control index 0d333691c017..2b3c1af3d80f 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/control +++ b/platform/broadcom/sonic-platform-modules-accton/debian/control @@ -68,6 +68,7 @@ Description: kernel modules for platform devices such as fan, led, sfp Package: sonic-platform-accton-as5835-54t Architecture: amd64 Description: kernel modules for platform devices such as fan, led, sfp + Package: sonic-platform-accton-as7312-54xs Architecture: amd64 Description: kernel modules for platform devices such as fan, led, sfp From bec60d1506020d4b943ac629beb81e91bbf6efbf Mon Sep 17 00:00:00 2001 From: Andriy Kokhan <43479230+akokhan@users.noreply.github.com> Date: Sat, 9 Nov 2019 07:43:18 +0200 Subject: [PATCH 149/278] [pmon][barefoot] Added pmon daemons control file (#3728) Signed-off-by: Andriy Kokhan --- .../pmon_daemon_control.json | 6 ++++++ .../pmon_daemon_control.json | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 device/barefoot/x86_64-accton_wedge100bf_32x-r0/pmon_daemon_control.json create mode 100644 device/barefoot/x86_64-accton_wedge100bf_65x-r0/pmon_daemon_control.json diff --git a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/pmon_daemon_control.json b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..3a76f2fdd0e4 --- /dev/null +++ b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/pmon_daemon_control.json @@ -0,0 +1,6 @@ +{ + "skip_ledd": true, + "skip_xcvrd": false, + "skip_psud": false, + "skip_syseepromd": false +} diff --git a/device/barefoot/x86_64-accton_wedge100bf_65x-r0/pmon_daemon_control.json b/device/barefoot/x86_64-accton_wedge100bf_65x-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..3a76f2fdd0e4 --- /dev/null +++ b/device/barefoot/x86_64-accton_wedge100bf_65x-r0/pmon_daemon_control.json @@ -0,0 +1,6 @@ +{ + "skip_ledd": true, + "skip_xcvrd": false, + "skip_psud": false, + "skip_syseepromd": false +} From 96fffd883d2ecb489fd360e3ff78cd7832b01cab Mon Sep 17 00:00:00 2001 From: Ying Xie Date: Fri, 8 Nov 2019 21:44:25 -0800 Subject: [PATCH 150/278] Revert "[services] make snmp.timer work again and delay telemetry.service (#3657)" (#3729) This reverts commit d346cb3898d58aeb16c22a66a79b117ab267d4b8. --- files/build_templates/snmp.service.j2 | 2 ++ files/build_templates/sonic_debian_extension.j2 | 6 ++---- files/build_templates/telemetry.service.j2 | 2 ++ files/build_templates/telemetry.timer | 9 --------- 4 files changed, 6 insertions(+), 13 deletions(-) delete mode 100644 files/build_templates/telemetry.timer diff --git a/files/build_templates/snmp.service.j2 b/files/build_templates/snmp.service.j2 index 9d419b8e0dfd..310048e68beb 100644 --- a/files/build_templates/snmp.service.j2 +++ b/files/build_templates/snmp.service.j2 @@ -14,3 +14,5 @@ ExecStop=/usr/bin/{{docker_container_name}}.sh stop Restart=always RestartSec=30 +[Install] +WantedBy=multi-user.target swss.service diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index bd1dfccd28dc..f5a734b3a273 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -317,7 +317,7 @@ EOF ## Bind docker path if [[ $CONFIGURED_ARCH == armhf || $CONFIGURED_ARCH == arm64 ]]; then sudo mkdir -p $FILESYSTEM_ROOT/dockerfs - sudo mount --bind dockerfs $FILESYSTEM_ROOT/dockerfs + sudo mount --bind dockerfs $FILESYSTEM_ROOT/dockerfs fi {% if installer_images.strip() -%} @@ -334,7 +334,7 @@ sudo LANG=C chroot $FILESYSTEM_ROOT docker $SONIC_NATIVE_DOCKERD_FOR_DOCKERFS ta {% endif %} {% endfor %} if [[ $CONFIGURED_ARCH == armhf || $CONFIGURED_ARCH == arm64 ]]; then - sudo umount $FILESYSTEM_ROOT/dockerfs + sudo umount $FILESYSTEM_ROOT/dockerfs sudo rm -fr $FILESYSTEM_ROOT/dockerfs sudo kill -9 `sudo $SONIC_NATIVE_DOCKERD_FOR_DOCKERFS_PID` || true else @@ -362,8 +362,6 @@ sudo LANG=C cp $SCRIPTS_DIR/syncd.sh $FILESYSTEM_ROOT/usr/local/bin/syncd.sh # It implements delayed start of services sudo cp $BUILD_TEMPLATES/snmp.timer $FILESYSTEM_ROOT/etc/systemd/system/ sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable snmp.timer -sudo cp $BUILD_TEMPLATES/telemetry.timer $FILESYSTEM_ROOT/etc/systemd/system/ -sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable telemetry.timer sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get purge -y python-dev sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get clean -y diff --git a/files/build_templates/telemetry.service.j2 b/files/build_templates/telemetry.service.j2 index 4d653e42327d..2e7e45218df2 100644 --- a/files/build_templates/telemetry.service.j2 +++ b/files/build_templates/telemetry.service.j2 @@ -10,3 +10,5 @@ ExecStartPre=/usr/bin/{{docker_container_name}}.sh start ExecStart=/usr/bin/{{docker_container_name}}.sh wait ExecStop=/usr/bin/{{docker_container_name}}.sh stop +[Install] +WantedBy=multi-user.target diff --git a/files/build_templates/telemetry.timer b/files/build_templates/telemetry.timer deleted file mode 100644 index e08f1c09eac6..000000000000 --- a/files/build_templates/telemetry.timer +++ /dev/null @@ -1,9 +0,0 @@ -[Unit] -Description=Delays telemetry container until SONiC has started - -[Timer] -OnBootSec=3min 30 sec -Unit=telemetry.service - -[Install] -WantedBy=timers.target From b2e15f2318d2cb26bfc166bcf62e73614720597a Mon Sep 17 00:00:00 2001 From: simonJi2018 <37395146+simonJi2018@users.noreply.github.com> Date: Sat, 9 Nov 2019 13:49:46 +0800 Subject: [PATCH 151/278] [device/accton] Platform2.0 API Implementation for accton as7116-54x (#3622) Implement Component platform2.0 API for accton as7116-54x platform --- .../buffers.json.j2 | 0 .../buffers_defaults_t0.j2 | 142 +-- .../buffers_defaults_t1.j2 | 142 +-- .../Accton-AS7116-54X-R0/led.bin | Bin 0 -> 748 bytes .../Accton-AS7116-54X-R0/nephos_dac.dsh | 414 ++++++ .../nephos_opt.dsh | 187 +-- .../pg_profile_lookup.ini | 0 .../port_config.ini | 0 .../port_config.nps | 1 + .../proc_init.nps | 0 .../qos.json.j2 | 0 .../Accton-AS7116-54X-R0/sai.profile | 2 + .../Accton-AS7116-54X/nephos_dac.dsh | 404 ------ .../Accton-AS7116-54X/sai.profile | 2 - .../x86_64-accton_as7116_54x-r0/default_sku | 2 +- .../x86_64-accton_as7116_54x-r0/fancontrol | 2 +- .../plugins/eeprom.py | 2 +- .../plugins/sfputil.py | 3 +- .../x86_64-accton_as7116_54x-r0/sensors.conf | 2 +- .../sonic_platform/__init__.py | 2 + .../sonic_platform/chassis.py | 174 +++ .../sonic_platform/component.py | 83 ++ .../sonic_platform/eeprom.py | 112 ++ .../sonic_platform/fan.py | 165 +++ .../sonic_platform/platform.py | 20 + .../sonic_platform/psu.py | 102 ++ .../sonic_platform/sfp.py | 1133 +++++++++++++++++ .../as7116-54x/classes/__init__.py | 0 .../as7116-54x/classes/fanutil.py | 0 .../as7116-54x/classes/thermalutil.py | 0 .../service/as7116-platform-init.service | 3 +- .../service/platform_api/platform_api_mgnt.sh | 41 + .../as7116-54x/setup.py | 43 +- .../as7116-54x/utils/accton_as7116_util.py | 309 ++--- .../debian/rules | 74 +- .../sonic-platform-accton-as7116-54x.install | 4 + .../sonic-platform-accton-as7116-54x.postinst | 5 + 37 files changed, 2710 insertions(+), 865 deletions(-) rename device/accton/x86_64-accton_as7116_54x-r0/{Accton-AS7116-54X => Accton-AS7116-54X-R0}/buffers.json.j2 (100%) rename device/accton/x86_64-accton_as7116_54x-r0/{Accton-AS7116-54X => Accton-AS7116-54X-R0}/buffers_defaults_t0.j2 (96%) rename device/accton/x86_64-accton_as7116_54x-r0/{Accton-AS7116-54X => Accton-AS7116-54X-R0}/buffers_defaults_t1.j2 (96%) create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/led.bin create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/nephos_dac.dsh rename device/accton/x86_64-accton_as7116_54x-r0/{Accton-AS7116-54X => Accton-AS7116-54X-R0}/nephos_opt.dsh (77%) rename device/accton/x86_64-accton_as7116_54x-r0/{Accton-AS7116-54X => Accton-AS7116-54X-R0}/pg_profile_lookup.ini (100%) rename device/accton/x86_64-accton_as7116_54x-r0/{Accton-AS7116-54X => Accton-AS7116-54X-R0}/port_config.ini (100%) rename device/accton/x86_64-accton_as7116_54x-r0/{Accton-AS7116-54X => Accton-AS7116-54X-R0}/port_config.nps (99%) rename device/accton/x86_64-accton_as7116_54x-r0/{Accton-AS7116-54X => Accton-AS7116-54X-R0}/proc_init.nps (100%) rename device/accton/x86_64-accton_as7116_54x-r0/{Accton-AS7116-54X => Accton-AS7116-54X-R0}/qos.json.j2 (100%) create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/sai.profile delete mode 100644 device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/nephos_dac.dsh delete mode 100644 device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/sai.profile create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/__init__.py create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/chassis.py create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/component.py create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/eeprom.py create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/fan.py create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/platform.py create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/psu.py create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/sfp.py delete mode 100644 platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/__init__.py delete mode 100644 platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/fanutil.py delete mode 100644 platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/thermalutil.py create mode 100755 platform/nephos/sonic-platform-modules-accton/as7116-54x/service/platform_api/platform_api_mgnt.sh create mode 100644 platform/nephos/sonic-platform-modules-accton/debian/sonic-platform-accton-as7116-54x.install create mode 100644 platform/nephos/sonic-platform-modules-accton/debian/sonic-platform-accton-as7116-54x.postinst diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/buffers.json.j2 b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/buffers.json.j2 similarity index 100% rename from device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/buffers.json.j2 rename to device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/buffers.json.j2 diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/buffers_defaults_t0.j2 b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/buffers_defaults_t0.j2 similarity index 96% rename from device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/buffers_defaults_t0.j2 rename to device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/buffers_defaults_t0.j2 index 300fecdb3555..a47675b8dfa4 100644 --- a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/buffers_defaults_t0.j2 +++ b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/buffers_defaults_t0.j2 @@ -1,72 +1,72 @@ -{% 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, 48) %} - {%- if PORT_ALL.append("Ethernet%d" % (port_idx)) %}{%- endif %} - {%- endfor %} - {%- for port_idx in range(48, 54) %} - {%- if PORT_ALL.append("Ethernet%d" % (48 + (port_idx-48) * 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": "static" - }, - "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_lossy_profile": { - "pool":"[BUFFER_POOL|egress_lossy_pool]", - "size":"3584", - "dynamic_th":"-4" - } - }, -{%- endmacro %} - -{# the typo of generate_pg_profils dued to buffers_config.j2 #} -{# Default, we do not bind any buffer profiles. #} -{%- macro generate_pg_profils(port_names) %} - "BUFFER_PG": { - } -{%- endmacro %} - -{# Default, we do not bind any buffer profiles. #} -{%- macro generate_queue_buffers(port_names) %} - "BUFFER_QUEUE": { - } +{% 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, 48) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx)) %}{%- endif %} + {%- endfor %} + {%- for port_idx in range(48, 54) %} + {%- if PORT_ALL.append("Ethernet%d" % (48 + (port_idx-48) * 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": "static" + }, + "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_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"3584", + "dynamic_th":"-4" + } + }, +{%- endmacro %} + +{# the typo of generate_pg_profils dued to buffers_config.j2 #} +{# Default, we do not bind any buffer profiles. #} +{%- macro generate_pg_profils(port_names) %} + "BUFFER_PG": { + } +{%- endmacro %} + +{# Default, we do not bind any buffer profiles. #} +{%- macro generate_queue_buffers(port_names) %} + "BUFFER_QUEUE": { + } {%- endmacro %} \ No newline at end of file diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/buffers_defaults_t1.j2 b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/buffers_defaults_t1.j2 similarity index 96% rename from device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/buffers_defaults_t1.j2 rename to device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/buffers_defaults_t1.j2 index 300fecdb3555..a47675b8dfa4 100644 --- a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/buffers_defaults_t1.j2 +++ b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/buffers_defaults_t1.j2 @@ -1,72 +1,72 @@ -{% 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, 48) %} - {%- if PORT_ALL.append("Ethernet%d" % (port_idx)) %}{%- endif %} - {%- endfor %} - {%- for port_idx in range(48, 54) %} - {%- if PORT_ALL.append("Ethernet%d" % (48 + (port_idx-48) * 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": "static" - }, - "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_lossy_profile": { - "pool":"[BUFFER_POOL|egress_lossy_pool]", - "size":"3584", - "dynamic_th":"-4" - } - }, -{%- endmacro %} - -{# the typo of generate_pg_profils dued to buffers_config.j2 #} -{# Default, we do not bind any buffer profiles. #} -{%- macro generate_pg_profils(port_names) %} - "BUFFER_PG": { - } -{%- endmacro %} - -{# Default, we do not bind any buffer profiles. #} -{%- macro generate_queue_buffers(port_names) %} - "BUFFER_QUEUE": { - } +{% 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, 48) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx)) %}{%- endif %} + {%- endfor %} + {%- for port_idx in range(48, 54) %} + {%- if PORT_ALL.append("Ethernet%d" % (48 + (port_idx-48) * 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": "static" + }, + "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_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"3584", + "dynamic_th":"-4" + } + }, +{%- endmacro %} + +{# the typo of generate_pg_profils dued to buffers_config.j2 #} +{# Default, we do not bind any buffer profiles. #} +{%- macro generate_pg_profils(port_names) %} + "BUFFER_PG": { + } +{%- endmacro %} + +{# Default, we do not bind any buffer profiles. #} +{%- macro generate_queue_buffers(port_names) %} + "BUFFER_QUEUE": { + } {%- endmacro %} \ No newline at end of file diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/led.bin b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/led.bin new file mode 100644 index 0000000000000000000000000000000000000000..bb4426fb59f43f29173af5c0cd272234cb0abe21 GIT binary patch literal 748 zcmZ9}xlRIM6oAp+M2*FO0}L?06POGzfIIHC?mODLG%k%xBNE@-Q+tz}^HsOGVIhPt z8^TI#=R#QKGMBi-MJ{s4A=kOiHLh`$tK8-`x46YkZgPVg+~+>`xW`@Ya)&#daKaz{ zaLh5k`OPnW@spqY;0NFN&NsgCm9Ko^3!nMSCqD6!k9^<*?|IKV-tm^V9C5@O-td~& zyy6uvdC3c2@SNv7;~7tR$`hXOn8!Tg5f6FD10L{q#vlGoG!;TL9YV~Q2@|GFnKNg` zjPt2=Yu?SGF6yE#=z=cjNJl!-6VY2Uf$r7LGYu5;bhUES3k-O(N0)@|L^ Jna*^k{{TSXGe`gc literal 0 HcmV?d00001 diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/nephos_dac.dsh b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/nephos_dac.dsh new file mode 100644 index 000000000000..42102053c3fb --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/nephos_dac.dsh @@ -0,0 +1,414 @@ +init start stage unit=0 low-level +init set port-map unit=0 port=0 eth-macro=2 lane=0 max-speed=25g active=true +init set port-map unit=0 port=1 eth-macro=2 lane=1 max-speed=25g active=true +init set port-map unit=0 port=2 eth-macro=2 lane=2 max-speed=25g active=true +init set port-map unit=0 port=3 eth-macro=2 lane=3 max-speed=25g active=true +init set port-map unit=0 port=4 eth-macro=3 lane=0 max-speed=25g active=true +init set port-map unit=0 port=5 eth-macro=3 lane=1 max-speed=25g active=true +init set port-map unit=0 port=6 eth-macro=3 lane=2 max-speed=25g active=true +init set port-map unit=0 port=7 eth-macro=3 lane=3 max-speed=25g active=true +init set port-map unit=0 port=8 eth-macro=4 lane=0 max-speed=25g active=true +init set port-map unit=0 port=9 eth-macro=4 lane=1 max-speed=25g active=true +init set port-map unit=0 port=10 eth-macro=4 lane=2 max-speed=25g active=true +init set port-map unit=0 port=11 eth-macro=4 lane=3 max-speed=25g active=true +init set port-map unit=0 port=12 eth-macro=5 lane=0 max-speed=25g active=true +init set port-map unit=0 port=13 eth-macro=5 lane=1 max-speed=25g active=true +init set port-map unit=0 port=14 eth-macro=5 lane=2 max-speed=25g active=true +init set port-map unit=0 port=15 eth-macro=5 lane=3 max-speed=25g active=true +init set port-map unit=0 port=16 eth-macro=8 lane=0 max-speed=25g active=true +init set port-map unit=0 port=17 eth-macro=8 lane=1 max-speed=25g active=true +init set port-map unit=0 port=18 eth-macro=8 lane=2 max-speed=25g active=true +init set port-map unit=0 port=19 eth-macro=8 lane=3 max-speed=25g active=true +init set port-map unit=0 port=20 eth-macro=10 lane=0 max-speed=25g active=true +init set port-map unit=0 port=21 eth-macro=10 lane=1 max-speed=25g active=true +init set port-map unit=0 port=22 eth-macro=10 lane=2 max-speed=25g active=true +init set port-map unit=0 port=23 eth-macro=10 lane=3 max-speed=25g active=true +init set port-map unit=0 port=24 eth-macro=12 lane=0 max-speed=25g active=true +init set port-map unit=0 port=25 eth-macro=12 lane=1 max-speed=25g active=true +init set port-map unit=0 port=26 eth-macro=12 lane=2 max-speed=25g active=true +init set port-map unit=0 port=27 eth-macro=12 lane=3 max-speed=25g active=true +init set port-map unit=0 port=28 eth-macro=14 lane=0 max-speed=25g active=true +init set port-map unit=0 port=29 eth-macro=14 lane=1 max-speed=25g active=true +init set port-map unit=0 port=30 eth-macro=14 lane=2 max-speed=25g active=true +init set port-map unit=0 port=31 eth-macro=14 lane=3 max-speed=25g active=true +init set port-map unit=0 port=32 eth-macro=16 lane=0 max-speed=25g active=true +init set port-map unit=0 port=33 eth-macro=16 lane=1 max-speed=25g active=true +init set port-map unit=0 port=34 eth-macro=16 lane=2 max-speed=25g active=true +init set port-map unit=0 port=35 eth-macro=16 lane=3 max-speed=25g active=true +init set port-map unit=0 port=36 eth-macro=17 lane=0 max-speed=25g active=true +init set port-map unit=0 port=37 eth-macro=17 lane=1 max-speed=25g active=true +init set port-map unit=0 port=38 eth-macro=17 lane=2 max-speed=25g active=true +init set port-map unit=0 port=39 eth-macro=17 lane=3 max-speed=25g active=true +init set port-map unit=0 port=40 eth-macro=18 lane=0 max-speed=25g active=true +init set port-map unit=0 port=41 eth-macro=18 lane=1 max-speed=25g active=true +init set port-map unit=0 port=42 eth-macro=18 lane=2 max-speed=25g active=true +init set port-map unit=0 port=43 eth-macro=18 lane=3 max-speed=25g active=true +init set port-map unit=0 port=44 eth-macro=19 lane=0 max-speed=25g active=true +init set port-map unit=0 port=45 eth-macro=19 lane=1 max-speed=25g active=true +init set port-map unit=0 port=46 eth-macro=19 lane=2 max-speed=25g active=true +init set port-map unit=0 port=47 eth-macro=19 lane=3 max-speed=25g active=true +init set port-map unit=0 port=48 eth-macro=21 lane=0 max-speed=100g active=true +init set port-map unit=0 port=49 eth-macro=20 lane=0 max-speed=100g active=true +init set port-map unit=0 port=50 eth-macro=26 lane=0 max-speed=100g active=true +init set port-map unit=0 port=51 eth-macro=27 lane=0 max-speed=100g active=true +init set port-map unit=0 port=52 eth-macro=28 lane=0 max-speed=100g active=true +init set port-map unit=0 port=53 eth-macro=29 lane=0 max-speed=100g active=true +init set port-map unit=0 port=129 eth-macro=0 lane=1 max-speed=10g active=true guarantee=true cpi=true +init set port-map unit=0 port=130 eth-macro=0 lane=0 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=1 property=tx data=0x0 +phy set lane-swap unit=0 portlist=1 lane-cnt=1 property=tx data=0x1 +phy set lane-swap unit=0 portlist=2 lane-cnt=1 property=tx data=0x2 +phy set lane-swap unit=0 portlist=3 lane-cnt=1 property=tx data=0x3 +phy set lane-swap unit=0 portlist=4 lane-cnt=1 property=tx data=0x3 +phy set lane-swap unit=0 portlist=5 lane-cnt=1 property=tx data=0x2 +phy set lane-swap unit=0 portlist=6 lane-cnt=1 property=tx data=0x1 +phy set lane-swap unit=0 portlist=7 lane-cnt=1 property=tx data=0x0 +phy set lane-swap unit=0 portlist=8 lane-cnt=1 property=tx data=0x0 +phy set lane-swap unit=0 portlist=9 lane-cnt=1 property=tx data=0x1 +phy set lane-swap unit=0 portlist=10 lane-cnt=1 property=tx data=0x2 +phy set lane-swap unit=0 portlist=11 lane-cnt=1 property=tx data=0x3 +phy set lane-swap unit=0 portlist=12 lane-cnt=1 property=tx data=0x3 +phy set lane-swap unit=0 portlist=13 lane-cnt=1 property=tx data=0x2 +phy set lane-swap unit=0 portlist=14 lane-cnt=1 property=tx data=0x1 +phy set lane-swap unit=0 portlist=15 lane-cnt=1 property=tx data=0x0 +phy set lane-swap unit=0 portlist=16 lane-cnt=1 property=tx data=0x3 +phy set lane-swap unit=0 portlist=17 lane-cnt=1 property=tx data=0x2 +phy set lane-swap unit=0 portlist=18 lane-cnt=1 property=tx data=0x0 +phy set lane-swap unit=0 portlist=19 lane-cnt=1 property=tx data=0x1 +phy set lane-swap unit=0 portlist=20 lane-cnt=1 property=tx data=0x3 +phy set lane-swap unit=0 portlist=21 lane-cnt=1 property=tx data=0x2 +phy set lane-swap unit=0 portlist=22 lane-cnt=1 property=tx data=0x1 +phy set lane-swap unit=0 portlist=23 lane-cnt=1 property=tx data=0x0 +phy set lane-swap unit=0 portlist=24 lane-cnt=1 property=tx data=0x3 +phy set lane-swap unit=0 portlist=25 lane-cnt=1 property=tx data=0x2 +phy set lane-swap unit=0 portlist=26 lane-cnt=1 property=tx data=0x1 +phy set lane-swap unit=0 portlist=27 lane-cnt=1 property=tx data=0x0 +phy set lane-swap unit=0 portlist=28 lane-cnt=1 property=tx data=0x3 +phy set lane-swap unit=0 portlist=29 lane-cnt=1 property=tx data=0x2 +phy set lane-swap unit=0 portlist=30 lane-cnt=1 property=tx data=0x1 +phy set lane-swap unit=0 portlist=31 lane-cnt=1 property=tx data=0x0 +phy set lane-swap unit=0 portlist=32 lane-cnt=1 property=tx data=0x0 +phy set lane-swap unit=0 portlist=33 lane-cnt=1 property=tx data=0x1 +phy set lane-swap unit=0 portlist=34 lane-cnt=1 property=tx data=0x2 +phy set lane-swap unit=0 portlist=35 lane-cnt=1 property=tx data=0x3 +phy set lane-swap unit=0 portlist=36 lane-cnt=1 property=tx data=0x0 +phy set lane-swap unit=0 portlist=37 lane-cnt=1 property=tx data=0x1 +phy set lane-swap unit=0 portlist=38 lane-cnt=1 property=tx data=0x2 +phy set lane-swap unit=0 portlist=39 lane-cnt=1 property=tx data=0x3 +phy set lane-swap unit=0 portlist=40 lane-cnt=1 property=tx data=0x0 +phy set lane-swap unit=0 portlist=41 lane-cnt=1 property=tx data=0x1 +phy set lane-swap unit=0 portlist=42 lane-cnt=1 property=tx data=0x2 +phy set lane-swap unit=0 portlist=43 lane-cnt=1 property=tx data=0x3 +phy set lane-swap unit=0 portlist=44 lane-cnt=1 property=tx data=0x0 +phy set lane-swap unit=0 portlist=45 lane-cnt=1 property=tx data=0x1 +phy set lane-swap unit=0 portlist=46 lane-cnt=1 property=tx data=0x2 +phy set lane-swap unit=0 portlist=47 lane-cnt=1 property=tx data=0x3 +phy set lane-swap unit=0 portlist=48 lane-cnt=4 property=tx data=0x1.3.0.2 +phy set lane-swap unit=0 portlist=49 lane-cnt=4 property=tx data=0x0.3.1.2 +phy set lane-swap unit=0 portlist=50 lane-cnt=4 property=tx data=0x1.3.0.2 +phy set lane-swap unit=0 portlist=51 lane-cnt=4 property=tx data=0x2.0.3.1 +phy set lane-swap unit=0 portlist=52 lane-cnt=4 property=tx data=0x3.2.1.0 +phy set lane-swap unit=0 portlist=53 lane-cnt=4 property=tx data=0x3.2.1.0 +phy set lane-swap unit=0 portlist=0 lane-cnt=1 property=rx data=0x0 +phy set lane-swap unit=0 portlist=1 lane-cnt=1 property=rx data=0x1 +phy set lane-swap unit=0 portlist=2 lane-cnt=1 property=rx data=0x2 +phy set lane-swap unit=0 portlist=3 lane-cnt=1 property=rx data=0x3 +phy set lane-swap unit=0 portlist=4 lane-cnt=1 property=rx data=0x3 +phy set lane-swap unit=0 portlist=5 lane-cnt=1 property=rx data=0x2 +phy set lane-swap unit=0 portlist=6 lane-cnt=1 property=rx data=0x1 +phy set lane-swap unit=0 portlist=7 lane-cnt=1 property=rx data=0x0 +phy set lane-swap unit=0 portlist=8 lane-cnt=1 property=rx data=0x0 +phy set lane-swap unit=0 portlist=9 lane-cnt=1 property=rx data=0x1 +phy set lane-swap unit=0 portlist=10 lane-cnt=1 property=rx data=0x2 +phy set lane-swap unit=0 portlist=11 lane-cnt=1 property=rx data=0x3 +phy set lane-swap unit=0 portlist=12 lane-cnt=1 property=rx data=0x3 +phy set lane-swap unit=0 portlist=13 lane-cnt=1 property=rx data=0x2 +phy set lane-swap unit=0 portlist=14 lane-cnt=1 property=rx data=0x0 +phy set lane-swap unit=0 portlist=15 lane-cnt=1 property=rx data=0x1 +phy set lane-swap unit=0 portlist=16 lane-cnt=1 property=rx data=0x0 +phy set lane-swap unit=0 portlist=17 lane-cnt=1 property=rx data=0x3 +phy set lane-swap unit=0 portlist=18 lane-cnt=1 property=rx data=0x2 +phy set lane-swap unit=0 portlist=19 lane-cnt=1 property=rx data=0x1 +phy set lane-swap unit=0 portlist=20 lane-cnt=1 property=rx data=0x3 +phy set lane-swap unit=0 portlist=21 lane-cnt=1 property=rx data=0x0 +phy set lane-swap unit=0 portlist=22 lane-cnt=1 property=rx data=0x1 +phy set lane-swap unit=0 portlist=23 lane-cnt=1 property=rx data=0x2 +phy set lane-swap unit=0 portlist=24 lane-cnt=1 property=rx data=0x3 +phy set lane-swap unit=0 portlist=25 lane-cnt=1 property=rx data=0x0 +phy set lane-swap unit=0 portlist=26 lane-cnt=1 property=rx data=0x1 +phy set lane-swap unit=0 portlist=27 lane-cnt=1 property=rx data=0x2 +phy set lane-swap unit=0 portlist=28 lane-cnt=1 property=rx data=0x3 +phy set lane-swap unit=0 portlist=29 lane-cnt=1 property=rx data=0x0 +phy set lane-swap unit=0 portlist=30 lane-cnt=1 property=rx data=0x1 +phy set lane-swap unit=0 portlist=31 lane-cnt=1 property=rx data=0x2 +phy set lane-swap unit=0 portlist=32 lane-cnt=1 property=rx data=0x1 +phy set lane-swap unit=0 portlist=33 lane-cnt=1 property=rx data=0x2 +phy set lane-swap unit=0 portlist=34 lane-cnt=1 property=rx data=0x3 +phy set lane-swap unit=0 portlist=35 lane-cnt=1 property=rx data=0x0 +phy set lane-swap unit=0 portlist=36 lane-cnt=1 property=rx data=0x1 +phy set lane-swap unit=0 portlist=37 lane-cnt=1 property=rx data=0x2 +phy set lane-swap unit=0 portlist=38 lane-cnt=1 property=rx data=0x3 +phy set lane-swap unit=0 portlist=39 lane-cnt=1 property=rx data=0x0 +phy set lane-swap unit=0 portlist=40 lane-cnt=1 property=rx data=0x1 +phy set lane-swap unit=0 portlist=41 lane-cnt=1 property=rx data=0x2 +phy set lane-swap unit=0 portlist=42 lane-cnt=1 property=rx data=0x3 +phy set lane-swap unit=0 portlist=43 lane-cnt=1 property=rx data=0x0 +phy set lane-swap unit=0 portlist=44 lane-cnt=1 property=rx data=0x1 +phy set lane-swap unit=0 portlist=45 lane-cnt=1 property=rx data=0x2 +phy set lane-swap unit=0 portlist=46 lane-cnt=1 property=rx data=0x3 +phy set lane-swap unit=0 portlist=47 lane-cnt=1 property=rx data=0x0 +phy set lane-swap unit=0 portlist=48 lane-cnt=4 property=rx data=0x2.1.0.3 +phy set lane-swap unit=0 portlist=49 lane-cnt=4 property=rx data=0x0.1.3.2 +phy set lane-swap unit=0 portlist=50 lane-cnt=4 property=rx data=0x3.1.0.2 +phy set lane-swap unit=0 portlist=51 lane-cnt=4 property=rx data=0x1.3.0.2 +phy set lane-swap unit=0 portlist=52 lane-cnt=4 property=rx data=0x3.2.1.0 +phy set lane-swap unit=0 portlist=53 lane-cnt=4 property=rx data=0x3.2.1.0 +phy set polarity-rev unit=0 portlist=0 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=1 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=2 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=3 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=4 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=5 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=6 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=7 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=8 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=9 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=10 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=11 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=12 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=13 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=14 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=15 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=16 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=17 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=18 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=19 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=20 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=21 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=22 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=23 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=24 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=25 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=26 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=27 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=28 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=29 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=30 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=31 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=32 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=33 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=34 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=35 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=36 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=37 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=38 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=39 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=40 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=41 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=42 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=43 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=44 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=45 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=46 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=47 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=48 lane-cnt=4 property=tx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=49 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=50 lane-cnt=4 property=tx data=0x1.1.0.0 +phy set polarity-rev unit=0 portlist=51 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.0.0 +phy set polarity-rev unit=0 portlist=53 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=0 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=1 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=2 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=3 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=4 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=5 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=6 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=7 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=8 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=9 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=10 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=11 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=12 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=13 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=14 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=15 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=16 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=17 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=18 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=19 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=20 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=21 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=22 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=23 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=24 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=25 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=26 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=27 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=28 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=29 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=30 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=31 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=32 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=33 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=34 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=35 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=36 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=37 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=38 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=39 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=40 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=41 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=42 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=43 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=44 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=45 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=46 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=47 lane-cnt=1 property=rx data=0x0 +phy set polarity-rev unit=0 portlist=48 lane-cnt=4 property=rx data=0x0.1.0.1 +phy set polarity-rev unit=0 portlist=49 lane-cnt=4 property=rx data=0x1.0.1.0 +phy set polarity-rev unit=0 portlist=50 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=51 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=52 lane-cnt=4 property=rx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=53 lane-cnt=4 property=rx data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=0 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=0 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=0 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=0 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=4 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=4 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=4 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=4 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=8 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=8 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=8 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=8 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=12 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=12 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=12 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=12 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=16 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=16 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=16 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=16 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=20 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=20 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=20 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=20 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=24 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=24 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=24 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=24 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=28 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=28 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=28 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=28 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=32 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=32 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=32 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=32 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=36 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=36 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=36 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=36 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=40 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=40 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=40 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=40 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=44 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=44 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=44 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=44 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=48 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=48 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=48 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=48 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=49 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=49 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=49 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=49 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=50 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=50 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=50 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=50 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=51 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=51 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=51 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=51 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=52 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=52 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=52 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=52 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set pre-emphasis unit=0 portlist=53 lane-cnt=4 property=c2 data=0x0.0.0.0 +phy set pre-emphasis unit=0 portlist=53 lane-cnt=4 property=cn1 data=0x4.4.4.4 +phy set pre-emphasis unit=0 portlist=53 lane-cnt=4 property=c0 data=0x1e.1e.1e.1e +phy set pre-emphasis unit=0 portlist=53 lane-cnt=4 property=c1 data=0x2.2.2.2 +phy set mdio portlist=0 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=1 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=2 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=3 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=4 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=5 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=6 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=7 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=8 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=9 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=10 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=11 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=12 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=13 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=14 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=15 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=16 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=17 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=18 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=19 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=20 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=21 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=22 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=23 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=24 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=25 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=26 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=27 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=28 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=29 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=30 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=31 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=32 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=33 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=34 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=35 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=36 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=37 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=38 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=39 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=40 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=41 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=42 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=43 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=44 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=45 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=46 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=47 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=48 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=49 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=50 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=51 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=52 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=53 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=129 devad=0x1E addr=0x2 data=0x0000 +phy set mdio portlist=130 devad=0x1E addr=0x2 data=0x0000 +port set property unit=0 portlist=0-47 speed=25g +port set property unit=0 portlist=48-53 speed=100g +port set property unit=0 portlist=129-130 speed=10g +port set property unit=0 portlist=0-47 medium-type=cr +port set property unit=0 portlist=48-53 medium-type=cr4 +port set property unit=0 portlist=129-130 medium-type=kr +port set adver unit=0 portlist=129-130 speed-10g-kr +port set property unit=0 portlist=129-130 an=enable +port set property unit=0 portlist=129-130 admin=enable +port set property unit=0 portlist=0-53 admin=disable diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/nephos_opt.dsh b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/nephos_opt.dsh similarity index 77% rename from device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/nephos_opt.dsh rename to device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/nephos_opt.dsh index 06bda1dc76a4..ca2bc6497685 100644 --- a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/nephos_opt.dsh +++ b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/nephos_opt.dsh @@ -1,63 +1,63 @@ -init start stage low-level -init set port-map port=0 eth-macro=2 lane=0 max-speed=25g active=true -init set port-map port=1 eth-macro=2 lane=1 max-speed=25g active=true -init set port-map port=2 eth-macro=2 lane=2 max-speed=25g active=true -init set port-map port=3 eth-macro=2 lane=3 max-speed=25g active=true -init set port-map port=4 eth-macro=3 lane=0 max-speed=25g active=true -init set port-map port=5 eth-macro=3 lane=1 max-speed=25g active=true -init set port-map port=6 eth-macro=3 lane=2 max-speed=25g active=true -init set port-map port=7 eth-macro=3 lane=3 max-speed=25g active=true -init set port-map port=8 eth-macro=4 lane=0 max-speed=25g active=true -init set port-map port=9 eth-macro=4 lane=1 max-speed=25g active=true -init set port-map port=10 eth-macro=4 lane=2 max-speed=25g active=true -init set port-map port=11 eth-macro=4 lane=3 max-speed=25g active=true -init set port-map port=12 eth-macro=5 lane=0 max-speed=25g active=true -init set port-map port=13 eth-macro=5 lane=1 max-speed=25g active=true -init set port-map port=14 eth-macro=5 lane=2 max-speed=25g active=true -init set port-map port=15 eth-macro=5 lane=3 max-speed=25g active=true -init set port-map port=16 eth-macro=8 lane=0 max-speed=25g active=true -init set port-map port=17 eth-macro=8 lane=1 max-speed=25g active=true -init set port-map port=18 eth-macro=8 lane=2 max-speed=25g active=true -init set port-map port=19 eth-macro=8 lane=3 max-speed=25g active=true -init set port-map port=20 eth-macro=10 lane=0 max-speed=25g active=true -init set port-map port=21 eth-macro=10 lane=1 max-speed=25g active=true -init set port-map port=22 eth-macro=10 lane=2 max-speed=25g active=true -init set port-map port=23 eth-macro=10 lane=3 max-speed=25g active=true -init set port-map port=24 eth-macro=12 lane=0 max-speed=25g active=true -init set port-map port=25 eth-macro=12 lane=1 max-speed=25g active=true -init set port-map port=26 eth-macro=12 lane=2 max-speed=25g active=true -init set port-map port=27 eth-macro=12 lane=3 max-speed=25g active=true -init set port-map port=28 eth-macro=14 lane=0 max-speed=25g active=true -init set port-map port=29 eth-macro=14 lane=1 max-speed=25g active=true -init set port-map port=30 eth-macro=14 lane=2 max-speed=25g active=true -init set port-map port=31 eth-macro=14 lane=3 max-speed=25g active=true -init set port-map port=32 eth-macro=16 lane=0 max-speed=25g active=true -init set port-map port=33 eth-macro=16 lane=1 max-speed=25g active=true -init set port-map port=34 eth-macro=16 lane=2 max-speed=25g active=true -init set port-map port=35 eth-macro=16 lane=3 max-speed=25g active=true -init set port-map port=36 eth-macro=17 lane=0 max-speed=25g active=true -init set port-map port=37 eth-macro=17 lane=1 max-speed=25g active=true -init set port-map port=38 eth-macro=17 lane=2 max-speed=25g active=true -init set port-map port=39 eth-macro=17 lane=3 max-speed=25g active=true -init set port-map port=40 eth-macro=18 lane=0 max-speed=25g active=true -init set port-map port=41 eth-macro=18 lane=1 max-speed=25g active=true -init set port-map port=42 eth-macro=18 lane=2 max-speed=25g active=true -init set port-map port=43 eth-macro=18 lane=3 max-speed=25g active=true -init set port-map port=44 eth-macro=19 lane=0 max-speed=25g active=true -init set port-map port=45 eth-macro=19 lane=1 max-speed=25g active=true -init set port-map port=46 eth-macro=19 lane=2 max-speed=25g active=true -init set port-map port=47 eth-macro=19 lane=3 max-speed=25g active=true -init set port-map port=48 eth-macro=20 lane=0 max-speed=100g active=true -init set port-map port=49 eth-macro=21 lane=0 max-speed=100g active=true -init set port-map port=50 eth-macro=26 lane=0 max-speed=100g active=true -init set port-map port=51 eth-macro=27 lane=0 max-speed=100g active=true -init set port-map port=52 eth-macro=28 lane=0 max-speed=100g active=true -init set port-map port=53 eth-macro=29 lane=0 max-speed=100g active=true -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 -init start stage task-rsrc -init start stage module -init start stage task +init start stage unit=0 low-level +init set port-map unit=0 port=0 eth-macro=2 lane=0 max-speed=25g active=true +init set port-map unit=0 port=1 eth-macro=2 lane=1 max-speed=25g active=true +init set port-map unit=0 port=2 eth-macro=2 lane=2 max-speed=25g active=true +init set port-map unit=0 port=3 eth-macro=2 lane=3 max-speed=25g active=true +init set port-map unit=0 port=4 eth-macro=3 lane=0 max-speed=25g active=true +init set port-map unit=0 port=5 eth-macro=3 lane=1 max-speed=25g active=true +init set port-map unit=0 port=6 eth-macro=3 lane=2 max-speed=25g active=true +init set port-map unit=0 port=7 eth-macro=3 lane=3 max-speed=25g active=true +init set port-map unit=0 port=8 eth-macro=4 lane=0 max-speed=25g active=true +init set port-map unit=0 port=9 eth-macro=4 lane=1 max-speed=25g active=true +init set port-map unit=0 port=10 eth-macro=4 lane=2 max-speed=25g active=true +init set port-map unit=0 port=11 eth-macro=4 lane=3 max-speed=25g active=true +init set port-map unit=0 port=12 eth-macro=5 lane=0 max-speed=25g active=true +init set port-map unit=0 port=13 eth-macro=5 lane=1 max-speed=25g active=true +init set port-map unit=0 port=14 eth-macro=5 lane=2 max-speed=25g active=true +init set port-map unit=0 port=15 eth-macro=5 lane=3 max-speed=25g active=true +init set port-map unit=0 port=16 eth-macro=8 lane=0 max-speed=25g active=true +init set port-map unit=0 port=17 eth-macro=8 lane=1 max-speed=25g active=true +init set port-map unit=0 port=18 eth-macro=8 lane=2 max-speed=25g active=true +init set port-map unit=0 port=19 eth-macro=8 lane=3 max-speed=25g active=true +init set port-map unit=0 port=20 eth-macro=10 lane=0 max-speed=25g active=true +init set port-map unit=0 port=21 eth-macro=10 lane=1 max-speed=25g active=true +init set port-map unit=0 port=22 eth-macro=10 lane=2 max-speed=25g active=true +init set port-map unit=0 port=23 eth-macro=10 lane=3 max-speed=25g active=true +init set port-map unit=0 port=24 eth-macro=12 lane=0 max-speed=25g active=true +init set port-map unit=0 port=25 eth-macro=12 lane=1 max-speed=25g active=true +init set port-map unit=0 port=26 eth-macro=12 lane=2 max-speed=25g active=true +init set port-map unit=0 port=27 eth-macro=12 lane=3 max-speed=25g active=true +init set port-map unit=0 port=28 eth-macro=14 lane=0 max-speed=25g active=true +init set port-map unit=0 port=29 eth-macro=14 lane=1 max-speed=25g active=true +init set port-map unit=0 port=30 eth-macro=14 lane=2 max-speed=25g active=true +init set port-map unit=0 port=31 eth-macro=14 lane=3 max-speed=25g active=true +init set port-map unit=0 port=32 eth-macro=16 lane=0 max-speed=25g active=true +init set port-map unit=0 port=33 eth-macro=16 lane=1 max-speed=25g active=true +init set port-map unit=0 port=34 eth-macro=16 lane=2 max-speed=25g active=true +init set port-map unit=0 port=35 eth-macro=16 lane=3 max-speed=25g active=true +init set port-map unit=0 port=36 eth-macro=17 lane=0 max-speed=25g active=true +init set port-map unit=0 port=37 eth-macro=17 lane=1 max-speed=25g active=true +init set port-map unit=0 port=38 eth-macro=17 lane=2 max-speed=25g active=true +init set port-map unit=0 port=39 eth-macro=17 lane=3 max-speed=25g active=true +init set port-map unit=0 port=40 eth-macro=18 lane=0 max-speed=25g active=true +init set port-map unit=0 port=41 eth-macro=18 lane=1 max-speed=25g active=true +init set port-map unit=0 port=42 eth-macro=18 lane=2 max-speed=25g active=true +init set port-map unit=0 port=43 eth-macro=18 lane=3 max-speed=25g active=true +init set port-map unit=0 port=44 eth-macro=19 lane=0 max-speed=25g active=true +init set port-map unit=0 port=45 eth-macro=19 lane=1 max-speed=25g active=true +init set port-map unit=0 port=46 eth-macro=19 lane=2 max-speed=25g active=true +init set port-map unit=0 port=47 eth-macro=19 lane=3 max-speed=25g active=true +init set port-map unit=0 port=48 eth-macro=21 lane=0 max-speed=100g active=true +init set port-map unit=0 port=49 eth-macro=20 lane=0 max-speed=100g active=true +init set port-map unit=0 port=50 eth-macro=26 lane=0 max-speed=100g active=true +init set port-map unit=0 port=51 eth-macro=27 lane=0 max-speed=100g active=true +init set port-map unit=0 port=52 eth-macro=28 lane=0 max-speed=100g active=true +init set port-map unit=0 port=53 eth-macro=29 lane=0 max-speed=100g active=true +init set port-map unit=0 port=129 eth-macro=0 lane=1 max-speed=10g active=true guarantee=true cpi=true +init set port-map unit=0 port=130 eth-macro=0 lane=0 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 portlist=0 lane-cnt=1 property=tx data=0x0 phy set lane-swap portlist=1 lane-cnt=1 property=tx data=0x1 phy set lane-swap portlist=2 lane-cnt=1 property=tx data=0x2 @@ -106,7 +106,12 @@ phy set lane-swap portlist=44 lane-cnt=1 property=tx data=0x0 phy set lane-swap portlist=45 lane-cnt=1 property=tx data=0x1 phy set lane-swap portlist=46 lane-cnt=1 property=tx data=0x2 phy set lane-swap portlist=47 lane-cnt=1 property=tx data=0x3 -phy set lane-swap portlist=48-53 lane-cnt=4 property=tx data=0x03.02.01.00 +phy set lane-swap portlist=48 lane-cnt=4 property=tx data=0x1.3.0.2 +phy set lane-swap portlist=49 lane-cnt=4 property=tx data=0x0.3.1.2 +phy set lane-swap portlist=50 lane-cnt=4 property=tx data=0x1.3.0.2 +phy set lane-swap portlist=51 lane-cnt=4 property=tx data=0x2.0.3.1 +phy set lane-swap portlist=52 lane-cnt=4 property=tx data=0x3.2.1.0 +phy set lane-swap portlist=53 lane-cnt=4 property=tx data=0x3.2.1.0 phy set lane-swap portlist=0 lane-cnt=1 property=rx data=0x0 phy set lane-swap portlist=1 lane-cnt=1 property=rx data=0x1 phy set lane-swap portlist=2 lane-cnt=1 property=rx data=0x2 @@ -155,7 +160,12 @@ phy set lane-swap portlist=44 lane-cnt=1 property=rx data=0x1 phy set lane-swap portlist=45 lane-cnt=1 property=rx data=0x2 phy set lane-swap portlist=46 lane-cnt=1 property=rx data=0x3 phy set lane-swap portlist=47 lane-cnt=1 property=rx data=0x0 -phy set lane-swap portlist=48-53 lane-cnt=4 property=rx data=0x03.02.01.00 +phy set lane-swap portlist=48 lane-cnt=4 property=rx data=0x2.1.0.3 +phy set lane-swap portlist=49 lane-cnt=4 property=rx data=0x0.1.3.2 +phy set lane-swap portlist=50 lane-cnt=4 property=rx data=0x3.1.0.2 +phy set lane-swap portlist=51 lane-cnt=4 property=rx data=0x1.3.0.2 +phy set lane-swap portlist=52 lane-cnt=4 property=rx data=0x3.2.1.0 +phy set lane-swap portlist=53 lane-cnt=4 property=rx data=0x3.2.1.0 phy set polarity-rev portlist=0 lane-cnt=1 property=tx data=0x0 phy set polarity-rev portlist=1 lane-cnt=1 property=tx data=0x0 phy set polarity-rev portlist=2 lane-cnt=1 property=tx data=0x0 @@ -204,9 +214,9 @@ phy set polarity-rev portlist=44 lane-cnt=1 property=tx data=0x0 phy set polarity-rev portlist=45 lane-cnt=1 property=tx data=0x0 phy set polarity-rev portlist=46 lane-cnt=1 property=tx data=0x0 phy set polarity-rev portlist=47 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=48 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev portlist=48 lane-cnt=4 property=tx data=0x0.0.0.1 phy set polarity-rev portlist=49 lane-cnt=4 property=tx data=0x0.0.0.0 -phy set polarity-rev portlist=50 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev portlist=50 lane-cnt=4 property=tx data=0x1.1.0.0 phy set polarity-rev portlist=51 lane-cnt=4 property=tx data=0x0.0.0.0 phy set polarity-rev portlist=52 lane-cnt=4 property=tx data=0x0.0.0.0 phy set polarity-rev portlist=53 lane-cnt=4 property=tx data=0x0.0.0.0 @@ -258,83 +268,83 @@ phy set polarity-rev portlist=44 lane-cnt=1 property=rx data=0x0 phy set polarity-rev portlist=45 lane-cnt=1 property=rx data=0x0 phy set polarity-rev portlist=46 lane-cnt=1 property=rx data=0x0 phy set polarity-rev portlist=47 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=48 lane-cnt=4 property=rx data=0x0.0.0.0 -phy set polarity-rev portlist=49 lane-cnt=4 property=rx data=0x0.0.0.0 -phy set polarity-rev portlist=50 lane-cnt=4 property=rx data=0x0.0.0.0 -phy set polarity-rev portlist=51 lane-cnt=4 property=rx data=0x0.0.0.0 +phy set polarity-rev portlist=48 lane-cnt=4 property=rx data=0x0.1.0.1 +phy set polarity-rev portlist=49 lane-cnt=4 property=rx data=0x1.0.1.0 +phy set polarity-rev portlist=50 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev portlist=51 lane-cnt=4 property=rx data=0x0.0.0.1 phy set polarity-rev portlist=52 lane-cnt=4 property=rx data=0x0.0.0.0 phy set polarity-rev portlist=53 lane-cnt=4 property=rx data=0x0.0.0.0 phy set pre-emphasis portlist=0 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=0 lane-cnt=4 property=cn1 data=0x1.1.1.1 -phy set pre-emphasis portlist=0 lane-cnt=4 property=c0 data=0x1A.1A.1A.1A +phy set pre-emphasis portlist=0 lane-cnt=4 property=c0 data=0x1a.1a.1a.1a phy set pre-emphasis portlist=0 lane-cnt=4 property=c1 data=0x7.7.7.7 phy set pre-emphasis portlist=4 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=4 lane-cnt=4 property=cn1 data=0x1.1.1.1 -phy set pre-emphasis portlist=4 lane-cnt=4 property=c0 data=0x1A.1A.1A.1A +phy set pre-emphasis portlist=4 lane-cnt=4 property=c0 data=0x1a.1a.1a.1a phy set pre-emphasis portlist=4 lane-cnt=4 property=c1 data=0x7.7.7.7 phy set pre-emphasis portlist=8 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=8 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=8 lane-cnt=4 property=c0 data=0x1C.1C.1C.1C +phy set pre-emphasis portlist=8 lane-cnt=4 property=c0 data=0x1c.1c.1c.1c phy set pre-emphasis portlist=8 lane-cnt=4 property=c1 data=0x6.6.6.6 phy set pre-emphasis portlist=12 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=12 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=12 lane-cnt=4 property=c0 data=0x1B.1B.1B.1B +phy set pre-emphasis portlist=12 lane-cnt=4 property=c0 data=0x1b.1b.1b.1b phy set pre-emphasis portlist=12 lane-cnt=4 property=c1 data=0x7.7.7.7 phy set pre-emphasis portlist=16 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=16 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=16 lane-cnt=4 property=c0 data=0x1C.1C.1C.1C +phy set pre-emphasis portlist=16 lane-cnt=4 property=c0 data=0x1c.1c.1c.1c phy set pre-emphasis portlist=16 lane-cnt=4 property=c1 data=0x6.6.6.6 phy set pre-emphasis portlist=20 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=20 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=20 lane-cnt=4 property=c0 data=0x1C.1C.1C.1C +phy set pre-emphasis portlist=20 lane-cnt=4 property=c0 data=0x1c.1c.1c.1c phy set pre-emphasis portlist=20 lane-cnt=4 property=c1 data=0x6.6.6.6 phy set pre-emphasis portlist=24 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=24 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=24 lane-cnt=4 property=c0 data=0x1C.1C.1C.1C +phy set pre-emphasis portlist=24 lane-cnt=4 property=c0 data=0x1c.1c.1c.1c phy set pre-emphasis portlist=24 lane-cnt=4 property=c1 data=0x6.6.6.6 phy set pre-emphasis portlist=28 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=28 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=28 lane-cnt=4 property=c0 data=0x1C.1C.1C.1C +phy set pre-emphasis portlist=28 lane-cnt=4 property=c0 data=0x1c.1c.1c.1c phy set pre-emphasis portlist=28 lane-cnt=4 property=c1 data=0x6.6.6.6 phy set pre-emphasis portlist=32 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=32 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=32 lane-cnt=4 property=c0 data=0x1C.1C.1C.1C +phy set pre-emphasis portlist=32 lane-cnt=4 property=c0 data=0x1c.1c.1c.1c phy set pre-emphasis portlist=32 lane-cnt=4 property=c1 data=0x6.6.6.6 phy set pre-emphasis portlist=36 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=36 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=36 lane-cnt=4 property=c0 data=0x1C.1C.1C.1C +phy set pre-emphasis portlist=36 lane-cnt=4 property=c0 data=0x1c.1c.1c.1c phy set pre-emphasis portlist=36 lane-cnt=4 property=c1 data=0x6.6.6.6 phy set pre-emphasis portlist=40 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=40 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=40 lane-cnt=4 property=c0 data=0x1C.1C.1C.1C +phy set pre-emphasis portlist=40 lane-cnt=4 property=c0 data=0x1c.1c.1c.1c phy set pre-emphasis portlist=40 lane-cnt=4 property=c1 data=0x6.6.6.6 phy set pre-emphasis portlist=44 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=44 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=44 lane-cnt=4 property=c0 data=0x1C.1C.1C.1C +phy set pre-emphasis portlist=44 lane-cnt=4 property=c0 data=0x1c.1c.1c.1c phy set pre-emphasis portlist=44 lane-cnt=4 property=c1 data=0x6.6.6.6 phy set pre-emphasis portlist=48 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=48 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=48 lane-cnt=4 property=c0 data=0x1B.1B.1B.1B +phy set pre-emphasis portlist=48 lane-cnt=4 property=c0 data=0x1b.1b.1b.1b phy set pre-emphasis portlist=48 lane-cnt=4 property=c1 data=0x6.6.6.6 phy set pre-emphasis portlist=49 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=49 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=49 lane-cnt=4 property=c0 data=0x1B.1B.1B.1B +phy set pre-emphasis portlist=49 lane-cnt=4 property=c0 data=0x1b.1b.1b.1b phy set pre-emphasis portlist=49 lane-cnt=4 property=c1 data=0x6.6.6.6 phy set pre-emphasis portlist=50 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=50 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=50 lane-cnt=4 property=c0 data=0x1B.1B.1B.1B +phy set pre-emphasis portlist=50 lane-cnt=4 property=c0 data=0x1b.1b.1b.1b phy set pre-emphasis portlist=50 lane-cnt=4 property=c1 data=0x7.7.7.7 phy set pre-emphasis portlist=51 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=51 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=51 lane-cnt=4 property=c0 data=0x1B.1B.1B.1B +phy set pre-emphasis portlist=51 lane-cnt=4 property=c0 data=0x1b.1b.1b.1b phy set pre-emphasis portlist=51 lane-cnt=4 property=c1 data=0x7.7.7.7 phy set pre-emphasis portlist=52 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=52 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis portlist=52 lane-cnt=4 property=c0 data=0x1A.1A.1A.1A +phy set pre-emphasis portlist=52 lane-cnt=4 property=c0 data=0x1a.1a.1a.1a phy set pre-emphasis portlist=52 lane-cnt=4 property=c1 data=0x8.8.8.8 phy set pre-emphasis portlist=53 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis portlist=53 lane-cnt=4 property=cn1 data=0x1.1.1.1 -phy set pre-emphasis portlist=53 lane-cnt=4 property=c0 data=0x1A.1A.1A.1A +phy set pre-emphasis portlist=53 lane-cnt=4 property=c0 data=0x1a.1a.1a.1a phy set pre-emphasis portlist=53 lane-cnt=4 property=c1 data=0x7.7.7.7 phy set mdio portlist=0 devad=0x1E addr=0x2 data=0x8000 phy set mdio portlist=1 devad=0x1E addr=0x2 data=0x8000 @@ -400,5 +410,6 @@ port set property portlist=48-53 medium-type=sr4 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 -port set property portlist=0-53 admin=disable +port set property unit=0 portlist=129-130 admin=enable +port set property unit=0 portlist=0-53 admin=disable + diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/pg_profile_lookup.ini b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/pg_profile_lookup.ini similarity index 100% rename from device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/pg_profile_lookup.ini rename to device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/pg_profile_lookup.ini diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/port_config.ini b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/port_config.ini similarity index 100% rename from device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/port_config.ini rename to device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/port_config.ini diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/port_config.nps b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/port_config.nps similarity index 99% rename from device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/port_config.nps rename to device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/port_config.nps index a4270503f34b..ca2bc6497685 100644 --- a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/port_config.nps +++ b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/port_config.nps @@ -412,3 +412,4 @@ port set adver portlist=129-130 speed-10g-kr port set property portlist=129-130 an=enable port set property unit=0 portlist=129-130 admin=enable port set property unit=0 portlist=0-53 admin=disable + diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/proc_init.nps b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/proc_init.nps similarity index 100% rename from device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/proc_init.nps rename to device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/proc_init.nps diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/qos.json.j2 b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/qos.json.j2 similarity index 100% rename from device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/qos.json.j2 rename to device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/qos.json.j2 diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/sai.profile b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/sai.profile new file mode 100644 index 000000000000..5e4ff9064d5b --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X-R0/sai.profile @@ -0,0 +1,2 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/proc_init.nps +SAI_DSH_CONFIG_FILE=/usr/share/sonic/hwsku/port_config.nps diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/nephos_dac.dsh b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/nephos_dac.dsh deleted file mode 100644 index 10a7b7a9df0e..000000000000 --- a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/nephos_dac.dsh +++ /dev/null @@ -1,404 +0,0 @@ -init start stage low-level -init set port-map port=0 eth-macro=2 lane=0 max-speed=25g active=true -init set port-map port=1 eth-macro=2 lane=1 max-speed=25g active=true -init set port-map port=2 eth-macro=2 lane=2 max-speed=25g active=true -init set port-map port=3 eth-macro=2 lane=3 max-speed=25g active=true -init set port-map port=4 eth-macro=3 lane=0 max-speed=25g active=true -init set port-map port=5 eth-macro=3 lane=1 max-speed=25g active=true -init set port-map port=6 eth-macro=3 lane=2 max-speed=25g active=true -init set port-map port=7 eth-macro=3 lane=3 max-speed=25g active=true -init set port-map port=8 eth-macro=4 lane=0 max-speed=25g active=true -init set port-map port=9 eth-macro=4 lane=1 max-speed=25g active=true -init set port-map port=10 eth-macro=4 lane=2 max-speed=25g active=true -init set port-map port=11 eth-macro=4 lane=3 max-speed=25g active=true -init set port-map port=12 eth-macro=5 lane=0 max-speed=25g active=true -init set port-map port=13 eth-macro=5 lane=1 max-speed=25g active=true -init set port-map port=14 eth-macro=5 lane=2 max-speed=25g active=true -init set port-map port=15 eth-macro=5 lane=3 max-speed=25g active=true -init set port-map port=16 eth-macro=8 lane=0 max-speed=25g active=true -init set port-map port=17 eth-macro=8 lane=1 max-speed=25g active=true -init set port-map port=18 eth-macro=8 lane=2 max-speed=25g active=true -init set port-map port=19 eth-macro=8 lane=3 max-speed=25g active=true -init set port-map port=20 eth-macro=10 lane=0 max-speed=25g active=true -init set port-map port=21 eth-macro=10 lane=1 max-speed=25g active=true -init set port-map port=22 eth-macro=10 lane=2 max-speed=25g active=true -init set port-map port=23 eth-macro=10 lane=3 max-speed=25g active=true -init set port-map port=24 eth-macro=12 lane=0 max-speed=25g active=true -init set port-map port=25 eth-macro=12 lane=1 max-speed=25g active=true -init set port-map port=26 eth-macro=12 lane=2 max-speed=25g active=true -init set port-map port=27 eth-macro=12 lane=3 max-speed=25g active=true -init set port-map port=28 eth-macro=14 lane=0 max-speed=25g active=true -init set port-map port=29 eth-macro=14 lane=1 max-speed=25g active=true -init set port-map port=30 eth-macro=14 lane=2 max-speed=25g active=true -init set port-map port=31 eth-macro=14 lane=3 max-speed=25g active=true -init set port-map port=32 eth-macro=16 lane=0 max-speed=25g active=true -init set port-map port=33 eth-macro=16 lane=1 max-speed=25g active=true -init set port-map port=34 eth-macro=16 lane=2 max-speed=25g active=true -init set port-map port=35 eth-macro=16 lane=3 max-speed=25g active=true -init set port-map port=36 eth-macro=17 lane=0 max-speed=25g active=true -init set port-map port=37 eth-macro=17 lane=1 max-speed=25g active=true -init set port-map port=38 eth-macro=17 lane=2 max-speed=25g active=true -init set port-map port=39 eth-macro=17 lane=3 max-speed=25g active=true -init set port-map port=40 eth-macro=18 lane=0 max-speed=25g active=true -init set port-map port=41 eth-macro=18 lane=1 max-speed=25g active=true -init set port-map port=42 eth-macro=18 lane=2 max-speed=25g active=true -init set port-map port=43 eth-macro=18 lane=3 max-speed=25g active=true -init set port-map port=44 eth-macro=19 lane=0 max-speed=25g active=true -init set port-map port=45 eth-macro=19 lane=1 max-speed=25g active=true -init set port-map port=46 eth-macro=19 lane=2 max-speed=25g active=true -init set port-map port=47 eth-macro=19 lane=3 max-speed=25g active=true -init set port-map port=48 eth-macro=20 lane=0 max-speed=100g active=true -init set port-map port=49 eth-macro=21 lane=0 max-speed=100g active=true -init set port-map port=50 eth-macro=26 lane=0 max-speed=100g active=true -init set port-map port=51 eth-macro=27 lane=0 max-speed=100g active=true -init set port-map port=52 eth-macro=28 lane=0 max-speed=100g active=true -init set port-map port=53 eth-macro=29 lane=0 max-speed=100g active=true -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 -init start stage task-rsrc -init start stage module -init start stage task -phy set lane-swap portlist=0 lane-cnt=1 property=tx data=0x0 -phy set lane-swap portlist=1 lane-cnt=1 property=tx data=0x1 -phy set lane-swap portlist=2 lane-cnt=1 property=tx data=0x2 -phy set lane-swap portlist=3 lane-cnt=1 property=tx data=0x3 -phy set lane-swap portlist=4 lane-cnt=1 property=tx data=0x3 -phy set lane-swap portlist=5 lane-cnt=1 property=tx data=0x2 -phy set lane-swap portlist=6 lane-cnt=1 property=tx data=0x1 -phy set lane-swap portlist=7 lane-cnt=1 property=tx data=0x0 -phy set lane-swap portlist=8 lane-cnt=1 property=tx data=0x0 -phy set lane-swap portlist=9 lane-cnt=1 property=tx data=0x1 -phy set lane-swap portlist=10 lane-cnt=1 property=tx data=0x2 -phy set lane-swap portlist=11 lane-cnt=1 property=tx data=0x3 -phy set lane-swap portlist=12 lane-cnt=1 property=tx data=0x3 -phy set lane-swap portlist=13 lane-cnt=1 property=tx data=0x2 -phy set lane-swap portlist=14 lane-cnt=1 property=tx data=0x1 -phy set lane-swap portlist=15 lane-cnt=1 property=tx data=0x0 -phy set lane-swap portlist=16 lane-cnt=1 property=tx data=0x3 -phy set lane-swap portlist=17 lane-cnt=1 property=tx data=0x2 -phy set lane-swap portlist=18 lane-cnt=1 property=tx data=0x0 -phy set lane-swap portlist=19 lane-cnt=1 property=tx data=0x1 -phy set lane-swap portlist=20 lane-cnt=1 property=tx data=0x3 -phy set lane-swap portlist=21 lane-cnt=1 property=tx data=0x2 -phy set lane-swap portlist=22 lane-cnt=1 property=tx data=0x1 -phy set lane-swap portlist=23 lane-cnt=1 property=tx data=0x0 -phy set lane-swap portlist=24 lane-cnt=1 property=tx data=0x3 -phy set lane-swap portlist=25 lane-cnt=1 property=tx data=0x2 -phy set lane-swap portlist=26 lane-cnt=1 property=tx data=0x1 -phy set lane-swap portlist=27 lane-cnt=1 property=tx data=0x0 -phy set lane-swap portlist=28 lane-cnt=1 property=tx data=0x3 -phy set lane-swap portlist=29 lane-cnt=1 property=tx data=0x2 -phy set lane-swap portlist=30 lane-cnt=1 property=tx data=0x1 -phy set lane-swap portlist=31 lane-cnt=1 property=tx data=0x0 -phy set lane-swap portlist=32 lane-cnt=1 property=tx data=0x0 -phy set lane-swap portlist=33 lane-cnt=1 property=tx data=0x1 -phy set lane-swap portlist=34 lane-cnt=1 property=tx data=0x2 -phy set lane-swap portlist=35 lane-cnt=1 property=tx data=0x3 -phy set lane-swap portlist=36 lane-cnt=1 property=tx data=0x0 -phy set lane-swap portlist=37 lane-cnt=1 property=tx data=0x1 -phy set lane-swap portlist=38 lane-cnt=1 property=tx data=0x2 -phy set lane-swap portlist=39 lane-cnt=1 property=tx data=0x3 -phy set lane-swap portlist=40 lane-cnt=1 property=tx data=0x0 -phy set lane-swap portlist=41 lane-cnt=1 property=tx data=0x1 -phy set lane-swap portlist=42 lane-cnt=1 property=tx data=0x2 -phy set lane-swap portlist=43 lane-cnt=1 property=tx data=0x3 -phy set lane-swap portlist=44 lane-cnt=1 property=tx data=0x0 -phy set lane-swap portlist=45 lane-cnt=1 property=tx data=0x1 -phy set lane-swap portlist=46 lane-cnt=1 property=tx data=0x2 -phy set lane-swap portlist=47 lane-cnt=1 property=tx data=0x3 -phy set lane-swap portlist=48-53 lane-cnt=4 property=tx data=0x03.02.01.00 -phy set lane-swap portlist=0 lane-cnt=1 property=rx data=0x0 -phy set lane-swap portlist=1 lane-cnt=1 property=rx data=0x1 -phy set lane-swap portlist=2 lane-cnt=1 property=rx data=0x2 -phy set lane-swap portlist=3 lane-cnt=1 property=rx data=0x3 -phy set lane-swap portlist=4 lane-cnt=1 property=rx data=0x3 -phy set lane-swap portlist=5 lane-cnt=1 property=rx data=0x2 -phy set lane-swap portlist=6 lane-cnt=1 property=rx data=0x1 -phy set lane-swap portlist=7 lane-cnt=1 property=rx data=0x0 -phy set lane-swap portlist=8 lane-cnt=1 property=rx data=0x0 -phy set lane-swap portlist=9 lane-cnt=1 property=rx data=0x1 -phy set lane-swap portlist=10 lane-cnt=1 property=rx data=0x2 -phy set lane-swap portlist=11 lane-cnt=1 property=rx data=0x3 -phy set lane-swap portlist=12 lane-cnt=1 property=rx data=0x3 -phy set lane-swap portlist=13 lane-cnt=1 property=rx data=0x2 -phy set lane-swap portlist=14 lane-cnt=1 property=rx data=0x0 -phy set lane-swap portlist=15 lane-cnt=1 property=rx data=0x1 -phy set lane-swap portlist=16 lane-cnt=1 property=rx data=0x0 -phy set lane-swap portlist=17 lane-cnt=1 property=rx data=0x3 -phy set lane-swap portlist=18 lane-cnt=1 property=rx data=0x2 -phy set lane-swap portlist=19 lane-cnt=1 property=rx data=0x1 -phy set lane-swap portlist=20 lane-cnt=1 property=rx data=0x3 -phy set lane-swap portlist=21 lane-cnt=1 property=rx data=0x0 -phy set lane-swap portlist=22 lane-cnt=1 property=rx data=0x1 -phy set lane-swap portlist=23 lane-cnt=1 property=rx data=0x2 -phy set lane-swap portlist=24 lane-cnt=1 property=rx data=0x3 -phy set lane-swap portlist=25 lane-cnt=1 property=rx data=0x0 -phy set lane-swap portlist=26 lane-cnt=1 property=rx data=0x1 -phy set lane-swap portlist=27 lane-cnt=1 property=rx data=0x2 -phy set lane-swap portlist=28 lane-cnt=1 property=rx data=0x3 -phy set lane-swap portlist=29 lane-cnt=1 property=rx data=0x0 -phy set lane-swap portlist=30 lane-cnt=1 property=rx data=0x1 -phy set lane-swap portlist=31 lane-cnt=1 property=rx data=0x2 -phy set lane-swap portlist=32 lane-cnt=1 property=rx data=0x1 -phy set lane-swap portlist=33 lane-cnt=1 property=rx data=0x2 -phy set lane-swap portlist=34 lane-cnt=1 property=rx data=0x3 -phy set lane-swap portlist=35 lane-cnt=1 property=rx data=0x0 -phy set lane-swap portlist=36 lane-cnt=1 property=rx data=0x1 -phy set lane-swap portlist=37 lane-cnt=1 property=rx data=0x2 -phy set lane-swap portlist=38 lane-cnt=1 property=rx data=0x3 -phy set lane-swap portlist=39 lane-cnt=1 property=rx data=0x0 -phy set lane-swap portlist=40 lane-cnt=1 property=rx data=0x1 -phy set lane-swap portlist=41 lane-cnt=1 property=rx data=0x2 -phy set lane-swap portlist=42 lane-cnt=1 property=rx data=0x3 -phy set lane-swap portlist=43 lane-cnt=1 property=rx data=0x0 -phy set lane-swap portlist=44 lane-cnt=1 property=rx data=0x1 -phy set lane-swap portlist=45 lane-cnt=1 property=rx data=0x2 -phy set lane-swap portlist=46 lane-cnt=1 property=rx data=0x3 -phy set lane-swap portlist=47 lane-cnt=1 property=rx data=0x0 -phy set lane-swap portlist=48-53 lane-cnt=4 property=rx data=0x03.02.01.00 -phy set polarity-rev portlist=0 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=1 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=2 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=3 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=4 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=5 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=6 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=7 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=8 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=9 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=10 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=11 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=12 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=13 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=14 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=15 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=16 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=17 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=18 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=19 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=20 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=21 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=22 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=23 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=24 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=25 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=26 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=27 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=28 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=29 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=30 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=31 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=32 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=33 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=34 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=35 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=36 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=37 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=38 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=39 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=40 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=41 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=42 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=43 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=44 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=45 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=46 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=47 lane-cnt=1 property=tx data=0x0 -phy set polarity-rev portlist=48 lane-cnt=4 property=tx data=0x0.0.0.0 -phy set polarity-rev portlist=49 lane-cnt=4 property=tx data=0x0.0.0.0 -phy set polarity-rev portlist=50 lane-cnt=4 property=tx data=0x0.0.0.0 -phy set polarity-rev portlist=51 lane-cnt=4 property=tx data=0x0.0.0.0 -phy set polarity-rev portlist=52 lane-cnt=4 property=tx data=0x0.0.0.0 -phy set polarity-rev portlist=53 lane-cnt=4 property=tx data=0x0.0.0.0 -phy set polarity-rev portlist=0 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=1 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=2 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=3 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=4 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=5 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=6 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=7 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=8 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=9 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=10 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=11 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=12 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=13 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=14 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=15 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=16 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=17 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=18 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=19 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=20 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=21 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=22 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=23 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=24 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=25 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=26 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=27 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=28 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=29 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=30 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=31 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=32 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=33 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=34 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=35 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=36 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=37 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=38 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=39 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=40 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=41 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=42 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=43 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=44 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=45 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=46 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=47 lane-cnt=1 property=rx data=0x0 -phy set polarity-rev portlist=48 lane-cnt=4 property=rx data=0x0.0.0.0 -phy set polarity-rev portlist=49 lane-cnt=4 property=rx data=0x0.0.0.0 -phy set polarity-rev portlist=50 lane-cnt=4 property=rx data=0x0.0.0.0 -phy set polarity-rev portlist=51 lane-cnt=4 property=rx data=0x0.0.0.0 -phy set polarity-rev portlist=52 lane-cnt=4 property=rx data=0x0.0.0.0 -phy set polarity-rev portlist=53 lane-cnt=4 property=rx data=0x0.0.0.0 -phy set pre-emphasis portlist=0 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=0 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=0 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=0 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=4 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=4 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=4 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=4 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=8 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=8 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=8 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=8 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=12 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=12 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=12 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=12 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=16 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=16 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=16 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=16 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=20 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=20 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=20 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=20 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=24 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=24 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=24 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=24 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=28 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=28 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=28 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=28 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=32 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=32 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=32 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=32 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=36 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=36 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=36 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=36 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=40 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=40 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=40 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=40 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=44 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=44 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=44 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=44 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=48 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=48 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=48 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=48 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=49 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=49 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=49 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=49 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=50 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=50 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=50 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=50 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=51 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=51 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=51 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=51 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=52 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=52 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=52 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=52 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set pre-emphasis portlist=53 lane-cnt=4 property=c2 data=0x0.0.0.0 -phy set pre-emphasis portlist=53 lane-cnt=4 property=cn1 data=0x4.4.4.4 -phy set pre-emphasis portlist=53 lane-cnt=4 property=c0 data=0x1E.1E.1E.1E -phy set pre-emphasis portlist=53 lane-cnt=4 property=c1 data=0x2.2.2.2 -phy set mdio portlist=0 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=1 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=2 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=3 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=4 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=5 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=6 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=7 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=8 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=9 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=10 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=11 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=12 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=13 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=14 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=15 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=16 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=17 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=18 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=19 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=20 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=21 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=22 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=23 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=24 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=25 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=26 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=27 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=28 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=29 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=30 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=31 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=32 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=33 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=34 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=35 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=36 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=37 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=38 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=39 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=40 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=41 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=42 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=43 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=44 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=45 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=46 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=47 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=48 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=49 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=50 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=51 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=52 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=53 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=129 devad=0x1E addr=0x2 data=0x0000 -phy set mdio portlist=130 devad=0x1E addr=0x2 data=0x0000 -port set property portlist=0-47 speed=25g -port set property portlist=48-53 speed=100g -port set property portlist=129-130 speed=10g -port set property portlist=0-47 medium-type=cr -port set property portlist=48-53 medium-type=cr4 -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 -port set property portlist=0-53 admin=disable diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/sai.profile b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/sai.profile deleted file mode 100644 index 02d31ffb2d54..000000000000 --- a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/sai.profile +++ /dev/null @@ -1,2 +0,0 @@ -SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/proc_init.nps -SAI_DSH_CONFIG_FILE=/usr/share/sonic/hwsku/port_config.nps \ No newline at end of file diff --git a/device/accton/x86_64-accton_as7116_54x-r0/default_sku b/device/accton/x86_64-accton_as7116_54x-r0/default_sku index 623c20034d36..146edca52638 100644 --- a/device/accton/x86_64-accton_as7116_54x-r0/default_sku +++ b/device/accton/x86_64-accton_as7116_54x-r0/default_sku @@ -1 +1 @@ -Accton-AS7116-54X t1 \ No newline at end of file +Accton-AS7116-54X-R0 t1 diff --git a/device/accton/x86_64-accton_as7116_54x-r0/fancontrol b/device/accton/x86_64-accton_as7116_54x-r0/fancontrol index 8b1798edcc00..e16d8f936f85 100644 --- a/device/accton/x86_64-accton_as7116_54x-r0/fancontrol +++ b/device/accton/x86_64-accton_as7116_54x-r0/fancontrol @@ -7,4 +7,4 @@ MAXTEMP=/sys/bus/i2c/devices/1-0063/fan_duty_cycle_percentage=58 MINSTART=/sys/bus/i2c/devices/1-0063/fan_duty_cycle_percentage=100 MINSTOP=/sys/bus/i2c/devices/1-0063/fan_duty_cycle_percentage=40 MINPWM=/sys/bus/i2c/devices/1-0063/fan_duty_cycle_percentage=40 -MAXPWM=/sys/bus/i2c/devices/1-0063/fan_duty_cycle_percentage=100 \ No newline at end of file +MAXPWM=/sys/bus/i2c/devices/1-0063/fan_duty_cycle_percentage=100 diff --git a/device/accton/x86_64-accton_as7116_54x-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as7116_54x-r0/plugins/eeprom.py index f5637458720e..1e7d1046d93d 100644 --- a/device/accton/x86_64-accton_as7116_54x-r0/plugins/eeprom.py +++ b/device/accton/x86_64-accton_as7116_54x-r0/plugins/eeprom.py @@ -18,4 +18,4 @@ 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/0-0056/eeprom" - super(board, self).__init__(self.eeprom_path, 0, '', True) \ No newline at end of file + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/accton/x86_64-accton_as7116_54x-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as7116_54x-r0/plugins/sfputil.py index 2faf4d5dfacf..4f0e4ef8273c 100644 --- a/device/accton/x86_64-accton_as7116_54x-r0/plugins/sfputil.py +++ b/device/accton/x86_64-accton_as7116_54x-r0/plugins/sfputil.py @@ -168,4 +168,5 @@ def get_transceiver_change_event(self, timeout=0): time.sleep(2) - return True, ret_present \ No newline at end of file + return True, ret_present + diff --git a/device/accton/x86_64-accton_as7116_54x-r0/sensors.conf b/device/accton/x86_64-accton_as7116_54x-r0/sensors.conf index ba976ef14536..9edb51a9e72d 100644 --- a/device/accton/x86_64-accton_as7116_54x-r0/sensors.conf +++ b/device/accton/x86_64-accton_as7116_54x-r0/sensors.conf @@ -10,4 +10,4 @@ chip "as7116_54x_fan-*" label fan7 "rear fan 2" label fan8 "rear fan 3" label fan9 "rear fan 4" - label fan10 "rear fan 5" \ No newline at end of file + label fan10 "rear fan 5" diff --git a/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/__init__.py b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/__init__.py new file mode 100644 index 000000000000..d82f3749319c --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * diff --git a/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/chassis.py new file mode 100644 index 000000000000..6d5ed915812e --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/chassis.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python + +############################################################################# +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# +try: + import sys + import re + import os + import subprocess + import json + import syslog + from sonic_platform_base.chassis_base import ChassisBase + from sonic_daemon_base.daemon_base import Logger + from sonic_platform.fan import Fan + from sonic_platform.psu import Psu + from sonic_platform.component import Component + from sonic_platform.thermal import Thermal + from sonic_platform.sfp import Sfp + from sonic_platform.eeprom import Tlv +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN_TRAY = 5 +NUM_FAN = 2 +NUM_PSU = 2 +NUM_THERMAL = 4 +NUM_SFP = 54 +SFP_PORT_START = 0 +QSFP_PORT_START = 48 +SFP_PORT_END = 47 +QSFP_PORT_END=53 +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" +PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" +REBOOT_CAUSE_FILE = "reboot-cause.txt" +PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" +COMPONENT_NAME_LIST = ["BIOS"] +HOST_CHK_CMD = "docker > /dev/null 2>&1" + + +class Chassis(ChassisBase): + """Platform-specific Chassis class""" + + def __init__(self): + super(Chassis, self).__init__() + + for fantray_index in range(0, NUM_FAN_TRAY): + for fan_index in range(0, NUM_FAN): + fan = Fan(fantray_index, fan_index) + self._fan_list.append(fan) + for index in range(0, NUM_PSU): + psu = Psu(index) + self._psu_list.append(psu) + for index in range(0, NUM_THERMAL): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + self.PORT_START = SFP_PORT_START + self.QSFP_PORT_START = QSFP_PORT_START + self.PORT_END = QSFP_PORT_END + for index in range(0, NUM_SFP): + if index in range(self.QSFP_PORT_START, self.QSPORT_END + 1): + sfp_module = Sfp(index, 'QSFP') + else: + sfp_module = Sfp(index, 'SFP') + self._sfp_list.append(sfp_module) + self._component_name_list = COMPONENT_NAME_LIST + self._watchdog = Watchdog() + self._eeprom = Tlv() + logger.log_info("Chassis loaded successfully") + + def __is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return None + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self._eeprom.get_mac() + + def get_serial_number(self): + """ + Retrieves the hardware serial number for the chassis + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.get_serial() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + """ + return self._eeprom.get_eeprom() + + def get_firmware_version(self, component_name): + """ + Retrieves platform-specific hardware/firmware versions for chassis + componenets such as BIOS, CPLD, FPGA, etc. + Args: + type: A string, component name + + Returns: + A string containing platform-specific component versions + """ + self.component = Component(component_name) + if component_name not in self._component_name_list: + return None + return self.component.get_firmware_version() + + def install_component_firmware(self, component_name, image_path): + """ + Install firmware to module + Args: + type: A string, component name. + image_path: A string, path to firmware image. + + Returns: + A boolean, True if install successfully, False if not + """ + self.component = Component(component_name) + if component_name not in self._component_name_list: + return False + return self.component.upgrade_firmware(image_path) + + 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. + """ + description = 'None' + reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER + + reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) if self.__is_host( + ) else PMON_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE + prev_reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE) if self.__is_host( + ) else PMON_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE + sw_reboot_cause = self.__read_txt_file( + reboot_cause_path) or "Unknown" + prev_sw_reboot_cause = self.__read_txt_file( + prev_reboot_cause_path) or "Unknown" + + if sw_reboot_cause != "Unknown": + reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE + description = sw_reboot_cause + else: + reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER + description = 'Unknown reason' + + return (reboot_cause, description) diff --git a/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/component.py new file mode 100644 index 000000000000..c8f109aa4db9 --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/component.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python + +############################################################################# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +############################################################################# + +import json +import os.path +import shutil +import shlex +import subprocess + +try: + from sonic_platform_base.device_base import DeviceBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" + +class Component(DeviceBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_name): + DeviceBase.__init__(self) + self.name = component_name.upper() + + def __run_command(self, command): + # Run bash command and print output to stdout + try: + process = subprocess.Popen( + shlex.split(command), stdout=subprocess.PIPE) + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + rc = process.poll() + if rc != 0: + return False + except: + return False + return True + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + bios_version = fd.read() + return bios_version.strip() + except Exception as e: + return None + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = None + + if self.name == "BIOS": + fw_version = self.__get_bios_version() + + return fw_version + + def upgrade_firmware(self, image_path): + """ + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + if not os.path.isfile(image_path): + return False + + if self.name == "BIOS": + print("Not supported") + return False + + return self.__run_command(install_command) diff --git a/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/eeprom.py new file mode 100644 index 000000000000..714ac8153e0e --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/eeprom.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python + +############################################################################# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# + +try: + import glob + import os + import sys + import imp + import re + from array import array + from cStringIO import StringIO + from sonic_platform_base.sonic_eeprom import eeprom_dts + from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' +CACHE_FILE = 'syseeprom_cache' + + +class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + + EEPROM_DECODE_HEADLINES = 6 + + def __init__(self): + self._eeprom_path = "/sys/bus/i2c/devices/0-0056/eeprom" + super(Tlv, self).__init__(self._eeprom_path, 0, '', True) + self._eeprom = self._load_eeprom() + + def __parse_output(self, decode_output): + decode_output.replace('\0', '') + lines = decode_output.split('\n') + lines = lines[self.EEPROM_DECODE_HEADLINES:] + _eeprom_info_dict = dict() + + for line in lines: + try: + match = re.search( + '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) + if match is not None: + idx = match.group(1) + value = match.group(3).rstrip('\0') + + _eeprom_info_dict[idx] = value + except: + pass + return _eeprom_info_dict + + def _load_eeprom(self): + original_stdout = sys.stdout + sys.stdout = StringIO() + err = self.read_eeprom_db() + if err: + # Failed to read EEPROM information from database. Read from cache file + pass + else: + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + return self.__parse_output(decode_output) + + status = self.check_status() + if status < 'ok': + return False + + if not os.path.exists(CACHE_ROOT): + try: + os.makedirs(CACHE_ROOT) + except: + pass + + # + # only the eeprom classes that inherit from eeprom_base + # support caching. Others will work normally + # + try: + self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) + except: + pass + + e = self.read_eeprom() + if e is None: + return 0 + + try: + self.update_cache(e) + except: + pass + + self.decode_eeprom(e) + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + + (is_valid, valid_crc) = self.is_checksum_valid(e) + if not is_valid: + return False + + return self.__parse_output(decode_output) + + def get_eeprom(self): + return self._eeprom + + def get_serial(self): + return self._eeprom.get('0x23', "Undefined.") + + def get_mac(self): + return self._eeprom.get('0x24', "Undefined.") diff --git a/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/fan.py new file mode 100644 index 000000000000..54878e3e1baa --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/fan.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python + +############################################################################# +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +import json +import math +import os.path + +try: + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FAN_PATH = "/sys/bus/i2c/devices/1-0063/" +FANTRAY_NAME_LIST = ["FANTRAY-1", "FANTRAY-2", + "FANTRAY-3", "FANTRAY-4", "FANTRAY-5"] +FAN_NAME_LIST = ["front", "rear"] + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, fan_tray_index, fan_index=0): + self.fan_index = fan_index + self.fan_tray_index = fan_tray_index + self.fan_presence = "fan{}_present" + self.fan_direction = "fan{}_direction" + self.fan_fault = "fan{}_{}_fault" + self.fan_speed_rpm = "fan{}_{}_speed_rpm" + FanBase.__init__(self) + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" + + def __write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except: + return False + return True + + def __search_file_by_name(self, directory, file_name): + for dirpath, dirnames, files in os.walk(directory): + for name in files: + file_path = os.path.join(dirpath, name) + if name in file_name: + return file_path + return None + + 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 + fan_direction_file = (FAN_PATH + + self.fan_direction.format(self.fan_tray_index+1)) + raw = self.__read_txt_file(fan_direction_file).strip('\r\n') + direction = self.FAN_DIRECTION_INTAKE if str( + raw).upper() == "1" else self.FAN_DIRECTION_EXHAUST + + 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 12000 (full speed) + """ + speed = 0 + if self.get_presence(): + fan_speed_file = (FAN_PATH + + self.fan_speed_rpm.format(self.fan_tray_index+1,FAN_NAME_LIST[self.fan_index])) + speed = self.__read_txt_file(fan_speed_file).strip('\r\n') + + return int(speed) + + 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) + """ + target = 0 + if self.get_presence(): + fan_speed_file=(FAN_PATH + + self.fan_speed_rpm.format(self.fan_tray_index+1, FAN_NAME_LIST[self.fan_index])) + target=self.__read_txt_file(fan_speed_file).strip('\r\n') + + return target + + 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 10 + + 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 + + Note: + Depends on pwm or target mode is selected: + 1) pwm = speed_pc * 255 <-- Currently use this mode. + 2) target_pwm = speed_pc * 100 / 255 + 2.1) set pwm{}_enable to 3 + + """ + 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 + """ + return False + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + fan_name = FAN_NAME_LIST[self.fan_tray_index] + + return fan_name + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + fan_direction_file = (FAN_PATH + + self.fan_presence.format(self.fan_tray_index+1)) + present_str = self.__read_txt_file(fan_direction_file) or '1' + + return int(present_str) == 0 diff --git a/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/platform.py b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/platform.py new file mode 100644 index 000000000000..44e03cdadbb3 --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/platform.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +############################################################################# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Platform(PlatformBase): + """Platform-specific Platform class""" + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/psu.py new file mode 100644 index 000000000000..b1c8029dced9 --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/psu.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python + +############################################################################# +# psuutil.py +# Platform-specific PSU status interface for SONiC +############################################################################# + +import os.path +import sonic_platform + +try: + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FAN_MAX_RPM = 9600 +PSU_NAME_LIST = ["PSU-0", "PSU-1"] + +class Psu(PsuBase): + """Platform-specific Psu class""" + + SYSFS_PSU_DIR = ["/sys/bus/i2c/devices/10-0050", + "/sys/bus/i2c/devices/11-0053"] + + def __init__(self): + self.index = psu_index + PsuBase.__init__(self) + + + def get_fan(self): + """ + Retrieves object representing the fan module contained in this PSU + Returns: + An object dervied from FanBase representing the fan module + contained in this PSU + """ + # Hardware not supported + return False + + 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 + Note: Only support green and off + Returns: + bool: True if status LED state is set successfully, False if not + """ + # Hardware not supported + return False + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return PSU_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + attr_file ='psu_present' + attr_path = self.SYSFS_PSU_DIR[self.index-1] +'/' + attr_file + status = 0 + try: + with open(attr_path, 'r') as psu_prs: + status = int(psu_prs.read()) + except IOError: + return False + + return status == 1 + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + attr_file = 'psu_power_good' + attr_path = self.SYSFS_PSU_DIR[self.index-1] +'/' + attr_file + status = 0 + try: + with open(attr_path, 'r') as power_status: + status = int(power_status.read()) + except IOError: + return False + + return status == 1 diff --git a/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/sfp.py new file mode 100644 index 000000000000..07e0649579ac --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/sonic_platform/sfp.py @@ -0,0 +1,1133 @@ +#!/usr/bin/env python + +############################################################################# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +############################################################################# +try: + import os + import time + import subprocess + import sonic_device_util + import syslog + from ctypes import create_string_buffer + 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.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from sonic_daemon_base.daemon_base import Logger +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +INFO_OFFSET = 0 +DOM_OFFSET = 256 + +QSFP_INFO_OFFSET = 128 +QSFP_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_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 + + +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') + +# 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_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') + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + + # Port number + PORT_START = 0 + PORT_END = 53 + + port_to_i2c_mapping = { + 0: 37, + 1: 38, + 2: 39, + 3: 40, + 4: 41, + 5: 42, + 6: 43, + 7: 44, + 8: 45, + 9: 46, + 10: 47, + 11: 48, + 12: 49, + 13: 50, + 14: 51, + 15: 52, + 16: 53, + 17: 54, + 18: 55, + 19: 56, + 20: 57, + 21: 58, + 22: 59, + 23: 60, + 24: 61, + 25: 62, + 26: 63, + 27: 64, + 28: 65, + 29: 66, + 30: 67, + 31: 68, + 32: 69, + 33: 70, + 34: 71, + 35: 72, + 36: 73, + 37: 74, + 38: 75, + 39: 76, + 40: 77, + 41: 78, + 42: 79, + 43: 80, + 44: 81, + 45: 82, + 46: 83, + 47: 84, + 48: 21, + 49: 22, + 50: 23, + 51: 24, + 52: 25, + 53: 26, + } + _sfp_port = range(48, PORT_END + 1) + RESET_PATH = "/sys/bus/i2c/devices/{}-0050/sfp_port_reset" + PRS_PATH = "/sys/bus/i2c/devices/{}-0050/sfp_is_present" + + PLATFORM_ROOT_PATH = '/usr/share/sonic/device' + PMON_HWSKU_PATH = '/usr/share/sonic/hwsku' + HOST_CHK_CMD = "docker > /dev/null 2>&1" + + PLATFORM = "x86_64-accton_as7116_54x-r0" + HWSKU = "Accton-AS7116-54X-R0" + + def __init__(self, sfp_index, sfp_type): + # Init index + self.index = sfp_index + self.port_num = self.index + 1 + self.sfp_type = sfp_type + + # Init eeprom path + eeprom_path = '/sys/bus/i2c/devices/{0}-0050/sfp_eeprom' + self.port_to_eeprom_mapping = {} + for x in range(self.PORT_START, self.PORT_END + 1): + p_num = x - 1 if self.PORT_START == 1 else x + self.port_to_eeprom_mapping[p_num] = eeprom_path.format( + self.port_to_i2c_mapping[p_num]) + + self.info_dict_keys = ['type', 'hardwarerev', 'serialnum', 'manufacturename', 'modelname', 'Connector', 'encoding', 'ext_identifier', + 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', 'specification_compliance', 'vendor_date', 'vendor_oui'] + + self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] + + self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + SfpBase.__init__(self) + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def __read_eeprom_specific_bytes(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.sfp_index] + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except: + pass + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + Returns: + A dict which contains following keys/values : + """ + if self.sfp_type == "SFP": + get_sfp_transceiver_info + else: + get_qsfp_transceiver_info + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + Returns: + A dict which contains following keys/values : + """ + if self.sfp_type == "SFP": + get_sfp_transceiver_bulk_status + else: + get_qsfp_transceiver_bulk_status + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + Returns: + A dict which contains following keys/values : + """ + if self.sfp_type == "SFP": + get_sfp_transceiver_threshold_info + else: + get_qsfp_transceiver_threshold_info + + def get_sfp_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 + nominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + ======================================================================== + """ + # check present status + 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(self.info_dict_keys, 'N/A') + compliance_code_dict = dict() + + 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['manufacturename'] = sfp_vendor_name_data[ + 'data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A' + transceiver_info_dict['modelname'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A' + transceiver_info_dict['hardwarerev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' + transceiver_info_dict['serialnum'] = 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']) + + for key in sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_info_dict + + def get_sfp_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. + ======================================================================== + """ + # check present status + sfpd_obj = sff8472Dom() + if not self.get_presence() or not sfpd_obj: + return {} + + 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(self.dom_dict_keys, 'N/A') + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_voltage_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_voltage_data['data']['TXPower']['value'] + transceiver_dom_info_dict['rx1power'] = dom_voltage_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_voltage_data['data']['TXBias']['value'] + + for key in transceiver_dom_info_dict: + transceiver_dom_info_dict[key] = self._convert_string_to_num( + transceiver_dom_info_dict[key]) + + transceiver_dom_info_dict['rx_los'] = self.get_rx_los() + transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + + return transceiver_dom_info_dict + + def get_sfp_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. + ======================================================================== + """ + # check present status + sfpd_obj = sff8472Dom() + + if not self.get_presence() and not sfpd_obj: + return {} + + 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( + self.threshold_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_qsfp_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 + nominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + ======================================================================== + """ + # check present status + 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(self.info_dict_keys, 'N/A') + compliance_code_dict = dict() + + 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['manufacturename'] = sfp_vendor_name_data[ + 'data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A' + transceiver_info_dict['modelname'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A' + transceiver_info_dict['hardwarerev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' + transceiver_info_dict['serialnum'] = 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']) + + for key in qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + + return transceiver_info_dict + + def get_qsfp_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. + ======================================================================== + """ + # check present status + 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(self.dom_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_qsfp_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['lp_mode'] = self.get_lpmode() + + return transceiver_dom_info_dict + + def get_qsfp_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. + ======================================================================== + """ + # check present status + sfpd_obj = sff8436Dom() + + if not self.get_presence() or not sfpd_obj: + return {} + + transceiver_dom_threshold_dict = dict.fromkeys( + self.threshold_dict_keys, 'N/A') + dom_thres_raw = self.__read_eeprom_specific_bytes( + QSFP_MODULE_THRESHOLD_OFFSET, QSFP_MODULE_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None + + if dom_thres_raw: + module_threshold_values = sfpd_obj.parse_module_threshold_values( + dom_thres_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_thres_raw = self.__read_eeprom_specific_bytes( + QSFP_CHANNEL_THRESHOLD_OFFSET, QSFP_CHANNEL_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None + channel_threshold_values = sfpd_obj.parse_channel_threshold_values( + dom_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 + """ + # 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_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.index] + 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_sfp_i2c_client_eeprom_path, mode="r+b", buffering=0) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom.seek(SFP_STATUS_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except: + #print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + return False + + 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 + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings( + self.__get_path_to_port_config_file()) + name = sfputil_helper.logical[self.index] or "Unknown" + return name + + def get_presence(self): + """ + Retrieves the presence of the SFP + Returns: + bool: True if SFP is present, False if not + """ + presence = False + + try: + with open(self.PRS_PATH.format(self.index), 'r') as sfp_presence: + presence = int(sfp_presence.read(), 16) + except IOError: + return False + logger.log_info("debug:port_ %s sfp presence is %s" % (str(self.index)), % (str(presence)) + return presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + transceiver_dom_info_dict = self.get_transceiver_info() + return transceiver_dom_info_dict.get("modelname", "N/A") + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + transceiver_dom_info_dict = self.get_transceiver_info() + return transceiver_dom_info_dict.get("serialnum", "N/A") diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/__init__.py b/platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/fanutil.py b/platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/fanutil.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/thermalutil.py b/platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/thermalutil.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/service/as7116-platform-init.service b/platform/nephos/sonic-platform-modules-accton/as7116-54x/service/as7116-platform-init.service index 4331c8828eea..6eaf4745210c 100755 --- a/platform/nephos/sonic-platform-modules-accton/as7116-54x/service/as7116-platform-init.service +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/service/as7116-platform-init.service @@ -1,6 +1,7 @@ [Unit] Description=Accton AS7116-54X Platform initialization service Before=pmon.service +After=sysinit.target DefaultDependencies=no [Service] @@ -10,4 +11,4 @@ ExecStop=/usr/local/bin/accton_as7116_util.py clean RemainAfterExit=yes [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/service/platform_api/platform_api_mgnt.sh b/platform/nephos/sonic-platform-modules-accton/as7116-54x/service/platform_api/platform_api_mgnt.sh new file mode 100755 index 000000000000..e1d330357894 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/service/platform_api/platform_api_mgnt.sh @@ -0,0 +1,41 @@ +#!/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 +} + +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/nephos/sonic-platform-modules-accton/as7116-54x/setup.py b/platform/nephos/sonic-platform-modules-accton/as7116-54x/setup.py index bb740409e310..088e1f30355a 100644 --- a/platform/nephos/sonic-platform-modules-accton/as7116-54x/setup.py +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/setup.py @@ -1,15 +1,34 @@ -#!/usr/bin/env python - -import os -import sys from setuptools import setup -os.listdir -setup( - name='as7116-54x', - version='1.0.0', - description='Module to initialize Accton AS7116-54X platforms', +DEVICE_NAME = 'accton' +HW_SKU = 'x86_64-accton_as7116_54x-r0' - packages=['as7116-54x'], - package_dir={'as7116-54x': 'as7116-54x/classes'}, - ) +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Accton Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + maintainer='Simon Ji', + maintainer_email='Simon.Ji@mediatek.com', + packages=[ + 'sonic_platform', + ], + package_dir={ + 'sonic_platform': '../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)}, + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 2.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/utils/accton_as7116_util.py b/platform/nephos/sonic-platform-modules-accton/as7116-54x/utils/accton_as7116_util.py index 26a8a3cc8f84..2d9ea128f976 100755 --- a/platform/nephos/sonic-platform-modules-accton/as7116-54x/utils/accton_as7116_util.py +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/utils/accton_as7116_util.py @@ -21,13 +21,13 @@ options: -h | --help : this help message -d | --debug : run with debug mode - -f | --force : ignore error during installation or clean + -f | --force : ignore error during installation or clean command: install : install drivers and generate related sysfs nodes clean : uninstall drivers and remove related sysfs nodes show : show all systen status sff : dump SFP eeprom - set : change board setting with fan|led|sfp + set : change board setting with fan|led|sfp """ import os @@ -46,7 +46,7 @@ verbose = False DEBUG = False args = [] -ALL_DEVICE = {} +ALL_DEVICE = {} DEVICE_NO = {'led':5, 'fan':1, 'thermal':3, 'psu':2, 'sfp':54} FORCE = 0 #logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG) @@ -55,37 +55,37 @@ if DEBUG == True: print sys.argv[0] - print 'ARGV :', sys.argv[1:] + print 'ARGV :', sys.argv[1:] def main(): global DEBUG global args global FORCE - + if len(sys.argv)<2: show_help() - + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', 'debug', 'force', ]) - if DEBUG == True: + if DEBUG == True: print options print args print len(sys.argv) - + for opt, arg in options: if opt in ('-h', '--help'): show_help() - elif opt in ('-d', '--debug'): + elif opt in ('-d', '--debug'): DEBUG = True logging.basicConfig(level=logging.INFO) - elif opt in ('-f', '--force'): + elif opt in ('-f', '--force'): FORCE = 1 else: - logging.info('no option') - for arg in args: + logging.info('no option') + for arg in args: if arg == 'install': do_install() elif arg == 'clean': @@ -95,23 +95,23 @@ def main(): elif arg == 'sff': if len(args)!=2: show_eeprom_help() - elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']: + elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']: show_eeprom_help() else: - show_eeprom(args[1]) - return + show_eeprom(args[1]) + return elif arg == 'set': if len(args)<3: show_set_help() else: - set_device(args[1:]) - return + set_device(args[1:]) + return else: show_help() - - - return 0 - + + + return 0 + def show_help(): print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} sys.exit(0) @@ -120,36 +120,36 @@ def show_set_help(): cmd = sys.argv[0].split("/")[-1]+ " " + args[0] print cmd +" [led|sfp|fan]" print " use \""+ cmd + " led 0-4 \" to set led color" - print " use \""+ cmd + " fan 0-100\" to set fan duty percetage" - print " use \""+ cmd + " sfp 1-54 {0|1}\" to set sfp# tx_disable" - sys.exit(0) - + print " use \""+ cmd + " fan 0-100\" to set fan duty percetage" + print " use \""+ cmd + " sfp 1-54 {0|1}\" to set sfp# tx_disable" + sys.exit(0) + def show_eeprom_help(): cmd = sys.argv[0].split("/")[-1]+ " " + args[0] - print " use \""+ cmd + " 1-54 \" to dump sfp# eeprom" - sys.exit(0) - + print " use \""+ cmd + " 1-54 \" to dump sfp# eeprom" + sys.exit(0) + def my_log(txt): if DEBUG == True: - print "[ROY]"+txt + print "[ROY]"+txt return - + def log_os_system(cmd, show): - logging.info('Run :'+cmd) - status, output = commands.getstatusoutput(cmd) + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) my_log (cmd +"with result:" + str(status)) - my_log (" output:"+output) + my_log (" output:"+output) if status: logging.info('Failed :'+cmd) if show: print('Failed :'+cmd) return status, output - + def driver_check(): ret, lsmod = log_os_system("lsmod| grep accton", 0) logging.info('mods:'+lsmod) if len(lsmod) ==0: - return False + return False return True @@ -169,19 +169,19 @@ def driver_install(): for i in range(0,len(kos)): status, output = log_os_system(kos[i], 1) if status: - if FORCE == 0: - return status + if FORCE == 0: + return status return 0 - + def driver_uninstall(): global FORCE for i in range(0,len(kos)): rm = kos[-(i+1)].replace("modprobe", "modprobe -rq") - rm = rm.replace("insmod", "rmmod") + rm = rm.replace("insmod", "rmmod") status, output = log_os_system(rm, 1) if status: - if FORCE == 0: - return status + if FORCE == 0: + return status return 0 led_prefix ='/sys/class/leds/'+PROJECT_NAME+'_led::' @@ -192,13 +192,13 @@ def driver_uninstall(): i2c_prefix = '/sys/bus/i2c/devices/' i2c_bus = {'fan': ['1-0063'] , 'thermal': ['17-004b','19-0049', '20-004a'] , - 'psu': ['10-0050','11-0058'], + 'psu': ['10-0050','11-0058'], 'sfp': ['-0050']} i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'] , 'thermal': ['hwmon/hwmon*/temp1_input'] , 'psu': ['psu_present ', 'psu_power_good'] , 'sfp': ['sfp_is_present ', 'sfp_tx_disable_all']} - + sfp_map = [37,38,39,40, 41,42,43,44,45,46,47,48,49,50, 51,52,53,54,55,56,57,58,59,60, @@ -234,23 +234,23 @@ def driver_uninstall(): def device_install(): global FORCE - + for i in range(0,len(mknod)): - #for pca954x need times to built new i2c buses + #for pca954x need times to built new i2c buses if mknod[i].find('pca954') != -1: time.sleep(1) - + status, output = log_os_system(mknod[i], 1) if status: print output - if FORCE == 0: + if FORCE == 0: return status - + for i in range(0,len(sfp_map)): status, output =log_os_system("echo as7116_54x_sfp"+str(i+1)+" 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) if status: print output - if FORCE == 0: + if FORCE == 0: return status if i <= 47: @@ -260,11 +260,11 @@ def device_install(): if FORCE == 0: return status - return - + return + def device_uninstall(): global FORCE - + status, output =log_os_system("ls /sys/bus/i2c/devices/1-0077", 0) for i in range(0,len(sfp_map)): @@ -272,11 +272,11 @@ def device_uninstall(): status, output =log_os_system("echo 0x50 > "+ target, 1) if status: print output - if FORCE == 0: + if FORCE == 0: return status - + nodelist = mknod - + for i in range(len(nodelist)): target = nodelist[-(i+1)] temp = target.split() @@ -285,72 +285,79 @@ def device_uninstall(): status, output = log_os_system(" ".join(temp), 1) if status: print output - if FORCE == 0: - return status - - return - + if FORCE == 0: + return status + + return + def system_ready(): if driver_check() == False: return False - if not device_exist(): + if not device_exist(): return False return True - + def do_install(): print "Checking system...." if driver_check() == False: - print "No driver, installing...." + print "No driver, installing...." status = driver_install() if status: - if FORCE == 0: + if FORCE == 0: return status else: - print PROJECT_NAME.upper()+" drivers detected...." + print PROJECT_NAME.upper()+" drivers detected...." if not device_exist(): - print "No device, installing...." - status = device_install() + print "No device, installing...." + status = device_install() if status: - if FORCE == 0: - return status + if FORCE == 0: + return status else: - print PROJECT_NAME.upper()+" devices detected...." + print PROJECT_NAME.upper()+" devices detected...." + + status, output = log_os_system( + "/bin/sh /usr/local/bin/platform_api_mgnt.sh init", 1) + if status: + print output + if FORCE == 0: + return status return - + def do_uninstall(): print "Checking system...." if not device_exist(): - print PROJECT_NAME.upper() +" has no device installed...." + print PROJECT_NAME.upper() +" has no device installed...." else: - print "Removing device...." - status = device_uninstall() + print "Removing device...." + status = device_uninstall() if status: - if FORCE == 0: - return status - + if FORCE == 0: + return status + if driver_check()== False : print PROJECT_NAME.upper() +" has no driver installed...." else: print "Removing installed driver...." status = driver_uninstall() if status: - if FORCE == 0: - return status - - return + if FORCE == 0: + return status + + return def devices_info(): global DEVICE_NO global ALL_DEVICE global i2c_bus, hwmon_types - for key in DEVICE_NO: - ALL_DEVICE[key]= {} + for key in DEVICE_NO: + ALL_DEVICE[key]= {} for i in range(0,DEVICE_NO[key]): ALL_DEVICE[key][key+str(i+1)] = [] - + for key in i2c_bus: buses = i2c_bus[key] - nodes = i2c_nodes[key] + nodes = i2c_nodes[key] for i in range(0,len(buses)): for j in range(0,len(nodes)): if 'fan' == key: @@ -358,52 +365,52 @@ def devices_info(): node = key+str(k+1) path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j] my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) + ALL_DEVICE[key][node].append(path) elif 'sfp' == key: for k in range(0,DEVICE_NO[key]): node = key+str(k+1) - path = i2c_prefix+ str(sfp_map[k])+ buses[i]+"/"+ nodes[j] + path = i2c_prefix+ str(sfp_map[k])+ buses[i]+"/"+ nodes[j] my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) + ALL_DEVICE[key][node].append(path) else: node = key+str(i+1) - path = i2c_prefix+ buses[i]+"/"+ nodes[j] + path = i2c_prefix+ buses[i]+"/"+ nodes[j] my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) - + ALL_DEVICE[key][node].append(path) + for key in hwmon_types: itypes = hwmon_types[key] - nodes = hwmon_nodes[key] + nodes = hwmon_nodes[key] for i in range(0,len(itypes)): - for j in range(0,len(nodes)): + for j in range(0,len(nodes)): node = key+"_"+itypes[i] - path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] + path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] my_log(node+": "+ path) - ALL_DEVICE[key][ key+str(i+1)].append(path) - + ALL_DEVICE[key][ key+str(i+1)].append(path) + #show dict all in the order if DEBUG == True: for i in sorted(ALL_DEVICE.keys()): print(i+": ") - for j in sorted(ALL_DEVICE[i].keys()): + for j in sorted(ALL_DEVICE[i].keys()): print(" "+j) - for k in (ALL_DEVICE[i][j]): + for k in (ALL_DEVICE[i][j]): print(" "+" "+k) - return - + return + def show_eeprom(index): if system_ready()==False: - print("System's not ready.") + print("System's not ready.") print("Please install first!") - return - + return + if len(ALL_DEVICE)==0: - devices_info() + devices_info() node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0] node = node.replace(node.split("/")[-1], 'sfp_eeprom') # check if got hexdump command in current environment ret, log = log_os_system("which hexdump", 0) - ret, log2 = log_os_system("which busybox hexdump", 0) + ret, log2 = log_os_system("which busybox hexdump", 0) if len(log): hex_cmd = 'hexdump' elif len(log2): @@ -412,111 +419,111 @@ def show_eeprom(index): log = 'Failed : no hexdump cmd!!' logging.info(log) print log - return 1 - + return 1 + print node + ":" ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1) - if ret==0: - print log + if ret==0: + print log else: - print "**********device no found**********" - return - + print "**********device no found**********" + return + def set_device(args): global DEVICE_NO global ALL_DEVICE if system_ready()==False: - print("System's not ready.") + print("System's not ready.") print("Please install first!") - return - + return + if len(ALL_DEVICE)==0: - devices_info() - + devices_info() + if args[0]=='led': if int(args[1])>4: show_set_help() return #print ALL_DEVICE['led'] - for i in range(0,len(ALL_DEVICE['led'])): - for k in (ALL_DEVICE['led']['led'+str(i+1)]): + for i in range(0,len(ALL_DEVICE['led'])): + for k in (ALL_DEVICE['led']['led'+str(i+1)]): ret, log = log_os_system("echo "+args[1]+" >"+k, 1) if ret: - return ret + return ret elif args[0]=='fan': if int(args[1])>100: show_set_help() return #print ALL_DEVICE['fan'] - #fan1~6 is all fine, all fan share same setting - node = ALL_DEVICE['fan'] ['fan1'][0] + #fan1~6 is all fine, all fan share same setting + node = ALL_DEVICE['fan'] ['fan1'][0] node = node.replace(node.split("/")[-1], 'fan_duty_cycle_percentage') - ret, log = log_os_system("cat "+ node, 1) + ret, log = log_os_system("cat "+ node, 1) if ret==0: - print ("Previous fan duty: " + log.strip() +"%") + print ("Previous fan duty: " + log.strip() +"%") ret, log = log_os_system("echo "+args[1]+" >"+node, 1) if ret==0: - print ("Current fan duty: " + args[1] +"%") + print ("Current fan duty: " + args[1] +"%") return ret elif args[0]=='sfp': if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0: show_set_help() - return + return if len(args)<2: show_set_help() - return - + return + if int(args[2])>1: show_set_help() return - - #print ALL_DEVICE[args[0]] - for i in range(0,len(ALL_DEVICE[args[0]])): - for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]: - if j.find('tx_disable')!= -1: + + #print ALL_DEVICE[args[0]] + for i in range(0,len(ALL_DEVICE[args[0]])): + for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]: + if j.find('tx_disable')!= -1: ret, log = log_os_system("echo "+args[2]+" >"+ j, 1) if ret: - return ret - + return ret + return - -#get digits inside a string. -#Ex: 31 for "sfp31" + +#get digits inside a string. +#Ex: 31 for "sfp31" def get_value(input): digit = re.findall('\d+', input) return int(digit[0]) - + def device_traversal(): if system_ready()==False: - print("System's not ready.") + print("System's not ready.") print("Please install first!") - return - + return + if len(ALL_DEVICE)==0: devices_info() for i in sorted(ALL_DEVICE.keys()): - print("============================================") + print("============================================") print(i.upper()+": ") print("============================================") - - for j in sorted(ALL_DEVICE[i].keys(), key=get_value): + + for j in sorted(ALL_DEVICE[i].keys(), key=get_value): print " "+j+":", for k in (ALL_DEVICE[i][j]): ret, log = log_os_system("cat "+k, 0) func = k.split("/")[-1].strip() func = re.sub(j+'_','',func,1) - func = re.sub(i.lower()+'_','',func,1) + func = re.sub(i.lower()+'_','',func,1) if ret==0: - print func+"="+log+" ", + print func+"="+log+" ", else: print func+"="+"X"+" ", - print + print print("----------------------------------------------------------------") - - + + print return - + def device_exist(): ret1, log = log_os_system("ls "+i2c_prefix+"*0077", 0) ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0) diff --git a/platform/nephos/sonic-platform-modules-accton/debian/rules b/platform/nephos/sonic-platform-modules-accton/debian/rules index 44caba25cfa2..de84b23d55ae 100755 --- a/platform/nephos/sonic-platform-modules-accton/debian/rules +++ b/platform/nephos/sonic-platform-modules-accton/debian/rules @@ -1,19 +1,8 @@ #!/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 +PYTHON ?= python2.7 PACKAGE_PRE_NAME := sonic-platform-accton KVERSION ?= $(shell uname -r) @@ -27,60 +16,25 @@ CLASSES_DIR := classes CONF_DIR := conf %: - dh $@ --with systemd,python2,python3 --buildsystem=pybuild - -clean: - dh_testdir - dh_testroot - dh_clean + dh $@ -build: - #make modules -C $(KERNEL_SRC)/build M=$(MODULE_SRC) +override_dh_auto_build: (for mod in $(MODULE_DIRS); do \ make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ - $(PYTHON) $${mod}/setup.py build; \ + $(PYTHON) $${mod}/setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ 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 +override_dh_auto_install: + (for mod in $(MODULE_DIRS); do \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} /$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko \ + debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + done) -binary-indep: - dh_testdir - dh_installdirs +override_dh_usrlocal: - # Custom package commands +override_dh_clean: + dh_clean (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} /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)/$${mod}/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ - cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \ - $(PYTHON) $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \ + make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules clean; \ 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 \ No newline at end of file diff --git a/platform/nephos/sonic-platform-modules-accton/debian/sonic-platform-accton-as7116-54x.install b/platform/nephos/sonic-platform-modules-accton/debian/sonic-platform-accton-as7116-54x.install new file mode 100644 index 000000000000..61423affe7ac --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/debian/sonic-platform-accton-as7116-54x.install @@ -0,0 +1,4 @@ +as7116-54x/utils/* usr/local/bin +as7116-54x/service/*.service lib/systemd/system +as7116-54x/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-accton_as7116_54x-r0 +as7116-54x/service/platform_api/platform_api_mgnt.sh usr/local/bin diff --git a/platform/nephos/sonic-platform-modules-accton/debian/sonic-platform-accton-as7116-54x.postinst b/platform/nephos/sonic-platform-modules-accton/debian/sonic-platform-accton-as7116-54x.postinst new file mode 100644 index 000000000000..a9947af877b6 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/debian/sonic-platform-accton-as7116-54x.postinst @@ -0,0 +1,5 @@ +depmod -a +systemctl enable as7116-platform-init.service +systemctl start as7116-platform-init.service + +/usr/local/bin/platform_api_mgnt.sh install From be3421c352c1a16c8efaa95b3ee39b2ede24306f Mon Sep 17 00:00:00 2001 From: "Sudharsan D.G" Date: Fri, 8 Nov 2019 22:57:05 -0800 Subject: [PATCH 152/278] [docker-ptf]: Added python-libpcap for the updated arp responder (#3731) Added python-libpcap to be used by arp_responder.py utility. This is needed to set conf.use_pcap which will make sure that L2pcapListenSocket uses libpcap instead of Linux PF_PACKET sockets. By using libpcap the vlan field will not be removed when the application receives the packet. --- dockers/docker-ptf/Dockerfile.j2 | 1 + 1 file changed, 1 insertion(+) diff --git a/dockers/docker-ptf/Dockerfile.j2 b/dockers/docker-ptf/Dockerfile.j2 index 79c2802c0429..dcf67aeff5f9 100644 --- a/dockers/docker-ptf/Dockerfile.j2 +++ b/dockers/docker-ptf/Dockerfile.j2 @@ -53,6 +53,7 @@ RUN sed --in-place 's/httpredir.debian.org/debian-archive.trafficmanager.net/' / tcpdump \ python \ python-dev \ + python-libpcap \ python-scapy \ python-six From c70d8bca9fcf97388c34d9a40bfc25aba496bc7f Mon Sep 17 00:00:00 2001 From: Olivier Singla <47356901+olivier-singla@users.noreply.github.com> Date: Sat, 9 Nov 2019 02:08:42 -0500 Subject: [PATCH 153/278] [baseimage]: kdump support (#3722) * In the event of a kernel crash, we need to gather as much information as possible to understand and identify the root cause of the crash. Currently, the kernel does not provide much information, which make kernel crash investigation difficult and time consuming. Fortunately, there is a way in the kernel to provide more information in the case of a kernel crash. kdump is a feature of the Linux kernel that creates crash dumps in the event of a kernel crash. This PR will add kermel kdump support. An extension to the CLI utilities config and show is provided to configure and manage kdump: - enable / disable kdump functionality - configure kdump (how many kernel crash logs can be saved, memory allocated for capture kernel) - view kernel crash logs --- build_debian.sh | 7 +++- .../build_templates/sonic_debian_extension.j2 | 4 ++ rules/kdump-tools.mk | 13 ++++++ slave.mk | 1 + sonic-slave-stretch/Dockerfile.j2 | 4 +- src/kdump-tools/Makefile | 32 +++++++++++++++ ...amfs-for-installed-kernels-in-chroot.patch | 41 +++++++++++++++++++ .../0002-core-file-prefixed-by-kdump.patch | 24 +++++++++++ src/kdump-tools/patch/series | 2 + 9 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 rules/kdump-tools.mk create mode 100644 src/kdump-tools/Makefile create mode 100644 src/kdump-tools/patch/0001-Generate-initramfs-for-installed-kernels-in-chroot.patch create mode 100644 src/kdump-tools/patch/0002-core-file-prefixed-by-kdump.patch create mode 100644 src/kdump-tools/patch/series diff --git a/build_debian.sh b/build_debian.sh index d1e5273b1c71..fb3ecfef6ce6 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -272,7 +272,8 @@ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y in locales \ cgroup-tools \ ipmitool \ - ndisc6 + ndisc6 \ + makedumpfile if [[ $CONFIGURED_ARCH == amd64 ]]; then @@ -289,6 +290,10 @@ sudo LANG=c chroot $FILESYSTEM_ROOT chmod 600 /etc/shadow sudo LANG=c chroot $FILESYSTEM_ROOT chmod 644 /etc/passwd sudo LANG=c chroot $FILESYSTEM_ROOT chmod 644 /etc/group +# Needed to install kdump-tools +sudo LANG=C chroot $FILESYSTEM_ROOT /bin/bash -c "mkdir -p /etc/initramfs-tools/conf.d" +sudo LANG=C chroot $FILESYSTEM_ROOT /bin/bash -c "echo 'MODULES=most' >> /etc/initramfs-tools/conf.d/driver-policy" + #Adds a locale to a debian system in non-interactive mode sudo sed -i '/^#.* en_US.* /s/^#//' $FILESYSTEM_ROOT/etc/locale.gen && \ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT locale-gen "en_US.UTF-8" diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index f5a734b3a273..d81815284a34 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -160,6 +160,10 @@ sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/libnss-tacplus_*.deb || \ sudo LANG=C chroot $FILESYSTEM_ROOT pam-auth-update --remove tacplus sudo sed -i -e '/^passwd/s/ tacplus//' $FILESYSTEM_ROOT/etc/nsswitch.conf +# Install a custom version of kdump-tools (and its dependencies via 'apt-get -y install -f') +sudo DEBIAN_FRONTEND=noninteractive dpkg --root=$FILESYSTEM_ROOT -i $debs_path/kdump-tools_*.deb || \ + sudo LANG=C DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=truechroot $FILESYSTEM_ROOT apt-get -q --no-install-suggests --no-install-recommends --force-no install + # Copy crontabs sudo cp -f $IMAGE_CONFIGS/cron.d/* $FILESYSTEM_ROOT/etc/cron.d/ diff --git a/rules/kdump-tools.mk b/rules/kdump-tools.mk new file mode 100644 index 000000000000..d5d2630389f3 --- /dev/null +++ b/rules/kdump-tools.mk @@ -0,0 +1,13 @@ +# kdump-tools package + +KDUMP_TOOLS_VERSION_BASE = 1.6.1 +KDUMP_TOOLS_VERSION = $(KDUMP_TOOLS_VERSION_BASE)-1 +export KDUMP_TOOLS_VERSION_BASE +export KDUMP_TOOLS_VERSION + +KDUMP_TOOLS = kdump-tools_$(KDUMP_TOOLS_VERSION)_all.deb +$(KDUMP_TOOLS)_SRC_PATH = $(SRC_PATH)/kdump-tools +SONIC_MAKE_DEBS += $(KDUMP_TOOLS) +SONIC_STRETCH_DEBS += $(KDUMP_TOOLS) + +export KDUMP_TOOLS diff --git a/slave.mk b/slave.mk index 1f5f3de7b3b0..f81895f74dd2 100644 --- a/slave.mk +++ b/slave.mk @@ -614,6 +614,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ $(SONIC_DEVICE_DATA) \ $(PYTHON_CLICK) \ $(IFUPDOWN2) \ + $(KDUMP_TOOLS) \ $(LIBPAM_TACPLUS) \ $(LIBNSS_TACPLUS)) \ $$(addprefix $(TARGET_PATH)/,$$($$*_DOCKERS)) \ diff --git a/sonic-slave-stretch/Dockerfile.j2 b/sonic-slave-stretch/Dockerfile.j2 index af6e7deadc31..f52bd943b0a7 100644 --- a/sonic-slave-stretch/Dockerfile.j2 +++ b/sonic-slave-stretch/Dockerfile.j2 @@ -289,7 +289,9 @@ RUN apt-get update && apt-get install -y \ rrdtool \ # For smartmontools 6.6-1 automake1.11 \ - libselinux1-dev + libselinux1-dev \ +# For kdump-tools + liblzo2-dev # For smartmontools 6.6-1 RUN apt-get -t stretch-backports install -y debhelper diff --git a/src/kdump-tools/Makefile b/src/kdump-tools/Makefile new file mode 100644 index 000000000000..18c2a369b5d7 --- /dev/null +++ b/src/kdump-tools/Makefile @@ -0,0 +1,32 @@ +.ONESHELL: +SHELL = /bin/bash +.SHELLFLAGS += -e + +MAIN_TARGET = $(KDUMP_TOOLS) + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # Remove any stale files + rm -rf ./makedumpfile_$(KDUMP_TOOLS_VERSION_BASE).orig.tar.gz ./makedumpfile_$(KDUMP_TOOLS_VERSION).debian.tar.xz + rm -rf ./makedumpfile-$(KDUMP_TOOLS_VERSION_BASE) + + # Get makedumpfile release + wget http://deb.debian.org/debian/pool/main/m/makedumpfile/makedumpfile_$(KDUMP_TOOLS_VERSION_BASE).orig.tar.gz + wget http://deb.debian.org/debian/pool/main/m/makedumpfile/makedumpfile_$(KDUMP_TOOLS_VERSION).debian.tar.xz + tar -f makedumpfile_$(KDUMP_TOOLS_VERSION_BASE).orig.tar.gz -x + pushd ./makedumpfile-$(KDUMP_TOOLS_VERSION_BASE) + tar -f ../makedumpfile_$(KDUMP_TOOLS_VERSION).debian.tar.xz -x + + git init + git add -f * + git commit -m "unmodified kdump-tools source" + + # Apply patches + stg init + stg import -s ../patch/series + + # Build source and Debian packages + fakeroot debian/rules binary-indep + popd + + # Move the newly-built .deb packages to the destination directory + mv $* $(DEST)/ diff --git a/src/kdump-tools/patch/0001-Generate-initramfs-for-installed-kernels-in-chroot.patch b/src/kdump-tools/patch/0001-Generate-initramfs-for-installed-kernels-in-chroot.patch new file mode 100644 index 000000000000..1d994b88bd58 --- /dev/null +++ b/src/kdump-tools/patch/0001-Generate-initramfs-for-installed-kernels-in-chroot.patch @@ -0,0 +1,41 @@ +From 7e6c0d5b0c7299154f75f281c02cf02cf85fb80e Mon Sep 17 00:00:00 2001 +From: Benjamin Drung +Date: Thu, 2 Mar 2017 19:52:23 +0100 +Subject: [PATCH] Generate initramfs for installed kernels in chroot + +The postinst script from kdump-tools creates an initramfs for the +running kernel. When running inside a chroot, the running kernel (from +the host) might differ from the kernels that are available in the +chroot. + +Thus generate the initramfs only when the running kernel is installed in +the system. Otherwise generate the initramfs for all installed kernels. + +Bug-Debian: #856594 +--- + debian/kdump-tools.postinst | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/debian/kdump-tools.postinst b/debian/kdump-tools.postinst +index 4b6c6be..f604c8e 100755 +--- a/debian/kdump-tools.postinst ++++ b/debian/kdump-tools.postinst +@@ -33,7 +33,15 @@ update_param() { + case "$1" in + configure) + # create smaller initrd.img files for kdump use +- /etc/kernel/postinst.d/kdump-tools $(uname -r) > /dev/null 2>&1 ++ if test -d /lib/modules/$(uname -r); then ++ /etc/kernel/postinst.d/kdump-tools $(uname -r) > /dev/null 2>&1 ++ else ++ # Running kernel not installed. Running in chroot? ++ for kernel_release in $(ls /lib/modules/); do ++ /etc/kernel/postinst.d/kdump-tools $kernel_release > /dev/null 2>&1 ++ kdump-config symlinks $kernel_release ++ done ++ fi + + # Customize crashkernel= value according to architecture + ARCH="$(arch)" +-- +2.9.3 diff --git a/src/kdump-tools/patch/0002-core-file-prefixed-by-kdump.patch b/src/kdump-tools/patch/0002-core-file-prefixed-by-kdump.patch new file mode 100644 index 000000000000..2ed480b26175 --- /dev/null +++ b/src/kdump-tools/patch/0002-core-file-prefixed-by-kdump.patch @@ -0,0 +1,24 @@ +--- a/debian/kdump-config.orig 2019-10-24 09:38:19.006679000 -0700 ++++ b/debian/kdump-config 2019-10-24 12:16:23.791899000 -0700 +@@ -639,8 +639,8 @@ + { + KDUMP_STAMP=`date +"%Y%m%d%H%M"` + KDUMP_STAMPDIR=$(define_stampdir $KDUMP_STAMP) +- KDUMP_CORETEMP="$KDUMP_STAMPDIR/dump-incomplete" +- KDUMP_COREFILE="$KDUMP_STAMPDIR/dump.$KDUMP_STAMP" ++ KDUMP_CORETEMP="$KDUMP_STAMPDIR/kdump-incomplete" ++ KDUMP_COREFILE="$KDUMP_STAMPDIR/kdump.$KDUMP_STAMP" + KDUMP_DMESGFILE="$KDUMP_STAMPDIR/dmesg.$KDUMP_STAMP" + + # If we use NFS, verify that we can mount the FS +@@ -755,8 +755,8 @@ + KDUMP_STAMP=`date +"%Y%m%d%H%M"` + KDUMP_STAMPDIR=$(define_stampdir $KDUMP_STAMP) + +- KDUMP_CORETEMP="$KDUMP_STAMPDIR/dump-incomplete" +- KDUMP_COREFILE="$KDUMP_STAMPDIR/dump.$KDUMP_STAMP" ++ KDUMP_CORETEMP="$KDUMP_STAMPDIR/kdump-incomplete" ++ KDUMP_COREFILE="$KDUMP_STAMPDIR/kdump.$KDUMP_STAMP" + KDUMP_TMPDMESG="/tmp/dmesg.$KDUMP_STAMP" + KDUMP_DMESGFILE="$KDUMP_STAMPDIR/dmesg.$KDUMP_STAMP" + ERROR=0 diff --git a/src/kdump-tools/patch/series b/src/kdump-tools/patch/series new file mode 100644 index 000000000000..e1a26e55ca1b --- /dev/null +++ b/src/kdump-tools/patch/series @@ -0,0 +1,2 @@ +0001-Generate-initramfs-for-installed-kernels-in-chroot.patch +0002-core-file-prefixed-by-kdump.patch From fd8232817f27304c4b2a13f3f3588a60af80b4dc Mon Sep 17 00:00:00 2001 From: sandeep-kulambi <50737942+sandeep-kulambi@users.noreply.github.com> Date: Sat, 9 Nov 2019 12:40:12 +0530 Subject: [PATCH 154/278] [lldp]: ensure the LLDP PDU is sent immediately when the tx-interval is modified. (#3705) When LLDP parameter tx-interval value is modified, there was no immediate PDU sent to peer to update the peer with the latest values. Due to this the update on peer happened only after the next PDU is sent which can cause a delay of upto 30 secs (default value). --- .../0003-update-tx-interval-immediately.patch | 20 +++++++++++++++++++ src/lldpd/patch/series | 1 + 2 files changed, 21 insertions(+) create mode 100644 src/lldpd/patch/0003-update-tx-interval-immediately.patch diff --git a/src/lldpd/patch/0003-update-tx-interval-immediately.patch b/src/lldpd/patch/0003-update-tx-interval-immediately.patch new file mode 100644 index 000000000000..b6b295001288 --- /dev/null +++ b/src/lldpd/patch/0003-update-tx-interval-immediately.patch @@ -0,0 +1,20 @@ +diff --git a/src/daemon/client.c b/src/daemon/client.c +index 8382d02..38cf3f3 100644 +--- a/src/daemon/client.c ++++ b/src/daemon/client.c +@@ -71,7 +71,6 @@ client_handle_set_configuration(struct lldpd *cfg, enum hmsg_type *type, + if (CHANGED(c_tx_interval) && config->c_tx_interval != 0) { + if (config->c_tx_interval < 0) { + log_debug("rpc", "client asked for immediate retransmission"); +- levent_send_now(cfg); + } else { + log_debug("rpc", "client change transmit interval to %d", + config->c_tx_interval); +@@ -79,6 +78,7 @@ client_handle_set_configuration(struct lldpd *cfg, enum hmsg_type *type, + LOCAL_CHASSIS(cfg)->c_ttl = cfg->g_config.c_tx_interval * + cfg->g_config.c_tx_hold; + } ++ levent_send_now(cfg); + } + if (CHANGED(c_tx_hold) && config->c_tx_hold > 0) { + log_debug("rpc", "client change transmit hold to %d", diff --git a/src/lldpd/patch/series b/src/lldpd/patch/series index 2ca46b575396..5e5e8bc99714 100644 --- a/src/lldpd/patch/series +++ b/src/lldpd/patch/series @@ -1,3 +1,4 @@ # This series applies on GIT commit 396961a038a38675d46f96eaa7b430b2a1f8701b 0001-return-error-when-port-does-not-exist.patch 0002-Let-linux-kernel-to-find-appropriate-nl_pid-automa.patch +0003-update-tx-interval-immediately.patch From 099f9b0a6ac0e7795516bdbb0791abae2161158c Mon Sep 17 00:00:00 2001 From: CharlieChenEC <49221644+CharlieChenEC@users.noreply.github.com> Date: Sun, 10 Nov 2019 02:23:18 +0800 Subject: [PATCH 155/278] [devices]:start opennsl modules after platform handle mac service on AS7326-56X/AS7726-56X (#3726) AS7326-56X and AS7726-56X use the same design so both devices have the same problem. The detailed description below takes AS7326-56X as the example to explain. Original implementation: - In platform/broadcom/sonic-platform-modules-accton/as7326-56x/service/as7326-platform-handle_mac.service, it executes the script file "accton_handle_idt.sh". - In "accton_handle_idt.sh", it modifies the content of the script file "/etc/init.d/opennsl-modules" to insert the lines to execute "idt_init.sh" before the command to load broadcom linux kernel module "linux-kernel-bde.ko". - The script "idt_init.sh" cannot be executed at the first boot of SONiC after installing SONiC under ONIE. This is the reason why all of the ports does not work. New implementation: - Let "as7326-platform-handle_mac.service" execute "idt_init.sh". - Change the content of "as7326-platform-handle_mac.service" to define the service type as "oneshot". Add the settings to ensure "as7326-platform-handle_mac.service" is executed before "opennsl-modules.service". By setting the service type as "oneshot", it is guaranteed that "opennsl-modules.services" is started only when the forked process to execute the script file "idt_init.sh" is terminated Signed-off-by: charlie_chen --- .../service/as7326-platform-handle_mac.service | 15 +++++++-------- .../as7726-32x-platform-handle_mac.service | 15 +++++++-------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/service/as7326-platform-handle_mac.service b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/service/as7326-platform-handle_mac.service index 0e35d5929ef9..3d03ec4f1540 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/service/as7326-platform-handle_mac.service +++ b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/service/as7326-platform-handle_mac.service @@ -1,16 +1,15 @@ [Unit] -Description=Accton AS7326-56X Platform MAC hnadle service -Before=pmon.service -After=sysinit.target -DefaultDependencies=no +Description=Accton AS7326-56X Platform MAC handle service +Before=opennsl-modules.service +After=local-fs.target [Service] -ExecStart=/usr/local/bin/accton_handle_idt.sh -KillSignal=SIGKILL -SuccessExitStatus=SIGKILL +Type=oneshot +ExecStart=/usr/local/bin/idt_init.sh +RemainAfterExit=yes # Resource Limitations LimitCORE=infinity [Install] -WantedBy=multi-user.target +WantedBy=opennsl-modules.service diff --git a/platform/broadcom/sonic-platform-modules-accton/as7726-32x/service/as7726-32x-platform-handle_mac.service b/platform/broadcom/sonic-platform-modules-accton/as7726-32x/service/as7726-32x-platform-handle_mac.service index d29342a56fe1..5492775eee62 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as7726-32x/service/as7726-32x-platform-handle_mac.service +++ b/platform/broadcom/sonic-platform-modules-accton/as7726-32x/service/as7726-32x-platform-handle_mac.service @@ -1,16 +1,15 @@ [Unit] -Description=Accton AS7726-32X Platform MAC hnadle service -Before=pmon.service -After=sysinit.target -DefaultDependencies=no +Description=Accton AS7726-32X Platform MAC handle service +Before=opennsl-modules.service +After=local-fs.target [Service] -ExecStart=/usr/local/bin/accton_handle_idt.sh -KillSignal=SIGKILL -SuccessExitStatus=SIGKILL +Type=oneshot +ExecStart=/usr/local/bin/idt_init.sh +RemainAfterExit=yes # Resource Limitations LimitCORE=infinity [Install] -WantedBy=multi-user.target +WantedBy=opennsl-modules.service From 85b0de3df1125ad291afe0c7c93628dd45f226db Mon Sep 17 00:00:00 2001 From: Joe LeVeque Date: Sat, 9 Nov 2019 10:26:39 -0800 Subject: [PATCH 156/278] [docker-syncd]: Restart SwSS, syncd and dependent services if a critical process in syncd container exits unexpectedly (#3534) Add the same mechanism I developed for the SwSS service in #2845 to the syncd service. However, in order to cause the SwSS service to also exit and restart in this situation, I developed a docker-wait-any program which the SwSS service uses to wait for either the swss or syncd containers to exit. --- .../build_templates/sonic_debian_extension.j2 | 3 + files/image_config/misc/docker-wait-any | 62 +++++++++++++++++++ files/scripts/swss.sh | 17 ++++- platform/barefoot/docker-syncd-bfn-rpc.mk | 1 + .../barefoot/docker-syncd-bfn/Dockerfile.j2 | 2 + .../docker-syncd-bfn/critical_processes | 1 + platform/broadcom/docker-syncd-brcm-rpc.mk | 2 +- .../broadcom/docker-syncd-brcm/Dockerfile.j2 | 2 + .../docker-syncd-brcm/critical_processes | 2 + .../docker-syncd-brcm/supervisord.conf | 8 ++- platform/cavium/docker-syncd-cavm-rpc.mk | 1 + platform/cavium/docker-syncd-cavm.mk | 1 + .../cavium/docker-syncd-cavm/Dockerfile.j2 | 2 + .../docker-syncd-cavm/critical_processes | 1 + .../cavium/docker-syncd-cavm/supervisord.conf | 8 ++- platform/centec/docker-syncd-centec-rpc.mk | 1 + platform/centec/docker-syncd-centec.mk | 1 + .../centec/docker-syncd-centec/Dockerfile.j2 | 2 + .../docker-syncd-centec/critical_processes | 1 + .../docker-syncd-centec/supervisord.conf | 8 ++- .../marvell-arm64/docker-syncd-mrvl-rpc.mk | 1 + .../docker-syncd-mrvl/Dockerfile.j2 | 2 + .../docker-syncd-mrvl/critical_processes | 1 + .../marvell-armhf/docker-syncd-mrvl-rpc.mk | 1 + .../docker-syncd-mrvl/Dockerfile.j2 | 2 + .../docker-syncd-mrvl/critical_processes | 1 + platform/marvell/docker-syncd-mrvl-rpc.mk | 1 + .../marvell/docker-syncd-mrvl/Dockerfile.j2 | 2 + .../docker-syncd-mrvl/critical_processes | 1 + .../docker-syncd-mrvl/supervisord.conf | 8 ++- platform/mellanox/docker-syncd-mlnx-rpc.mk | 1 + .../mellanox/docker-syncd-mlnx/Dockerfile.j2 | 2 + .../docker-syncd-mlnx/critical_processes | 1 + .../docker-syncd-mlnx/supervisord.conf | 8 ++- .../nephos/docker-syncd-nephos/Dockerfile.j2 | 2 + .../docker-syncd-nephos/critical_processes | 2 + .../docker-syncd-nephos/supervisord.conf | 8 ++- platform/template/docker-syncd-base.mk | 2 + 38 files changed, 164 insertions(+), 8 deletions(-) create mode 100755 files/image_config/misc/docker-wait-any create mode 100644 platform/barefoot/docker-syncd-bfn/critical_processes create mode 100644 platform/broadcom/docker-syncd-brcm/critical_processes create mode 100644 platform/cavium/docker-syncd-cavm/critical_processes create mode 100644 platform/centec/docker-syncd-centec/critical_processes create mode 100644 platform/marvell-arm64/docker-syncd-mrvl/critical_processes create mode 100644 platform/marvell-armhf/docker-syncd-mrvl/critical_processes create mode 100644 platform/marvell/docker-syncd-mrvl/critical_processes create mode 100644 platform/mellanox/docker-syncd-mlnx/critical_processes create mode 100644 platform/nephos/docker-syncd-nephos/critical_processes diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index d81815284a34..13d5432e09ea 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -218,6 +218,9 @@ sudo cp $IMAGE_CONFIGS/hostname/hostname-config.service $FILESYSTEM_ROOT/etc/sy echo "hostname-config.service" | sudo tee -a $GENERATED_SERVICE_FILE sudo cp $IMAGE_CONFIGS/hostname/hostname-config.sh $FILESYSTEM_ROOT/usr/bin/ +# Copy miscellaneous scripts +sudo cp $IMAGE_CONFIGS/misc/docker-wait-any $FILESYSTEM_ROOT/usr/bin/ + # Copy updategraph script and service file j2 files/build_templates/updategraph.service.j2 | sudo tee $FILESYSTEM_ROOT/etc/systemd/system/updategraph.service sudo cp $IMAGE_CONFIGS/updategraph/updategraph $FILESYSTEM_ROOT/usr/bin/ diff --git a/files/image_config/misc/docker-wait-any b/files/image_config/misc/docker-wait-any new file mode 100755 index 000000000000..3988a9fbdf57 --- /dev/null +++ b/files/image_config/misc/docker-wait-any @@ -0,0 +1,62 @@ +#!/usr/bin/env python + +""" + docker-wait-any + This script takes one or more Docker container names as arguments, + and it will block indefinitely while all of the specified containers + are running. If any of the specified containers stop, the script will + exit. + This script was created because the 'docker wait' command is lacking + this functionality. It will block until ALL specified containers have + stopped running. Here, we spawn multiple threads and wait on one + container per thread. If any of the threads exit, the entire + application will exit. + NOTE: This script is written against docker-py version 1.6.0. Newer + versions of docker-py have a different API. +""" + +import sys +import threading +from docker import Client + +# Instantiate a global event to share among our threads +g_thread_exit_event = threading.Event() + + +def usage(): + print("Usage: {} [ ...]".format(sys.argv[0])) + sys.exit(1) + + +def wait_for_container(docker_client, container_name): + docker_client.wait(container_name) + + print("No longer waiting on container '{}'".format(container_name)) + + # Signal the main thread to exit + g_thread_exit_event.set() + + +def main(): + thread_list = [] + + docker_client = Client(base_url='unix://var/run/docker.sock') + + # Ensure we were passed at least one argument + if len(sys.argv) < 2: + usage() + + container_names = sys.argv[1:] + + for container_name in container_names: + t = threading.Thread(target=wait_for_container, args=[docker_client, container_name]) + t.daemon = True + t.start() + thread_list.append(t) + + # Wait until we receive an event signifying one of the containers has stopped + g_thread_exit_event.wait() + sys.exit(0) + +if __name__ == '__main__': + main() diff --git a/files/scripts/swss.sh b/files/scripts/swss.sh index 5b2f582ef4c4..65eaf08148a8 100755 --- a/files/scripts/swss.sh +++ b/files/scripts/swss.sh @@ -131,7 +131,22 @@ start() { wait() { start_peer_and_dependent_services - /usr/bin/${SERVICE}.sh wait + + # Allow some time for peer container to start + # NOTE: This assumes Docker containers share the same names as their + # corresponding services + for SECS in {1..60}; do + RUNNING=$(docker inspect -f '{{.State.Running}}' ${PEER}) + if [[ x"$RUNNING" == x"true" ]]; then + break + else + sleep 1 + fi + done + + # NOTE: This assumes Docker containers share the same names as their + # corresponding services + /usr/bin/docker-wait-any ${SERVICE} ${PEER} } stop() { diff --git a/platform/barefoot/docker-syncd-bfn-rpc.mk b/platform/barefoot/docker-syncd-bfn-rpc.mk index 4fbe4eb1721c..d9cb0b5d6172 100644 --- a/platform/barefoot/docker-syncd-bfn-rpc.mk +++ b/platform/barefoot/docker-syncd-bfn-rpc.mk @@ -3,6 +3,7 @@ DOCKER_SYNCD_BFN_RPC = docker-syncd-bfn-rpc.gz $(DOCKER_SYNCD_BFN_RPC)_PATH = $(PLATFORM_PATH)/docker-syncd-bfn-rpc $(DOCKER_SYNCD_BFN_RPC)_DEPENDS += $(SYNCD_RPC) $(LIBTHRIFT) +$(DOCKER_SYNCD_BFN_RPC)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) ifeq ($(INSTALL_DEBUG_TOOLS), y) $(DOCKER_SYNCD_BFN_RPC)_DEPENDS += $(SYNCD_RPC_DBG) \ $(LIBSWSSCOMMON_DBG) \ diff --git a/platform/barefoot/docker-syncd-bfn/Dockerfile.j2 b/platform/barefoot/docker-syncd-bfn/Dockerfile.j2 index 73a12b8a05cc..c12c36b1260b 100755 --- a/platform/barefoot/docker-syncd-bfn/Dockerfile.j2 +++ b/platform/barefoot/docker-syncd-bfn/Dockerfile.j2 @@ -29,6 +29,8 @@ debs/{{ deb }}{{' '}} COPY ["start.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor/"] ## Clean up RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y diff --git a/platform/barefoot/docker-syncd-bfn/critical_processes b/platform/barefoot/docker-syncd-bfn/critical_processes new file mode 100644 index 000000000000..6082f242b872 --- /dev/null +++ b/platform/barefoot/docker-syncd-bfn/critical_processes @@ -0,0 +1 @@ +syncd diff --git a/platform/broadcom/docker-syncd-brcm-rpc.mk b/platform/broadcom/docker-syncd-brcm-rpc.mk index ed7fc1b5265e..80d6ea2d8147 100644 --- a/platform/broadcom/docker-syncd-brcm-rpc.mk +++ b/platform/broadcom/docker-syncd-brcm-rpc.mk @@ -9,7 +9,7 @@ $(DOCKER_SYNCD_BRCM_RPC)_DEPENDS += $(SYNCD_RPC_DBG) \ $(LIBSAIMETADATA_DBG) \ $(LIBSAIREDIS_DBG) endif -$(DOCKER_SYNCD_BRCM_RPC)_FILES += $(DSSERVE) $(BCMCMD) +$(DOCKER_SYNCD_BRCM_RPC)_FILES += $(DSSERVE) $(BCMCMD) $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) $(DOCKER_SYNCD_BRCM_RPC)_LOAD_DOCKERS += $(DOCKER_SYNCD_BASE) SONIC_DOCKER_IMAGES += $(DOCKER_SYNCD_BRCM_RPC) SONIC_STRETCH_DOCKERS += $(DOCKER_SYNCD_BRCM_RPC) diff --git a/platform/broadcom/docker-syncd-brcm/Dockerfile.j2 b/platform/broadcom/docker-syncd-brcm/Dockerfile.j2 index 328f698fdb6d..b20e353f842f 100755 --- a/platform/broadcom/docker-syncd-brcm/Dockerfile.j2 +++ b/platform/broadcom/docker-syncd-brcm/Dockerfile.j2 @@ -26,6 +26,8 @@ COPY ["files/dsserve", "files/bcmcmd", "start.sh", "bcmsh", "/usr/bin/"] RUN chmod +x /usr/bin/dsserve /usr/bin/bcmcmd COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor/"] ## Clean up RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y diff --git a/platform/broadcom/docker-syncd-brcm/critical_processes b/platform/broadcom/docker-syncd-brcm/critical_processes new file mode 100644 index 000000000000..489668a89e08 --- /dev/null +++ b/platform/broadcom/docker-syncd-brcm/critical_processes @@ -0,0 +1,2 @@ +dsserve +syncd diff --git a/platform/broadcom/docker-syncd-brcm/supervisord.conf b/platform/broadcom/docker-syncd-brcm/supervisord.conf index a2e0743b1cf5..cd6712acbf22 100644 --- a/platform/broadcom/docker-syncd-brcm/supervisord.conf +++ b/platform/broadcom/docker-syncd-brcm/supervisord.conf @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 @@ -15,7 +21,7 @@ stderr_logfile=syslog command=/usr/sbin/rsyslogd -n priority=2 autostart=false -autorestart=false +autorestart=unexpected stdout_logfile=syslog stderr_logfile=syslog diff --git a/platform/cavium/docker-syncd-cavm-rpc.mk b/platform/cavium/docker-syncd-cavm-rpc.mk index cb1077c5a391..e57370fce5ca 100644 --- a/platform/cavium/docker-syncd-cavm-rpc.mk +++ b/platform/cavium/docker-syncd-cavm-rpc.mk @@ -3,6 +3,7 @@ DOCKER_SYNCD_CAVM_RPC = docker-syncd-cavm-rpc.gz $(DOCKER_SYNCD_CAVM_RPC)_PATH = $(PLATFORM_PATH)/docker-syncd-cavm-rpc $(DOCKER_SYNCD_CAVM_RPC)_DEPENDS += $(SYNCD_RPC) $(LIBTHRIFT) $(CAVM_LIBSAI) $(XP_TOOLS) $(REDIS_TOOLS) +$(DOCKER_SYNCD_CAVM_RPC)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) ifeq ($(INSTALL_DEBUG_TOOLS), y) $(DOCKER_SYNCD_CAVM_RPC)_DEPENDS += $(SYNCD_RPC_DBG) \ $(LIBSWSSCOMMON_DBG) \ diff --git a/platform/cavium/docker-syncd-cavm.mk b/platform/cavium/docker-syncd-cavm.mk index 5cec8390593f..a136828dbff1 100644 --- a/platform/cavium/docker-syncd-cavm.mk +++ b/platform/cavium/docker-syncd-cavm.mk @@ -3,6 +3,7 @@ DOCKER_SYNCD_CAVM = docker-syncd-cavm.gz $(DOCKER_SYNCD_CAVM)_PATH = $(PLATFORM_PATH)/docker-syncd-cavm $(DOCKER_SYNCD_CAVM)_DEPENDS += $(SYNCD) $(CAVM_LIBSAI) $(XP_TOOLS) $(REDIS_TOOLS) +$(DOCKER_SYNCD_CAVM)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) ifeq ($(INSTALL_DEBUG_TOOLS), y) $(DOCKER_SYNCD_CAVM)_DEPENDS += $(SYNCD_DBG) \ $(LIBSWSSCOMMON_DBG) \ diff --git a/platform/cavium/docker-syncd-cavm/Dockerfile.j2 b/platform/cavium/docker-syncd-cavm/Dockerfile.j2 index 800be7e1bb04..0e2bc4b6bbc7 100755 --- a/platform/cavium/docker-syncd-cavm/Dockerfile.j2 +++ b/platform/cavium/docker-syncd-cavm/Dockerfile.j2 @@ -23,6 +23,8 @@ debs/{{ deb }}{{' '}} COPY ["start.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor/"] COPY ["profile.ini", "/etc/ssw/AS7512/"] diff --git a/platform/cavium/docker-syncd-cavm/critical_processes b/platform/cavium/docker-syncd-cavm/critical_processes new file mode 100644 index 000000000000..6082f242b872 --- /dev/null +++ b/platform/cavium/docker-syncd-cavm/critical_processes @@ -0,0 +1 @@ +syncd diff --git a/platform/cavium/docker-syncd-cavm/supervisord.conf b/platform/cavium/docker-syncd-cavm/supervisord.conf index 1af5d70a1d0c..c823ab5680ef 100644 --- a/platform/cavium/docker-syncd-cavm/supervisord.conf +++ b/platform/cavium/docker-syncd-cavm/supervisord.conf @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 @@ -15,7 +21,7 @@ stderr_logfile=syslog command=/usr/sbin/rsyslogd -n priority=2 autostart=false -autorestart=false +autorestart=unexpected stdout_logfile=syslog stderr_logfile=syslog diff --git a/platform/centec/docker-syncd-centec-rpc.mk b/platform/centec/docker-syncd-centec-rpc.mk index 744f60a71ff1..71c8ef7753c1 100644 --- a/platform/centec/docker-syncd-centec-rpc.mk +++ b/platform/centec/docker-syncd-centec-rpc.mk @@ -3,6 +3,7 @@ DOCKER_SYNCD_CENTEC_RPC = docker-syncd-centec-rpc.gz $(DOCKER_SYNCD_CENTEC_RPC)_PATH = $(PLATFORM_PATH)/docker-syncd-centec-rpc $(DOCKER_SYNCD_CENTEC_RPC)_DEPENDS += $(SYNCD_RPC) $(LIBTHRIFT) +$(DOCKER_SYNCD_CENTEC_RPC)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) ifeq ($(INSTALL_DEBUG_TOOLS), y) $(DOCKER_SYNCD_CENTEC_RPC)_DEPENDS += $(SYNCD_RPC_DBG) \ $(LIBSWSSCOMMON_DBG) \ diff --git a/platform/centec/docker-syncd-centec.mk b/platform/centec/docker-syncd-centec.mk index 7447dd54717b..360690731a58 100644 --- a/platform/centec/docker-syncd-centec.mk +++ b/platform/centec/docker-syncd-centec.mk @@ -3,6 +3,7 @@ DOCKER_SYNCD_CENTEC = docker-syncd-centec.gz $(DOCKER_SYNCD_CENTEC)_PATH = $(PLATFORM_PATH)/docker-syncd-centec $(DOCKER_SYNCD_CENTEC)_DEPENDS += $(SYNCD) +$(DOCKER_SYNCD_CENTEC)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) ifeq ($(INSTALL_DEBUG_TOOLS), y) $(DOCKER_SYNCD_CENTEC)_DEPENDS += $(SYNCD_DBG) \ $(LIBSWSSCOMMON_DBG) \ diff --git a/platform/centec/docker-syncd-centec/Dockerfile.j2 b/platform/centec/docker-syncd-centec/Dockerfile.j2 index d5b9bc73eeca..b40103a24f28 100755 --- a/platform/centec/docker-syncd-centec/Dockerfile.j2 +++ b/platform/centec/docker-syncd-centec/Dockerfile.j2 @@ -24,6 +24,8 @@ RUN apt-get install -f kmod COPY ["start.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor/"] ## Clean up RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y diff --git a/platform/centec/docker-syncd-centec/critical_processes b/platform/centec/docker-syncd-centec/critical_processes new file mode 100644 index 000000000000..6082f242b872 --- /dev/null +++ b/platform/centec/docker-syncd-centec/critical_processes @@ -0,0 +1 @@ +syncd diff --git a/platform/centec/docker-syncd-centec/supervisord.conf b/platform/centec/docker-syncd-centec/supervisord.conf index 1af5d70a1d0c..c823ab5680ef 100644 --- a/platform/centec/docker-syncd-centec/supervisord.conf +++ b/platform/centec/docker-syncd-centec/supervisord.conf @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 @@ -15,7 +21,7 @@ stderr_logfile=syslog command=/usr/sbin/rsyslogd -n priority=2 autostart=false -autorestart=false +autorestart=unexpected stdout_logfile=syslog stderr_logfile=syslog diff --git a/platform/marvell-arm64/docker-syncd-mrvl-rpc.mk b/platform/marvell-arm64/docker-syncd-mrvl-rpc.mk index f5eb6d2de272..0e1b65f2fd5d 100644 --- a/platform/marvell-arm64/docker-syncd-mrvl-rpc.mk +++ b/platform/marvell-arm64/docker-syncd-mrvl-rpc.mk @@ -3,6 +3,7 @@ DOCKER_SYNCD_MRVL_RPC = docker-syncd-mrvl-rpc.gz $(DOCKER_SYNCD_MRVL_RPC)_PATH = $(PLATFORM_PATH)/docker-syncd-mrvl-rpc $(DOCKER_SYNCD_MRVL_RPC)_DEPENDS += $(SYNCD_RPC) $(LIBTHRIFT) +$(DOCKER_SYNCD_MRVL_RPC)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) ifeq ($(INSTALL_DEBUG_TOOLS), y) $(DOCKER_SYNCD_MRVL_RPC)_DEPENDS += $(SYNCD_RPC_DBG) \ $(LIBSWSSCOMMON_DBG) \ diff --git a/platform/marvell-arm64/docker-syncd-mrvl/Dockerfile.j2 b/platform/marvell-arm64/docker-syncd-mrvl/Dockerfile.j2 index 201d52284361..410911e6a4f8 100755 --- a/platform/marvell-arm64/docker-syncd-mrvl/Dockerfile.j2 +++ b/platform/marvell-arm64/docker-syncd-mrvl/Dockerfile.j2 @@ -28,6 +28,8 @@ debs/{{ deb }}{{' '}} COPY ["start.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor/"] ## Clean up RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y diff --git a/platform/marvell-arm64/docker-syncd-mrvl/critical_processes b/platform/marvell-arm64/docker-syncd-mrvl/critical_processes new file mode 100644 index 000000000000..6082f242b872 --- /dev/null +++ b/platform/marvell-arm64/docker-syncd-mrvl/critical_processes @@ -0,0 +1 @@ +syncd diff --git a/platform/marvell-armhf/docker-syncd-mrvl-rpc.mk b/platform/marvell-armhf/docker-syncd-mrvl-rpc.mk index f5eb6d2de272..0e1b65f2fd5d 100644 --- a/platform/marvell-armhf/docker-syncd-mrvl-rpc.mk +++ b/platform/marvell-armhf/docker-syncd-mrvl-rpc.mk @@ -3,6 +3,7 @@ DOCKER_SYNCD_MRVL_RPC = docker-syncd-mrvl-rpc.gz $(DOCKER_SYNCD_MRVL_RPC)_PATH = $(PLATFORM_PATH)/docker-syncd-mrvl-rpc $(DOCKER_SYNCD_MRVL_RPC)_DEPENDS += $(SYNCD_RPC) $(LIBTHRIFT) +$(DOCKER_SYNCD_MRVL_RPC)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) ifeq ($(INSTALL_DEBUG_TOOLS), y) $(DOCKER_SYNCD_MRVL_RPC)_DEPENDS += $(SYNCD_RPC_DBG) \ $(LIBSWSSCOMMON_DBG) \ diff --git a/platform/marvell-armhf/docker-syncd-mrvl/Dockerfile.j2 b/platform/marvell-armhf/docker-syncd-mrvl/Dockerfile.j2 index 201d52284361..410911e6a4f8 100755 --- a/platform/marvell-armhf/docker-syncd-mrvl/Dockerfile.j2 +++ b/platform/marvell-armhf/docker-syncd-mrvl/Dockerfile.j2 @@ -28,6 +28,8 @@ debs/{{ deb }}{{' '}} COPY ["start.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor/"] ## Clean up RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y diff --git a/platform/marvell-armhf/docker-syncd-mrvl/critical_processes b/platform/marvell-armhf/docker-syncd-mrvl/critical_processes new file mode 100644 index 000000000000..6082f242b872 --- /dev/null +++ b/platform/marvell-armhf/docker-syncd-mrvl/critical_processes @@ -0,0 +1 @@ +syncd diff --git a/platform/marvell/docker-syncd-mrvl-rpc.mk b/platform/marvell/docker-syncd-mrvl-rpc.mk index 375c6ba91cd1..5b1968bde39c 100644 --- a/platform/marvell/docker-syncd-mrvl-rpc.mk +++ b/platform/marvell/docker-syncd-mrvl-rpc.mk @@ -3,6 +3,7 @@ DOCKER_SYNCD_MRVL_RPC = docker-syncd-mrvl-rpc.gz $(DOCKER_SYNCD_MRVL_RPC)_PATH = $(PLATFORM_PATH)/docker-syncd-mrvl-rpc $(DOCKER_SYNCD_MRVL_RPC)_DEPENDS += $(SYNCD_RPC) $(LIBTHRIFT) +$(DOCKER_SYNCD_MRVL_RPC)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) ifeq ($(INSTALL_DEBUG_TOOLS), y) $(DOCKER_SYNCD_MRVL_RPC)_DEPENDS += $(SYNCD_RPC_DBG) \ $(LIBSWSSCOMMON_DBG) \ diff --git a/platform/marvell/docker-syncd-mrvl/Dockerfile.j2 b/platform/marvell/docker-syncd-mrvl/Dockerfile.j2 index 889971652c61..40973653e8d3 100755 --- a/platform/marvell/docker-syncd-mrvl/Dockerfile.j2 +++ b/platform/marvell/docker-syncd-mrvl/Dockerfile.j2 @@ -23,6 +23,8 @@ debs/{{ deb }}{{' '}} COPY ["start.sh", "syncd.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor/"] ## Clean up RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y diff --git a/platform/marvell/docker-syncd-mrvl/critical_processes b/platform/marvell/docker-syncd-mrvl/critical_processes new file mode 100644 index 000000000000..6082f242b872 --- /dev/null +++ b/platform/marvell/docker-syncd-mrvl/critical_processes @@ -0,0 +1 @@ +syncd diff --git a/platform/marvell/docker-syncd-mrvl/supervisord.conf b/platform/marvell/docker-syncd-mrvl/supervisord.conf index 1e015fef931f..aea4d45b9afd 100644 --- a/platform/marvell/docker-syncd-mrvl/supervisord.conf +++ b/platform/marvell/docker-syncd-mrvl/supervisord.conf @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 @@ -15,7 +21,7 @@ stderr_logfile=syslog command=/usr/sbin/rsyslogd -n priority=2 autostart=false -autorestart=false +autorestart=unexpected stdout_logfile=syslog stderr_logfile=syslog diff --git a/platform/mellanox/docker-syncd-mlnx-rpc.mk b/platform/mellanox/docker-syncd-mlnx-rpc.mk index f154f8c28d2e..608c1bb3ad20 100644 --- a/platform/mellanox/docker-syncd-mlnx-rpc.mk +++ b/platform/mellanox/docker-syncd-mlnx-rpc.mk @@ -3,6 +3,7 @@ DOCKER_SYNCD_MLNX_RPC = docker-syncd-mlnx-rpc.gz $(DOCKER_SYNCD_MLNX_RPC)_PATH = $(PLATFORM_PATH)/docker-syncd-mlnx-rpc $(DOCKER_SYNCD_MLNX_RPC)_DEPENDS += $(SYNCD_RPC) $(LIBTHRIFT) +$(DOCKER_SYNCD_MLNX_RPC)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) ifeq ($(INSTALL_DEBUG_TOOLS), y) $(DOCKER_SYNCD_MLNX_RPC)_DEPENDS += $(SYNCD_RPC_DBG) \ $(LIBSWSSCOMMON_DBG) \ diff --git a/platform/mellanox/docker-syncd-mlnx/Dockerfile.j2 b/platform/mellanox/docker-syncd-mlnx/Dockerfile.j2 index d3716dffcbbc..4d22335ec783 100755 --- a/platform/mellanox/docker-syncd-mlnx/Dockerfile.j2 +++ b/platform/mellanox/docker-syncd-mlnx/Dockerfile.j2 @@ -35,5 +35,7 @@ RUN apt-get clean -y && \ COPY ["start.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor/"] ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/platform/mellanox/docker-syncd-mlnx/critical_processes b/platform/mellanox/docker-syncd-mlnx/critical_processes new file mode 100644 index 000000000000..6082f242b872 --- /dev/null +++ b/platform/mellanox/docker-syncd-mlnx/critical_processes @@ -0,0 +1 @@ +syncd diff --git a/platform/mellanox/docker-syncd-mlnx/supervisord.conf b/platform/mellanox/docker-syncd-mlnx/supervisord.conf index 1af5d70a1d0c..c823ab5680ef 100644 --- a/platform/mellanox/docker-syncd-mlnx/supervisord.conf +++ b/platform/mellanox/docker-syncd-mlnx/supervisord.conf @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 @@ -15,7 +21,7 @@ stderr_logfile=syslog command=/usr/sbin/rsyslogd -n priority=2 autostart=false -autorestart=false +autorestart=unexpected stdout_logfile=syslog stderr_logfile=syslog diff --git a/platform/nephos/docker-syncd-nephos/Dockerfile.j2 b/platform/nephos/docker-syncd-nephos/Dockerfile.j2 index b889200f6ca4..f891ace1e8e4 100755 --- a/platform/nephos/docker-syncd-nephos/Dockerfile.j2 +++ b/platform/nephos/docker-syncd-nephos/Dockerfile.j2 @@ -36,6 +36,8 @@ COPY ["files/dsserve", "files/npx_diag", "start.sh", "/usr/bin/"] RUN chmod +x /usr/bin/npx_diag /usr/bin/dsserve COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor/"] ## Clean up RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y diff --git a/platform/nephos/docker-syncd-nephos/critical_processes b/platform/nephos/docker-syncd-nephos/critical_processes new file mode 100644 index 000000000000..489668a89e08 --- /dev/null +++ b/platform/nephos/docker-syncd-nephos/critical_processes @@ -0,0 +1,2 @@ +dsserve +syncd diff --git a/platform/nephos/docker-syncd-nephos/supervisord.conf b/platform/nephos/docker-syncd-nephos/supervisord.conf index 1af5d70a1d0c..c823ab5680ef 100644 --- a/platform/nephos/docker-syncd-nephos/supervisord.conf +++ b/platform/nephos/docker-syncd-nephos/supervisord.conf @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 @@ -15,7 +21,7 @@ stderr_logfile=syslog command=/usr/sbin/rsyslogd -n priority=2 autostart=false -autorestart=false +autorestart=unexpected stdout_logfile=syslog stderr_logfile=syslog diff --git a/platform/template/docker-syncd-base.mk b/platform/template/docker-syncd-base.mk index d8776d179a02..cefcf15ebd62 100644 --- a/platform/template/docker-syncd-base.mk +++ b/platform/template/docker-syncd-base.mk @@ -7,6 +7,8 @@ DOCKER_SYNCD_BASE_DBG = $(DOCKER_SYNCD_BASE_STEM)-$(DBG_IMAGE_MARK).gz $(DOCKER_SYNCD_BASE)_PATH = $(PLATFORM_PATH)/docker-syncd-$(DOCKER_SYNCD_PLATFORM_CODE) +$(DOCKER_SYNCD_BASE)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) + $(DOCKER_SYNCD_BASE)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_STRETCH) $(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_DEPENDS) From 6e926a184206d4a7f2490e87eab9f6dc1c3ec9c6 Mon Sep 17 00:00:00 2001 From: dereksun01 <52683998+dereksun01@users.noreply.github.com> Date: Sun, 10 Nov 2019 06:16:16 +0800 Subject: [PATCH 157/278] [device]: rename as5835_54x configuration file (#3429) Signed-off-by: derek_sun --- ...0G+6x100G.config.bcm => mv2-as5835-48x10G+6x100G.config.bcm} | 0 .../x86_64-accton_as5835_54x-r0/Accton-AS5835-54X/sai.profile | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename device/accton/x86_64-accton_as5835_54x-r0/Accton-AS5835-54X/{td3-as5835-48x10G+6x100G.config.bcm => mv2-as5835-48x10G+6x100G.config.bcm} (100%) diff --git a/device/accton/x86_64-accton_as5835_54x-r0/Accton-AS5835-54X/td3-as5835-48x10G+6x100G.config.bcm b/device/accton/x86_64-accton_as5835_54x-r0/Accton-AS5835-54X/mv2-as5835-48x10G+6x100G.config.bcm similarity index 100% rename from device/accton/x86_64-accton_as5835_54x-r0/Accton-AS5835-54X/td3-as5835-48x10G+6x100G.config.bcm rename to device/accton/x86_64-accton_as5835_54x-r0/Accton-AS5835-54X/mv2-as5835-48x10G+6x100G.config.bcm diff --git a/device/accton/x86_64-accton_as5835_54x-r0/Accton-AS5835-54X/sai.profile b/device/accton/x86_64-accton_as5835_54x-r0/Accton-AS5835-54X/sai.profile index 04c02ee5861d..8b795f81c4f2 100644 --- a/device/accton/x86_64-accton_as5835_54x-r0/Accton-AS5835-54X/sai.profile +++ b/device/accton/x86_64-accton_as5835_54x-r0/Accton-AS5835-54X/sai.profile @@ -1 +1 @@ -SAI_INIT_CONFIG_FILE=/etc/bcm/td3-as5835-48x10G+6x100G.config.bcm +SAI_INIT_CONFIG_FILE=/etc/bcm/mv2-as5835-48x10G+6x100G.config.bcm From d8931db996309fec1a32c075cc0b3f591d20d78a Mon Sep 17 00:00:00 2001 From: Guohan Lu Date: Sat, 9 Nov 2019 19:32:10 +0000 Subject: [PATCH 158/278] [submodules]: update swss/sairedis/utilities swss: * f354798 2019-11-09 | [tests] fix build agains real SAI (#1123) (HEAD, origin/master, origin/HEAD) [Stepan Blyshchak] * 56d66a1 2019-11-07 | Sub port interface implementation (#969) [Wenda Ni] * c57fc34 2019-11-07 | [bufferorch] Fixed buffer and buffer profile attributes types accoring to changes in SAI 1.5 (#1120) [Vitaliy Senchyshyn] * 85ff17d 2019-11-07 | [VRF]: submit vrf feature (#943) [Tyler Li] * 5604566 2019-11-06 | [vs_test] fix fdb test failed randomly (#1118) [Tyler Li] * 038d994 2019-11-05 | [vnet]: Correct VNET route table size for BITMAP implementation (#1115) [Volodymyr Samotiy] * bb4e19c 2019-11-04 | Not wait till kernel net_devices are created for all physical ports to (#1109) [Wenda Ni] * bab7b93 2019-11-02 | [portsorch] fix PortsOrch::allPortsReady() returns true when it should not (#1103) [Stepan Blyshchak] * 5ab3f6b 2019-10-31 | Updating pytest for sflow (#1095) [Sudharsan D.G] * d4ccdc3 2019-10-29 | Quote input strings before constructing a command line (#1098) [Qi Luo] * 5516ec4 2019-10-29 | Check RIF/Port exists only for add entries (#1110) [Prince Sunny] * 59440f2 2019-10-29 | Allow buffer profile apply after init (#1099) [Wenda Ni] sairedis: * d9faa58 2019-10-24 | Copp changes for supporting genetlink in vs (#522) [Sudharsan D.G] utiltiies: * e4a5e4c 2019-11-07 | Do not start pfcwd for M0 devices (#726) (HEAD, origin/master, origin/HEAD) [Neetha John] * 2c0af8a 2019-11-07 | Add an on/off knob for BGP EOIU pulling on warm restart (#655) [heidinet2007] * 2bce9ce 2019-11-07 | Make configlet application script idempotent for updates. (#728) [Renuka Manavalan] * 4740617 2019-11-06 | Revert "show BPS, PPS, UTIL rates w/o previous clear (#508)" (#718) [Mykola F] --- src/sonic-sairedis | 2 +- src/sonic-swss | 2 +- src/sonic-utilities | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 1f4a1d76bd9c..d9faa5890b68 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 1f4a1d76bd9cd3e8865911840ab8e47c0ba221f1 +Subproject commit d9faa5890b6843a6a31e620752e865eba23f9564 diff --git a/src/sonic-swss b/src/sonic-swss index 20747fa63d59..f3547983a1e2 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit 20747fa63d59f4aadaa06da282e23d8e1e0b9fdf +Subproject commit f3547983a1e2c67bdacb4e87593e65f20b483d8e diff --git a/src/sonic-utilities b/src/sonic-utilities index 0e23e1cd0a3b..e4a5e4ce1c3f 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit 0e23e1cd0a3b3538061c8f971acd579bf2a9e151 +Subproject commit e4a5e4ce1c3f55600ca3e6bcbffbd4bcaef4cbe6 From c07ae3b16f379a0649ca091fa8194976a976b8c7 Mon Sep 17 00:00:00 2001 From: Tyler Li Date: Sat, 9 Nov 2019 21:51:43 +0000 Subject: [PATCH 159/278] Loopback ip addresses move to intfmgrd for supporting VRF --- files/image_config/interfaces/interfaces.j2 | 7 ------- .../tests/sample_output/interfaces | 13 ------------- .../tests/sample_output/mvrf_interfaces | 13 ------------- 3 files changed, 33 deletions(-) diff --git a/files/image_config/interfaces/interfaces.j2 b/files/image_config/interfaces/interfaces.j2 index ad7b5202637d..91be4437fc06 100644 --- a/files/image_config/interfaces/interfaces.j2 +++ b/files/image_config/interfaces/interfaces.j2 @@ -14,13 +14,6 @@ iface mgmt # The loopback network interface auto lo iface lo inet loopback -# Use command 'ip addr list dev lo' to check all addresses -{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %} -iface lo {{ 'inet' if prefix | ipv4 else 'inet6' }} static - address {{ prefix | ip }} - netmask {{ prefix | netmask if prefix | ipv4 else prefix | prefixlen }} -# -{% endfor %} {% if (MGMT_VRF_CONFIG) and (MGMT_VRF_CONFIG['vrf_global']['mgmtVrfEnabled'] == "true") %} # The loopback network interface for mgmt VRF that is required for applications like NTP up ip link add lo-m type dummy diff --git a/src/sonic-config-engine/tests/sample_output/interfaces b/src/sonic-config-engine/tests/sample_output/interfaces index 2c4c01b7b9b1..d3921bcbab4d 100644 --- a/src/sonic-config-engine/tests/sample_output/interfaces +++ b/src/sonic-config-engine/tests/sample_output/interfaces @@ -6,19 +6,6 @@ # The loopback network interface auto lo iface lo inet loopback -# Use command 'ip addr list dev lo' to check all addresses -iface lo inet static - address 10.1.0.32 - netmask 255.255.255.255 -# -iface lo inet6 static - address fc00:1::32 - netmask 128 -# -iface lo inet static - address 10.10.0.99 - netmask 255.255.255.255 -# # The management network interface auto eth0 diff --git a/src/sonic-config-engine/tests/sample_output/mvrf_interfaces b/src/sonic-config-engine/tests/sample_output/mvrf_interfaces index e66b1b252835..afd0615b81e9 100644 --- a/src/sonic-config-engine/tests/sample_output/mvrf_interfaces +++ b/src/sonic-config-engine/tests/sample_output/mvrf_interfaces @@ -9,19 +9,6 @@ iface mgmt # The loopback network interface auto lo iface lo inet loopback -# Use command 'ip addr list dev lo' to check all addresses -iface lo inet static - address 10.1.0.32 - netmask 255.255.255.255 -# -iface lo inet6 static - address fc00:1::32 - netmask 128 -# -iface lo inet static - address 10.10.0.99 - netmask 255.255.255.255 -# # The loopback network interface for mgmt VRF that is required for applications like NTP up ip link add lo-m type dummy up ip addr add 127.0.0.1/8 dev lo-m From 473fc6d4f37f89bc30ab2b66182f0e3386cf2e73 Mon Sep 17 00:00:00 2001 From: "Dante (Kuo-Jung) Su" Date: Wed, 13 Nov 2019 07:26:11 +0800 Subject: [PATCH 160/278] celestica: reallocate the empty LIST at the constructor of subclasses (#3738) Signed-off-by: Dante Su --- device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py | 2 +- .../celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py | 2 +- device/celestica/x86_64-cel_seastone-r0/sonic_platform/psu.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py index 291ece986222..99eb49ce53e0 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py @@ -42,6 +42,7 @@ class Chassis(ChassisBase): """Platform-specific Chassis class""" def __init__(self): + ChassisBase.__init__(self) self.config_data = {} for fant_index in range(0, NUM_FAN_TRAY): for fan_index in range(0, NUM_FAN): @@ -59,7 +60,6 @@ def __init__(self): for index in range(0, NUM_COMPONENT): component = Component(index) self._component_list.append(component) - ChassisBase.__init__(self) self._reboot_cause_path = HOST_REBOOT_CAUSE_PATH if self.__is_host( ) else PMON_REBOOT_CAUSE_PATH diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py index 768a15ce22ef..c9447b56a2fe 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py @@ -44,6 +44,7 @@ class Chassis(ChassisBase): """Platform-specific Chassis class""" def __init__(self): + ChassisBase.__init__(self) self.config_data = {} for fant_index in range(0, NUM_FAN_TRAY): for fan_index in range(0, NUM_FAN): @@ -61,7 +62,6 @@ def __init__(self): for index in range(0, NUM_COMPONENT): component = Component(index) self._component_list.append(component) - ChassisBase.__init__(self) self._watchdog = Watchdog() self._eeprom = Tlv() diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/psu.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/psu.py index 7e18827cbfb0..8558b0b0cadd 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/psu.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/psu.py @@ -39,6 +39,7 @@ class Psu(PsuBase): """Platform-specific Psu class""" def __init__(self, psu_index): + PsuBase.__init__(self) self.index = psu_index self.green_led_path = GREEN_LED_PATH.format(self.index+1) self.dx010_psu_gpio = [ @@ -52,7 +53,6 @@ def __init__(self, psu_index): for fan_index in range(0, PSU_NUM_FAN[self.index]): fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) self._fan_list.append(fan) - PsuBase.__init__(self) def __read_txt_file(self, file_path): try: From 64c43f767a7b3d8e6af1549396df797c36302bc0 Mon Sep 17 00:00:00 2001 From: Guohan Lu Date: Mon, 11 Nov 2019 20:19:23 +0000 Subject: [PATCH 161/278] [submodule]: update sonic-sairedis * afe2a0d 2019-10-30 | [vs]: Fix learn fdb events after fdb flush event (#524) (HEAD, origin/master, origin/HEAD) [Kamil Cudnik] * d29760f 2019-10-28 | [sai_redis_interface_query] Add sairedis support for sai_object_type_get_availability (#528) [Danny Allen] * ff5306e 2019-10-28 | [sai_redis_interface_query] Add sairedis support for sai_query_attribute_enum_values_capability (#525) [Danny Allen] Signed-off-by: Guohan Lu --- src/sonic-sairedis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-sairedis b/src/sonic-sairedis index d9faa5890b68..afe2a0d29299 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit d9faa5890b6843a6a31e620752e865eba23f9564 +Subproject commit afe2a0d29299128d314b93c9e4726e62d3116948 From 5174ec89239bfc42c1d1bc851572d244eea84c56 Mon Sep 17 00:00:00 2001 From: Danny Allen Date: Tue, 12 Nov 2019 12:15:45 -0800 Subject: [PATCH 162/278] [bcm SAI] Upgrade Broadcom SAI to version 3.5.3.1m-26 (#50) Signed-off-by: Danny Allen --- platform/broadcom/sai.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/broadcom/sai.mk b/platform/broadcom/sai.mk index 6ef784e21ced..833c22f6bb94 100644 --- a/platform/broadcom/sai.mk +++ b/platform/broadcom/sai.mk @@ -1,9 +1,9 @@ BRCM_SAI = libsaibcm_3.5.3.1m-25_amd64.deb -$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm_3.5.3.1m-25_amd64.deb?sv=2015-04-05&sr=b&sig=kLfhfLeBmENmTXVa%2BZ90k2Fq8ZOQ84kxn5%2FzY3KLV2s%3D&se=2033-06-17T23%3A45%3A50Z&sp=r" +$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm_3.5.3.1m-26_amd64.deb?sv=2015-04-05&sr=b&sig=zo83IKnlT7goymXwynW8%2Fx6rR2eIh0AiIS%2BSrSMUhRE%3D&se=2033-07-21T18%3A50%3A27Z&sp=r" BRCM_SAI_DEV = libsaibcm-dev_3.5.3.1m-25_amd64.deb $(eval $(call add_derived_package,$(BRCM_SAI),$(BRCM_SAI_DEV))) -$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm-dev_3.5.3.1m-25_amd64.deb?sv=2015-04-05&sr=b&sig=a%2BvxIrNcVwnp0CBXS%2BTGiGl%2F%2Fl8mo9ZKPkZyroPY0bI%3D&se=2033-06-17T23%3A45%3A21Z&sp=r" +$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm-dev_3.5.3.1m-26_amd64.deb?sv=2015-04-05&sr=b&sig=tQmkCIy2mnb9rH7B9oXFUZDwijMGXWnVtta2CNTMbFM%3D&se=2033-07-21T18%3A50%3A47Z&sp=r" SONIC_ONLINE_DEBS += $(BRCM_SAI) $(BRCM_SAI_DEV)_DEPENDS += $(BRCM_SAI) From 73721223cd92679cb730830322e27c043b1ba5d9 Mon Sep 17 00:00:00 2001 From: ciju-juniper <53076238+ciju-juniper@users.noreply.github.com> Date: Wed, 13 Nov 2019 22:36:45 +0530 Subject: [PATCH 163/278] [Juniper][QFX5210] Updating platform README (#3746) * Updating the platform README Added the steps for configuring FEC mode Signed-off-by: Ciju Rajan K --- .../sonic-platform-modules-juniper/qfx5210/utils/README | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/README b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/README index a69ac017c6f2..ec9ebe97f0ee 100755 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/README +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/README @@ -64,8 +64,10 @@ SFPs There are 64 QSFP+ modules supported in qfx5210 platform. EEPORMs will be mapped under /sys/bus/i2c/devices/[25-88]-0050/ sysfs directory. -FEC should be turned on for SR4 optics and should be turned off for LR4 -optics. +FEC should be turned on for 100G SR optics and should be turned off for +100G LR optics. If the optic is changed, please update the entry and +reload the configuration. If the FEC mode is not set as per the optic +type the port may not link up or work properly. As an example, see this configuration for FEC for 100G SR4 optics in /etc/sonic/config_db.json From 864a7c60bd9cbd5d6a03dab4e33fb9577787dc08 Mon Sep 17 00:00:00 2001 From: heidinet2007 <43017482+heidinet2007@users.noreply.github.com> Date: Wed, 13 Nov 2019 14:10:11 -0800 Subject: [PATCH 164/278] start bgp_eoiu_mark service to populate bgp eoiu marker flags for warm start, if configured so (#3489) * start bgp_eoiu_mark service to populate bgp eoiu marker if configured so * Address code review comments: check db value via "-v" option in sonic-cfggen * Address code review comment 2: check string against 'true' directly, instead of couting * Update start.sh --- dockers/docker-fpm-frr/start.sh | 7 +++++++ dockers/docker-fpm-frr/supervisord.conf | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/dockers/docker-fpm-frr/start.sh b/dockers/docker-fpm-frr/start.sh index ad9beec766d3..80f9c69ec989 100755 --- a/dockers/docker-fpm-frr/start.sh +++ b/dockers/docker-fpm-frr/start.sh @@ -33,6 +33,13 @@ rm -f /var/run/rsyslogd.pid supervisorctl start rsyslogd +# start eoiu pulling, only if configured so +if [[ $(sonic-cfggen -d -v 'WARM_RESTART.bgp.bgp_eoiu') == 'true' ]]; then + supervisorctl start bgp_eoiu_marker +fi + +supervisorctl start bgpcfgd + # Start Quagga processes supervisorctl start zebra supervisorctl start staticd diff --git a/dockers/docker-fpm-frr/supervisord.conf b/dockers/docker-fpm-frr/supervisord.conf index ba9f38507b80..fe0ce6eda1a4 100644 --- a/dockers/docker-fpm-frr/supervisord.conf +++ b/dockers/docker-fpm-frr/supervisord.conf @@ -75,3 +75,13 @@ autorestart=false startsecs=0 stdout_logfile=syslog stderr_logfile=syslog + +[program:bgp_eoiu_marker] +command=/usr/bin/bgp_eoiu_marker.py +priority=7 +autostart=false +autorestart=false +startsecs=0 +startretries=0 +stdout_logfile=syslog +stderr_logfile=syslog From f5f45f8b6b57f95c7c3635f028cf2725e014bec8 Mon Sep 17 00:00:00 2001 From: Prince Sunny Date: Wed, 13 Nov 2019 14:33:35 -0800 Subject: [PATCH 165/278] [Submodule] Update sonic-utilities (#3750) --- src/sonic-utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-utilities b/src/sonic-utilities index e4a5e4ce1c3f..fe4446a4808b 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit e4a5e4ce1c3f55600ca3e6bcbffbd4bcaef4cbe6 +Subproject commit fe4446a4808bc98ca2b24b0a9afe822aaa50a7ce From f9dea23191e199b75bcc498c7b2f642c1c8ae610 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Wed, 13 Nov 2019 16:41:41 -0800 Subject: [PATCH 166/278] Don't run bgpcfgd twice (#3752) --- dockers/docker-fpm-frr/start.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dockers/docker-fpm-frr/start.sh b/dockers/docker-fpm-frr/start.sh index 80f9c69ec989..b3cef5e63244 100755 --- a/dockers/docker-fpm-frr/start.sh +++ b/dockers/docker-fpm-frr/start.sh @@ -35,11 +35,9 @@ supervisorctl start rsyslogd # start eoiu pulling, only if configured so if [[ $(sonic-cfggen -d -v 'WARM_RESTART.bgp.bgp_eoiu') == 'true' ]]; then - supervisorctl start bgp_eoiu_marker + supervisorctl start bgp_eoiu_marker fi -supervisorctl start bgpcfgd - # Start Quagga processes supervisorctl start zebra supervisorctl start staticd From c50c390eb4d9ef4ca717a197d087acc2560e6297 Mon Sep 17 00:00:00 2001 From: Joe LeVeque Date: Thu, 14 Nov 2019 00:00:55 -0800 Subject: [PATCH 167/278] [rsyslog] Add support for IPv6 remote addresses (#3754) --- files/image_config/rsyslog/rsyslog.conf.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/image_config/rsyslog/rsyslog.conf.j2 b/files/image_config/rsyslog/rsyslog.conf.j2 index e714fcec5ab4..fbf8bf20160a 100644 --- a/files/image_config/rsyslog/rsyslog.conf.j2 +++ b/files/image_config/rsyslog/rsyslog.conf.j2 @@ -42,7 +42,7 @@ $ActionFileDefaultTemplate SONiCFileFormat #Set remote syslog server {% for server in SYSLOG_SERVER %} -*.* @{{ server }}:514;SONiCFileFormat +*.* @[{{ server }}]:514;SONiCFileFormat {% endfor %} # From c78465b78fefcae3fe0f87ed65519a0c162a8d2e Mon Sep 17 00:00:00 2001 From: Volodymyr Samotiy Date: Thu, 14 Nov 2019 10:02:32 +0200 Subject: [PATCH 168/278] [Mellanox]: Update SAI submodule to 1.15.2 (#3748) Signed-off-by: Volodymyr Samotiy --- platform/mellanox/mlnx-sai.mk | 2 +- platform/mellanox/mlnx-sai/SAI-Implementation | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/mellanox/mlnx-sai.mk b/platform/mellanox/mlnx-sai.mk index 2bf37a7600bb..39942111f26a 100644 --- a/platform/mellanox/mlnx-sai.mk +++ b/platform/mellanox/mlnx-sai.mk @@ -1,6 +1,6 @@ # Mellanox SAI -MLNX_SAI_VERSION = SAIRel1.15.1-ptf-rif-vlan-fix +MLNX_SAI_VERSION = SAIRel1.15.2-master export MLNX_SAI_VERSION diff --git a/platform/mellanox/mlnx-sai/SAI-Implementation b/platform/mellanox/mlnx-sai/SAI-Implementation index d93eaed7ba8b..925116eb63a5 160000 --- a/platform/mellanox/mlnx-sai/SAI-Implementation +++ b/platform/mellanox/mlnx-sai/SAI-Implementation @@ -1 +1 @@ -Subproject commit d93eaed7ba8b996fb70e000af468c485bbfbbfae +Subproject commit 925116eb63a5a9012dcc22a7a0682ada6e976380 From 4f35a810656b9568125fddf461efa99ab80419b9 Mon Sep 17 00:00:00 2001 From: Aravind Mani <53524901+aravindmani-1@users.noreply.github.com> Date: Thu, 14 Nov 2019 13:34:11 +0530 Subject: [PATCH 169/278] DellEMC:optoe driver support in DellEMC platforms (#3747) - optoe driver truncates invalid pages(ff) but sff driver doesn't truncate.so,the DOM related calculation made by sff8436 driver will show incorrect data. - Few optics doesn't support DOM. - SFP plugins currently returns None for unreadable pages and this'd throw the below mentioned error in sfpshow eeprom --dom. --- .../plugins/sfputil.py | 36 +++++++++---------- .../s6000/scripts/s6000_platform.sh | 2 +- .../s6000/sonic_platform/sfp.py | 26 ++++++++------ .../s6100/scripts/s6100_platform.sh | 6 ++-- .../s6100/sonic_platform/sfp.py | 20 +++++------ .../z9100/scripts/z9100_platform.sh | 6 ++-- .../z9100/sonic_platform/sfp.py | 25 +++++++------ 7 files changed, 64 insertions(+), 57 deletions(-) diff --git a/device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py index df841bf88355..bb1c961ab670 100644 --- a/device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py @@ -362,11 +362,11 @@ def get_transceiver_dom_info_dict(self, port_num): sfpd_obj = sff8436Dom() if sfpd_obj is None: - return None + return transceiver_dom_info_dict sfpi_obj = sff8436InterfaceId() if sfpi_obj is None: - return None + return transceiver_dom_info_dict # 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, @@ -376,25 +376,25 @@ def get_transceiver_dom_info_dict(self, port_num): if qsfp_dom_capability_raw is not None: qspf_dom_capability_data = sfpi_obj.parse_qsfp_dom_capability(qsfp_dom_capability_raw, 0) else: - return None + return transceiver_dom_info_dict dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) else: - return None + return transceiver_dom_info_dict dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) else: - return None + return transceiver_dom_info_dict qsfp_dom_rev_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) else: - return None + return transceiver_dom_info_dict transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] @@ -409,7 +409,7 @@ def get_transceiver_dom_info_dict(self, port_num): 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 + return transceiver_dom_info_dict transceiver_dom_info_dict['tx1power'] = 'N/A' transceiver_dom_info_dict['tx2power'] = 'N/A' @@ -433,7 +433,7 @@ def get_transceiver_dom_info_dict(self, port_num): transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] else: - offset = 0 + 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 @@ -452,21 +452,21 @@ def get_transceiver_dom_info_dict(self, port_num): if dom_temperature_raw is not None: dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) else: - return None + return transceiver_dom_info_dict 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 + return transceiver_dom_info_dict dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_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 + return transceiver_dom_info_dict try: sysfsfile_eeprom.close() @@ -519,11 +519,11 @@ def get_transceiver_dom_threshold_info_dict(self, port_num): sfpd_obj = sff8436Dom() if sfpd_obj is None: - return None + return transceiver_dom_threshold_info_dict # Dom Threshold data starts from offset 384 # Revert offset back to 0 once data is retrieved - offset = 0 + offset = 384 dom_module_threshold_raw = self._read_eeprom_specific_bytes( sysfsfile_eeprom, (offset + QSFP_MODULE_THRESHOLD_OFFSET), @@ -531,7 +531,7 @@ def get_transceiver_dom_threshold_info_dict(self, port_num): if dom_module_threshold_raw is not None: dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) else: - return None + return transceiver_dom_threshold_info_dict dom_channel_threshold_raw = self._read_eeprom_specific_bytes( sysfsfile_eeprom, @@ -540,7 +540,7 @@ def get_transceiver_dom_threshold_info_dict(self, port_num): if dom_channel_threshold_raw is not None: dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values(dom_channel_threshold_raw, 0) else: - return None + return transceiver_dom_threshold_info_dict try: sysfsfile_eeprom.close() @@ -567,7 +567,7 @@ def get_transceiver_dom_threshold_info_dict(self, port_num): transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] else: - offset = 0 + 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 @@ -580,7 +580,7 @@ def get_transceiver_dom_threshold_info_dict(self, port_num): sfpd_obj = sff8472Dom(None,1) if sfpd_obj is None: - return None + return transceiver_dom_threshold_info_dict dom_module_threshold_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) @@ -588,7 +588,7 @@ def get_transceiver_dom_threshold_info_dict(self, port_num): if dom_module_threshold_raw is not None: dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(dom_module_threshold_raw, 0) else: - return None + return transceiver_dom_threshold_info_dict try: sysfsfile_eeprom.close() diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/scripts/s6000_platform.sh b/platform/broadcom/sonic-platform-modules-dell/s6000/scripts/s6000_platform.sh index 316fbaec5fee..bf6c730425e7 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6000/scripts/s6000_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/s6000/scripts/s6000_platform.sh @@ -32,7 +32,7 @@ add_i2c_devices() { echo 24c02 0x52 > /sys/class/i2c-adapter/i2c-11/new_device echo 24c02 0x53 > /sys/class/i2c-adapter/i2c-11/new_device for i in `seq 0 31`; do - echo sff8436 0x50 > /sys/class/i2c-adapter/i2c-$((20+i))/new_device + echo optoe1 0x50 > /sys/class/i2c-adapter/i2c-$((20+i))/new_device done } diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py index a334aa7a7f97..9ab89db5d61a 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py @@ -44,7 +44,7 @@ 'manufacturename', 'modelname', 'Connector', 'encoding', 'ext_identifier', 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', - 'specification_compliance', 'vendor_date', 'vendor_oui'] + 'specification_compliance', 'type_abbrv_name','vendor_date', 'vendor_oui'] dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', @@ -87,6 +87,7 @@ 'nominal_bit_rate': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], 'specification_compliance': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'type_abbrv_name' : [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], 'manufacturename': [INFO_OFFSET, 20, 16, 'parse_vendor_name'], 'vendor_oui': [INFO_OFFSET, 37, 3, 'parse_vendor_oui'], 'modelname': [INFO_OFFSET, 40, 16, 'parse_vendor_pn'], @@ -168,6 +169,7 @@ def _get_eeprom_data(self, eeprom_key): return eeprom_data + def get_transceiver_info(self): """ Retrieves transceiver info of this SFP @@ -184,6 +186,7 @@ def get_transceiver_info(self): ext_id = iface_data['data']['Extended Identifier']['value'] rate_identifier = iface_data['data']['RateIdentifier']['value'] identifier = iface_data['data']['type']['value'] + type_abbrv_name=iface_data['data']['type_abbrv_name']['value'] bit_rate = str( iface_data['data']['Nominal Bit Rate(100Mbs)']['value']) @@ -195,7 +198,7 @@ def get_transceiver_info(self): cable_type = key cable_length = str(iface_data['data'][key]['value']) else: - return None + return transceiver_info_dict # Vendor Date vendor_date_data = self._get_eeprom_data('vendor_date') @@ -209,36 +212,36 @@ def get_transceiver_info(self): if (vendor_name_data is not None): vendor_name = vendor_name_data['data']['Vendor Name']['value'] else: - return None + return transceiver_info_dict # Vendor OUI vendor_oui_data = self._get_eeprom_data('vendor_oui') if (vendor_oui_data is not None): vendor_oui = vendor_oui_data['data']['Vendor OUI']['value'] else: - return None + return transceiver_info_dict # Vendor PN vendor_pn_data = self._get_eeprom_data('modelname') if (vendor_pn_data is not None): vendor_pn = vendor_pn_data['data']['Vendor PN']['value'] else: - return None + return transceiver_info_dict # Vendor Revision vendor_rev_data = self._get_eeprom_data('hardwarerev') if (vendor_rev_data is not None): vendor_rev = vendor_rev_data['data']['Vendor Rev']['value'] else: - return None + return transceiver_info_dict # Vendor Serial Number vendor_sn_data = self._get_eeprom_data('serialnum') if (vendor_sn_data is not None): vendor_sn = vendor_sn_data['data']['Vendor SN']['value'] else: - return None - + return transceiver_info_dict + # Fill The Dictionary and return transceiver_info_dict['type'] = identifier transceiver_info_dict['hardwarerev'] = vendor_rev @@ -256,6 +259,7 @@ def get_transceiver_info(self): compliance_code_dict) transceiver_info_dict['vendor_date'] = vendor_date transceiver_info_dict['vendor_oui'] = vendor_oui + transceiver_info_dict['type_abbrv_name']=type_abbrv_name return transceiver_info_dict @@ -279,7 +283,7 @@ def get_transceiver_threshold_info(self): vccHighWarn = module_threshold_data['data']['VccHighWarning']['value'] vccLowWarn = module_threshold_data['data']['VccLowWarning']['value'] else: - return None + return transceiver_dom_threshold_dict # Channel Threshold channel_threshold_data = self._get_eeprom_data('ChannelThreshold') @@ -293,7 +297,7 @@ def get_transceiver_threshold_info(self): txBiasHighWarn = channel_threshold_data['data']['TxBiasHighWarning']['value'] txBiasLowWarn = channel_threshold_data['data']['TxBiasLowWarning']['value'] else: - return None + return transceiver_dom_threshold_dict transceiver_dom_threshold_dict['temphighalarm'] = tempHighAlarm transceiver_dom_threshold_dict['templowalarm'] = tempLowAlarm @@ -367,7 +371,7 @@ def get_transceiver_bulk_status(self): rx_power = channel_monitor_data['data']['RX4Power']['value'] rx_power_list.append(rx_power) else: - return None + return transceiver_dom_dict transceiver_dom_dict['rx_los'] = rx_los transceiver_dom_dict['tx_fault'] = tx_fault diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh index 52eb757ad696..d8b13ca02c1e 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh @@ -109,8 +109,8 @@ switch_board_qsfp_mux() { #Attach/Detach the SFP modules on PCA9548_2 switch_board_sfp() { case $1 in - "new_device") i2c_config "echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-11/$1" - i2c_config "echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-12/$1" + "new_device") i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-11/$1" + i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-12/$1" ;; "delete_device") i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-11/$1" i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-12/$1" @@ -125,7 +125,7 @@ qsfp_device_mod() { case $1 in "new_device") for ((i=$2;i<=$3;i++)); do - i2c_config "echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-$i/$1" + i2c_config "echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-$i/$1" done ;; "delete_device") for ((i=$2;i<=$3;i++)); diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/sfp.py index 8f8f63266f7b..e94c53b11a95 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/sfp.py @@ -195,49 +195,49 @@ def get_transceiver_info(self): cable_type = key cable_length = str(iface_data['data'][key]['value']) else: - return None + return transceiver_info_dict # Vendor Date vendor_date_data = self._get_eeprom_data('vendor_date') if (vendor_date_data is not None): vendor_date = vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] else: - return None + return transceiver_info_dict # Vendor Name vendor_name_data = self._get_eeprom_data('manufacturename') if (vendor_name_data is not None): vendor_name = vendor_name_data['data']['Vendor Name']['value'] else: - return None + return transceiver_info_dict # Vendor OUI vendor_oui_data = self._get_eeprom_data('vendor_oui') if (vendor_oui_data is not None): vendor_oui = vendor_oui_data['data']['Vendor OUI']['value'] else: - return None + return transceiver_info_dict # Vendor PN vendor_pn_data = self._get_eeprom_data('modelname') if (vendor_pn_data is not None): vendor_pn = vendor_pn_data['data']['Vendor PN']['value'] else: - return None + return transceiver_info_dict # Vendor Revision vendor_rev_data = self._get_eeprom_data('hardwarerev') if (vendor_rev_data is not None): vendor_rev = vendor_rev_data['data']['Vendor Rev']['value'] else: - return None + return transceiver_info_dict # Vendor Serial Number vendor_sn_data = self._get_eeprom_data('serialnum') if (vendor_sn_data is not None): vendor_sn = vendor_sn_data['data']['Vendor SN']['value'] else: - return None + return transceiver_info_dict # Fill The Dictionary and return transceiver_info_dict['type'] = identifier @@ -279,7 +279,7 @@ def get_transceiver_threshold_info(self): vccHighWarn = module_threshold_data['data']['VccHighWarning']['value'] vccLowWarn = module_threshold_data['data']['VccLowWarning']['value'] else: - return None + return transceiver_dom_threshold_dict # Channel Threshold channel_threshold_data = self._get_eeprom_data('ChannelThreshold') @@ -293,7 +293,7 @@ def get_transceiver_threshold_info(self): txBiasHighWarn = channel_threshold_data['data']['TxBiasHighWarning']['value'] txBiasLowWarn = channel_threshold_data['data']['TxBiasLowWarning']['value'] else: - return None + return transceiver_dom_threshold_dict transceiver_dom_threshold_dict['temphighalarm'] = tempHighAlarm transceiver_dom_threshold_dict['templowalarm'] = tempLowAlarm @@ -367,7 +367,7 @@ def get_transceiver_bulk_status(self): rx_power = channel_monitor_data['data']['RX4Power']['value'] rx_power_list.append(rx_power) else: - return None + return transceiver_dom_dict transceiver_dom_dict['rx_los'] = rx_los transceiver_dom_dict['tx_fault'] = tx_fault diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/z9100_platform.sh b/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/z9100_platform.sh index 276acd882f14..7fe841ef5447 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/z9100_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/z9100_platform.sh @@ -107,8 +107,8 @@ switch_board_qsfp_mux() { #Attach/Detach the SFP modules on PCA9548_2 switch_board_sfp() { case $1 in - "new_device") i2c_config "echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-11/$1" - i2c_config "echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-12/$1" + "new_device") i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-11/$1" + i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-12/$1" ;; "delete_device") i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-11/$1" i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-12/$1" @@ -125,7 +125,7 @@ switch_board_qsfp() { "new_device") for ((i=18;i<=49;i++)); do - i2c_config "echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-$i/$1" + i2c_config "echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-$i/$1" done ;; "delete_device") diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py index f29b708b8ea5..87057545cbb7 100644 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py @@ -44,7 +44,7 @@ 'manufacturename', 'modelname', 'Connector', 'encoding', 'ext_identifier', 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', - 'specification_compliance', 'vendor_date', 'vendor_oui'] + 'specification_compliance', ,'type_abbrv_name','vendor_date', 'vendor_oui'] dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', @@ -87,6 +87,7 @@ 'nominal_bit_rate': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], 'specification_compliance': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'type_abbrv_name': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], 'manufacturename': [INFO_OFFSET, 20, 16, 'parse_vendor_name'], 'vendor_oui': [INFO_OFFSET, 37, 3, 'parse_vendor_oui'], 'modelname': [INFO_OFFSET, 40, 16, 'parse_vendor_pn'], @@ -186,6 +187,7 @@ def get_transceiver_info(self): identifier = iface_data['data']['type']['value'] bit_rate = str( iface_data['data']['Nominal Bit Rate(100Mbs)']['value']) + type_abbrv_name=iface_data['data']['type_abbrv_name']['value'] for key in compliance_code_tup: if key in iface_data['data']['Specification compliance']['value']: @@ -195,49 +197,49 @@ def get_transceiver_info(self): cable_type = key cable_length = str(iface_data['data'][key]['value']) else: - return None + return transceiver_info_dict # Vendor Date vendor_date_data = self._get_eeprom_data('vendor_date') if (vendor_date_data is not None): vendor_date = vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] else: - return None + return transceiver_info_dict # Vendor Name vendor_name_data = self._get_eeprom_data('manufacturename') if (vendor_name_data is not None): vendor_name = vendor_name_data['data']['Vendor Name']['value'] else: - return None + return transceiver_info_dict # Vendor OUI vendor_oui_data = self._get_eeprom_data('vendor_oui') if (vendor_oui_data is not None): vendor_oui = vendor_oui_data['data']['Vendor OUI']['value'] else: - return None + return transceiver_info_dict # Vendor PN vendor_pn_data = self._get_eeprom_data('modelname') if (vendor_pn_data is not None): vendor_pn = vendor_pn_data['data']['Vendor PN']['value'] else: - return None + return transceiver_info_dict # Vendor Revision vendor_rev_data = self._get_eeprom_data('hardwarerev') if (vendor_rev_data is not None): vendor_rev = vendor_rev_data['data']['Vendor Rev']['value'] else: - return None + return transceiver_info_dict # Vendor Serial Number vendor_sn_data = self._get_eeprom_data('serialnum') if (vendor_sn_data is not None): vendor_sn = vendor_sn_data['data']['Vendor SN']['value'] else: - return None + return transceiver_info_dict # Fill The Dictionary and return transceiver_info_dict['type'] = identifier @@ -256,6 +258,7 @@ def get_transceiver_info(self): compliance_code_dict) transceiver_info_dict['vendor_date'] = vendor_date transceiver_info_dict['vendor_oui'] = vendor_oui + transceiver_info_dict['type_abbrv_name']=type_abbrv_name return transceiver_info_dict @@ -279,7 +282,7 @@ def get_transceiver_threshold_info(self): vccHighWarn = module_threshold_data['data']['VccHighWarning']['value'] vccLowWarn = module_threshold_data['data']['VccLowWarning']['value'] else: - return None + return transceiver_dom_threshold_dict # Channel Threshold channel_threshold_data = self._get_eeprom_data('ChannelThreshold') @@ -293,7 +296,7 @@ def get_transceiver_threshold_info(self): txBiasHighWarn = channel_threshold_data['data']['TxBiasHighWarning']['value'] txBiasLowWarn = channel_threshold_data['data']['TxBiasLowWarning']['value'] else: - return None + return transceiver_dom_threshold_dict transceiver_dom_threshold_dict['temphighalarm'] = tempHighAlarm transceiver_dom_threshold_dict['templowalarm'] = tempLowAlarm @@ -367,7 +370,7 @@ def get_transceiver_bulk_status(self): rx_power = channel_monitor_data['data']['RX4Power']['value'] rx_power_list.append(rx_power) else: - return None + return transceiver_dom_dict transceiver_dom_dict['rx_los'] = rx_los transceiver_dom_dict['tx_fault'] = tx_fault From 4007d9ba9c1be83d56cf9fcec20edfd32a4d51cc Mon Sep 17 00:00:00 2001 From: kannankvs Date: Thu, 14 Nov 2019 13:36:54 +0530 Subject: [PATCH 170/278] [ntp]: modified ntp script to hide the error related to cfggen (#3745) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR is to handle the issue 3527. When device boots up, NTP throws a traceback as explained in the issue 3527. - Traceback will be seen when MGMT_VRF_CONFIG does not exist in the database. Traceback is coming from the script “/etc/init.d/ntpâ€. - Traceback does not affect the NTP functionality with/without management VRF. When MGMT_VRF_CONFIG does not exist or when MGMT_VRF_CONFIG’s mgmtVrfEnabled is configured to “falseâ€, “NTP†will be started in the “default VRF†context, which is working fine even with this traceback. - This traceback error will be hidden by redirecting the error to /dev/null without affecting functionality. --- files/image_config/ntp/ntp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/image_config/ntp/ntp b/files/image_config/ntp/ntp index 976269241bbb..ecf0e5089071 100755 --- a/files/image_config/ntp/ntp +++ b/files/image_config/ntp/ntp @@ -50,7 +50,7 @@ case $1 in fi ( flock -w 180 9 - vrfEnabled=$(/usr/local/bin/sonic-cfggen -d -v 'MGMT_VRF_CONFIG["vrf_global"]["mgmtVrfEnabled"]') + vrfEnabled=$(/usr/local/bin/sonic-cfggen -d -v 'MGMT_VRF_CONFIG["vrf_global"]["mgmtVrfEnabled"]' 2> /dev/null) if [ "$vrfEnabled" = "true" ] then log_daemon_msg "Starting NTP server in mgmt-vrf" "ntpd" From 413f07820d55e1fdd95a6982855fedebbcb5fb4b Mon Sep 17 00:00:00 2001 From: srideepDell Date: Thu, 14 Nov 2019 01:08:15 -0700 Subject: [PATCH 171/278] [devices]: Firmware upgrade support for DellEMC platforms(s5248,s5232,z9100,s6100,z9264f) (#3743) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * This method is used to update firmware components such as CPLD,FPGA,BIOS,SMF * This uses ONIE firmware upgrade design to stage firmware update from NOS. a) Copy latest firmware updater image to target running sonic. b) Run “./fw-updater -u onie-firmware-x86_64-dellemc_s5200_c3538-r0.3.40.5.1-9.binâ€. c) This would automatically reboot ONIE into update mode and update firmware components to latest and reboot back to sonic without any user intervention. Signed-off-by: Srideep Devireddy --- platform/broadcom/platform-modules-dell.mk | 5 + .../common/fw-updater | 91 +++++++++++++++++++ .../debian/platform-modules-s5232f.install | 1 + .../debian/platform-modules-s5248f.install | 1 + .../debian/platform-modules-s6100.install | 1 + .../debian/platform-modules-z9100.install | 1 + .../debian/platform-modules-z9264f.install | 1 + 7 files changed, 101 insertions(+) create mode 100755 platform/broadcom/sonic-platform-modules-dell/common/fw-updater diff --git a/platform/broadcom/platform-modules-dell.mk b/platform/broadcom/platform-modules-dell.mk index 34e404cfae45..583f74f72d8b 100644 --- a/platform/broadcom/platform-modules-dell.mk +++ b/platform/broadcom/platform-modules-dell.mk @@ -5,12 +5,14 @@ DELL_Z9100_PLATFORM_MODULE_VERSION = 1.1 DELL_S6100_PLATFORM_MODULE_VERSION = 1.1 DELL_Z9264F_PLATFORM_MODULE_VERSION = 1.1 DELL_S5232F_PLATFORM_MODULE_VERSION = 1.1 +DELL_S5248F_PLATFORM_MODULE_VERSION = 1.1 export DELL_S6000_PLATFORM_MODULE_VERSION export DELL_Z9100_PLATFORM_MODULE_VERSION export DELL_S6100_PLATFORM_MODULE_VERSION export DELL_Z9264F_PLATFORM_MODULE_VERSION export DELL_S5232F_PLATFORM_MODULE_VERSION +export DELL_S5248F_PLATFORM_MODULE_VERSION DELL_Z9100_PLATFORM_MODULE = platform-modules-z9100_$(DELL_Z9100_PLATFORM_MODULE_VERSION)_amd64.deb $(DELL_Z9100_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-dell @@ -35,6 +37,9 @@ DELL_S5232F_PLATFORM_MODULE = platform-modules-s5232f_$(DELL_S5232F_PLATFORM_MOD $(DELL_S5232F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5232f_c3538-r0 $(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5232F_PLATFORM_MODULE))) +DELL_S5248F_PLATFORM_MODULE = platform-modules-s5248f_$(DELL_S5248F_PLATFORM_MODULE_VERSION)_amd64.deb +$(DELL_S5248F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5248f_c3538-r0 +$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5248F_PLATFORM_MODULE))) SONIC_STRETCH_DEBS += $(DELL_Z9100_PLATFORM_MODULE) #flashrom tool diff --git a/platform/broadcom/sonic-platform-modules-dell/common/fw-updater b/platform/broadcom/sonic-platform-modules-dell/common/fw-updater new file mode 100755 index 000000000000..6905664672ad --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/common/fw-updater @@ -0,0 +1,91 @@ +#!/usr/bin/python + +# dell staging fw updater script + +import os +import sys +import subprocess +import argparse + + +onie_boot_folder = '/mnt/onie-boot/onie/tools/bin/onie-fwpkg' +onie_fwpkg_tool = '/mnt/onie-boot/onie/tools/bin/onie-fwpkg' +ONIE_BOOT_MODE_CMD = '/mnt/onie-boot/onie/tools/bin/onie-boot-mode' +HOST_GRUB_DIR = '/host' +HOST_GRUB_CFG = HOST_GRUB_DIR + '/grub/grub.cfg' +HOST_GRUB_ENV = HOST_GRUB_DIR + '/grub/grubenv' +HOST_GRUB_BOOT_DIR = '--boot-directory=' + HOST_GRUB_DIR +HOST_PLATFORM_INFO = HOST_GRUB_DIR + '/platform' +dell_reload_tool = '/usr/bin/reboot' + + + + +def set_onie_mode(option): + """Select the ONIE boot mode, and set the next_entry to point to ONIE""" + _set_env_option('next_entry', 'ONIE') + subprocess.check_call([ONIE_BOOT_MODE_CMD, '-o', option]) + +def set_onie_fw_update_env(): + """Select the ONIE boot mode, and set the next_entry to point to ONIE""" + + if not os.path.exists(onie_boot_folder): + os.makedirs(onie_boot_folder) + + try: + subprocess.check_call(['mount','/dev/disk/by-label/ONIE-BOOT','/mnt/onie-boot']) + except: + print "onie-boot not able to mount" + +def _set_env_option(option, value): + """Set an option in the GRUB environment block. Pass None to value to + unset the option""" + if value is None: + action = 'unset' + key_value = option + else: + action = 'set' + key_value = '%s=%s' % (option, value) + + subprocess.check_call(['grub-editenv', HOST_GRUB_ENV, action, key_value]) + + +def dell_firmware_update_staging(image_name): + + try: + p = subprocess.Popen([onie_fwpkg_tool,"purge"],stdout=subprocess.PIPE,stdin=subprocess.PIPE) + p.communicate("y") + except: + print "onie-fwpkg command not found for purging old fw updates" + + try: + subprocess.check_call([onie_fwpkg_tool,"add", str(image_name)]) + except: + print "onie-fwpkg is not found to stage fw updates" + + try: + set_onie_mode("update") + except: + print "dell-image command not found" + + try: + subprocess.check_call([dell_reload_tool]) + except: + print "reload command not found" + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Dell HOST Firmware updates') + opts = parser.add_mutually_exclusive_group(required=True) + opts.add_argument('-u', '--update', nargs=1, metavar='IMAGE', + help='update specified image') + + args = parser.parse_args() + + if os.getuid() != 0: + parser.exit(127, 'ERROR: Must be root\n') + + if args.update: + set_onie_fw_update_env() + dell_firmware_update_staging(args.update[0]) + diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5232f.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5232f.install index 51bed7edd95a..b577c5cd5b10 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5232f.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5232f.install @@ -7,3 +7,4 @@ s5232f/scripts/qsfp_irq_enable.py usr/bin s5232f/cfg/s5232f-modules.conf etc/modules-load.d s5232f/systemd/platform-modules-s5232f.service etc/systemd/system common/platform_reboot usr/share/sonic/device/x86_64-dellemc_s5232f_c3538-r0 +common/fw-updater usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.install index 084208955317..7aa27d23b536 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.install @@ -7,3 +7,4 @@ s5248f/scripts/qsfp_irq_enable.py usr/bin s5248f/cfg/s5248f-modules.conf etc/modules-load.d s5248f/systemd/platform-modules-s5248f.service etc/systemd/system common/platform_reboot usr/share/sonic/device/x86_64-dellemc_s5248f_c3538-r0 +common/fw-updater usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install index b0c27702cb4a..5d1cb6341fc7 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install @@ -13,3 +13,4 @@ s6100/scripts/sensors usr/bin s6100/systemd/platform-modules-s6100.service etc/systemd/system s6100/systemd/s6100-lpc-monitor.service etc/systemd/system tools/flashrom/flashrom usr/local/bin/ +common/fw-updater usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.install index bb3d869cf274..5c5c4cc55be2 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.install @@ -11,3 +11,4 @@ z9100/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64- z9100/cfg/z9100-modules.conf etc/modules-load.d z9100/systemd/platform-modules-z9100.service etc/systemd/system z9100/systemd/z9100-lpc-monitor.service etc/systemd/system +common/fw-updater usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.install index 6a2f15511d66..29e8b1df2e36 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.install @@ -7,3 +7,4 @@ z9264f/scripts/qsfp_irq_enable.py usr/bin z9264f/cfg/z9264f-modules.conf etc/modules-load.d z9264f/systemd/platform-modules-z9264f.service etc/systemd/system common/platform_reboot usr/share/sonic/device/x86_64-dellemc_z9264f_c3538-r0 +common/fw-updater usr/local/bin From f9e36d3b0b73c34a10e31951d25b53ddb0eaa949 Mon Sep 17 00:00:00 2001 From: lguohan Date: Thu, 14 Nov 2019 17:58:28 -0800 Subject: [PATCH 172/278] [submodule]: update sonic-utilities (#3756) * be337d4 2019-11-14 | [bugfix]: allow loopback vrf migration from version 1_0_1 (#737) (HEAD, origin/master, origin/HEAD) [lguohan] * 201132d 2019-11-14 | [config]: add the vid range check for creating vlan. (#634) [wangshengjun] Signed-off-by: Guohan Lu --- src/sonic-utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-utilities b/src/sonic-utilities index fe4446a4808b..be337d4f09c9 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit fe4446a4808bc98ca2b24b0a9afe822aaa50a7ce +Subproject commit be337d4f09c9fc901c85d2d615a3cdebbc039a33 From df11b2b9f18394782f089a6d6bc4e28d3b6392f4 Mon Sep 17 00:00:00 2001 From: yozhao101 <56170650+yozhao101@users.noreply.github.com> Date: Mon, 18 Nov 2019 16:56:44 -0800 Subject: [PATCH 173/278] [Services] Restart Telemetry service upon unexpected critical process exit. (#3768) Signed-off-by: Yong Zhao --- dockers/docker-sonic-telemetry/Dockerfile.j2 | 2 ++ dockers/docker-sonic-telemetry/critical_processes | 2 ++ dockers/docker-sonic-telemetry/supervisord.conf | 12 +++++++++--- files/build_templates/telemetry.service.j2 | 4 ++++ rules/telemetry.mk | 1 + 5 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 dockers/docker-sonic-telemetry/critical_processes diff --git a/dockers/docker-sonic-telemetry/Dockerfile.j2 b/dockers/docker-sonic-telemetry/Dockerfile.j2 index cfbe7c6f266c..3a5716001ca5 100644 --- a/dockers/docker-sonic-telemetry/Dockerfile.j2 +++ b/dockers/docker-sonic-telemetry/Dockerfile.j2 @@ -35,5 +35,7 @@ RUN apt-get clean -y && \ COPY ["start.sh", "telemetry.sh", "dialout.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor"] ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-sonic-telemetry/critical_processes b/dockers/docker-sonic-telemetry/critical_processes new file mode 100644 index 000000000000..d6953dd0c883 --- /dev/null +++ b/dockers/docker-sonic-telemetry/critical_processes @@ -0,0 +1,2 @@ +telemetry +dialout diff --git a/dockers/docker-sonic-telemetry/supervisord.conf b/dockers/docker-sonic-telemetry/supervisord.conf index dcd8a9eb1e80..b6a01de58a7b 100644 --- a/dockers/docker-sonic-telemetry/supervisord.conf +++ b/dockers/docker-sonic-telemetry/supervisord.conf @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=always +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 @@ -15,7 +21,7 @@ stderr_logfile=syslog command=/usr/sbin/rsyslogd -n priority=2 autostart=false -autorestart=false +autorestart=true stdout_logfile=syslog stderr_logfile=syslog @@ -23,7 +29,7 @@ stderr_logfile=syslog command=/usr/bin/telemetry.sh priority=3 autostart=false -autorestart=true +autorestart=false stdout_logfile=syslog stderr_logfile=syslog @@ -31,6 +37,6 @@ stderr_logfile=syslog command=/usr/bin/dialout.sh priority=4 autostart=false -autorestart=true +autorestart=false stdout_logfile=syslog stderr_logfile=syslog diff --git a/files/build_templates/telemetry.service.j2 b/files/build_templates/telemetry.service.j2 index 2e7e45218df2..98ae2871bf6f 100644 --- a/files/build_templates/telemetry.service.j2 +++ b/files/build_templates/telemetry.service.j2 @@ -3,12 +3,16 @@ Description=Telemetry container Requires=database.service After=database.service swss.service syncd.service Before=ntp-config.service +StartLimitIntervalSec=1200 +StartLimitBurst=3 [Service] User={{ sonicadmin_user }} ExecStartPre=/usr/bin/{{docker_container_name}}.sh start ExecStart=/usr/bin/{{docker_container_name}}.sh wait ExecStop=/usr/bin/{{docker_container_name}}.sh stop +Restart=always +RestartSec=30 [Install] WantedBy=multi-user.target diff --git a/rules/telemetry.mk b/rules/telemetry.mk index 1d903e603251..af568fb5bd6f 100644 --- a/rules/telemetry.mk +++ b/rules/telemetry.mk @@ -3,3 +3,4 @@ SONIC_TELEMETRY = sonic-telemetry_0.1_$(CONFIGURED_ARCH).deb $(SONIC_TELEMETRY)_SRC_PATH = $(SRC_PATH)/telemetry SONIC_DPKG_DEBS += $(SONIC_TELEMETRY) +$(SONIC_TELEMETRY)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) From 7c65f8c58abcc6756be2f193ccd6063b9abb75f9 Mon Sep 17 00:00:00 2001 From: Tyler Li Date: Wed, 20 Nov 2019 00:15:33 +0800 Subject: [PATCH 174/278] Fix vrf test failed after frr update to 7.2 (#3763) --- ...nexthops-compare-vrf-only-if-ip-type.patch | 73 +++++++++++++++++++ src/sonic-frr/patch/series | 1 + 2 files changed, 74 insertions(+) create mode 100644 src/sonic-frr/patch/0005-nexthops-compare-vrf-only-if-ip-type.patch diff --git a/src/sonic-frr/patch/0005-nexthops-compare-vrf-only-if-ip-type.patch b/src/sonic-frr/patch/0005-nexthops-compare-vrf-only-if-ip-type.patch new file mode 100644 index 000000000000..343f1b3262d9 --- /dev/null +++ b/src/sonic-frr/patch/0005-nexthops-compare-vrf-only-if-ip-type.patch @@ -0,0 +1,73 @@ +From 2f0b5aef66316b47d2cc8ac18453600621a6a317 Mon Sep 17 00:00:00 2001 +From: Tyler Li +Date: Thu, 14 Nov 2019 23:46:52 -0800 +Subject: [PATCH] nexthops compare vrf only if ip type + +--- + lib/nexthop.c | 12 ++++++------ + lib/zclient.c | 12 ++++++------ + 2 files changed, 12 insertions(+), 12 deletions(-) + +diff --git a/lib/nexthop.c b/lib/nexthop.c +index cf5bed3d6..7d9f646c9 100644 +--- a/lib/nexthop.c ++++ b/lib/nexthop.c +@@ -105,12 +105,6 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1, + { + int ret = 0; + +- if (next1->vrf_id < next2->vrf_id) +- return -1; +- +- if (next1->vrf_id > next2->vrf_id) +- return 1; +- + if (next1->type < next2->type) + return -1; + +@@ -120,6 +114,12 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1, + switch (next1->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV6: ++ if (next1->vrf_id < next2->vrf_id) ++ return -1; ++ ++ if (next1->vrf_id > next2->vrf_id) ++ return 1; ++ + ret = _nexthop_gateway_cmp(next1, next2); + if (ret != 0) + return ret; +diff --git a/lib/zclient.c b/lib/zclient.c +index c739af043..0d37c46d1 100644 +--- a/lib/zclient.c ++++ b/lib/zclient.c +@@ -783,12 +783,6 @@ static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1, + { + int ret = 0; + +- if (next1->vrf_id < next2->vrf_id) +- return -1; +- +- if (next1->vrf_id > next2->vrf_id) +- return 1; +- + if (next1->type < next2->type) + return -1; + +@@ -798,6 +792,12 @@ static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1, + switch (next1->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV6: ++ if (next1->vrf_id < next2->vrf_id) ++ return -1; ++ ++ if (next1->vrf_id > next2->vrf_id) ++ return 1; ++ + ret = nexthop_g_addr_cmp(next1->type, &next1->gate, + &next2->gate); + if (ret != 0) +-- +2.11.0 + diff --git a/src/sonic-frr/patch/series b/src/sonic-frr/patch/series index 233021ace50b..13619c87ff65 100644 --- a/src/sonic-frr/patch/series +++ b/src/sonic-frr/patch/series @@ -2,4 +2,5 @@ 0002-Reduce-severity-of-Vty-connected-from-message.patch 0003-Use-vrf_id-for-vrf-not-tabled_id.patch 0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch +0005-nexthops-compare-vrf-only-if-ip-type.patch 0006-changes-for-making-snmp-socket-non-blocking.patch From b25ec7d59176b5e196903bc3d6078abdf6a034f1 Mon Sep 17 00:00:00 2001 From: Qi Luo Date: Tue, 19 Nov 2019 13:09:42 -0800 Subject: [PATCH 175/278] Update submodule: sonic-snmpagent (#3782) --- src/sonic-snmpagent | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-snmpagent b/src/sonic-snmpagent index 875831ecda26..862e51ab85d4 160000 --- a/src/sonic-snmpagent +++ b/src/sonic-snmpagent @@ -1 +1 @@ -Subproject commit 875831ecda2601a88612c0185242d11e97eb6e82 +Subproject commit 862e51ab85d48290082adfcbb801bfbbe3a95bf3 From 0e0699ce4e2057e86b572f0a424109b7eaaf2df7 Mon Sep 17 00:00:00 2001 From: Prince Sunny Date: Tue, 19 Nov 2019 22:13:21 -0800 Subject: [PATCH 176/278] [Submodule] Update sonic-swss-common (#3770) a4a1e10 - 2019-11-07 : Changes in swss-common submodule to support NAT feature. (#304) [Kiran Kumar Kella] b1375bb - 2019-10-28 : [consumer_table] Add messages for performing object availability query (#314) [Danny Allen] 2fe2327 - 2019-10-25 : adding FDB table in CFG db (#303) [anilkpandey] 2018880 - 2019-09-26 : added COUNTERS_LAG_NAME_MAP_TABLE in COUNTERS_DB [anilkpandey] f41dcc3 - 2019-10-07 : added lua script to flush fdb entries [anilkpandey] c87a7cf - 2019-10-25 : [consumer_table] Add messages for performing attribute enum value capabilities query (#313) [Danny Allen] --- src/sonic-swss-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-swss-common b/src/sonic-swss-common index aaa8133e8be9..a4a1e108afb3 160000 --- a/src/sonic-swss-common +++ b/src/sonic-swss-common @@ -1 +1 @@ -Subproject commit aaa8133e8be9eb2a2f924c9eec997a502b795544 +Subproject commit a4a1e108afb3e75717e204da49a975681d964e8c From fc495dc10ecd942ba8e8766cd01f8b5933f73a3e Mon Sep 17 00:00:00 2001 From: Andriy Kokhan <43479230+akokhan@users.noreply.github.com> Date: Wed, 20 Nov 2019 08:14:29 +0200 Subject: [PATCH 177/278] [barefoot][build] Fixed BFN platform build failure (#3766) Signed-off-by: Andriy Kokhan --- .../x86_64-arista_7170_64c/Arista-7170-64C/switch-sai.conf | 2 +- .../Arista-7170-64C/switch-tna-sai.conf | 2 +- .../x86_64-arista_7170_64c/Arista-7170-Q59S20/switch-sai.conf | 2 +- .../Arista-7170-Q59S20/switch-tna-sai.conf | 2 +- .../x86_64-accton_as9516bf_32d-r0/newport/switch-tna-sai.conf | 2 +- .../x86_64-accton_wedge100bf_32x-r0/montara/switch-sai.conf | 2 +- .../montara/switch-tna-sai.conf | 2 +- .../x86_64-accton_wedge100bf_65x-r0/mavericks/switch-sai.conf | 2 +- .../mavericks/switch-tna-sai.conf | 2 +- .../INGRASYS-S9180-32X/switch-sai.conf | 2 +- .../INGRASYS-S9180-32X/switch-tna-sai.conf | 2 +- .../INGRASYS-S9280-64X/switch-sai.conf | 2 +- .../INGRASYS-S9280-64X/switch-tna-sai.conf | 2 +- .../wnc/x86_64-wnc_osw1800-r0/OSW1800-48x6q/switch-sai.conf | 2 +- .../x86_64-wnc_osw1800-r0/OSW1800-48x6q/switch-tna-sai.conf | 2 +- platform/barefoot/bfn-platform.mk | 4 ++-- platform/barefoot/bfn-sai.mk | 4 ++-- 17 files changed, 19 insertions(+), 19 deletions(-) diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/switch-sai.conf b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/switch-sai.conf index c3abb3ebd8fc..0a807b1c9ea7 100644 --- a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/switch-sai.conf +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/switch-sai.conf @@ -25,7 +25,7 @@ "table-config": "share/tofinopd/switch/context.json", "tofino-bin": "share/tofinopd/switch/tofino.bin", "switchapi": "lib/libswitchapi.so", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "switchapi_port_add": false, "non_default_port_ppgs": 5 } diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/switch-tna-sai.conf b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/switch-tna-sai.conf index 403b08d6bb5e..ece3fcbe6a90 100644 --- a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/switch-tna-sai.conf +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/switch-tna-sai.conf @@ -27,7 +27,7 @@ } ], "program-name": "switch", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "bfrt-config": "share/switch/bf-rt.json", "model_json_path" : "share/switch/aug_model.json", "switchapi_port_add": false, diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/switch-sai.conf b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/switch-sai.conf index c3abb3ebd8fc..0a807b1c9ea7 100644 --- a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/switch-sai.conf +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/switch-sai.conf @@ -25,7 +25,7 @@ "table-config": "share/tofinopd/switch/context.json", "tofino-bin": "share/tofinopd/switch/tofino.bin", "switchapi": "lib/libswitchapi.so", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "switchapi_port_add": false, "non_default_port_ppgs": 5 } diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/switch-tna-sai.conf b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/switch-tna-sai.conf index 403b08d6bb5e..ece3fcbe6a90 100644 --- a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/switch-tna-sai.conf +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/switch-tna-sai.conf @@ -27,7 +27,7 @@ } ], "program-name": "switch", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "bfrt-config": "share/switch/bf-rt.json", "model_json_path" : "share/switch/aug_model.json", "switchapi_port_add": false, diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/switch-tna-sai.conf b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/switch-tna-sai.conf index a1ee06da879c..cf6e445dba1a 100644 --- a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/switch-tna-sai.conf +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/switch-tna-sai.conf @@ -28,7 +28,7 @@ } ], "program-name": "switch", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "bfrt-config": "share/switch/bf-rt.json", "model_json_path" : "share/switch/aug_model.json", "switchapi_port_add": false, diff --git a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/montara/switch-sai.conf b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/montara/switch-sai.conf index 089153b6a5ce..fc224c9602e4 100644 --- a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/montara/switch-sai.conf +++ b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/montara/switch-sai.conf @@ -25,7 +25,7 @@ "table-config": "share/tofinopd/switch/context.json", "tofino-bin": "share/tofinopd/switch/tofino.bin", "switchapi": "lib/libswitchapi.so", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "agent0": "lib/platform/x86_64-accton_wedge100bf_32x-r0/libpltfm_mgr.so", "switchapi_port_add": false, "non_default_port_ppgs": 5 diff --git a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/montara/switch-tna-sai.conf b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/montara/switch-tna-sai.conf index a459e925531c..085a1b8dcdfc 100644 --- a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/montara/switch-tna-sai.conf +++ b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/montara/switch-tna-sai.conf @@ -28,7 +28,7 @@ } ], "program-name": "switch", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "bfrt-config": "share/switch/bf-rt.json", "model_json_path" : "share/switch/aug_model.json", "switchapi_port_add": false, diff --git a/device/barefoot/x86_64-accton_wedge100bf_65x-r0/mavericks/switch-sai.conf b/device/barefoot/x86_64-accton_wedge100bf_65x-r0/mavericks/switch-sai.conf index 1f0ff8b32bb1..81a7d7bc28c3 100644 --- a/device/barefoot/x86_64-accton_wedge100bf_65x-r0/mavericks/switch-sai.conf +++ b/device/barefoot/x86_64-accton_wedge100bf_65x-r0/mavericks/switch-sai.conf @@ -25,7 +25,7 @@ "table-config": "share/tofinopd/switch/context.json", "tofino-bin": "share/tofinopd/switch/tofino.bin", "switchapi": "lib/libswitchapi.so", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "agent0": "lib/platform/x86_64-accton_wedge100bf_65x-r0/libpltfm_mgr.so", "switchapi_port_add": false, "non_default_port_ppgs": 5 diff --git a/device/barefoot/x86_64-accton_wedge100bf_65x-r0/mavericks/switch-tna-sai.conf b/device/barefoot/x86_64-accton_wedge100bf_65x-r0/mavericks/switch-tna-sai.conf index 5497836266e1..ddcb9d4ba287 100644 --- a/device/barefoot/x86_64-accton_wedge100bf_65x-r0/mavericks/switch-tna-sai.conf +++ b/device/barefoot/x86_64-accton_wedge100bf_65x-r0/mavericks/switch-tna-sai.conf @@ -28,7 +28,7 @@ } ], "program-name": "switch", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "bfrt-config": "share/switch/bf-rt.json", "model_json_path" : "share/switch/aug_model.json", "switchapi_port_add": false, diff --git a/device/ingrasys/x86_64-ingrasys_s9180_32x-r0/INGRASYS-S9180-32X/switch-sai.conf b/device/ingrasys/x86_64-ingrasys_s9180_32x-r0/INGRASYS-S9180-32X/switch-sai.conf index 4f316bb9e5af..bf15b40d0c58 100644 --- a/device/ingrasys/x86_64-ingrasys_s9180_32x-r0/INGRASYS-S9180-32X/switch-sai.conf +++ b/device/ingrasys/x86_64-ingrasys_s9180_32x-r0/INGRASYS-S9180-32X/switch-sai.conf @@ -25,7 +25,7 @@ "table-config": "share/tofinopd/switch/context.json", "tofino-bin": "share/tofinopd/switch/tofino.bin", "switchapi": "lib/libswitchapi.so", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "agent0": "lib/platform/x86_64-ingrasys_s9180_32x-r0/libpltfm_mgr.so", "switchapi_port_add": false } diff --git a/device/ingrasys/x86_64-ingrasys_s9180_32x-r0/INGRASYS-S9180-32X/switch-tna-sai.conf b/device/ingrasys/x86_64-ingrasys_s9180_32x-r0/INGRASYS-S9180-32X/switch-tna-sai.conf index 43ed0e4af6ae..9fbf9d3cdb69 100644 --- a/device/ingrasys/x86_64-ingrasys_s9180_32x-r0/INGRASYS-S9180-32X/switch-tna-sai.conf +++ b/device/ingrasys/x86_64-ingrasys_s9180_32x-r0/INGRASYS-S9180-32X/switch-tna-sai.conf @@ -28,7 +28,7 @@ } ], "program-name": "switch", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "bfrt-config": "share/switch/bf-rt.json", "model_json_path" : "share/switch/aug_model.json", "switchapi_port_add": false, diff --git a/device/ingrasys/x86_64-ingrasys_s9280_64x-r0/INGRASYS-S9280-64X/switch-sai.conf b/device/ingrasys/x86_64-ingrasys_s9280_64x-r0/INGRASYS-S9280-64X/switch-sai.conf index 224d1fc58b18..f1e9c0bc10da 100644 --- a/device/ingrasys/x86_64-ingrasys_s9280_64x-r0/INGRASYS-S9280-64X/switch-sai.conf +++ b/device/ingrasys/x86_64-ingrasys_s9280_64x-r0/INGRASYS-S9280-64X/switch-sai.conf @@ -25,7 +25,7 @@ "table-config": "share/tofinopd/switch/context.json", "tofino-bin": "share/tofinopd/switch/tofino.bin", "switchapi": "lib/libswitchapi.so", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "agent0": "lib/platform/x86_64-ingrasys_s9280_64x-r0/libpltfm_mgr.so", "switchapi_port_add": false } diff --git a/device/ingrasys/x86_64-ingrasys_s9280_64x-r0/INGRASYS-S9280-64X/switch-tna-sai.conf b/device/ingrasys/x86_64-ingrasys_s9280_64x-r0/INGRASYS-S9280-64X/switch-tna-sai.conf index 29e8f4bae0b3..4895ac901ff6 100644 --- a/device/ingrasys/x86_64-ingrasys_s9280_64x-r0/INGRASYS-S9280-64X/switch-tna-sai.conf +++ b/device/ingrasys/x86_64-ingrasys_s9280_64x-r0/INGRASYS-S9280-64X/switch-tna-sai.conf @@ -28,7 +28,7 @@ } ], "program-name": "switch", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "bfrt-config": "share/switch/bf-rt.json", "model_json_path" : "share/switch/aug_model.json", "switchapi_port_add": false, diff --git a/device/wnc/x86_64-wnc_osw1800-r0/OSW1800-48x6q/switch-sai.conf b/device/wnc/x86_64-wnc_osw1800-r0/OSW1800-48x6q/switch-sai.conf index 65a02a621f03..ae01f3ebe96a 100644 --- a/device/wnc/x86_64-wnc_osw1800-r0/OSW1800-48x6q/switch-sai.conf +++ b/device/wnc/x86_64-wnc_osw1800-r0/OSW1800-48x6q/switch-sai.conf @@ -25,7 +25,7 @@ "table-config": "share/tofinopd/switch/context.json", "tofino-bin": "share/tofinopd/switch/tofino.bin", "switchapi": "lib/libswitchapi.so", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "agent0": "lib/platform/x86_64-wnc_osw1800-r0/libpltfm_mgr.so", "switchapi_port_add": false } diff --git a/device/wnc/x86_64-wnc_osw1800-r0/OSW1800-48x6q/switch-tna-sai.conf b/device/wnc/x86_64-wnc_osw1800-r0/OSW1800-48x6q/switch-tna-sai.conf index f156534f873d..7cb3ddc48fc9 100644 --- a/device/wnc/x86_64-wnc_osw1800-r0/OSW1800-48x6q/switch-tna-sai.conf +++ b/device/wnc/x86_64-wnc_osw1800-r0/OSW1800-48x6q/switch-tna-sai.conf @@ -28,7 +28,7 @@ } ], "program-name": "switch", - "switchsai": "lib/libswitchsai.so", + "sai": "lib/libsai.so", "bfrt-config": "share/switch/bf-rt.json", "model_json_path" : "share/switch/aug_model.json", "switchapi_port_add": false, diff --git a/platform/barefoot/bfn-platform.mk b/platform/barefoot/bfn-platform.mk index 32ba62e3feb2..854026b52949 100644 --- a/platform/barefoot/bfn-platform.mk +++ b/platform/barefoot/bfn-platform.mk @@ -1,5 +1,5 @@ -BFN_PLATFORM = bfnplatform_20191107_deb9.deb -$(BFN_PLATFORM)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/dev/bfnplatform_20191107_deb9.deb" +BFN_PLATFORM = bfnplatform_20191115_deb9.deb +$(BFN_PLATFORM)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/dev/bfnplatform_20191115_deb9.deb" SONIC_ONLINE_DEBS += $(BFN_PLATFORM) $(BFN_SAI_DEV)_DEPENDS += $(BFN_PLATFORM) diff --git a/platform/barefoot/bfn-sai.mk b/platform/barefoot/bfn-sai.mk index 366a7487deb8..6f413d50c11e 100644 --- a/platform/barefoot/bfn-sai.mk +++ b/platform/barefoot/bfn-sai.mk @@ -1,5 +1,5 @@ -BFN_SAI = bfnsdk_20191107_deb9.deb -$(BFN_SAI)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/dev/bfnsdk_20191107_deb9.deb" +BFN_SAI = bfnsdk_20191115_deb9.deb +$(BFN_SAI)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/dev/bfnsdk_20191115_deb9.deb" SONIC_ONLINE_DEBS += $(BFN_SAI) $(BFN_SAI_DEV)_DEPENDS += $(BFN_SAI) From 5466bb53264b22c0eeaee21d28801b0db646d3e1 Mon Sep 17 00:00:00 2001 From: lguohan Date: Tue, 19 Nov 2019 22:52:29 -0800 Subject: [PATCH 178/278] [sonic-mgmt]: install ansible 2.8.7 and pytest-ansible 2.2.2 (#3776) Signed-off-by: Guohan Lu --- dockers/docker-sonic-mgmt/Dockerfile.j2 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dockers/docker-sonic-mgmt/Dockerfile.j2 b/dockers/docker-sonic-mgmt/Dockerfile.j2 index d4ac92feec50..d24df1ca5d77 100644 --- a/dockers/docker-sonic-mgmt/Dockerfile.j2 +++ b/dockers/docker-sonic-mgmt/Dockerfile.j2 @@ -76,7 +76,7 @@ RUN pip install azure-kusto-data==0.0.13 \ azure-kusto-ingest==0.0.13 # Install pytest-ansible module -RUN pip install pytest-ansible==2.0.2 +RUN pip install pytest-ansible==2.2.2 ## Copy and install sonic-mgmt docker dependencies COPY \ @@ -90,8 +90,7 @@ RUN dpkg -i \ debs/{{ deb }}{{' '}} {%- endfor %} -RUN git clone https://github.com/ansible/ansible -RUN cd ansible && git checkout v2.0.0.2-1 -b v2.0.0.2-1 && git submodule update --init --recursive && make && make install +RUN pip install ansible==2.8.7 RUN mkdir /var/run/sshd EXPOSE 22 From 420278f286fcc5e4ccfa60766761b3430baa4380 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Wed, 20 Nov 2019 07:39:49 -0800 Subject: [PATCH 179/278] [docker-base/ptf]: Make a link to vim. Add tmux to docker-ptf (#3758) --- dockers/docker-base-stretch/Dockerfile.j2 | 2 ++ dockers/docker-ptf/Dockerfile.j2 | 1 + 2 files changed, 3 insertions(+) diff --git a/dockers/docker-base-stretch/Dockerfile.j2 b/dockers/docker-base-stretch/Dockerfile.j2 index ed59c3298715..95272e2322ce 100644 --- a/dockers/docker-base-stretch/Dockerfile.j2 +++ b/dockers/docker-base-stretch/Dockerfile.j2 @@ -83,4 +83,6 @@ COPY ["etc/rsyslog.conf", "/etc/rsyslog.conf"] COPY ["etc/rsyslog.d/*", "/etc/rsyslog.d/"] COPY ["root/.vimrc", "/root/.vimrc"] +RUN ln /usr/bin/vim.tiny /usr/bin/vim + COPY ["etc/supervisor/supervisord.conf", "/etc/supervisor/"] diff --git a/dockers/docker-ptf/Dockerfile.j2 b/dockers/docker-ptf/Dockerfile.j2 index dcf67aeff5f9..deb1892959e6 100644 --- a/dockers/docker-ptf/Dockerfile.j2 +++ b/dockers/docker-ptf/Dockerfile.j2 @@ -51,6 +51,7 @@ RUN sed --in-place 's/httpredir.debian.org/debian-archive.trafficmanager.net/' / hping3 \ curl \ tcpdump \ + tmux \ python \ python-dev \ python-libpcap \ From 82e309f6dea47058037941e1f0629dc7c45d5de1 Mon Sep 17 00:00:00 2001 From: ChiouRung Haung Date: Wed, 20 Nov 2019 23:41:04 +0800 Subject: [PATCH 180/278] [broadcom]: Add bcmcmd and bcmsh to docker-syncd-brcm-rpc (#3739) Signed-off-by: chiourung_huang --- platform/broadcom/docker-syncd-brcm-rpc.mk | 4 ++++ .../broadcom/docker-syncd-brcm-rpc/base_image_files/bcmcmd | 3 +++ .../broadcom/docker-syncd-brcm-rpc/base_image_files/bcmsh | 3 +++ 3 files changed, 10 insertions(+) create mode 100755 platform/broadcom/docker-syncd-brcm-rpc/base_image_files/bcmcmd create mode 100755 platform/broadcom/docker-syncd-brcm-rpc/base_image_files/bcmsh diff --git a/platform/broadcom/docker-syncd-brcm-rpc.mk b/platform/broadcom/docker-syncd-brcm-rpc.mk index 80d6ea2d8147..bd2ef01c5eed 100644 --- a/platform/broadcom/docker-syncd-brcm-rpc.mk +++ b/platform/broadcom/docker-syncd-brcm-rpc.mk @@ -23,3 +23,7 @@ $(DOCKER_SYNCD_BRCM_RPC)_RUN_OPT += -v /host/machine.conf:/etc/machine.conf $(DOCKER_SYNCD_BRCM_RPC)_RUN_OPT += -v /host/warmboot:/var/warmboot $(DOCKER_SYNCD_BRCM_RPC)_RUN_OPT += -v /var/run/docker-syncd:/var/run/sswsyncd $(DOCKER_SYNCD_BRCM_RPC)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro + +$(DOCKER_SYNCD_BRCM_RPC)_BASE_IMAGE_FILES += bcmcmd:/usr/bin/bcmcmd +$(DOCKER_SYNCD_BRCM_RPC)_BASE_IMAGE_FILES += bcmsh:/usr/bin/bcmsh + diff --git a/platform/broadcom/docker-syncd-brcm-rpc/base_image_files/bcmcmd b/platform/broadcom/docker-syncd-brcm-rpc/base_image_files/bcmcmd new file mode 100755 index 000000000000..7903db6ed6a3 --- /dev/null +++ b/platform/broadcom/docker-syncd-brcm-rpc/base_image_files/bcmcmd @@ -0,0 +1,3 @@ +#!/bin/bash + +docker exec -i syncd bcmcmd "$@" diff --git a/platform/broadcom/docker-syncd-brcm-rpc/base_image_files/bcmsh b/platform/broadcom/docker-syncd-brcm-rpc/base_image_files/bcmsh new file mode 100755 index 000000000000..3bb78b0da796 --- /dev/null +++ b/platform/broadcom/docker-syncd-brcm-rpc/base_image_files/bcmsh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker exec -it syncd bcmsh "$@" From 1d5005bc8cb624079fc07968e6db2b3fc08fbb07 Mon Sep 17 00:00:00 2001 From: Dong Zhang <41927498+dzhangalibaba@users.noreply.github.com> Date: Wed, 20 Nov 2019 10:40:19 -0800 Subject: [PATCH 181/278] [multiDB] add database_config.json into vs images (#3757) --- platform/vs/docker-sonic-vs/Dockerfile.j2 | 1 + .../vs/docker-sonic-vs/database_config.json | 57 +++++++++++++++++++ platform/vs/docker-sonic-vs/start.sh | 3 +- 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 platform/vs/docker-sonic-vs/database_config.json diff --git a/platform/vs/docker-sonic-vs/Dockerfile.j2 b/platform/vs/docker-sonic-vs/Dockerfile.j2 index 85db514d77bb..7cc6f98921ff 100644 --- a/platform/vs/docker-sonic-vs/Dockerfile.j2 +++ b/platform/vs/docker-sonic-vs/Dockerfile.j2 @@ -106,6 +106,7 @@ COPY ["files/configdb-load.sh", "/usr/bin/"] COPY ["files/arp_update", "/usr/bin/"] COPY ["files/buffers_config.j2", "files/qos_config.j2", "/usr/share/sonic/templates/"] COPY ["files/sonic_version.yml", "/etc/sonic/"] +COPY ["database_config.json", "/etc/default/sonic-db/"] # Workaround the tcpdump issue RUN mv /usr/sbin/tcpdump /usr/bin/tcpdump diff --git a/platform/vs/docker-sonic-vs/database_config.json b/platform/vs/docker-sonic-vs/database_config.json new file mode 100644 index 000000000000..b86ae11bba98 --- /dev/null +++ b/platform/vs/docker-sonic-vs/database_config.json @@ -0,0 +1,57 @@ +{ + "INSTANCES": { + "redis":{ + "hostname" : "127.0.0.1", + "port" : 6379, + "unix_socket_path" : "/var/run/redis/redis.sock" + } + }, + "DATABASES" : { + "APPL_DB" : { + "id" : 0, + "separator": ":", + "instance" : "redis" + }, + "ASIC_DB" : { + "id" : 1, + "separator": ":", + "instance" : "redis" + }, + "COUNTERS_DB" : { + "id" : 2, + "separator": ":", + "instance" : "redis" + }, + "LOGLEVEL_DB" : { + "id" : 3, + "separator": ":", + "instance" : "redis" + }, + "CONFIG_DB" : { + "id" : 4, + "separator": "|", + "instance" : "redis" + }, + "PFC_WD_DB" : { + "id" : 5, + "separator": ":", + "instance" : "redis" + }, + "FLEX_COUNTER_DB" : { + "id" : 5, + "separator": ":", + "instance" : "redis" + }, + "STATE_DB" : { + "id" : 6, + "separator": "|", + "instance" : "redis" + }, + "SNMP_OVERLAY_DB" : { + "id" : 7, + "separator": "|", + "instance" : "redis" + } + }, + "VERSION" : "1.0" +} diff --git a/platform/vs/docker-sonic-vs/start.sh b/platform/vs/docker-sonic-vs/start.sh index 8770d304fcd8..614541961c87 100755 --- a/platform/vs/docker-sonic-vs/start.sh +++ b/platform/vs/docker-sonic-vs/start.sh @@ -29,7 +29,8 @@ rm -f /var/run/rsyslogd.pid supervisorctl start rsyslogd -mkdir -p /var/run/redis +mkdir -p /var/run/redis/sonic-db +cp /etc/default/sonic-db/database_config.json /var/run/redis/sonic-db/ supervisorctl start redis-server From 29a74516c5fe56f76dd3a6eb70d1daa3abc174aa Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Thu, 21 Nov 2019 08:27:55 +0800 Subject: [PATCH 182/278] [submodule] advance submodule head for sonic-platform-common (#3787) --- src/sonic-platform-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-platform-common b/src/sonic-platform-common index cc2dac5963a1..d22f0a0e64f3 160000 --- a/src/sonic-platform-common +++ b/src/sonic-platform-common @@ -1 +1 @@ -Subproject commit cc2dac5963a14d04dd15735de35df9b30cff1e41 +Subproject commit d22f0a0e64f30e9e26064824fb11f27b2d636850 From 0c9040dec9642688fdb944f2f2da161acbfe07a2 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Thu, 21 Nov 2019 08:30:05 +0800 Subject: [PATCH 183/278] [Mellanox] support get_transceiver_threshold_info (#3777) * [sonic_platform.sfp] support get_transceiver_dom_threshold_info_dict * [platform/sfp]qsfp threshold and beautify code 1. qsfp threshold: tx power 2. beautify code, removing some magic numbers 3. optimize get_present by only reading one byte. --- .../mlnx-platform-api/sonic_platform/sfp.py | 218 ++++++++++++++++-- 1 file changed, 200 insertions(+), 18 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py index dac6a8e4d4d6..845f355e28f1 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py @@ -76,6 +76,9 @@ # 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 @@ -97,7 +100,7 @@ QSFP_VOLT_OFFSET = 26 QSFP_VOLT_WIDTH = 2 QSFP_VERSION_COMPLIANCE_OFFSET = 1 -QSFP_VERSION_COMPLIANCE_WIDTH = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 2 QSFP_CHANNL_MON_OFFSET = 34 QSFP_CHANNL_MON_WIDTH = 16 QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 @@ -118,6 +121,12 @@ QSFP_OPTION_VALUE_OFFSET = 192 QSFP_OPTION_VALUE_WIDTH = 4 +QSFP_MODULE_UPPER_PAGE3_START = 384 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNL_THRESHOLD_OFFSET = 176 +QSFP_CHANNL_THRESHOLD_WIDTH = 24 + SFP_TEMPE_OFFSET = 96 SFP_TEMPE_WIDTH = 2 SFP_VOLT_OFFSET = 98 @@ -203,6 +212,7 @@ def __init__(self, sfp_index, sfp_type): self.sdk_handle = None self.sdk_index = sfp_index + #SDK initializing stuff def _initialize_sdk_handle(self): """ @@ -215,6 +225,7 @@ def _initialize_sdk_handle(self): self.mypid = os.getpid() + def _open_sdk(self): if self.sdk_handle is None: self._initialize_sdk_handle() @@ -226,18 +237,21 @@ def _open_sdk(self): return True + def _close_sdk(self): rc = sxd_access_reg_deinit() if rc != 0: logger.log_warning("Failed to deinitializing register access.") #no further actions here + def _init_sx_meta_data(self): meta = sxd_reg_meta_t() meta.dev_id = DEVICE_ID meta.swid = SWITCH_ID return meta + def get_presence(self): """ Retrieves the presence of the device @@ -246,7 +260,7 @@ def get_presence(self): bool: True if device is present, False if not """ presence = False - ethtool_cmd = "ethtool -m sfp{} hex on offset 0 length 4 2>/dev/null".format(self.index) + ethtool_cmd = "ethtool -m sfp{} hex on offset 0 length 1 2>/dev/null".format(self.index) try: proc = subprocess.Popen(ethtool_cmd, stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT) stdout = proc.communicate()[0] @@ -260,6 +274,7 @@ def get_presence(self): return presence + # Read out any bytes from any offset def _read_eeprom_specific_bytes(self, offset, num_bytes): eeprom_raw = [] @@ -277,6 +292,7 @@ def _read_eeprom_specific_bytes(self, offset, num_bytes): return eeprom_raw + def _dom_capability_detect(self): if not self.get_presence(): self.dom_supported = False @@ -300,28 +316,30 @@ def _dom_capability_detect(self): # in SFF-8636 dom capability definitions evolving with the versions. qsfp_dom_capability_raw = self._read_eeprom_specific_bytes((offset + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) if qsfp_dom_capability_raw is not None: - qsfp_version_compliance_raw = self._read_eeprom_specific_bytes(QSFP_VERSION_COMPLIANCE_OFFSET, QSFP_VERSION_COMPLIANCE_OFFSET) + qsfp_version_compliance_raw = self._read_eeprom_specific_bytes(QSFP_VERSION_COMPLIANCE_OFFSET, QSFP_VERSION_COMPLIANCE_WIDTH) qsfp_version_compliance = int(qsfp_version_compliance_raw[0], 16) - qspf_dom_capability = int(qsfp_dom_capability_raw[0], 16) + dom_capability = sfpi_obj.parse_qsfp_dom_capability(qsfp_dom_capability_raw, 0) if qsfp_version_compliance >= 0x08: - self.dom_temp_supported = (qspf_dom_capability & 0x20 != 0) - self.dom_volt_supported = (qspf_dom_capability & 0x10 != 0) - self.dom_rx_power_supported = (qspf_dom_capability & 0x08 != 0) - self.dom_tx_power_supported = (qspf_dom_capability & 0x04 != 0) + self.dom_temp_supported = dom_capability['data']['Temp_support']['value'] == 'On' + self.dom_volt_supported = dom_capability['data']['Voltage_support']['value'] == 'On' + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = dom_capability['data']['Tx_power_support']['value'] == 'On' else: self.dom_temp_supported = True self.dom_volt_supported = True - self.dom_rx_power_supported = (qspf_dom_capability & 0x08 != 0) + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' self.dom_tx_power_supported = True self.dom_supported = True self.calibration = 1 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None qsfp_option_value_raw = self._read_eeprom_specific_bytes(QSFP_OPTION_VALUE_OFFSET, QSFP_OPTION_VALUE_WIDTH) if qsfp_option_value_raw is not None: - sfpd_obj = sff8436Dom() - if sfpd_obj is None: - return None - self.optional_capability = sfpd_obj.parse_option_params(qsfp_option_value_raw, 0) - self.dom_tx_disable_supported = self.optional_capability['data']['TxDisable']['value'] == 'On' + optional_capability = sfpd_obj.parse_option_params(qsfp_option_value_raw, 0) + self.dom_tx_disable_supported = optional_capability['data']['TxDisable']['value'] == 'On' + dom_status_indicator = sfpd_obj.parse_dom_status_indicator(qsfp_version_compliance_raw, 1) + self.qsfp_page3_available = dom_status_indicator['data']['FlatMem']['value'] == 'Off' else: self.dom_supported = False self.dom_temp_supported = False @@ -329,6 +347,7 @@ def _dom_capability_detect(self): self.dom_rx_power_supported = False self.dom_tx_power_supported = False self.calibration = 0 + self.qsfp_page3_available = False elif self.sfp_type == "SFP": sfpi_obj = sff8472InterfaceId() if sfpi_obj is None: @@ -362,6 +381,7 @@ def _dom_capability_detect(self): self.dom_rx_power_supported = False self.dom_tx_power_supported = False + def _convert_string_to_num(self, value_str): if "-inf" in value_str: return 'N/A' @@ -382,6 +402,7 @@ def _convert_string_to_num(self, value_str): else: return 'N/A' + def get_transceiver_info(self): """ Retrieves transceiver info of this SFP @@ -563,6 +584,7 @@ def get_transceiver_info(self): return transceiver_info_dict + def get_transceiver_bulk_status(self): """ Retrieves transceiver bulk status of this SFP @@ -689,6 +711,143 @@ def get_transceiver_bulk_status(self): return transceiver_dom_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + transceiver_dom_threshold_info_dict = {} + + dom_info_dict_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning' + ] + transceiver_dom_threshold_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported or not self.qsfp_page3_available: + return transceiver_dom_threshold_info_dict + + # Dom Threshold data starts from offset 384 + # Revert offset back to 0 once data is retrieved + offset = QSFP_MODULE_UPPER_PAGE3_START + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_raw = self._read_eeprom_specific_bytes((offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + + dom_channel_threshold_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_THRESHOLD_OFFSET), + QSFP_CHANNL_THRESHOLD_WIDTH) + if dom_channel_threshold_raw is None: + return transceiver_dom_threshold_info_dict + dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values(dom_channel_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_channel_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_channel_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_channel_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_channel_threshold_data['data']['TxPowerLowWarning']['value'] + + else: + offset = SFP_MODULE_ADDRA2_OFFSET + + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = sff8472Dom(None, self.calibration) + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_raw = self._read_eeprom_specific_bytes((offset + SFP_MODULE_THRESHOLD_OFFSET), + SFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(dom_module_threshold_raw, 0) + else: + return transceiver_dom_threshold_info_dict + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + return transceiver_dom_threshold_info_dict + + def get_reset_status(self): """ Retrieves the reset status of SFP @@ -731,6 +890,7 @@ def get_reset_status(self): else: return False + def get_rx_los(self): """ Retrieves the RX LOS (lost-of-signal) status of SFP @@ -764,6 +924,7 @@ def get_rx_los(self): return None return rx_los_list + def get_tx_fault(self): """ Retrieves the TX fault status of SFP @@ -797,6 +958,7 @@ def get_tx_fault(self): return None return tx_fault_list + def get_tx_disable(self): """ Retrieves the tx_disable status of this SFP @@ -833,6 +995,7 @@ def get_tx_disable(self): return None return tx_disable_list + def get_tx_disable_channel(self): """ Retrieves the TX disabled channels in this SFP @@ -852,6 +1015,7 @@ def get_tx_disable_channel(self): tx_disabled |= 1 << i return tx_disabled + def get_lpmode(self): """ Retrieves the lpmode (low power mode) status of this SFP @@ -882,6 +1046,7 @@ def get_lpmode(self): else: return NotImplementedError + def get_power_override(self): """ Retrieves the power-override status of this SFP @@ -902,6 +1067,7 @@ def get_power_override(self): else: return NotImplementedError + def get_temperature(self): """ Retrieves the temperature of this SFP @@ -944,6 +1110,7 @@ def get_temperature(self): else: return None + def get_voltage(self): """ Retrieves the supply voltage of this SFP @@ -986,7 +1153,8 @@ def get_voltage(self): return voltage else: return None - + + def get_tx_bias(self): """ Retrieves the TX bias current of this SFP @@ -1031,7 +1199,8 @@ def get_tx_bias(self): return None return tx_bias_list - + + def get_rx_power(self): """ Retrieves the received optical power for this SFP @@ -1085,7 +1254,8 @@ def get_rx_power(self): else: return None return rx_power_list - + + def get_tx_power(self): """ Retrieves the TX power of this SFP @@ -1138,7 +1308,8 @@ def get_tx_power(self): else: return None return tx_power_list - + + def reset(self): """ Reset SFP and return all user module settings to their default state. @@ -1174,6 +1345,7 @@ def reset(self): self._close_sdk() return rc == SXD_STATUS_SUCCESS + def _write_i2c_via_mcia(self, page, i2caddr, address, data, mask): handle = self._open_sdk() if handle is None: @@ -1208,6 +1380,7 @@ def _write_i2c_via_mcia(self, page, i2caddr, address, data, mask): self._close_sdk() return rc == SXD_STATUS_SUCCESS + def tx_disable(self, tx_disable): """ Disable SFP TX for all channels @@ -1251,6 +1424,7 @@ def tx_disable(self, tx_disable): else: return NotImplementedError + def tx_disable_channel(self, channel, disable): """ Sets the tx_disable for specified SFP channels @@ -1280,9 +1454,11 @@ def tx_disable_channel(self, channel, disable): else: return NotImplementedError + def is_nve(self, port): return (port & NVE_MASK) != 0 + def is_port_admin_status_up(self, log_port): oper_state_p = new_sx_port_oper_state_t_p() admin_state_p = new_sx_port_admin_state_t_p() @@ -1296,10 +1472,12 @@ def is_port_admin_status_up(self, log_port): else: return False + def set_port_admin_status_by_log_port(self, log_port, admin_status): rc = sx_api_port_state_set(self.sdk_handle, log_port, admin_status) assert rc == SX_STATUS_SUCCESS, "sx_api_port_state_set failed, rc = %d" % rc + # Get all the ports related to the sfp, if port admin status is up, put it to list def get_log_ports(self): port_attributes_list = new_sx_port_attributes_t_arr(SX_PORT_ATTR_ARR_SIZE) @@ -1320,6 +1498,7 @@ def get_log_ports(self): return log_port_list + def _set_sfp_admin_status_raw(self, admin_status): # Get PMAOS pmaos = ku_pmaos_reg() @@ -1343,6 +1522,7 @@ def _set_sfp_admin_status_raw(self, admin_status): rc = sxd_access_reg_pmaos(pmaos, meta, REGISTER_NUM, None, None) assert rc == SXD_STATUS_SUCCESS, "sxd_access_reg_pmaos failed, rc = %d" % rc + def _set_lpmode_raw(self, lpmode): # Get PMMP pmmp = ku_pmmp_reg() @@ -1364,6 +1544,7 @@ def _set_lpmode_raw(self, lpmode): return rc + def set_lpmode(self, lpmode): """ Sets the lpmode (low power mode) of SFP @@ -1396,6 +1577,7 @@ def set_lpmode(self, lpmode): self._close_sdk() return False + def set_power_override(self, power_override, power_set): """ Sets SFP power level using power_override and power_set From cb2e01d503aefbcf89e3c1d0d623d3842d575cc8 Mon Sep 17 00:00:00 2001 From: Danny Allen Date: Thu, 21 Nov 2019 10:58:21 -0800 Subject: [PATCH 184/278] [submodule]: Update sairedis/swss/utilities (#3786) sairedis: * [SAI] Update SAI submodule to v1.5.1 (#532) * Cleanup Makefile.am from BFN specific code (#530) * [vs] Implement indices for debug counters in VS (#531) * Enable FastReboot if we have key "FAST_REBOOT|system" in State db (#529) * [flex_counter] Add sairedis support for drop counters (#520) swss: * [orchagent] Add swss support for drop counters (#1075) * [orchagent] warning fixes for 32bit arch compilation (#1129) * [utilities] Create utility classes for interacting with flex counters (#1093) * [portsorch] add support to set mac-address learning attribute on bridge-port (#809) * Fix traceroute issue (#1113) utilities: * Add CLI support for configurable drop counters (#688) * Revert "SONiC Management Framework Release 1.0 (#659)" (#741) * SONiC Management Framework Release 1.0 (#659) Signed-off-by: Danny Allen --- src/sonic-sairedis | 2 +- src/sonic-swss | 2 +- src/sonic-utilities | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sonic-sairedis b/src/sonic-sairedis index afe2a0d29299..667f74427497 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit afe2a0d29299128d314b93c9e4726e62d3116948 +Subproject commit 667f74427497b9b188b949269a29791642f81d17 diff --git a/src/sonic-swss b/src/sonic-swss index f3547983a1e2..c3b8fe10b156 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit f3547983a1e2c67bdacb4e87593e65f20b483d8e +Subproject commit c3b8fe10b1568022fa025ef4be9cb063bfe49df4 diff --git a/src/sonic-utilities b/src/sonic-utilities index be337d4f09c9..587e630ace4f 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit be337d4f09c9fc901c85d2d615a3cdebbc039a33 +Subproject commit 587e630ace4f5e6d2df1d0fbfa112aef19283d3a From bad57cc51afa8881373a8fe6d4c1e02b2376f8ca Mon Sep 17 00:00:00 2001 From: pra-moh <49077256+pra-moh@users.noreply.github.com> Date: Thu, 21 Nov 2019 12:54:28 -0800 Subject: [PATCH 185/278] [minigraph.py] Generate items needed by streaming telemetry service (#3759) --- src/sonic-config-engine/minigraph.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 7799f3367d95..a82cd4c48582 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -627,7 +627,13 @@ def parse_xml(filename, platform=None, port_config_file=None): 'hostname': hostname, 'hwsku': hwsku, 'type': current_device['type'] - }} + }, + 'x509': { + 'server_crt': '/etc/sonic/telemetry/streamingtelemetryserver.cer', + 'server_key': '/etc/sonic/telemetry/streamingtelemetryclient.key', + 'ca_crt': '/etc/sonic/telemetry/dsmsroot.cer' + } + } results['BGP_NEIGHBOR'] = bgp_sessions results['BGP_MONITORS'] = bgp_monitors results['BGP_PEER_RANGE'] = bgp_peers_with_range @@ -806,6 +812,13 @@ def parse_xml(filename, platform=None, port_config_file=None): 'status': 'enabled' } } + results['TELEMETRY'] = { + 'gnmi': { + 'client_auth': 'true', + 'port': '50051', + 'log_level': '2' + } + } # Do not configure the minigraph's mirror session, which is currently unused # mirror_sessions = {} From 3470000e3a12d265f04ad7affe7a93cc0a6680a1 Mon Sep 17 00:00:00 2001 From: Qi Luo Date: Thu, 21 Nov 2019 16:14:32 -0800 Subject: [PATCH 186/278] [sonic-slave]: Remove `base` from image name, rename folder to prevent user confliction (jessie) (#3790) --- Makefile.work | 4 ++-- {sonic-slave => sonic-slave-jessie}/Dockerfile.j2 | 0 {sonic-slave => sonic-slave-jessie}/Dockerfile.user | 2 +- {sonic-slave => sonic-slave-jessie}/sonic-jenkins-id_rsa.pub | 0 sonic-slave-stretch/Dockerfile.user | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename {sonic-slave => sonic-slave-jessie}/Dockerfile.j2 (100%) rename {sonic-slave => sonic-slave-jessie}/Dockerfile.user (93%) rename {sonic-slave => sonic-slave-jessie}/sonic-jenkins-id_rsa.pub (100%) diff --git a/Makefile.work b/Makefile.work index 37ee2e11529d..b81ac591246f 100644 --- a/Makefile.work +++ b/Makefile.work @@ -74,11 +74,11 @@ endif ifeq ($(BLDENV), stretch) SLAVE_DIR = sonic-slave-stretch else -SLAVE_DIR = sonic-slave +SLAVE_DIR = sonic-slave-jessie endif SLAVE_BASE_TAG = $(shell CONFIGURED_ARCH=$(CONFIGURED_ARCH) j2 $(SLAVE_DIR)/Dockerfile.j2 > $(SLAVE_DIR)/Dockerfile && sha1sum $(SLAVE_DIR)/Dockerfile | awk '{print substr($$1,0,11);}') SLAVE_TAG = $(shell cat $(SLAVE_DIR)/Dockerfile.user $(SLAVE_DIR)/Dockerfile | sha1sum | awk '{print substr($$1,0,11);}') -SLAVE_BASE_IMAGE = $(SLAVE_DIR)-base +SLAVE_BASE_IMAGE = $(SLAVE_DIR) SLAVE_IMAGE = $(SLAVE_BASE_IMAGE)-$(USER) OVERLAY_MODULE_CHECK := \ diff --git a/sonic-slave/Dockerfile.j2 b/sonic-slave-jessie/Dockerfile.j2 similarity index 100% rename from sonic-slave/Dockerfile.j2 rename to sonic-slave-jessie/Dockerfile.j2 diff --git a/sonic-slave/Dockerfile.user b/sonic-slave-jessie/Dockerfile.user similarity index 93% rename from sonic-slave/Dockerfile.user rename to sonic-slave-jessie/Dockerfile.user index 253475b21878..37dd7256c4e5 100644 --- a/sonic-slave/Dockerfile.user +++ b/sonic-slave-jessie/Dockerfile.user @@ -1,5 +1,5 @@ ARG slave_base_tag_ref=latest -FROM sonic-slave-base:${slave_base_tag_ref} +FROM sonic-slave-jessie:${slave_base_tag_ref} # Add user ARG user diff --git a/sonic-slave/sonic-jenkins-id_rsa.pub b/sonic-slave-jessie/sonic-jenkins-id_rsa.pub similarity index 100% rename from sonic-slave/sonic-jenkins-id_rsa.pub rename to sonic-slave-jessie/sonic-jenkins-id_rsa.pub diff --git a/sonic-slave-stretch/Dockerfile.user b/sonic-slave-stretch/Dockerfile.user index 1e5b91414393..87e4d9568bb1 100644 --- a/sonic-slave-stretch/Dockerfile.user +++ b/sonic-slave-stretch/Dockerfile.user @@ -1,5 +1,5 @@ ARG slave_base_tag_ref=latest -FROM sonic-slave-stretch-base:${slave_base_tag_ref} +FROM sonic-slave-stretch:${slave_base_tag_ref} # Add user ARG user From 8a7c1300c24aa6446dc062918a00ce6f9a04bbe8 Mon Sep 17 00:00:00 2001 From: byu343 Date: Thu, 21 Nov 2019 16:21:08 -0800 Subject: [PATCH 187/278] [devices]: Fix the clock setting on arista 7280 (#3788) * Fix serdes setting for B0/B1 revision chip on 7280 --- .../jr2-a7280cr3-32p4-28x100G-8x10G.config.bcm | 14 +++++++++----- .../jr2-a7280cr3-32p4-40x100G.config.bcm | 14 +++++++++----- src/sonic-device-data/tests/config_checker | 2 +- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/jr2-a7280cr3-32p4-28x100G-8x10G.config.bcm b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/jr2-a7280cr3-32p4-28x100G-8x10G.config.bcm index 3c0a0ee443a4..3d89e2b41b4a 100644 --- a/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/jr2-a7280cr3-32p4-28x100G-8x10G.config.bcm +++ b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C28S8/jr2-a7280cr3-32p4-28x100G-8x10G.config.bcm @@ -277,11 +277,15 @@ bcm_stat_interval.BCM8869X=1000 mem_cache_enable_ecc.BCM8869X=1 mem_cache_enable_parity.BCM8869X=1 -serdes_nif_clk_freq_in.BCM8869X=2 -serdes_nif_clk_freq_out.BCM8869X=1 - -serdes_fabric_clk_freq_in.BCM8869X=2 -serdes_fabric_clk_freq_out.BCM8869X=1 +serdes_nif_clk_freq_in.BCM8869X_A0=2 +serdes_nif_clk_freq_out.BCM8869X_A0=1 +serdes_fabric_clk_freq_in.BCM8869X_A0=2 +serdes_fabric_clk_freq_out.BCM8869X_A0=1 + +serdes_nif_clk_freq_in.BCM8869X=1 +serdes_nif_clk_freq_out.BCM8869X=bypass +serdes_fabric_clk_freq_in.BCM8869X=1 +serdes_fabric_clk_freq_out.BCM8869X=bypass dram_phy_tune_mode_on_init.BCM8869X=RUN_TUNE diff --git a/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/jr2-a7280cr3-32p4-40x100G.config.bcm b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/jr2-a7280cr3-32p4-40x100G.config.bcm index 4787dc7db709..654a4d8f158f 100644 --- a/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/jr2-a7280cr3-32p4-40x100G.config.bcm +++ b/device/arista/x86_64-arista_7280cr3_32p4/Arista-7280CR3-C40/jr2-a7280cr3-32p4-40x100G.config.bcm @@ -281,11 +281,15 @@ bcm_stat_interval.BCM8869X=1000 mem_cache_enable_ecc.BCM8869X=1 mem_cache_enable_parity.BCM8869X=1 -serdes_nif_clk_freq_in.BCM8869X=2 -serdes_nif_clk_freq_out.BCM8869X=1 - -serdes_fabric_clk_freq_in.BCM8869X=2 -serdes_fabric_clk_freq_out.BCM8869X=1 +serdes_nif_clk_freq_in.BCM8869X_A0=2 +serdes_nif_clk_freq_out.BCM8869X_A0=1 +serdes_fabric_clk_freq_in.BCM8869X_A0=2 +serdes_fabric_clk_freq_out.BCM8869X_A0=1 + +serdes_nif_clk_freq_in.BCM8869X=1 +serdes_nif_clk_freq_out.BCM8869X=bypass +serdes_fabric_clk_freq_in.BCM8869X=1 +serdes_fabric_clk_freq_out.BCM8869X=bypass dram_phy_tune_mode_on_init.BCM8869X=RUN_TUNE diff --git a/src/sonic-device-data/tests/config_checker b/src/sonic-device-data/tests/config_checker index 6d95c13efc7c..6cb4d029be58 100755 --- a/src/sonic-device-data/tests/config_checker +++ b/src/sonic-device-data/tests/config_checker @@ -31,7 +31,7 @@ def check_file(file_name): p = line.split("=", 1)[0] # Remove trailing chip name "bcm8869x" - p = re.sub(r"\.bcm8869x(_adapter)?$", "", p) + p = re.sub(r"\.bcm8869x(_adapter|_[a-z]\d)?$", "", p) # Remove trailing unit ".$" p = re.sub(r"\.[0-9]+$", '', p) # Remove trailing port name From 643ef82a2ff88302b0217811052ffd33f0a6a645 Mon Sep 17 00:00:00 2001 From: Tyler Li Date: Fri, 22 Nov 2019 09:49:31 +0800 Subject: [PATCH 188/278] [config] supplement loopback interface in mimigraph (#3792) --- src/sonic-config-engine/minigraph.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index a82cd4c48582..443d96c31161 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -573,7 +573,7 @@ def parse_xml(filename, platform=None, port_config_file=None): vlan_members = None pcs = None mgmt_intf = None - lo_intf = None + lo_intfs = None neighbors = None devices = None hostname = None @@ -656,7 +656,10 @@ def parse_xml(filename, platform=None, port_config_file=None): if alias in port_speeds_default: results['MGMT_PORT'][name]['speed'] = port_speeds_default[alias] results['MGMT_INTERFACE'][(name, key[1])] = mgmt_intf[key] - results['LOOPBACK_INTERFACE'] = lo_intfs + results['LOOPBACK_INTERFACE'] = {} + for lo_intf in lo_intfs: + results['LOOPBACK_INTERFACE'][lo_intf] = lo_intfs[lo_intf] + results['LOOPBACK_INTERFACE'][lo_intf[0]] = {} results['MGMT_VRF_CONFIG'] = mvrf phyport_intfs = {} From 6864ed58866dc1cd6b6bd95c3de58404edb5f220 Mon Sep 17 00:00:00 2001 From: Danny Allen Date: Fri, 22 Nov 2019 00:34:17 -0800 Subject: [PATCH 189/278] [sairedis] Submodule update for sairedis (#3801) - [syncd] Fix off-by-one error for attribute enum values query (#536) - Add support for remove hostif when using tap device (#533) Signed-off-by: Danny Allen --- src/sonic-sairedis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 667f74427497..54d2864a2261 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 667f74427497b9b188b949269a29791642f81d17 +Subproject commit 54d2864a2261e518f969cb0bf7e2569fe4825ea7 From a5423357d55ea9d81f04b144b64ea38ee4d84486 Mon Sep 17 00:00:00 2001 From: lguohan Date: Fri, 22 Nov 2019 10:04:56 -0800 Subject: [PATCH 190/278] [submodule]: update sonic-sairedis (#3804) * 5337490 2019-11-22 | Send port status notification when creating hostif interface (#535) [Kamil Cudnik] Signed-off-by: Guohan Lu --- src/sonic-sairedis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 54d2864a2261..533749062f63 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 54d2864a2261e518f969cb0bf7e2569fe4825ea7 +Subproject commit 533749062f638f74ebc09c4bd0a5162b2c575564 From a73eb66546900aeea9dc451b6f5a509cfdd8d654 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Fri, 22 Nov 2019 11:07:36 -0800 Subject: [PATCH 191/278] [docker-fpm-frr]: Refactor bgpcfgd (#3789) --- dockers/docker-fpm-frr/bgpcfgd | 383 +++++++++++++++++++++++---------- 1 file changed, 266 insertions(+), 117 deletions(-) diff --git a/dockers/docker-fpm-frr/bgpcfgd b/dockers/docker-fpm-frr/bgpcfgd index b98a3f7ad45a..120e07fcdbe2 100755 --- a/dockers/docker-fpm-frr/bgpcfgd +++ b/dockers/docker-fpm-frr/bgpcfgd @@ -8,11 +8,11 @@ import syslog import signal import traceback import os -import shutil import tempfile import json from collections import defaultdict from pprint import pprint +from pprint import pformat import jinja2 import netaddr @@ -34,6 +34,7 @@ def run_command(command, shell=False): return p.returncode, stdout, stderr + class TemplateFabric(object): def __init__(self): j2_template_paths = ['/usr/share/sonic/templates'] @@ -76,130 +77,18 @@ class TemplateFabric(object): return addr.version == 6 -class BGPConfigManager(object): - def __init__(self, daemon): - self.bgp_asn = None - self.meta = None - self.neig_meta = {} - self.bgp_messages = [] - self.peers = self.load_peers() # we can have bgp monitors peers here. it could be fixed by adding support for it here - fabric = TemplateFabric() - self.bgp_peer_add_template = fabric.from_file('bgpd.peer.conf.j2') - self.bgp_peer_del_template = fabric.from_string('no neighbor {{ neighbor_addr }}') - self.bgp_peer_shutdown = fabric.from_string('neighbor {{ neighbor_addr }} shutdown') - self.bgp_peer_no_shutdown = fabric.from_string('no neighbor {{ neighbor_addr }} shutdown') - daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, self.__metadata_handler) - daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_NEIGHBOR_METADATA_TABLE_NAME, self.__neighbor_metadata_handler) - daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_BGP_NEIGHBOR_TABLE_NAME, self.__bgp_handler) - - def load_peers(self): - peers = set() - command = ["vtysh", "-c", "show bgp neighbors json"] - rc, out, err = run_command(command) - if rc == 0: - js_bgp = json.loads(out) - peers = set(js_bgp.keys()) - return peers - - def __metadata_handler(self, key, op, data): - if key != "localhost" \ - or "bgp_asn" not in data \ - or self.bgp_asn == data["bgp_asn"]: - return - - # TODO add ASN update commands - - self.meta = { 'localhost': data } - self.bgp_asn = data["bgp_asn"] - self.__update_bgp() - - def __neighbor_metadata_handler(self, key, op, data): - if op == swsscommon.SET_COMMAND: - self.neig_meta[key] = data - elif op == swsscommon.DEL_COMMAND: - if key in self.neig_meta: - del self.neig_meta[key] - else: - syslog.syslog(syslog.LOG_ERR,"Can't remove key '%s' from neighbor metadata handler. The key doesn't exist" % key) - else: - syslog.syslog(syslog.LOG_ERR,"Wrong operation '%s' for neighbor metadata handler" % op) - self.__update_bgp() - - def __update_bgp(self): - cmds = [] - new_bgp_messages = [] - for key, op, data in self.bgp_messages: - if op == swsscommon.SET_COMMAND: - if key not in self.peers: - if 'name' in data and data['name'] not in self.neig_meta: - # DEVICE_NEIGHBOR_METADATA should be populated before the rendering - new_bgp_messages.append((key, op, data)) - continue - try: - txt = self.bgp_peer_add_template.render(DEVICE_METADATA=self.meta, DEVICE_NEIGHBOR_METADATA=self.neig_meta, neighbor_addr=key, bgp_session=data) - cmds.append(txt) - except: - syslog.syslog(syslog.LOG_ERR, 'Peer {}. Error in rendering the template for "SET" command {}'.format(key, data)) - else: - syslog.syslog(syslog.LOG_INFO, 'Peer {} added with attributes {}'.format(key, data)) - self.peers.add(key) - else: - # when the peer is already configured we support "shutdown/no shutdown" - # commands for the peers only - if "admin_status" in data: - if data['admin_status'] == 'up': - cmds.append(self.bgp_peer_no_shutdown.render(neighbor_addr=key)) - syslog.syslog(syslog.LOG_INFO, 'Peer {} admin state is set to "up"'.format(key)) - elif data['admin_status'] == 'down': - cmds.append(self.bgp_peer_shutdown.render(neighbor_addr=key)) - syslog.syslog(syslog.LOG_INFO, 'Peer {} admin state is set to "down"'.format(key)) - else: - syslog.syslog(syslog.LOG_ERR, "Peer {}: Can't update the peer. has wrong attribute value attr['admin_status'] = '{}'".format(key, data['admin_status'])) - else: - syslog.syslog(syslog.LOG_INFO, "Peer {}: Can't update the peer. No 'admin_status' attribute in the request".format(key)) - elif op == swsscommon.DEL_COMMAND: - if key in self.peers: - cmds.append(self.bgp_peer_del_template.render(neighbor_addr=key)) - syslog.syslog(syslog.LOG_INFO, 'Peer {} has been removed'.format(key)) - self.peers.remove(key) - else: - syslog.syslog(syslog.LOG_WARNING, 'Peer {} is not found'.format(key)) - self.bgp_messages = new_bgp_messages - - if len(cmds) == 0: - return - - fd, tmp_filename = tempfile.mkstemp(dir='/tmp') - os.close(fd) - with open (tmp_filename, 'w') as fp: - fp.write('router bgp %s\n' % self.bgp_asn) - for cmd in cmds: - fp.write("%s\n" % cmd) - - command = ["vtysh", "-f", tmp_filename] - run_command(command) #FIXME - os.remove(tmp_filename) - - def __bgp_handler(self, key, op, data): - self.bgp_messages.append((key, op, data)) - # If ASN is not set, we just cache this message until the ASN is set. - if self.bgp_asn is not None: - self.__update_bgp() - - class Daemon(object): SELECT_TIMEOUT = 1000 - DATABASE_LIST = [ swsscommon.CONFIG_DB ] def __init__(self): - self.db_connectors = { db : swsscommon.DBConnector(db, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) for db in Daemon.DATABASE_LIST } + self.db_connectors = {} self.selector = swsscommon.Select() self.callbacks = defaultdict(lambda : defaultdict(list)) # db -> table -> [] self.subscribers = set() def add_manager(self, db, table_name, callback): - if db not in Daemon.DATABASE_LIST: - raise ValueError("database {} isn't supported. Supported '{}' only.".format(db, ",".join(Daemon.DATABASE_LIST))) + if db not in self.db_connectors: + self.db_connectors[db] = swsscommon.DBConnector(db, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) if table_name not in self.callbacks[db]: conn = self.db_connectors[db] @@ -226,6 +115,260 @@ class Daemon(object): callback(key, op, dict(fvs)) +class Directory(object): + def __init__(self): + self.data = defaultdict(dict) + self.notify = defaultdict(lambda: defaultdict(list)) + + def path_exist(self, slot, path): + if slot not in self.data: + return False + elif path == '': + return True + d = self.data[slot] + for p in path.split("/"): + if p not in d: + return False + d = d[p] + return True + + def get_path(self, slot, path): + if slot not in self.data: + return None + elif path == '': + return self.data[slot] + d = self.data[slot] + for p in path.split("/"): + if p not in d: + return None + d = d[p] + return d + + def put(self, slot, key, value): + self.data[slot][key] = value + if slot in self.notify: + for path in self.notify[slot].keys(): + if self.path_exist(slot, path): + for handler in self.notify[slot][path]: + handler() + + def get(self, slot, key): + return self.data[slot][key] + + def remove(self, slot, key): + if slot in self.data: + if key in self.data[slot]: + del self.data[slot][key] + else: + syslog.syslog(syslog.LOG_ERR, "Directory: Can't remove key '%s' from slot '%s'. The key doesn't exist" % (key, slot)) + else: + syslog.syslog(syslog.LOG_ERR, "Directory: Can't remove key '%s' from slot '%s'. The slot doesn't exist" % (key, slot)) + + def remove_slot(self, slot, key): + if slot in self.data: + del self.data[slot] + else: + syslog.syslog(syslog.LOG_ERR, "Directory: Can't remove slot '%s'. The slot doesn't exist" % slot) + + def get_slot(self, slot): + return self.data[slot] + + def available_slot(self, slot): + return slot in self.data + + def available_deps(self, deps): + res = True + for slot, path in deps: + res = res and self.path_exist(slot, path) + return res + + def subscribe(self, deps, handler): + for slot, path in deps: + self.notify[slot][path].append(handler) + + +class Manager(object): + def __init__(self, daemon, directory, deps, database, table_name): + self.directory = directory + self.deps = deps + self.set_queue = [] + daemon.add_manager(database, table_name, self.handler) + directory.subscribe(deps, self.on_deps_change) + + def handler(self, key, op, data): + if op == swsscommon.SET_COMMAND: + if self.directory.available_deps(self.deps): + res = self.set_handler(key, data) + if not res: + self.set_queue.append((key, data)) + else: + self.set_queue.append((key, data)) + elif op == swsscommon.DEL_COMMAND: + self.del_handler(key) + else: + syslog.syslog(syslog.LOG_ERR, 'Invalid operation "%s" for key "%s"' % (op, key)) + + def on_deps_change(self): + new_queue = [] + for key, data in self.set_queue: + res = self.set_handler(key, data) + if not res: + new_queue.append((key, data)) + self.set_queue = new_queue + + def set_handler(self, key, data): + syslog.syslog(syslog.LOG_ERR, "%s wasn't implemented for %s" % (self.__name__, self.__class__)) + + def del_handler(self, key): + syslog.syslog(syslog.LOG_ERR, "%s wasn't implemented for %s" % (self.__name__, self.__class__)) + + +class BGPDeviceMetaMgr(Manager): + def __init__(self, daemon, directory): + super(BGPDeviceMetaMgr, self).__init__( + daemon, + directory, + [], + swsscommon.CONFIG_DB, + swsscommon.CFG_DEVICE_METADATA_TABLE_NAME + ) + + def set_handler(self, key, data): + if key != "localhost" or "bgp_asn" not in data: + return + if self.directory.path_exist("meta", "localhost/bgp_asn"): + bgp_asn = self.directory.get_path("meta", "localhost/bgp_asn") + if bgp_asn == data["bgp_asn"]: + return + self.directory.put("meta", key, data) + + return True + + def del_handler(self, key): + self.directory.remove("meta", key) + + +class BGPNeighborMetaMgr(Manager): + def __init__(self, daemon, directory): + super(BGPNeighborMetaMgr, self).__init__( + daemon, + directory, + [], + swsscommon.CONFIG_DB, + swsscommon.CFG_DEVICE_NEIGHBOR_METADATA_TABLE_NAME + ) + + def set_handler(self, key, data): + self.directory.put("neigmeta", key, data) + + return True + + def del_handler(self, key): + self.directory.remove("neigmeta", key) + + +class BGPPeerMgr(Manager): + def __init__(self, daemon, directory): + super(BGPPeerMgr, self).__init__( + daemon, + directory, + [ + ("meta", "localhost/bgp_asn"), + ("neigmeta", ""), + ], + swsscommon.CONFIG_DB, + swsscommon.CFG_BGP_NEIGHBOR_TABLE_NAME + ) + self.peers = self.load_peers() + fabric = TemplateFabric() + self.templates = { + "add": fabric.from_file('bgpd.peer.conf.j2'), + "delete": fabric.from_string('no neighbor {{ neighbor_addr }}'), + "shutdown": fabric.from_string('neighbor {{ neighbor_addr }} shutdown'), + "no shutdown": fabric.from_string('no neighbor {{ neighbor_addr }} shutdown'), + } + + def set_handler(self, key, data): + if key not in self.peers: + cmd = None + neigmeta = self.directory.get_slot("neigmeta") + if 'name' in data and data["name"] not in neigmeta: + return False + try: + cmd = self.templates["add"].render( + DEVICE_METADATA=self.directory.get_slot("meta"), + DEVICE_NEIGHBOR_METADATA=neigmeta, + neighbor_addr=key, + bgp_session=data + ) + except: + syslog.syslog(syslog.LOG_ERR, 'Peer {}. Error in rendering the template for "SET" command {}'.format(key, data)) + return True + if cmd is not None: + rc = self.apply_op(cmd) + if rc: + self.peers.add(key) + syslog.syslog(syslog.LOG_INFO, 'Peer {} added with attributes {}'.format(key, data)) + else: + syslog.syslog(syslog.LOG_ERR, "Peer {} wasn't added.".format(key)) + else: + # when the peer is already configured we support "shutdown/no shutdown" + # commands for the peers only + if "admin_status" in data: + if data['admin_status'] == 'up': + rc = self.apply_op(self.templates["no shutdown"].render(neighbor_addr=key)) + if rc: + syslog.syslog(syslog.LOG_INFO, 'Peer {} admin state is set to "up"'.format(key)) + else: + syslog.syslog(syslog.LOG_ERR, "Peer {} admin state wasn't set to 'up'.".format(key)) + elif data['admin_status'] == 'down': + rc = self.apply_op(self.templates["shutdown"].render(neighbor_addr=key)) + if rc: + syslog.syslog(syslog.LOG_INFO, 'Peer {} admin state is set to "down"'.format(key)) + else: + syslog.syslog(syslog.LOG_ERR, "Peer {} admin state wasn't set to 'down'.".format(key)) + else: + syslog.syslog(syslog.LOG_ERR, "Peer {}: Can't update the peer. has wrong attribute value attr['admin_status'] = '{}'".format(key, data['admin_status'])) + else: + syslog.syslog(syslog.LOG_ERR, "Peer {}: Can't update the peer. No 'admin_status' attribute in the request".format(key)) + return True + + def del_handler(self, key): + if key not in self.peers: + syslog.syslog(syslog.LOG_WARNING, 'Peer {} has not been found'.format(key)) + return + cmd = self.templates["delete"].render(neighbor_addr=key) + rc = self.apply_op(cmd) + if rc: + syslog.syslog(syslog.LOG_INFO, 'Peer {} has been removed'.format(key)) + self.peers.remove(key) + else: + syslog.syslog(syslog.LOG_ERR, "Peer {} hasn't been removed".format(key)) + + def apply_op(self, cmd): + bgp_asn = self.directory.get_slot("meta")["localhost"]["bgp_asn"] + fd, tmp_filename = tempfile.mkstemp(dir='/tmp') + os.close(fd) + with open(tmp_filename, 'w') as fp: + fp.write('router bgp %s\n' % bgp_asn) + fp.write("%s\n" % cmd) + + command = ["vtysh", "-f", tmp_filename] + rc, _, _ = run_command(command) + os.remove(tmp_filename) + return rc == 0 + + @staticmethod + def load_peers(): + peers = set() + command = ["vtysh", "-c", "show bgp neighbors json"] + rc, out, err = run_command(command) + if rc == 0: + js_bgp = json.loads(out) + peers = set(js_bgp.keys()) + return peers + + def wait_for_bgpd(): # wait for 20 seconds stop_time = datetime.datetime.now() + datetime.timedelta(seconds=20) @@ -240,9 +383,15 @@ def wait_for_bgpd(): def main(): + managers = [ + BGPDeviceMetaMgr, + BGPNeighborMetaMgr, + BGPPeerMgr, + ] wait_for_bgpd() daemon = Daemon() - bgp_manager = BGPConfigManager(daemon) + directory = Directory() + manager_instanses = [ manager(daemon, directory) for manager in managers ] daemon.run() From 295b0bdc5655ff6dc8b7cdf9f4fbd21bfce31609 Mon Sep 17 00:00:00 2001 From: Volodymyr Samotiy Date: Fri, 22 Nov 2019 22:48:35 +0200 Subject: [PATCH 192/278] [Mellanox] Update FW/SDK: 13/29.2000.2602 and 4.3.2602 (#3796) Signed-off-by: Volodymyr Samotiy --- platform/mellanox/fw.mk | 4 ++-- platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers | 2 +- platform/mellanox/sdk.mk | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/mellanox/fw.mk b/platform/mellanox/fw.mk index 2df1fd11cd75..9d506c1f5bdd 100644 --- a/platform/mellanox/fw.mk +++ b/platform/mellanox/fw.mk @@ -11,12 +11,12 @@ else FW_FROM_URL = n endif -MLNX_SPC_FW_VERSION = 13.2000.2308 +MLNX_SPC_FW_VERSION = 13.2000.2602 MLNX_SPC_FW_FILE = fw-SPC-rel-$(subst .,_,$(MLNX_SPC_FW_VERSION))-EVB.mfa $(MLNX_SPC_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC_FW_FILE) -MLNX_SPC2_FW_VERSION = 29.2000.2308 +MLNX_SPC2_FW_VERSION = 29.2000.2602 MLNX_SPC2_FW_FILE = fw-SPC2-rel-$(subst .,_,$(MLNX_SPC2_FW_VERSION))-EVB.mfa $(MLNX_SPC2_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC2_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC2_FW_FILE) diff --git a/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers b/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers index f4df2ccaa534..87f7a7911275 160000 --- a/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers +++ b/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers @@ -1 +1 @@ -Subproject commit f4df2ccaa5342e7f3fa5a45a851ef32ea59c0654 +Subproject commit 87f7a7911275285abc63c24ba39aa4af4c4b4678 diff --git a/platform/mellanox/sdk.mk b/platform/mellanox/sdk.mk index dee478e7d52c..73568ce84596 100644 --- a/platform/mellanox/sdk.mk +++ b/platform/mellanox/sdk.mk @@ -1,5 +1,5 @@ MLNX_SDK_BASE_PATH = $(PLATFORM_PATH)/sdk-src/sx-kernel/Switch-SDK-drivers/bin/ -MLNX_SDK_VERSION = 4.3.2308 +MLNX_SDK_VERSION = 4.3.2602 MLNX_SDK_ISSU_VERSION = 101 MLNX_SDK_DEB_VERSION = $(subst _,.,$(MLNX_SDK_VERSION)) From f943440fcbbb9a4dd76f313ea6d83109ed4f52c2 Mon Sep 17 00:00:00 2001 From: Andriy Kokhan <43479230+akokhan@users.noreply.github.com> Date: Sat, 23 Nov 2019 00:28:40 +0200 Subject: [PATCH 193/278] Moved telemetry exit listener from process package into Docker (#3805) Signed-off-by: Andriy Kokhan --- rules/docker-telemetry.mk | 1 + rules/telemetry.mk | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/docker-telemetry.mk b/rules/docker-telemetry.mk index 94920c464381..defeb4d00821 100644 --- a/rules/docker-telemetry.mk +++ b/rules/docker-telemetry.mk @@ -28,3 +28,4 @@ $(DOCKER_TELEMETRY)_CONTAINER_NAME = telemetry $(DOCKER_TELEMETRY)_RUN_OPT += --net=host --privileged -t $(DOCKER_TELEMETRY)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro +$(DOCKER_TELEMETRY)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) diff --git a/rules/telemetry.mk b/rules/telemetry.mk index af568fb5bd6f..1d903e603251 100644 --- a/rules/telemetry.mk +++ b/rules/telemetry.mk @@ -3,4 +3,3 @@ SONIC_TELEMETRY = sonic-telemetry_0.1_$(CONFIGURED_ARCH).deb $(SONIC_TELEMETRY)_SRC_PATH = $(SRC_PATH)/telemetry SONIC_DPKG_DEBS += $(SONIC_TELEMETRY) -$(SONIC_TELEMETRY)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) From 351410ea8cd7e45be42ab394e138a350c241183a Mon Sep 17 00:00:00 2001 From: Joe LeVeque Date: Fri, 22 Nov 2019 20:39:09 -0800 Subject: [PATCH 194/278] [swss.sh] When starting, call 'systemctl restart' on dependents, not (#3807) 'systemctl start' --- files/scripts/swss.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/scripts/swss.sh b/files/scripts/swss.sh index 65eaf08148a8..f54c13697753 100755 --- a/files/scripts/swss.sh +++ b/files/scripts/swss.sh @@ -85,7 +85,9 @@ start_peer_and_dependent_services() { if [[ x"$WARM_BOOT" != x"true" ]]; then /bin/systemctl start ${PEER} for dep in ${DEPENDENT}; do - /bin/systemctl start ${dep} + # Here we call `systemctl restart` on each dependent service instead of `systemctl start` to + # ensure the services actually get stopped and started in case they were not previously stopped. + /bin/systemctl restart ${dep} done fi } From 3d80afa41546fe29d6e0d45ed05a2de421d84f0d Mon Sep 17 00:00:00 2001 From: Dong Zhang <41927498+dzhangalibaba@users.noreply.github.com> Date: Fri, 22 Nov 2019 20:41:45 -0800 Subject: [PATCH 195/278] [swsssdk-py] submodule update for sonic-py-swsssdk (#3808) update multiDB changes in sonic-py-swsssdk, including: *[multi-DB] Part 4: add sonic-db-cli to replace redis-cli (#54) *[multi-DB] Part 3: Python API changes (#52) *remove SonicV2Connector which is not used any more (#53) --- src/sonic-py-swsssdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-py-swsssdk b/src/sonic-py-swsssdk index 4cee38534919..bc3964b788c3 160000 --- a/src/sonic-py-swsssdk +++ b/src/sonic-py-swsssdk @@ -1 +1 @@ -Subproject commit 4cee38534919e34f407363ac3ab5f31b4d09be6d +Subproject commit bc3964b788c3a4a45f2b359a5df5934ecdee84c2 From d44cc30191043be64d27403eb53ab1f46fda92eb Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Fri, 22 Nov 2019 20:43:44 -0800 Subject: [PATCH 196/278] [docker-fpm-frr]: Enable sending ipv6 prefixes over ipv4 BGPMON session (#3799) * Enable ipv6 prefixes over ipv4 BGPMON session --- dockers/docker-fpm-frr/bgpd.conf.default.j2 | 21 +++++++++++-------- .../tests/sample_output/bgpd_frr.conf | 21 +++++++++++-------- .../tests/sample_output/frr.conf | 21 +++++++++++-------- 3 files changed, 36 insertions(+), 27 deletions(-) diff --git a/dockers/docker-fpm-frr/bgpd.conf.default.j2 b/dockers/docker-fpm-frr/bgpd.conf.default.j2 index b53e5dff6762..e12782b035aa 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.default.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.default.j2 @@ -24,9 +24,9 @@ route-map TO_BGP_PEER_V4 permit 100 route-map TO_BGP_PEER_V6 permit 100 ! {% if BGP_MONITORS is defined and BGP_MONITORS|length > 0 %} -route-map FROM_BGPMON_V4 deny 10 +route-map FROM_BGPMON deny 10 ! -route-map TO_BGPMON_V4 permit 10 +route-map TO_BGPMON permit 10 ! {% endif %} ! @@ -136,21 +136,24 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% endblock bgp_peers_with_range %} {% block bgp_monitors %} {% if BGP_MONITORS is defined and BGP_MONITORS|length > 0 %} - neighbor BGPMON_V4 peer-group + neighbor BGPMON peer-group {% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %} {% if prefix | ipv4 and name == 'Loopback0' %} - neighbor BGPMON_V4 update-source {{ prefix | ip }} + neighbor BGPMON update-source {{ prefix | ip }} {% endif %} {% endfor %} - neighbor BGPMON_V4 route-map FROM_BGPMON_V4 in - neighbor BGPMON_V4 route-map TO_BGPMON_V4 out - neighbor BGPMON_V4 send-community - neighbor BGPMON_V4 maximum-prefix 1 + neighbor BGPMON route-map FROM_BGPMON in + neighbor BGPMON route-map TO_BGPMON out + neighbor BGPMON send-community + neighbor BGPMON maximum-prefix 1 {% for neighbor_addr, bgp_session in BGP_MONITORS.items() %} neighbor {{ neighbor_addr }} remote-as {{ DEVICE_METADATA['localhost']['bgp_asn'] }} - neighbor {{ neighbor_addr }} peer-group BGPMON_V4 + neighbor {{ neighbor_addr }} peer-group BGPMON neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} neighbor {{ neighbor_addr }} activate + address-family ipv6 + neighbor {{ neighbor_addr }} activate + exit-address-family {% endfor %} {% endif %} {% endblock bgp_monitors %} diff --git a/src/sonic-config-engine/tests/sample_output/bgpd_frr.conf b/src/sonic-config-engine/tests/sample_output/bgpd_frr.conf index 3a8abf050b45..566d6384fcfd 100644 --- a/src/sonic-config-engine/tests/sample_output/bgpd_frr.conf +++ b/src/sonic-config-engine/tests/sample_output/bgpd_frr.conf @@ -31,9 +31,9 @@ route-map TO_BGP_PEER_V4 permit 100 ! route-map TO_BGP_PEER_V6 permit 100 ! -route-map FROM_BGPMON_V4 deny 10 +route-map FROM_BGPMON deny 10 ! -route-map TO_BGPMON_V4 permit 10 +route-map TO_BGPMON permit 10 ! ! route-map ISOLATE permit 10 @@ -73,14 +73,17 @@ router bgp 65100 neighbor PEER_V6 soft-reconfiguration inbound neighbor PEER_V6 route-map TO_BGP_PEER_V6 out exit-address-family - neighbor BGPMON_V4 peer-group - neighbor BGPMON_V4 update-source 10.1.0.32 - neighbor BGPMON_V4 route-map FROM_BGPMON_V4 in - neighbor BGPMON_V4 route-map TO_BGPMON_V4 out - neighbor BGPMON_V4 send-community - neighbor BGPMON_V4 maximum-prefix 1 + neighbor BGPMON peer-group + neighbor BGPMON update-source 10.1.0.32 + neighbor BGPMON route-map FROM_BGPMON in + neighbor BGPMON route-map TO_BGPMON out + neighbor BGPMON send-community + neighbor BGPMON maximum-prefix 1 neighbor 10.20.30.40 remote-as 65100 - neighbor 10.20.30.40 peer-group BGPMON_V4 + neighbor 10.20.30.40 peer-group BGPMON neighbor 10.20.30.40 description BGPMonitor neighbor 10.20.30.40 activate + address-family ipv6 + neighbor 10.20.30.40 activate + exit-address-family !! diff --git a/src/sonic-config-engine/tests/sample_output/frr.conf b/src/sonic-config-engine/tests/sample_output/frr.conf index edcf0939a03f..47855ce7c841 100644 --- a/src/sonic-config-engine/tests/sample_output/frr.conf +++ b/src/sonic-config-engine/tests/sample_output/frr.conf @@ -63,9 +63,9 @@ route-map TO_BGP_PEER_V4 permit 100 ! route-map TO_BGP_PEER_V6 permit 100 ! -route-map FROM_BGPMON_V4 deny 10 +route-map FROM_BGPMON deny 10 ! -route-map TO_BGPMON_V4 permit 10 +route-map TO_BGPMON permit 10 ! ! route-map ISOLATE permit 10 @@ -105,14 +105,17 @@ router bgp 65100 neighbor PEER_V6 soft-reconfiguration inbound neighbor PEER_V6 route-map TO_BGP_PEER_V6 out exit-address-family - neighbor BGPMON_V4 peer-group - neighbor BGPMON_V4 update-source 10.1.0.32 - neighbor BGPMON_V4 route-map FROM_BGPMON_V4 in - neighbor BGPMON_V4 route-map TO_BGPMON_V4 out - neighbor BGPMON_V4 send-community - neighbor BGPMON_V4 maximum-prefix 1 + neighbor BGPMON peer-group + neighbor BGPMON update-source 10.1.0.32 + neighbor BGPMON route-map FROM_BGPMON in + neighbor BGPMON route-map TO_BGPMON out + neighbor BGPMON send-community + neighbor BGPMON maximum-prefix 1 neighbor 10.20.30.40 remote-as 65100 - neighbor 10.20.30.40 peer-group BGPMON_V4 + neighbor 10.20.30.40 peer-group BGPMON neighbor 10.20.30.40 description BGPMonitor neighbor 10.20.30.40 activate + address-family ipv6 + neighbor 10.20.30.40 activate + exit-address-family !! From f558f170bb5fcf48a0fe5e80685c7f2f9ba984ca Mon Sep 17 00:00:00 2001 From: simonJi2018 <37395146+simonJi2018@users.noreply.github.com> Date: Sat, 23 Nov 2019 12:44:32 +0800 Subject: [PATCH 197/278] [nephos] upgrade Nephos SAI to version 06a67d (#3793) [Nephos SAI] upgrade Nephos SAI to version 06a67d --- platform/nephos/sai.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/nephos/sai.mk b/platform/nephos/sai.mk index edaa245cf5ad..5f7c4a23ae95 100644 --- a/platform/nephos/sai.mk +++ b/platform/nephos/sai.mk @@ -1,6 +1,6 @@ SDK_VERSION = 3.0.0 SAI_VERSION = 1.5.0 -SAI_COMMIT_ID = 426624 +SAI_COMMIT_ID = 06a67d # Place here URL where SAI deb exist NEPHOS_SAI_DEB_LOCAL_URL = From 8d4516ca3d7e43f19a0d1a17a6849a600c1eb957 Mon Sep 17 00:00:00 2001 From: lguohan Date: Sat, 23 Nov 2019 12:30:22 -0800 Subject: [PATCH 198/278] [kvm]: increase mem to 3G to avoid OOM during onie installation (#3811) Signed-off-by: Guohan Lu --- build_image.sh | 2 +- build_kvm_image.sh => scripts/build_kvm_image.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename build_kvm_image.sh => scripts/build_kvm_image.sh (99%) diff --git a/build_image.sh b/build_image.sh index 3084a4a2bd5d..9635201ae067 100755 --- a/build_image.sh +++ b/build_image.sh @@ -96,7 +96,7 @@ elif [ "$IMAGE_TYPE" = "kvm" ]; then generate_onie_installer_image - SONIC_USERNAME=$USERNAME PASSWD=$PASSWORD sudo -E ./build_kvm_image.sh $KVM_IMAGE_DISK $onie_recovery_image $OUTPUT_ONIE_IMAGE $KVM_IMAGE_DISK_SIZE + SONIC_USERNAME=$USERNAME PASSWD=$PASSWORD sudo -E ./scripts/build_kvm_image.sh $KVM_IMAGE_DISK $onie_recovery_image $OUTPUT_ONIE_IMAGE $KVM_IMAGE_DISK_SIZE if [ $? -ne 0 ]; then echo "Error : build kvm image failed" diff --git a/build_kvm_image.sh b/scripts/build_kvm_image.sh similarity index 99% rename from build_kvm_image.sh rename to scripts/build_kvm_image.sh index bc0f54e12d5c..a8ae21c9777a 100755 --- a/build_kvm_image.sh +++ b/scripts/build_kvm_image.sh @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: GPL-2.0 -MEM=2048 +MEM=3072 DISK=$1 ONIE_RECOVERY_ISO=$2 INSTALLER=$3 From 65f7da87a7c71dbd69e858a1f4b62fab285f3347 Mon Sep 17 00:00:00 2001 From: pra-moh <49077256+pra-moh@users.noreply.github.com> Date: Sat, 23 Nov 2019 12:30:56 -0800 Subject: [PATCH 199/278] [telemetry.sh] Fix string null check with special characters by adding quotes (#3810) * adding quotes for string comparison with special characters * Update dockers/docker-sonic-telemetry/telemetry.sh Co-Authored-By: Joe LeVeque * Update dockers/docker-sonic-telemetry/telemetry.sh Co-Authored-By: Joe LeVeque --- dockers/docker-sonic-telemetry/telemetry.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dockers/docker-sonic-telemetry/telemetry.sh b/dockers/docker-sonic-telemetry/telemetry.sh index 053b1dae6ead..8cfd8a531cca 100755 --- a/dockers/docker-sonic-telemetry/telemetry.sh +++ b/dockers/docker-sonic-telemetry/telemetry.sh @@ -7,7 +7,7 @@ TELEMETRY=`sonic-cfggen -d -v 'TELEMETRY.keys() | join(" ") if TELEMETRY'` TELEMETRY_ARGS=" -logtostderr" -if [ ! -z $X509 ]; then +if [ -n "$X509" ]; then SERVER_CRT=`sonic-cfggen -d -v "DEVICE_METADATA['x509']['server_crt']"` SERVER_KEY=`sonic-cfggen -d -v "DEVICE_METADATA['x509']['server_key']"` if [ -z $SERVER_CRT ] || [ -z $SERVER_KEY ]; then @@ -19,7 +19,7 @@ else TELEMETRY_ARGS+=" --insecure" fi -if [ ! -z $X509 ]; then +if [ -n "$X509" ]; then CA_CRT=`sonic-cfggen -d -v "DEVICE_METADATA['x509']['ca_crt']"` if [ ! -z $CA_CRT ]; then TELEMETRY_ARGS+=" --ca_crt $CA_CRT" @@ -47,5 +47,3 @@ else fi exec /usr/sbin/telemetry ${TELEMETRY_ARGS} - - From 45e13b9929d6bd0e86942b52263315380bea14ba Mon Sep 17 00:00:00 2001 From: pra-moh <49077256+pra-moh@users.noreply.github.com> Date: Sat, 23 Nov 2019 12:31:23 -0800 Subject: [PATCH 200/278] [sonic-telemetry]: correcting server key name in configdb (#3809) --- src/sonic-config-engine/minigraph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 443d96c31161..3ba6362c6ff0 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -630,7 +630,7 @@ def parse_xml(filename, platform=None, port_config_file=None): }, 'x509': { 'server_crt': '/etc/sonic/telemetry/streamingtelemetryserver.cer', - 'server_key': '/etc/sonic/telemetry/streamingtelemetryclient.key', + 'server_key': '/etc/sonic/telemetry/streamingtelemetryserver.key', 'ca_crt': '/etc/sonic/telemetry/dsmsroot.cer' } } From 62a7846960797204600bfd86003872e651cb174b Mon Sep 17 00:00:00 2001 From: padmanarayana Date: Sun, 24 Nov 2019 15:21:43 -0800 Subject: [PATCH 201/278] [sFlow]: Upgrade hsflowd to 2.0.26-1 (#3812) --- rules/sflow.mk | 4 ++-- src/sflow/hsflowd/Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rules/sflow.mk b/rules/sflow.mk index 4366e3479734..f267353c0f93 100644 --- a/rules/sflow.mk +++ b/rules/sflow.mk @@ -1,7 +1,7 @@ # host-sflow package -HSFLOWD_VERSION = 2.0.25 -HSFLOWD_SUBVERSION = 4 +HSFLOWD_VERSION = 2.0.26 +HSFLOWD_SUBVERSION = 1 export HSFLOWD_VERSION HSFLOWD_SUBVERSION HSFLOWD = hsflowd_$(HSFLOWD_VERSION)-$(HSFLOWD_SUBVERSION)_$(CONFIGURED_ARCH).deb diff --git a/src/sflow/hsflowd/Makefile b/src/sflow/hsflowd/Makefile index f0ff92a7af62..0a8094e3b695 100644 --- a/src/sflow/hsflowd/Makefile +++ b/src/sflow/hsflowd/Makefile @@ -10,7 +10,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : git clone https://github.com/sflow/host-sflow pushd ./host-sflow - git checkout -b sflow tags/v2.0.25-4 + git checkout -b sflow tags/v2.0.26-1 # Apply patch series stg init From 4ae1f7069f10532149d45ee01c540eb6efd0d38c Mon Sep 17 00:00:00 2001 From: lguohan Date: Mon, 25 Nov 2019 08:32:55 -0800 Subject: [PATCH 202/278] Revert "[swsssdk-py] submodule update for sonic-py-swsssdk (#3808)" (#3816) This reverts commit 3d80afa41546fe29d6e0d45ed05a2de421d84f0d. --- src/sonic-py-swsssdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-py-swsssdk b/src/sonic-py-swsssdk index bc3964b788c3..4cee38534919 160000 --- a/src/sonic-py-swsssdk +++ b/src/sonic-py-swsssdk @@ -1 +1 @@ -Subproject commit bc3964b788c3a4a45f2b359a5df5934ecdee84c2 +Subproject commit 4cee38534919e34f407363ac3ab5f31b4d09be6d From 57728c5c8bf9013fe67f59eace42450b2e6fbe39 Mon Sep 17 00:00:00 2001 From: lguohan Date: Mon, 25 Nov 2019 09:00:47 -0800 Subject: [PATCH 203/278] [docker-ptf]: add ethtool and telnet package in ptf (#3815) --- dockers/docker-ptf/Dockerfile.j2 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dockers/docker-ptf/Dockerfile.j2 b/dockers/docker-ptf/Dockerfile.j2 index deb1892959e6..326df49d9764 100644 --- a/dockers/docker-ptf/Dockerfile.j2 +++ b/dockers/docker-ptf/Dockerfile.j2 @@ -29,10 +29,12 @@ RUN sed --in-place 's/httpredir.debian.org/debian-archive.trafficmanager.net/' / && apt-get install -y \ openssh-server \ vim \ + telnet \ net-tools \ traceroute \ lsof \ tcpdump \ + ethtool \ unzip \ pkg-config \ binutils \ From 67fc68513ee784e12e4588f7eb6c8f51135bd16b Mon Sep 17 00:00:00 2001 From: yozhao101 <56170650+yozhao101@users.noreply.github.com> Date: Mon, 25 Nov 2019 13:02:00 -0800 Subject: [PATCH 204/278] [Services] Restart Sflow service upon unexpected critical process exit. (#3751) Signed-off-by: Yong Zhao --- dockers/docker-sflow/Dockerfile.j2 | 2 ++ dockers/docker-sflow/critical_processes | 1 + dockers/docker-sflow/supervisord.conf | 6 ++++++ files/build_templates/sflow.service.j2 | 4 ++++ rules/docker-sflow.mk | 2 +- 5 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 dockers/docker-sflow/critical_processes diff --git a/dockers/docker-sflow/Dockerfile.j2 b/dockers/docker-sflow/Dockerfile.j2 index e88789fb6992..75da64e02e4d 100644 --- a/dockers/docker-sflow/Dockerfile.j2 +++ b/dockers/docker-sflow/Dockerfile.j2 @@ -29,5 +29,7 @@ RUN sed -ri '/^DAEMON_ARGS=""/c DAEMON_ARGS="-c /var/log/hsflowd.crash"' /etc/in COPY ["start.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor"] ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-sflow/critical_processes b/dockers/docker-sflow/critical_processes new file mode 100644 index 000000000000..5b24e2d8e1da --- /dev/null +++ b/dockers/docker-sflow/critical_processes @@ -0,0 +1 @@ +sflowmgrd diff --git a/dockers/docker-sflow/supervisord.conf b/dockers/docker-sflow/supervisord.conf index e4f9259712b5..50986f197d88 100644 --- a/dockers/docker-sflow/supervisord.conf +++ b/dockers/docker-sflow/supervisord.conf @@ -3,6 +3,12 @@ logfile_maxbytes=1MB logfile_backups=2 nodaemon=true +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + [program:start.sh] command=/usr/bin/start.sh priority=1 diff --git a/files/build_templates/sflow.service.j2 b/files/build_templates/sflow.service.j2 index 3a5752412b98..de08f027adff 100644 --- a/files/build_templates/sflow.service.j2 +++ b/files/build_templates/sflow.service.j2 @@ -3,12 +3,16 @@ Description=sFlow container Requires=swss.service After=swss.service syncd.service Before=ntp-config.service +StartLimitIntervalSec=1200 +StartLimitBurst=3 [Service] User={{ sonicadmin_user }} ExecStartPre=/usr/bin/{{docker_container_name}}.sh start ExecStart=/usr/bin/{{docker_container_name}}.sh wait ExecStop=/usr/bin/{{docker_container_name}}.sh stop +Restart=always +RestartSec=30 [Install] WantedBy=multi-user.target diff --git a/rules/docker-sflow.mk b/rules/docker-sflow.mk index 19b0f290bf99..94b568481885 100644 --- a/rules/docker-sflow.mk +++ b/rules/docker-sflow.mk @@ -32,4 +32,4 @@ $(DOCKER_SFLOW)_RUN_OPT += -v /host/warmboot:/var/warmboot $(DOCKER_SFLOW)_BASE_IMAGE_FILES += psample:/usr/bin/psample $(DOCKER_SFLOW)_BASE_IMAGE_FILES += sflowtool:/usr/bin/sflowtool - +$(DOCKER_SFLOW)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) From 794d459483042427a06ad602de2a7b93d24b1a49 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Mon, 25 Nov 2019 13:12:57 -0800 Subject: [PATCH 205/278] Update frr with latest changes from frr master (#3806) --- .gitmodules | 2 +- src/sonic-frr/frr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 08546d46073a..cfc6878c7291 100644 --- a/.gitmodules +++ b/.gitmodules @@ -47,7 +47,7 @@ [submodule "src/sonic-frr/frr"] path = src/sonic-frr/frr url = https://github.com/Azure/sonic-frr.git - branch = frr/7.1 + branch = frr/7.2 [submodule "platform/p4/p4-hlir/p4-hlir-v1.1"] path = platform/p4/p4-hlir/p4-hlir-v1.1 url = https://github.com/p4lang/p4-hlir.git diff --git a/src/sonic-frr/frr b/src/sonic-frr/frr index 514f508fc60e..d49e8f75bd46 160000 --- a/src/sonic-frr/frr +++ b/src/sonic-frr/frr @@ -1 +1 @@ -Subproject commit 514f508fc60e0573d9863beaad8924927d373954 +Subproject commit d49e8f75bd46879c799375f304506dbc5d26230f From d3a1555f3042bd3002d3d35c371a375fe6f58af3 Mon Sep 17 00:00:00 2001 From: pra-moh <49077256+pra-moh@users.noreply.github.com> Date: Tue, 26 Nov 2019 14:11:12 -0800 Subject: [PATCH 206/278] [hostcfgd] Add support to enable/disable optional features (#3653) --- files/image_config/hostcfgd/hostcfgd | 41 +++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/files/image_config/hostcfgd/hostcfgd b/files/image_config/hostcfgd/hostcfgd index b32e3d8cd668..7fa8ed2ba205 100755 --- a/files/image_config/hostcfgd/hostcfgd +++ b/files/image_config/hostcfgd/hostcfgd @@ -304,6 +304,45 @@ class HostConfigDaemon: add = False self.iptables.iptables_handler(key, data, add) + + def feature_status_handler(self, key, data): + status_data = self.config_db.get_table('FEATURE') + for key in status_data.keys(): + if not key: + syslog.syslog(syslog.LOG_WARNING, "FEATURE key is missing") + return + status = status_data[key]['status'] + if not status: + syslog.syslog(syslog.LOG_WARNING, "status is missing for {}".format(key)) + return + if status == "enabled": + start_cmds=[] + start_cmds.append("sudo systemctl enable {}".format(key)) + start_cmds.append("sudo systemctl start {}".format(key)) + for cmd in start_cmds: + syslog.syslog(syslog.LOG_INFO, "Running cmd - {}".format(cmd)) + try: + subprocess.check_call(cmd, shell=True) + except subprocess.CalledProcessError as err: + syslog.syslog(syslog.LOG_ERR, "{} - failed: return code - {}, output:\n{}" + .format(err.cmd, err.returncode, err.output)) + return + syslog.syslog(syslog.LOG_INFO, "Feature '{}' is enabled and started".format(key)) + elif status == "disabled": + stop_cmds=[] + stop_cmds.append("sudo systemctl stop {}".format(key)) + stop_cmds.append("sudo systemctl disable {}".format(key)) + for cmd in stop_cmds: + syslog.syslog(syslog.LOG_INFO, "Running cmd - {}".format(cmd)) + try: + subprocess.check_call(cmd, shell=True) + except subprocess.CalledProcessError as err: + syslog.syslog(syslog.LOG_ERR, "{} - failed: return code - {}, output:\n{}" + .format(err.cmd, err.returncode, err.output)) + return + syslog.syslog(syslog.LOG_INFO, "Feature '{}' is stopped and disabled".format(key)) + else: + syslog.syslog(syslog.LOG_ERR, "Unexpected status value '{}' for '{}'".format(status, key)) def start(self): self.config_db.subscribe('AAA', lambda table, key, data: self.aaa_handler(key, data)) @@ -311,6 +350,7 @@ class HostConfigDaemon: self.config_db.subscribe('TACPLUS', lambda table, key, data: self.tacacs_global_handler(key, data)) self.config_db.subscribe('DEVICE_METADATA', lambda table, key, data: self.hostname_handler(key, data)) self.config_db.subscribe('LOOPBACK_INTERFACE', lambda table, key, data: self.lpbk_handler(key, data)) + self.config_db.subscribe('FEATURE', lambda table, key, data: self.feature_status_handler(key, data)) self.config_db.listen() @@ -321,4 +361,3 @@ def main(): if __name__ == "__main__": main() - From 5e6f8adb2236dbd0d5aefae9a95df7d833447859 Mon Sep 17 00:00:00 2001 From: Joe LeVeque Date: Tue, 26 Nov 2019 16:59:45 -0800 Subject: [PATCH 207/278] [services] Remove explicit dependencies from dhcp_relay service file, control in swss.sh (#3823) --- files/build_templates/dhcp_relay.service.j2 | 4 ++-- files/scripts/swss.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/files/build_templates/dhcp_relay.service.j2 b/files/build_templates/dhcp_relay.service.j2 index 9106e29a41e2..d501a663feba 100644 --- a/files/build_templates/dhcp_relay.service.j2 +++ b/files/build_templates/dhcp_relay.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=DHCP relay container -Requires=updategraph.service swss.service teamd.service +Requires=updategraph.service After=updategraph.service swss.service syncd.service teamd.service Before=ntp-config.service StartLimitIntervalSec=1200 @@ -15,4 +15,4 @@ Restart=always RestartSec=30 [Install] -WantedBy=multi-user.target swss.service teamd.service +WantedBy=multi-user.target diff --git a/files/scripts/swss.sh b/files/scripts/swss.sh index f54c13697753..416075d8b33a 100755 --- a/files/scripts/swss.sh +++ b/files/scripts/swss.sh @@ -2,7 +2,7 @@ SERVICE="swss" PEER="syncd" -DEPENDENT="teamd radv" +DEPENDENT="teamd radv dhcp_relay" DEBUGLOG="/tmp/swss-syncd-debug.log" LOCKFILE="/tmp/swss-syncd-lock" From 7622a30d98553288ca5cb53bb3b1eff210d40a77 Mon Sep 17 00:00:00 2001 From: Joe LeVeque Date: Tue, 26 Nov 2019 18:16:57 -0800 Subject: [PATCH 208/278] [dhcp_relay] Add extra sleep before starting relay agent processes (#3824) --- dockers/docker-dhcp-relay/start.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dockers/docker-dhcp-relay/start.sh b/dockers/docker-dhcp-relay/start.sh index 0ac5ea1a10ec..54e58dd42a07 100755 --- a/dockers/docker-dhcp-relay/start.sh +++ b/dockers/docker-dhcp-relay/start.sh @@ -16,6 +16,12 @@ if [ $(supervisorctl status | grep -c "^isc-dhcp-relay:") -gt 0 ]; then # lifetime of the process. /usr/bin/wait_for_intf.sh + # Allow a bit more time for interfaces to settle before starting the + # relay agent processes. + # FIXME: Remove/decrease this once we determine how to prevent future race + # conditions here. + sleep 180 + # Start all DHCP relay agent(s) supervisorctl start isc-dhcp-relay:* fi From bfa96bbce36462115974e3c1a748c02294c80920 Mon Sep 17 00:00:00 2001 From: pra-moh <49077256+pra-moh@users.noreply.github.com> Date: Wed, 27 Nov 2019 15:35:41 -0800 Subject: [PATCH 209/278] Add daemon which periodically pushes process and docker stats to State DB (#3525) --- .../build_templates/sonic_debian_extension.j2 | 5 + .../procdockerstatsd/procdockerstatsd | 214 ++++++++++++++++++ .../procdockerstatsd/procdockerstatsd.service | 13 ++ 3 files changed, 232 insertions(+) create mode 100644 files/image_config/procdockerstatsd/procdockerstatsd create mode 100644 files/image_config/procdockerstatsd/procdockerstatsd.service diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index 13d5432e09ea..f62ef44f0fc0 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -253,6 +253,11 @@ sudo cp $IMAGE_CONFIGS/caclmgrd/caclmgrd.service $FILESYSTEM_ROOT/etc/systemd/s echo "caclmgrd.service" | sudo tee -a $GENERATED_SERVICE_FILE sudo cp $IMAGE_CONFIGS/caclmgrd/caclmgrd $FILESYSTEM_ROOT/usr/bin/ +# Copy process/docker cpu/memory utilization data export daemon +sudo cp $IMAGE_CONFIGS/procdockerstatsd/procdockerstatsd.service $FILESYSTEM_ROOT/etc/systemd/system/ +echo "procdockerstatsd.service" | sudo tee -a $GENERATED_SERVICE_FILE +sudo cp $IMAGE_CONFIGS/procdockerstatsd/procdockerstatsd $FILESYSTEM_ROOT/usr/bin/ + # Copy process-reboot-cause service files sudo cp $IMAGE_CONFIGS/process-reboot-cause/process-reboot-cause.service $FILESYSTEM_ROOT/etc/systemd/system/ echo "process-reboot-cause.service" | sudo tee -a $GENERATED_SERVICE_FILE diff --git a/files/image_config/procdockerstatsd/procdockerstatsd b/files/image_config/procdockerstatsd/procdockerstatsd new file mode 100644 index 000000000000..66d2d45009d5 --- /dev/null +++ b/files/image_config/procdockerstatsd/procdockerstatsd @@ -0,0 +1,214 @@ +# !/usr/bin/env python +''' +procdockerstatsd +Daemon which periodically gathers process and docker statistics and pushes the data to STATE_DB +''' + +import os +import re +import subprocess +import sys +import syslog +import time +from datetime import datetime + +import swsssdk + +VERSION = '1.0' + +SYSLOG_IDENTIFIER = "procdockerstatsd" + +REDIS_HOSTIP = "127.0.0.1" + +# ========================== Syslog wrappers ========================== +def log_info(msg, also_print_to_console=False): + syslog.openlog(SYSLOG_IDENTIFIER) + syslog.syslog(syslog.LOG_INFO, msg) + syslog.closelog() + +def log_warning(msg, also_print_to_console=False): + syslog.openlog(SYSLOG_IDENTIFIER) + syslog.syslog(syslog.LOG_WARNING, msg) + syslog.closelog() + +def log_error(msg, also_print_to_console=False): + syslog.openlog(SYSLOG_IDENTIFIER) + syslog.syslog(syslog.LOG_ERR, msg) + syslog.closelog() + +# ========================== ProcessDocker class ========================== +class ProcDockerStats: + + def __init__(self): + self.state_db = swsssdk.SonicV2Connector(host=REDIS_HOSTIP) + self.state_db.connect("STATE_DB") + + def run_command(self, cmd): + proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + (stdout, stderr) = proc.communicate() + if proc.returncode != 0: + log_error("Error running command '{}'".format(cmd)) + return None + else: + return stdout + + def format_docker_cmd_output(self, cmdout): + lines = re.split("\n", cmdout) + keys = re.split(" +", lines[0]) + docker_data = dict() + docker_data_list = [] + for item in lines[1:]: + values1 = re.split(" +", item) + docker_data = dict(zip(keys, values1)) + docker_data_list.append(docker_data) + formatted_dict = self.create_docker_dict(docker_data_list) + return formatted_dict + + def format_process_cmd_output(self, cmdout): + lines = re.split("\n", cmdout) + keys = re.split(" +", lines[0]) + keylist = list(filter(None, keys)) + process_data = dict() + process_data_list = [] + for item in lines[1:]: + values1 = re.split(" +", str(item)) + # To remove extra space before UID + val = list(filter(None, values1)) + # Merging extra columns created due to space in cmd ouput + val[8:] = [''.join(val[8:])] + process_data = dict(zip(keylist, val)) + process_data_list.append(process_data) + return process_data_list + + def convert_to_bytes(self, value): + unit_value = re.search('[a-zA-Z]+', value) + value_to_convert = float(filter(str.isdigit, value)) + unit = unit_value.group(0) + UNITS_B = 'B' + UNITS_KB = 'KB' + UNITS_MB = 'MB' + UNITS_MiB = 'MiB' + UNITS_GiB = 'GiB' + if unit.lower() == UNITS_B.lower(): + return int(round(value_to_convert)) + elif unit.lower() == UNITS_KB.lower(): + value_converted = value_to_convert * 1000 + return int(round(value_converted)) + elif unit.lower() == UNITS_MB.lower(): + value_converted = value_to_convert * 1000 * 1000 + return int(round(value_converted)) + elif unit.lower() == UNITS_MiB.lower(): + value_converted = value_to_convert * 1024 * 1024 + return int(round(value_converted)) + elif unit.lower() == UNITS_GiB.lower(): + value_converted = value_to_convert * 1024 * 1024 * 1024 + return int(round(value_converted)) + + def create_docker_dict(self, dict_list): + dockerdict = {} + for row in dict_list[0:]: + cid = row.get('CONTAINER ID') + if cid: + key = 'DOCKER_STATS|' + str(cid) + dockerdict[key] = {} + dockerdict[key]['NAME'] = row.get('NAME') + + splitcol = row.get('CPU %') + cpu = re.split("%", str(splitcol)) + dockerdict[key]['CPU%'] = str(cpu[0]) + + splitcol = row.get('MEM USAGE / LIMIT') + memuse = re.split(" / ", str(splitcol)) + # converting MiB and GiB to bytes + dockerdict[key]['MEM_BYTES'] = str(self.convert_to_bytes(memuse[0])) + dockerdict[key]['MEM_LIMIT_BYTES'] = str(self.convert_to_bytes(memuse[1])) + + splitcol = row.get('MEM %') + mem = re.split("%", str(splitcol)) + dockerdict[key]['MEM%'] = str(mem[0]) + + splitcol = row.get('NET I/O') + netio = re.split(" / ", str(splitcol)) + dockerdict[key]['NET_IN_BYTES'] = str(self.convert_to_bytes(netio[0])) + dockerdict[key]['NET_OUT_BYTES'] = str(self.convert_to_bytes(netio[1])) + + splitcol = row.get('BLOCK I/O') + blockio = re.split(" / ", str(splitcol)) + dockerdict[key]['BLOCK_IN_BYTES'] = str(self.convert_to_bytes(blockio[0])) + dockerdict[key]['BLOCK_OUT_BYTES'] = str(self.convert_to_bytes(blockio[1])) + + dockerdict[key]['PIDS'] = row.get('PIDS') + return dockerdict + + def update_dockerstats_command(self): + cmd = "docker stats --no-stream -a" + data = self.run_command(cmd) + if not data: + log_error("'{}' returned null output".format(cmd)) + return False + dockerdata = self.format_docker_cmd_output(data) + if not dockerdata: + log_error("formatting for docker output failed") + return False + # wipe out all data from state_db before updating + self.state_db.delete_all_by_pattern('STATE_DB', 'DOCKER_STATS|*') + for k1,v1 in dockerdata.iteritems(): + for k2,v2 in v1.iteritems(): + self.update_state_db(k1, k2, v2) + return True + + def update_processstats_command(self): + data = self.run_command("ps -eo uid,pid,ppid,%mem,%cpu,stime,tty,time,cmd --sort -%cpu | head -1024") + processdata = self.format_process_cmd_output(data) + value = "" + # wipe out all data before updating with new values + self.state_db.delete_all_by_pattern('STATE_DB', 'PROCESS_STATS|*') + for row in processdata[0:]: + cid = row.get('PID') + if cid: + value = 'PROCESS_STATS|' + str(cid) + uid = row.get('UID') + self.update_state_db(value, 'UID', uid) + ppid = row.get('PPID') + self.update_state_db(value, 'PPID', ppid) + cpu = row.get('%CPU') + self.update_state_db(value, '%CPU', str(cpu)) + mem = row.get('%MEM') + self.update_state_db(value, '%MEM', str(mem)) + stime = row.get('STIME') + self.update_state_db(value, 'STIME', stime) + tty = row.get('TT') + self.update_state_db(value, 'TT', tty) + time = row.get('TIME') + self.update_state_db(value, 'TIME', time) + cmd = row.get('CMD') + self.update_state_db(value, 'CMD', cmd) + + def update_state_db(self, key1, key2, value2): + self.state_db.set('STATE_DB', key1, key2, value2) + + def run(self): + self.update_dockerstats_command() + datetimeobj = datetime.now() + # Adding key to store latest update time. + self.update_state_db('DOCKER_STATS|LastUpdateTime', 'lastupdate', datetimeobj) + self.update_processstats_command() + self.update_state_db('PROCESS_STATS|LastUpdateTime', 'lastupdate', datetimeobj) + +# main start +def main(): + log_info("process-docker stats daemon starting up..") + if not os.getuid() == 0: + log_error("Must be root to run process-docker daemon") + print "Error: Must be root to run process-docker daemon" + sys.exit(1) + pd = ProcDockerStats() + # Data need to be updated every 2 mins. hence adding delay of 120 seconds + while True: + pd.run() + time.sleep(120) + log_info("process-docker stats daemon exited") + +if __name__ == '__main__': + main() + diff --git a/files/image_config/procdockerstatsd/procdockerstatsd.service b/files/image_config/procdockerstatsd/procdockerstatsd.service new file mode 100644 index 000000000000..4e38c350a577 --- /dev/null +++ b/files/image_config/procdockerstatsd/procdockerstatsd.service @@ -0,0 +1,13 @@ +[Unit] +Description=Process and docker CPU/memory utilization data export daemon +Requires=database.service updategraph.service +After=database.service updategraph.service + +[Service] +Type=simple +ExecStart=/usr/bin/procdockerstatsd +Restart=Always + +[Install] +WantedBy=multi-user.target + From 5b18aa5f4d3e6685707c575031042283173fdb33 Mon Sep 17 00:00:00 2001 From: Arun Saravanan Balachandran <52521751+ArunSaravananBalachandran@users.noreply.github.com> Date: Fri, 29 Nov 2019 04:11:58 +0530 Subject: [PATCH 210/278] DellEMC: Skip starting 'ledd' in pmon in DellEMC platforms (#3762) --- .../dell/x86_64-dell_s6000_s1220-r0/pmon_daemon_control.json | 3 +++ .../dell/x86_64-dell_s6100_c2538-r0/pmon_daemon_control.json | 3 +++ .../dell/x86_64-dell_z9100_c2538-r0/pmon_daemon_control.json | 3 +++ .../x86_64-dellemc_s5232f_c3538-r0/pmon_daemon_control.json | 3 +++ .../x86_64-dellemc_s5248f_c3538-r0/pmon_daemon_control.json | 3 +++ .../x86_64-dellemc_z9264f_c3538-r0/pmon_daemon_control.json | 3 +++ 6 files changed, 18 insertions(+) create mode 100644 device/dell/x86_64-dell_s6000_s1220-r0/pmon_daemon_control.json create mode 100644 device/dell/x86_64-dell_s6100_c2538-r0/pmon_daemon_control.json create mode 100644 device/dell/x86_64-dell_z9100_c2538-r0/pmon_daemon_control.json create mode 100644 device/dell/x86_64-dellemc_s5232f_c3538-r0/pmon_daemon_control.json create mode 100644 device/dell/x86_64-dellemc_s5248f_c3538-r0/pmon_daemon_control.json create mode 100644 device/dell/x86_64-dellemc_z9264f_c3538-r0/pmon_daemon_control.json diff --git a/device/dell/x86_64-dell_s6000_s1220-r0/pmon_daemon_control.json b/device/dell/x86_64-dell_s6000_s1220-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..94592fa8cebc --- /dev/null +++ b/device/dell/x86_64-dell_s6000_s1220-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} diff --git a/device/dell/x86_64-dell_s6100_c2538-r0/pmon_daemon_control.json b/device/dell/x86_64-dell_s6100_c2538-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..94592fa8cebc --- /dev/null +++ b/device/dell/x86_64-dell_s6100_c2538-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} diff --git a/device/dell/x86_64-dell_z9100_c2538-r0/pmon_daemon_control.json b/device/dell/x86_64-dell_z9100_c2538-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..94592fa8cebc --- /dev/null +++ b/device/dell/x86_64-dell_z9100_c2538-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} diff --git a/device/dell/x86_64-dellemc_s5232f_c3538-r0/pmon_daemon_control.json b/device/dell/x86_64-dellemc_s5232f_c3538-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..94592fa8cebc --- /dev/null +++ b/device/dell/x86_64-dellemc_s5232f_c3538-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/pmon_daemon_control.json b/device/dell/x86_64-dellemc_s5248f_c3538-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..94592fa8cebc --- /dev/null +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} diff --git a/device/dell/x86_64-dellemc_z9264f_c3538-r0/pmon_daemon_control.json b/device/dell/x86_64-dellemc_z9264f_c3538-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..94592fa8cebc --- /dev/null +++ b/device/dell/x86_64-dellemc_z9264f_c3538-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} From 7a3e4972d10e6a484bf6db799b7aa212c8b7a6c4 Mon Sep 17 00:00:00 2001 From: Andriy Kokhan <43479230+akokhan@users.noreply.github.com> Date: Sat, 30 Nov 2019 21:42:28 +0200 Subject: [PATCH 211/278] [barefoot][as9516] Updated Newport configuration (#3797) - Updated buffers config; - Set eth2 as CPU port; - Added systemd service file to load bf_fpga.ko Signed-off-by: Andriy Kokhan --- .../newport/buffers_defaults_t0.j2 | 10 +++++----- .../newport/buffers_defaults_t1.j2 | 10 +++++----- .../newport/switch-tna-sai.conf | 3 ++- .../configs/network/interfaces.d/eth2 | 4 ++++ .../configs/systemd/system/bfn-newport.service | 14 ++++++++++++++ .../debian/install | 1 + .../debian/postinst | 6 ++++++ 7 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/configs/network/interfaces.d/eth2 create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/configs/systemd/system/bfn-newport.service create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/debian/install create mode 100644 platform/barefoot/sonic-platform-modules-bfn-newport/debian/postinst diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t0.j2 b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t0.j2 index 199f4ad135fb..33698097285e 100644 --- a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t0.j2 +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t0.j2 @@ -1,8 +1,8 @@ {% set default_cable = '5m' %} -{% set ingress_lossless_pool_size = '4194304' %} -{% set ingress_lossy_pool_size = '7340032' %} -{% set egress_lossless_pool_size = '16777152' %} -{% set egress_lossy_pool_size = '7340032' %} +{% set ingress_lossless_pool_size = '23850816' %} +{% set ingress_lossy_pool_size = '36222208' %} +{% set egress_lossless_pool_size = '29482816' %} +{% set egress_lossy_pool_size = '26400000' %} {%- macro generate_port_lists(PORT_ALL) %} {# Generate list of ports #} @@ -17,7 +17,7 @@ "size": "{{ ingress_lossless_pool_size }}", "type": "ingress", "mode": "dynamic", - "xoff": "2867200" + "xoff": "36222208" }, "ingress_lossy_pool": { "size": "{{ ingress_lossy_pool_size }}", diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t1.j2 b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t1.j2 index 01f50a4419e9..33698097285e 100644 --- a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t1.j2 +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/buffers_defaults_t1.j2 @@ -1,8 +1,8 @@ {% set default_cable = '5m' %} -{% set ingress_lossless_pool_size = '2097152' %} -{% set ingress_lossy_pool_size = '5242880' %} -{% set egress_lossless_pool_size = '16777152' %} -{% set egress_lossy_pool_size = '5242880' %} +{% set ingress_lossless_pool_size = '23850816' %} +{% set ingress_lossy_pool_size = '36222208' %} +{% set egress_lossless_pool_size = '29482816' %} +{% set egress_lossy_pool_size = '26400000' %} {%- macro generate_port_lists(PORT_ALL) %} {# Generate list of ports #} @@ -17,7 +17,7 @@ "size": "{{ ingress_lossless_pool_size }}", "type": "ingress", "mode": "dynamic", - "xoff": "2867200" + "xoff": "36222208" }, "ingress_lossy_pool": { "size": "{{ ingress_lossy_pool_size }}", diff --git a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/switch-tna-sai.conf b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/switch-tna-sai.conf index cf6e445dba1a..ca838c1bb5da 100644 --- a/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/switch-tna-sai.conf +++ b/device/barefoot/x86_64-accton_as9516bf_32d-r0/newport/switch-tna-sai.conf @@ -32,7 +32,8 @@ "bfrt-config": "share/switch/bf-rt.json", "model_json_path" : "share/switch/aug_model.json", "switchapi_port_add": false, - "non_default_port_ppgs": 5 + "non_default_port_ppgs": 5, + "cpu_port": "eth2" } ] } diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/configs/network/interfaces.d/eth2 b/platform/barefoot/sonic-platform-modules-bfn-newport/configs/network/interfaces.d/eth2 new file mode 100644 index 000000000000..725bc89e0ebb --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/configs/network/interfaces.d/eth2 @@ -0,0 +1,4 @@ +# eth cpu port +auto eth2 +iface eth2 inet +up ifconfig eth2 promisc mtu 9000 diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/configs/systemd/system/bfn-newport.service b/platform/barefoot/sonic-platform-modules-bfn-newport/configs/systemd/system/bfn-newport.service new file mode 100644 index 000000000000..9d6ca1271e85 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/configs/systemd/system/bfn-newport.service @@ -0,0 +1,14 @@ +[Unit] +Description=Barefoot Newport FPGA driver +Before=syncd.service + +[Service] +User=root +ExecStartPre=/sbin/depmod -a +ExecStart=/sbin/modprobe bf_fpga +ExecStartPost=/sbin/modprobe bf_tun +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target + diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/debian/install b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/install new file mode 100644 index 000000000000..7cb6ed7fe336 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/install @@ -0,0 +1 @@ +configs/systemd/system/bfn-newport.service etc/systemd/system diff --git a/platform/barefoot/sonic-platform-modules-bfn-newport/debian/postinst b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/postinst new file mode 100644 index 000000000000..a89ac4f4f5b2 --- /dev/null +++ b/platform/barefoot/sonic-platform-modules-bfn-newport/debian/postinst @@ -0,0 +1,6 @@ +#!/bin/sh +set -e +depmod -a +systemctl enable bfn-newport.service +systemctl start bfn-newport.service +#DEBHELPER# From 558292f462d37f03718e5f08968bd739214fe0df Mon Sep 17 00:00:00 2001 From: Dong Zhang <41927498+dzhangalibaba@users.noreply.github.com> Date: Sun, 1 Dec 2019 11:19:22 -0800 Subject: [PATCH 212/278] [sonic-utilities] submodule update for sonic-utilities (#3825) update multiDB changes in sonic-utilities, including earlier commit by others as well: - [multiDB]: all application should use API to get redis_client (#753) - [VRF]: submit vrf CLI #392 (#558) - [show] Add 'features' subcommand to display status for optional features (#712) - [neighbor_advertiser] Adds initial support for HTTPS to neighbor advertiser (#750) after this update , we are able to update sonic-py-swsssdk submodule without hitting error as before. Signed-off-by: Dong Zhang d.zhang@alibaba-inc.com --- src/sonic-utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-utilities b/src/sonic-utilities index 587e630ace4f..1898102cf2c3 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit 587e630ace4f5e6d2df1d0fbfa112aef19283d3a +Subproject commit 1898102cf2c399ebf2360c461297b0ac9fae98e4 From f0a3d85ec2b50cc9fa785340bdbaf601aabe97ac Mon Sep 17 00:00:00 2001 From: lguohan Date: Mon, 2 Dec 2019 10:27:35 -0800 Subject: [PATCH 213/278] [submodule]: update sonic-sairedis (#3833) * 27a93ff 2019-11-25 | Don't learn fdb entries on LAG when rif based (#538) [Kamil Cudnik] * 5ef1764 2019-11-22 | Changes in sonic-sairedis repo to support the NAT feature. (#519) [Kiran Kumar Kella] Signed-off-by: Guohan Lu --- src/sonic-sairedis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 533749062f63..27a93ff0d5f0 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 533749062f638f74ebc09c4bd0a5162b2c575564 +Subproject commit 27a93ff0d5f0e5fae74c2ef6b78258ad89a066a8 From eff9d868725c813635b4399b64d916b2c7f1f03f Mon Sep 17 00:00:00 2001 From: Dong Zhang <41927498+dzhangalibaba@users.noreply.github.com> Date: Mon, 2 Dec 2019 14:20:35 -0800 Subject: [PATCH 214/278] [swsssdk-py] update submodule for sonic-py-swsssdk (#3826) update multiDB changes in sonic-py-swsssdk, including: *[multi-DB] Part 4: add sonic-db-cli to replace redis-cli (#54) *[multi-DB] Part 3: Python API changes (#52) *remove SonicV2Connector which is not used any more (#53) This needs #3825 to be merged first. Otherwise when reloading minigraph/config will hit error. Signed-off-by: Dong Zhang d.zhang@alibaba-inc.com --- src/sonic-py-swsssdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-py-swsssdk b/src/sonic-py-swsssdk index 4cee38534919..bc3964b788c3 160000 --- a/src/sonic-py-swsssdk +++ b/src/sonic-py-swsssdk @@ -1 +1 @@ -Subproject commit 4cee38534919e34f407363ac3ab5f31b4d09be6d +Subproject commit bc3964b788c3a4a45f2b359a5df5934ecdee84c2 From fc36ca6e4586812651677e95cc1fd537f43008e7 Mon Sep 17 00:00:00 2001 From: Ying Xie Date: Mon, 2 Dec 2019 15:54:55 -0800 Subject: [PATCH 215/278] Revert "[swss.sh] When starting, call 'systemctl restart' on dependents, not (#3807)" (#3835) This reverts commit 351410ea8cd7e45be42ab394e138a350c241183a. --- files/scripts/swss.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/files/scripts/swss.sh b/files/scripts/swss.sh index 416075d8b33a..7dde4aecb365 100755 --- a/files/scripts/swss.sh +++ b/files/scripts/swss.sh @@ -85,9 +85,7 @@ start_peer_and_dependent_services() { if [[ x"$WARM_BOOT" != x"true" ]]; then /bin/systemctl start ${PEER} for dep in ${DEPENDENT}; do - # Here we call `systemctl restart` on each dependent service instead of `systemctl start` to - # ensure the services actually get stopped and started in case they were not previously stopped. - /bin/systemctl restart ${dep} + /bin/systemctl start ${dep} done fi } From d3e544e7ba31ddc56804a2b22b157d5c12eec1b2 Mon Sep 17 00:00:00 2001 From: Joe LeVeque Date: Tue, 3 Dec 2019 08:32:50 -0800 Subject: [PATCH 216/278] [sonic-utilities] Update submodule (#3829) [config] Add 'feature' subcommand (#746) Fix a bug in idempotent check. (#755) --- src/sonic-utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-utilities b/src/sonic-utilities index 1898102cf2c3..08169487110a 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit 1898102cf2c399ebf2360c461297b0ac9fae98e4 +Subproject commit 08169487110a95152d2e52dc0f2584f6e3b16579 From 100d67941a42a5ff1452c4e8085c5a8f7c73a0c3 Mon Sep 17 00:00:00 2001 From: Joe LeVeque Date: Tue, 3 Dec 2019 09:50:49 -0800 Subject: [PATCH 217/278] [services] sflow service sets swss service as Requisite=, not Requires= (#3819) The sflow service should not start unless the swss service is started. However, if this service is not started, the sflow service should not attempt to start them, instead it should simply fail to start. Using Requisite=, we will achieve this behavior, whereas using Requires= will cause the required service to be started. --- files/build_templates/sflow.service.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/build_templates/sflow.service.j2 b/files/build_templates/sflow.service.j2 index de08f027adff..643bf646964d 100644 --- a/files/build_templates/sflow.service.j2 +++ b/files/build_templates/sflow.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=sFlow container -Requires=swss.service +Requisite=swss.service After=swss.service syncd.service Before=ntp-config.service StartLimitIntervalSec=1200 From 343ad789316700b0d3994e894675fd8ff1f1c793 Mon Sep 17 00:00:00 2001 From: Arun Saravanan Balachandran <52521751+ArunSaravananBalachandran@users.noreply.github.com> Date: Wed, 4 Dec 2019 00:06:41 +0530 Subject: [PATCH 218/278] DellEMC : Platform2.0 API Implementation [S6100, S6000, Z9100] (#3740) --- .../common/dell_pmc.c | 36 +++++++++----- .../s6000/sonic_platform/chassis.py | 14 +++--- .../s6000/sonic_platform/eeprom.py | 25 +++++++--- .../s6000/sonic_platform/fan.py | 44 +++++++++++++---- .../s6000/sonic_platform/psu.py | 3 ++ .../s6100/scripts/platform_sensors.py | 8 ++-- .../s6100/scripts/s6100_platform.sh | 24 +++++++++- .../s6100/sonic_platform/chassis.py | 15 +++--- .../s6100/sonic_platform/eeprom.py | 27 ++++++++--- .../s6100/sonic_platform/fan.py | 48 ++++++++++++++----- .../s6100/sonic_platform/module.py | 13 ++--- .../z9100/scripts/platform_sensors.py | 8 ++-- .../z9100/sonic_platform/chassis.py | 14 +++--- .../z9100/sonic_platform/fan.py | 48 ++++++++++++++----- 14 files changed, 233 insertions(+), 94 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c b/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c index 7c258cdfeab7..e8cddf4fad11 100644 --- a/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c +++ b/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c @@ -631,7 +631,7 @@ static ssize_t show_fan(struct device *dev, ret = smf_read_reg16(data, PSU_2_FAN_SPEED); break; case 12: - ret = ~smf_read_reg(data, FAN_TRAY_PRESENCE); + ret = (~smf_read_reg(data, FAN_TRAY_PRESENCE) & 0xff); export_hex = 1; break; @@ -682,14 +682,26 @@ static ssize_t show_fan_alarm(struct device *dev, struct smf_data *data = dev_get_drvdata(dev); int ret, psu_fan_status=0; - if(index < 2) - psu_fan_status = smf_read_reg(data, FAN_STATUS_GROUP_B); + if (data->kind == z9100smf) { + if ((index % 2) == 0) + index = index / 2; + else + index = (index / 2) + 5; + } + + if (data->kind == s6100smf) + index = index / 2; + + if (index > 7) { + psu_fan_status = ~smf_read_reg(data, FAN_STATUS_GROUP_A); + index = index % 8; + } else + psu_fan_status = ~smf_read_reg(data, FAN_STATUS_GROUP_B); if (psu_fan_status & (1 << (index))) ret=0; - - if (ret < 0) - return ret; + else + ret=1; return sprintf(buf, "%d\n", ret); } @@ -726,12 +738,12 @@ static ssize_t show_psu_fan(struct device *dev, if (index < FAN_601_FAULT){ fan_status = smf_read_reg(data, PSU_1_FAN_STATUS); - ret = fan_status & (1 << index); + ret = (fan_status >> index) & 1; } else{ fan_status = smf_read_reg(data, PSU_2_FAN_STATUS); - ret = fan_status & (1 << (index - 3)); + ret = (fan_status >> (index - 3)) & 1; } if (ret < 0) @@ -1319,17 +1331,15 @@ static ssize_t show_current(struct device *dev, else ret = smf_read_reg16(data, SWITCH_CURRENT_Z9100 + index * 2); else if (index < CURR602_INPUT) - curr = smf_read_reg16(data, PSU_1_INPUT_CURRENT + (index % 4) * 2); + ret = smf_read_reg16(data, PSU_1_INPUT_CURRENT + (index % 2) * 2); else - curr = smf_read_reg16(data, PSU_2_INPUT_CURRENT + (index % 4) * 2); + ret = smf_read_reg16(data, PSU_2_INPUT_CURRENT + (index % 4) * 2); if (ret < 0) return ret; - /* TODO: docs say 10mA, value look like A? */ - if(index < 2) - curr = ret*1000; + curr = ret*10; return sprintf(buf, "%d\n", curr); } diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/chassis.py index 005fdd15b269..c212df88c147 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/chassis.py @@ -65,7 +65,7 @@ def __init__(self): # Get Transceiver status self.modprs_register = self._get_transceiver_status() - self.sys_eeprom = Eeprom() + self._eeprom = Eeprom() for i in range(MAX_S6000_FAN): fan = Fan(i) self._fan_list.append(fan) @@ -105,7 +105,7 @@ def get_name(self): Returns: string: The name of the chassis """ - return self.sys_eeprom.modelstr() + return self._eeprom.modelstr() def get_presence(self): """ @@ -121,7 +121,7 @@ def get_model(self): Returns: string: Model/part number of chassis """ - return self.sys_eeprom.part_number_str() + return self._eeprom.part_number_str() def get_serial(self): """ @@ -129,7 +129,7 @@ def get_serial(self): Returns: string: Serial number of chassis """ - return self.sys_eeprom.serial_str() + return self._eeprom.serial_str() def get_status(self): """ @@ -148,7 +148,7 @@ def get_base_mac(self): A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ - return self.sys_eeprom.base_mac_addr() + return self._eeprom.base_mac_addr() def get_serial_number(self): """ @@ -158,7 +158,7 @@ def get_serial_number(self): A string containing the hardware serial number for this chassis. """ - return self.sys_eeprom.serial_number_str() + return self._eeprom.serial_number_str() def get_system_eeprom_info(self): """ @@ -170,7 +170,7 @@ def get_system_eeprom_info(self): OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ - return self.sys_eeprom.system_eeprom_info() + return self._eeprom.system_eeprom_info() def get_reboot_cause(self): """ diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/eeprom.py index 3d824ba28268..32462e5a256e 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/eeprom.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/eeprom.py @@ -28,14 +28,15 @@ psu_eeprom_format = [ ('PPID', 's', 20), ('DPN Rev', 's', 3), ('Service Tag', 's', 7), ('Part Number', 's', 10), ('Part Num Revision', 's', 3), - ('Mfg Test', 's', 2), ('PSU Type', 's', 1), ('Fab Rev', 's', 2) + ('Mfg Test', 's', 2), ('Redundant copy', 's', 83), ('PSU Type', 's', 1), + ('Fab Rev', 's', 2) ] # Fan eeprom fields in format required by EepromDecoder fan_eeprom_format = [ ('PPID', 's', 20), ('DPN Rev', 's', 3), ('Service Tag', 's', 7), ('Part Number', 's', 10), ('Part Num Revision', 's', 3), - ('Mfg Test', 's', 2), ('Redundant copy', 's', 82), + ('Mfg Test', 's', 2), ('Redundant copy', 's', 83), ('Number of Fans', 's', 1), ('Fan Type', 's', 1), ('Fab Rev', 's', 2) ] @@ -168,11 +169,18 @@ def _load_device_eeprom(self): else: self.part_number = 'NA' - (valid, data) = self._get_eeprom_field("Fan Type") - if valid: - self.fan_type = data + if self.is_psu_eeprom: + (valid, data) = self._get_eeprom_field("PSU Type") + if valid: + self.psu_type = data + else: + self.psu_type = 'NA' else: - self.fan_type = 'NA' + (valid, data) = self._get_eeprom_field("Fan Type") + if valid: + self.fan_type = data + else: + self.fan_type = 'NA' def _get_eeprom_field(self, field_name): """ @@ -204,7 +212,10 @@ def airflow_fan_type(self): """ Returns the airflow fan type. """ - return int(self.fan_type.encode('hex'), 16) + if self.is_psu_eeprom: + return int(self.psu_type.encode('hex'), 16) + else: + return int(self.fan_type.encode('hex'), 16) # System EEPROM specific methods def base_mac_addr(self): diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/fan.py index 3350b4818401..29555b443a22 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/fan.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/fan.py @@ -17,6 +17,7 @@ raise ImportError(str(e) + "- required module not found") +MAX_S6000_PSU_FAN_SPEED = 18000 MAX_S6000_FAN_SPEED = 19000 @@ -26,12 +27,12 @@ class Fan(FanBase): CPLD_DIR = "/sys/devices/platform/dell-s6000-cpld.0/" I2C_DIR = "/sys/class/i2c-adapter/" - def __init__(self, fan_index, psu_fan=False): - # Fan is 1-based in DellEMC platforms - self.index = fan_index + 1 + def __init__(self, fan_index, psu_fan=False, dependency=None): self.is_psu_fan = psu_fan if not self.is_psu_fan: + # Fan is 1-based in DellEMC platforms + self.index = fan_index + 1 self.fan_presence_reg = "fan_prs" self.fan_led_reg = "fan{}_led".format(fan_index) self.get_fan_speed_reg = self.I2C_DIR + "i2c-11/11-0029/" +\ @@ -42,8 +43,13 @@ def __init__(self, fan_index, psu_fan=False): self.max_fan_speed = MAX_S6000_FAN_SPEED self.supported_led_color = ['off', 'green', 'amber'] else: - self.get_fan_speed_reg = self.I2C_DIR + "i2c-1/1-005{}/" +\ - "fan1_input".format(10 - self.index) + self.index = fan_index + self.dependency = dependency + self.get_fan_speed_reg = self.I2C_DIR +\ + "i2c-1/1-005{}/fan1_target".format(10 - self.index) + self.set_fan_speed_reg = self.I2C_DIR +\ + "i2c-1/1-005{}/fan1_target".format(10 - self.index) + self.max_fan_speed = MAX_S6000_PSU_FAN_SPEED def _get_cpld_register(self, reg_name): # On successful read, returns the value read from given @@ -136,6 +142,9 @@ def get_presence(self): bool: True if Fan is present, False if not """ status = False + if self.is_psu_fan: + return self.dependency.get_presence() + fan_presence = self._get_cpld_register(self.fan_presence_reg) if (fan_presence != 'ERR'): fan_presence = int(fan_presence,16) & self.index @@ -151,7 +160,10 @@ def get_model(self): Returns: string: Part number of Fan """ - return self.eeprom.part_number_str() + if not self.is_psu_fan: + return self.eeprom.part_number_str() + else: + return 'NA' def get_serial(self): """ @@ -161,7 +173,10 @@ def get_serial(self): string: Serial number of Fan """ # Sample Serial number format "US-01234D-54321-25A-0123-A00" - return self.eeprom.serial_number_str() + if not self.is_psu_fan: + return self.eeprom.serial_number_str() + else: + return 'NA' def get_status(self): """ @@ -186,8 +201,13 @@ def get_direction(self): A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST depending on fan direction """ - direction = {1: 'FAN_DIRECTION_INTAKE', 2: 'FAN_DIRECTION_EXHAUST'} - fan_direction = self.eeprom.airflow_fan_type() + if self.is_psu_fan: + direction = {1: 'FAN_DIRECTION_EXHAUST', 2: 'FAN_DIRECTION_INTAKE', + 3: 'FAN_DIRECTION_EXHAUST', 4: 'FAN_DIRECTION_INTAKE'} + fan_direction = self.dependency.eeprom.airflow_fan_type() + else: + direction = {1: 'FAN_DIRECTION_EXHAUST', 2: 'FAN_DIRECTION_INTAKE'} + fan_direction = self.eeprom.airflow_fan_type() return direction.get(fan_direction,'NA') @@ -248,7 +268,7 @@ def set_status_led(self, color): Returns: bool: True if set success, False if fail. """ - if color not in self.supported_led_color: + if self.is_psu_fan or (color not in self.supported_led_color): return False if(color == self.STATUS_LED_COLOR_AMBER): color = 'yellow' @@ -266,6 +286,10 @@ def get_status_led(self): Returns: A string, one of the predefined STATUS_LED_COLOR_* strings. """ + if self.is_psu_fan: + # No LED available for PSU Fan + return None + fan_led = self._get_cpld_register(self.fan_led_reg) if (fan_led != 'ERR'): if (fan_led == 'yellow'): diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/psu.py index dfbd2a87eb5d..e2897a78d9fd 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/psu.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/psu.py @@ -13,6 +13,7 @@ import os from sonic_platform_base.psu_base import PsuBase from sonic_platform.eeprom import Eeprom + from sonic_platform.fan import Fan except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -46,6 +47,8 @@ def __init__(self, psu_index): # make it unique per Psu object self._fan_list = [] + self._fan_list.append(Fan(self.index, psu_fan=True, dependency=self)) + def _get_cpld_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/platform_sensors.py index a0231bc507cf..b94b69388300 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/platform_sensors.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/platform_sensors.py @@ -255,8 +255,8 @@ def print_psu(psu): psu_fan_present = int(get_pmc_register('fan11_fault')) input_voltage = float(get_pmc_register('in29_input')) / 1000 output_voltage = float(get_pmc_register('in30_input')) / 1000 - input_current = float(get_pmc_register('curr601_input')) / 100 - output_current = float(get_pmc_register('curr602_input')) / 100 + input_current = float(get_pmc_register('curr601_input')) / 1000 + output_current = float(get_pmc_register('curr602_input')) / 1000 input_power = float(get_pmc_register('power1_input')) / 1000000 output_power = float(get_pmc_register('power2_input')) / 1000000 if (input_power != 0): @@ -268,8 +268,8 @@ def print_psu(psu): psu_fan_present = int(get_pmc_register('fan12_fault')) input_voltage = float(get_pmc_register('in31_input')) / 1000 output_voltage = float(get_pmc_register('in32_input')) / 1000 - input_current = float(get_pmc_register('curr701_input')) / 100 - output_current = float(get_pmc_register('curr702_input')) / 100 + input_current = float(get_pmc_register('curr701_input')) / 1000 + output_current = float(get_pmc_register('curr702_input')) / 1000 input_power = float(get_pmc_register('power3_input')) / 1000000 output_power = float(get_pmc_register('power4_input')) / 1000000 if (input_power != 0): diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh index d8b13ca02c1e..8533d9a198e2 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh @@ -54,6 +54,26 @@ sys_eeprom() { esac } +#Attach/Detach eeprom on each IOM +switch_board_eeprom() { + case $1 in + "new_device") + for ((i=14;i<=17;i++)); + do + i2c_config "echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-$i/$1" + done + ;; + "delete_device") + for ((i=14;i<=17;i++)); + do + i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-$i/$1" + done + ;; + *) echo "s6100_platform: switch_board_eeprom : invalid command !" + ;; + esac +} + #Attach/Detach CPLD devices to drivers for each IOM switch_board_cpld() { case $1 in @@ -245,7 +265,7 @@ install_python_api_package() { remove_python_api_package() { rv=$(pip show sonic-platform > /dev/null 2>/dev/null) if [ $? -eq 0 ]; then - rv = $(pip uninstall -y sonic-platform > /dev/null 2>/dev/null) + rv=$(pip uninstall -y sonic-platform > /dev/null 2>/dev/null) fi } @@ -267,6 +287,7 @@ if [[ "$1" == "init" ]]; then cpu_board_mux "new_device" switch_board_mux "new_device" sys_eeprom "new_device" + switch_board_eeprom "new_device" switch_board_cpld "new_device" switch_board_qsfp_mux "new_device" switch_board_sfp "new_device" @@ -280,6 +301,7 @@ elif [[ "$1" == "deinit" ]]; then xcvr_presence_interrupts "disable" switch_board_sfp "delete_device" switch_board_cpld "delete_device" + switch_board_eeprom "delete_device" switch_board_mux "delete_device" sys_eeprom "delete_device" switch_board_qsfp "delete_device" diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py index e39e8480e2c7..ec1848fc8dca 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py @@ -54,10 +54,11 @@ def __init__(self): ChassisBase.__init__(self) # Initialize EEPROM - self.sys_eeprom = Eeprom() + self._eeprom = Eeprom() for i in range(MAX_S6100_MODULE): module = Module(i) self._module_list.append(module) + self._sfp_list.extend(module._sfp_list) for i in range(MAX_S6100_FAN): fan = Fan(i) @@ -107,7 +108,7 @@ def get_name(self): Returns: string: The name of the chassis """ - return self.sys_eeprom.modelstr() + return self._eeprom.modelstr() def get_presence(self): """ @@ -123,7 +124,7 @@ def get_model(self): Returns: string: Model/part number of chassis """ - return self.sys_eeprom.part_number_str() + return self._eeprom.part_number_str() def get_serial(self): """ @@ -131,7 +132,7 @@ def get_serial(self): Returns: string: Serial number of chassis """ - return self.sys_eeprom.serial_str() + return self._eeprom.serial_str() def get_status(self): """ @@ -150,7 +151,7 @@ def get_base_mac(self): A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ - return self.sys_eeprom.base_mac_addr() + return self._eeprom.base_mac_addr() def get_serial_number(self): """ @@ -160,7 +161,7 @@ def get_serial_number(self): A string containing the hardware serial number for this chassis. """ - return self.sys_eeprom.serial_number_str() + return self._eeprom.serial_number_str() def get_system_eeprom_info(self): """ @@ -170,7 +171,7 @@ def get_system_eeprom_info(self): OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ - return self.sys_eeprom.system_eeprom_info() + return self._eeprom.system_eeprom_info() def get_reboot_cause(self): """ diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/eeprom.py index 4e683e1e511b..8bd900b6c26b 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/eeprom.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/eeprom.py @@ -18,15 +18,26 @@ class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): - def __init__(self): - self.eeprom_path = "/sys/class/i2c-adapter/i2c-2/2-0050/eeprom" + def __init__(self, i2c_line=0, iom_eeprom=False): + self.is_module = iom_eeprom + if self.is_module: + self.eeprom_path = ("/sys/class/i2c-adapter" + "/i2c-{0}/{0}-0050/eeprom").format(i2c_line) + else: + self.eeprom_path = "/sys/class/i2c-adapter/i2c-2/2-0050/eeprom" super(Eeprom, self).__init__(self.eeprom_path, 0, '', True) self.eeprom_tlv_dict = dict() + try: - self.eeprom_data = self.read_eeprom() + if self.is_module: + self.write_eeprom("\x00\x00") + self.eeprom_data = self.read_eeprom_bytes(256) + else: + self.eeprom_data = self.read_eeprom() except: self.eeprom_data = "N/A" - raise RuntimeError("Eeprom is not Programmed") + if not self.is_module: + raise RuntimeError("Eeprom is not Programmed") else: eeprom = self.eeprom_data @@ -76,8 +87,12 @@ def base_mac_addr(self): return ":".join([binascii.b2a_hex(T) for T in results[2]]) def modelstr(self): - (is_valid, results) = self.get_tlv_field( - self.eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if self.is_module: + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_PLATFORM_NAME) + else: + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_PRODUCT_NAME) if not is_valid: return "N/A" diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/fan.py index 2aef71b756e7..a2ee0cd10421 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/fan.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/fan.py @@ -33,6 +33,10 @@ def __init__(self, fantray_index=1, fan_index=1, psu_fan=False): # from 1 self.fantrayindex = fantray_index + 1 self.fanindex = fan_index + 1 + self.fan_presence_reg = "fan{}_fault".format( + 2 * self.fantrayindex - 1) + self.fan_status_reg = "fan{}_alarm".format( + 2 * self.fantrayindex - 1) self.get_fan_speed_reg = "fan{}_input".format( 2 * self.fantrayindex - 1) self.get_fan_dir_reg = "fan{}_airflow".format( @@ -43,7 +47,9 @@ def __init__(self, fantray_index=1, fan_index=1, psu_fan=False): else: # PSU Fan index starts from 11 self.fanindex = fan_index + 10 + self.fan_presence_reg = "fan{}_fault".format(self.fanindex) self.get_fan_speed_reg = "fan{}_input".format(self.fanindex) + self.get_fan_dir_reg = "fan{}_airflow".format(self.fanindex) self.max_fan_speed = MAX_S6100_PSU_FAN_SPEED def _get_pmc_register(self, reg_name): @@ -84,6 +90,9 @@ def get_model(self): """ # For Serial number "US-01234D-54321-25A-0123-A00", the part # number is "01234D" + if self.is_psu_fan: + return 'NA' + fan_serialno = self._get_pmc_register(self.fan_serialno_reg) if (fan_serialno != 'ERR') and self.get_presence(): if (len(fan_serialno.split('-')) > 1): @@ -102,6 +111,9 @@ def get_serial(self): string: Serial number of FAN """ # Sample Serial number format "US-01234D-54321-25A-0123-A00" + if self.is_psu_fan: + return 'NA' + fan_serialno = self._get_pmc_register(self.fan_serialno_reg) if (fan_serialno == 'ERR') or not self.get_presence(): fan_serialno = 'NA' @@ -115,11 +127,11 @@ def get_presence(self): bool: True if fan is present, False if not """ status = False - fantray_presence = self._get_pmc_register(self.get_fan_speed_reg) + fantray_presence = self._get_pmc_register(self.fan_presence_reg) if (fantray_presence != 'ERR'): fantray_presence = int(fantray_presence, 10) - if (fantray_presence > 0): - status = True + if (~fantray_presence & 0b1): + status = True return status @@ -130,11 +142,18 @@ def get_status(self): bool: True if FAN is operating properly, False if not """ status = False - fantray_status = self._get_pmc_register(self.get_fan_speed_reg) - if (fantray_status != 'ERR'): - fantray_status = int(fantray_status, 10) - if (fantray_status > 5000): - status = True + if self.is_psu_fan: + fantray_status = self._get_pmc_register(self.get_fan_speed_reg) + if (fantray_status != 'ERR'): + fantray_status = int(fantray_status, 10) + if (fantray_status > 5000): + status = True + else: + fantray_status = self._get_pmc_register(self.fan_status_reg) + if (fantray_status != 'ERR'): + fantray_status = int(fantray_status, 10) + if (~fantray_status & 0b1): + status = True return status @@ -216,10 +235,17 @@ def get_status_led(self): Returns: A string, one of the predefined STATUS_LED_COLOR_* strings. """ - if self.get_status(): - return self.STATUS_LED_COLOR_GREEN + if self.is_psu_fan: + # No LED available for PSU Fan + return None else: - return self.STATUS_LED_COLOR_OFF + if self.get_presence(): + if self.get_status(): + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_AMBER + else: + return self.STATUS_LED_COLOR_OFF def get_target_speed(self): """ diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/module.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/module.py index 265dc206ad0c..19198098dfd7 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/module.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/module.py @@ -14,6 +14,7 @@ from sonic_platform_base.module_base import ModuleBase from sonic_platform.sfp import Sfp from sonic_platform.component import Component + from sonic_platform.eeprom import Eeprom except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -55,7 +56,7 @@ def __init__(self, module_index): self.port_start = (self.index - 1) * 16 self.port_end = (self.index * 16) - 1 self.port_i2c_line = self.IOM_I2C_MAPPING[self.index] - self.eeprom_tlv_dict = dict() + self._eeprom = Eeprom(iom_eeprom=True, i2c_line=self.port_i2c_line) self.iom_status_reg = "iom_status" self.iom_presence_reg = "iom_presence" @@ -108,7 +109,7 @@ def get_name(self): Returns: string: The name of the device """ - return "IOM{}: 16xQSFP+".format(self.index) + return "IOM{}: {}".format(self.index, self._eeprom.modelstr()) def get_presence(self): """ @@ -133,7 +134,7 @@ def get_model(self): Returns: string: part number of module """ - return 'NA' + return self._eeprom.part_number_str() def get_serial(self): """ @@ -142,7 +143,7 @@ def get_serial(self): Returns: string: Serial number of module """ - return 'NA' + return self._eeprom.serial_str() def get_status(self): """ @@ -178,7 +179,7 @@ def get_serial_number(self): Returns: A string containing the hardware serial number for this module. """ - return 'NA' + return self._eeprom.serial_number_str() def get_system_eeprom_info(self): """ @@ -192,4 +193,4 @@ def get_system_eeprom_info(self): ‘0x24’:’001c0f000fcd0a’, ‘0x25’:’02/03/2018 16:22:00’, ‘0x26’:’01’, ‘0x27’:’REV01’, ‘0x28’:’AG9064-C2358-16G’} """ - return self.eeprom_tlv_dict + return self._eeprom.system_eeprom_info() diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/platform_sensors.py index 76e527e13d73..05cbb3a1a4c1 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/platform_sensors.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/platform_sensors.py @@ -262,8 +262,8 @@ def print_psu(psu): psu_fan_present = int(get_pmc_register('fan11_fault')) input_voltage = float(get_pmc_register('in29_input')) / 1000 output_voltage = float(get_pmc_register('in30_input')) / 1000 - input_current = float(get_pmc_register('curr601_input')) / 100 - output_current = float(get_pmc_register('curr602_input')) /100 + input_current = float(get_pmc_register('curr601_input')) / 1000 + output_current = float(get_pmc_register('curr602_input')) / 1000 input_power = float(get_pmc_register('power1_input')) / 1000000 output_power = float(get_pmc_register('power2_input')) / 1000000 if (input_power != 0): @@ -275,8 +275,8 @@ def print_psu(psu): psu_fan_present = int(get_pmc_register('fan12_fault')) input_voltage = float(get_pmc_register('in31_input')) / 1000 output_voltage = float(get_pmc_register('in32_input')) / 1000 - input_current = float(get_pmc_register('curr701_input')) / 100 - output_current = float(get_pmc_register('curr702_input')) / 100 + input_current = float(get_pmc_register('curr701_input')) / 1000 + output_current = float(get_pmc_register('curr702_input')) / 1000 input_power = float(get_pmc_register('power3_input')) / 1000000 output_power = float(get_pmc_register('power4_input')) / 1000000 if (input_power != 0): diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/chassis.py index 3472bb3e7fb0..27164409d962 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/chassis.py @@ -94,7 +94,7 @@ def __init__(self): ChassisBase.__init__(self) # Initialize EEPROM - self.sys_eeprom = Eeprom() + self._eeprom = Eeprom() for i in range(MAX_Z9100_FANTRAY): for j in range(MAX_Z9100_FAN): fan = Fan(i, j) @@ -137,7 +137,7 @@ def get_name(self): Returns: string: The name of the chassis """ - return self.sys_eeprom.modelstr() + return self._eeprom.modelstr() def get_presence(self): """ @@ -153,7 +153,7 @@ def get_model(self): Returns: string: Model/part number of chassis """ - return self.sys_eeprom.part_number_str() + return self._eeprom.part_number_str() def get_serial(self): """ @@ -161,7 +161,7 @@ def get_serial(self): Returns: string: Serial number of chassis """ - return self.sys_eeprom.serial_str() + return self._eeprom.serial_str() def get_status(self): """ @@ -180,7 +180,7 @@ def get_base_mac(self): A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ - return self.sys_eeprom.base_mac_addr() + return self._eeprom.base_mac_addr() def get_serial_number(self): """ @@ -189,7 +189,7 @@ def get_serial_number(self): Returns: A string containing the hardware serial number for this chassis. """ - return self.sys_eeprom.serial_number_str() + return self._eeprom.serial_number_str() def get_system_eeprom_info(self): """ @@ -200,7 +200,7 @@ def get_system_eeprom_info(self): OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ - return self.sys_eeprom.system_eeprom_info() + return self._eeprom.system_eeprom_info() def get_reboot_cause(self): """ diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/fan.py index ae3c5e9fbcab..03ac8cd5c71f 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/fan.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/fan.py @@ -33,6 +33,10 @@ def __init__(self, fantray_index=1, fan_index=1, psu_fan=False): # from 1 self.fantrayindex = fantray_index + 1 self.fanindex = fan_index + 1 + self.fan_presence_reg = "fan{}_fault".format( + 2 * (self.fantrayindex - 1) + (self.fanindex - 1) + 1 ) + self.fan_status_reg = "fan{}_alarm".format( + 2 * (self.fantrayindex - 1) + (self.fanindex - 1) + 1 ) self.get_fan_speed_reg = "fan{}_input".format( 2 * (self.fantrayindex - 1) + (self.fanindex - 1) + 1 ) self.get_fan_dir_reg = "fan{}_airflow".format( @@ -43,7 +47,9 @@ def __init__(self, fantray_index=1, fan_index=1, psu_fan=False): else: # PSU Fan index starts from 11 self.fanindex = fan_index + 10 + self.fan_presence_reg = "fan{}_fault".format(self.fanindex) self.get_fan_speed_reg = "fan{}_input".format(self.fanindex) + self.get_fan_dir_reg = "fan{}_airflow".format(self.fanindex) self.max_fan_speed = MAX_Z9100_PSU_FAN_SPEED def _get_pmc_register(self, reg_name): @@ -83,6 +89,9 @@ def get_model(self): """ # For Serial number "US-01234D-54321-25A-0123-A00", the part # number is "01234D" + if self.is_psu_fan: + return 'NA' + fan_serialno = self._get_pmc_register(self.fan_serialno_reg) if (fan_serialno != 'ERR') and self.get_presence(): if (len(fan_serialno.split('-')) > 1): @@ -101,6 +110,9 @@ def get_serial(self): string: Serial number of FAN """ # Sample Serial number format "US-01234D-54321-25A-0123-A00" + if self.is_psu_fan: + return 'NA' + fan_serialno = self._get_pmc_register(self.fan_serialno_reg) if (fan_serialno == 'ERR') or not self.get_presence(): fan_serialno = 'NA' @@ -114,11 +126,11 @@ def get_presence(self): bool: True if fan is present, False if not """ status = False - fantray_presence = self._get_pmc_register(self.get_fan_speed_reg) + fantray_presence = self._get_pmc_register(self.fan_presence_reg) if (fantray_presence != 'ERR'): fantray_presence = int(fantray_presence, 10) - if (fantray_presence > 0): - status = True + if (~fantray_presence & 0b1): + status = True return status @@ -129,11 +141,18 @@ def get_status(self): bool: True if FAN is operating properly, False if not """ status = False - fantray_status = self._get_pmc_register(self.get_fan_speed_reg) - if (fantray_status != 'ERR'): - fantray_status = int(fantray_status, 10) - if (fantray_status > 5000): - status = True + if self.is_psu_fan: + fantray_status = self._get_pmc_register(self.get_fan_speed_reg) + if (fantray_status != 'ERR'): + fantray_status = int(fantray_status, 10) + if (fantray_status > 5000): + status = True + else: + fantray_status = self._get_pmc_register(self.fan_status_reg) + if (fantray_status != 'ERR'): + fantray_status = int(fantray_status, 10) + if (~fantray_status & 0b1): + status = True return status @@ -215,10 +234,17 @@ def get_status_led(self): Returns: A string, one of the predefined STATUS_LED_COLOR_* strings. """ - if self.get_status(): - return self.STATUS_LED_COLOR_GREEN + if self.is_psu_fan: + # No LED available for PSU Fan + return None else: - return self.STATUS_LED_COLOR_OFF + if self.get_presence(): + if self.get_status(): + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_AMBER + else: + return self.STATUS_LED_COLOR_OFF def get_target_speed(self): """ From 654bb0eae7c2e17eebda2cf586c3efae8e7d3a03 Mon Sep 17 00:00:00 2001 From: lguohan Date: Tue, 3 Dec 2019 13:54:57 -0800 Subject: [PATCH 219/278] [kvm]: reconnect during kvm installation process (#3837) * [kvm]: reconnect during kvm installation process retry connect every 1 second for 10 maximum times Signed-off-by: Guohan Lu --- check_install.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/check_install.py b/check_install.py index 09979f61e4ba..d95d831daa70 100755 --- a/check_install.py +++ b/check_install.py @@ -24,7 +24,17 @@ def main(): cmd_prompt = "%s@sonic:~\$ $" % args.u grub_selection = "The highlighted entry will be executed" - p = pexpect.spawn("telnet 127.0.0.1 %s" % args.p, timeout=600, logfile=sys.stdout) + i = 0 + while True: + try: + p = pexpect.spawn("telnet 127.0.0.1 %s" % args.p, timeout=600, logfile=sys.stdout) + break + except Exception as e: + print str(e) + i += 1 + if i == 10: + raise + time.sleep(1) # select ONIE embed p.expect(grub_selection) From 3853b31f3cc50a6bf4e53745c2563c268acec9da Mon Sep 17 00:00:00 2001 From: Tony Titus <49417625+tonytitus@users.noreply.github.com> Date: Tue, 3 Dec 2019 13:55:25 -0800 Subject: [PATCH 220/278] [innovium]: Add Innovium Jenkins build (#3820) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 129af89f05d4..1ab18f5e646f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ *master*: +Innovium: [![Innovium](https://sonic-jenkins.westus2.cloudapp.azure.com/job/innovium/job/buildimage-invm-all/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/innovium/job/buildimage-invm-all) Barefoot: [![Barefoot](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-all/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-all) Broadcom: [![Broadcom](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-all/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-all) Mellanox: [![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-all/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-all) @@ -16,6 +17,7 @@ Mellanox: [![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mell VS: [![VS](https://sonic-jenkins.westus2.cloudapp.azure.com/job/vs/job/buildimage-vs-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/vs/job/buildimage-vs-201904) *201811*: +Innovium: [![Innovium](https://sonic-jenkins.westus2.cloudapp.azure.com/job/innovium/job/buildimage-invm-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/innovium/job/buildimage-invm-201811/) Broadcom: [![Broadcom](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201811/) Barefoot: [![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201811/) Centec: [![Centec](https://sonic-jenkins.westus2.cloudapp.azure.com/job/centec/job/buildimage-centec-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/centec/job/buildimage-centec-201811/) From eec594adf207aec69b255f58ea86075c8be729e4 Mon Sep 17 00:00:00 2001 From: rajendra-dendukuri <47423477+rajendra-dendukuri@users.noreply.github.com> Date: Wed, 4 Dec 2019 07:50:56 -0500 Subject: [PATCH 221/278] [sonic-ztp]: Build sonic-ztp package (#3299) * Build sonic-ztp package - Add changes in make rules to conditionally include sonic-ztp package Signed-off-by: Rajendra Dendukuri --- Makefile.work | 2 ++ files/build_templates/sonic_debian_extension.j2 | 6 ++++++ rules/config | 3 +++ rules/sonic-ztp.mk | 17 +++++++++++++++++ slave.mk | 3 +++ 5 files changed, 31 insertions(+) create mode 100644 rules/sonic-ztp.mk diff --git a/Makefile.work b/Makefile.work index b81ac591246f..71175d5c4757 100644 --- a/Makefile.work +++ b/Makefile.work @@ -7,6 +7,7 @@ # * BUILD_NUMBER: Desired version-number to pass to the building-system. # * ENABLE_DHCP_GRAPH_SERVICE: Enables get-graph service to fetch minigraph files # through http. +# * ENABLE_ZTP: Enables zero touch provisioning. # * SHUTDOWN_BGP_ON_START: Sets admin-down state for all bgp peerings after restart. # * ENABLE_PFCWD_ON_START: Enable PFC Watchdog (PFCWD) on server-facing ports # * by default for TOR switch. @@ -162,6 +163,7 @@ SONIC_BUILD_INSTRUCTION := make \ BUILD_NUMBER=$(BUILD_NUMBER) \ BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) \ ENABLE_DHCP_GRAPH_SERVICE=$(ENABLE_DHCP_GRAPH_SERVICE) \ + ENABLE_ZTP=$(ENABLE_ZTP) \ SHUTDOWN_BGP_ON_START=$(SHUTDOWN_BGP_ON_START) \ SONIC_ENABLE_PFCWD_ON_START=$(ENABLE_PFCWD_ON_START) \ SONIC_ENABLE_SYNCD_RPC=$(ENABLE_SYNCD_RPC) \ diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index f62ef44f0fc0..58ebf24bdf7c 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -141,6 +141,12 @@ sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install tabulat sudo dpkg --root=$FILESYSTEM_ROOT -i $python_debs_path/python-sonic-utilities_*.deb || \ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f +{% if enable_ztp == "y" %} +# Install ZTP (and its dependencies via 'apt-get -y install -f') +sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/sonic-ztp_*.deb || \ + sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f +{% endif %} + # SONiC utilities installs bash-completion as a dependency. However, it is disabled by default # in bash.bashrc, so we copy a version of the file with it enabled here. sudo cp -f $IMAGE_CONFIGS/bash/bash.bashrc $FILESYSTEM_ROOT/etc/ diff --git a/rules/config b/rules/config index 04af59ccd818..c158fcc27726 100644 --- a/rules/config +++ b/rules/config @@ -44,6 +44,9 @@ DEFAULT_PASSWORD = YourPaSsWoRd # If not set (default behavior) the default minigraph built into the image will be used. # ENABLE_DHCP_GRAPH_SERVICE = y +# ENABLE_ZTP - installs Zero Touch Provisioning support. +# ENABLE_ZTP = y + # SHUTDOWN_BGP_ON_START - if set to y all bgp sessions will be in admin down state when # bgp service starts. # SHUTDOWN_BGP_ON_START = y diff --git a/rules/sonic-ztp.mk b/rules/sonic-ztp.mk new file mode 100644 index 000000000000..43615b7dcc8a --- /dev/null +++ b/rules/sonic-ztp.mk @@ -0,0 +1,17 @@ +# SONiC ztp package +# + +ifeq ($(ENABLE_ZTP), y) + +SONIC_ZTP_VERSION = 1.0.0 + +SONIC_ZTP = sonic-ztp_$(SONIC_ZTP_VERSION)_all.deb +$(SONIC_ZTP)_SRC_PATH = $(SRC_PATH)/sonic-ztp +SONIC_DPKG_DEBS += $(SONIC_ZTP) +SONIC_STRETCH_DEBS += $(SONIC_ZTP) + +export SONIC_ZTP_VERSION +export SONIC_ZTP + +endif + diff --git a/slave.mk b/slave.mk index f81895f74dd2..e518f1e4d8a5 100644 --- a/slave.mk +++ b/slave.mk @@ -190,6 +190,7 @@ $(info "ENABLE_ORGANIZATION_EXTENSIONS" : "$(ENABLE_ORGANIZATION_EXTENSIONS)") $(info "HTTP_PROXY" : "$(HTTP_PROXY)") $(info "HTTPS_PROXY" : "$(HTTPS_PROXY)") $(info "ENABLE_SYSTEM_TELEMETRY" : "$(ENABLE_SYSTEM_TELEMETRY)") +$(info "ENABLE_ZTP" : "$(ENABLE_ZTP)") $(info "SONIC_DEBUGGING_ON" : "$(SONIC_DEBUGGING_ON)") $(info "SONIC_PROFILING_ON" : "$(SONIC_PROFILING_ON)") $(info "KERNEL_PROCURE_METHOD" : "$(KERNEL_PROCURE_METHOD)") @@ -619,6 +620,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ $(LIBNSS_TACPLUS)) \ $$(addprefix $(TARGET_PATH)/,$$($$*_DOCKERS)) \ $$(addprefix $(FILES_PATH)/,$$($$*_FILES)) \ + $(if $(findstring y,$(ENABLE_ZTP)),$(addprefix $(DEBS_PATH)/,$(SONIC_ZTP))) \ $(addprefix $(STRETCH_FILES_PATH)/, $(if $(filter $(CONFIGURED_ARCH),amd64), $(IXGBE_DRIVER))) \ $(addprefix $(PYTHON_DEBS_PATH)/,$(SONIC_UTILS)) \ $(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_CONFIG_ENGINE)) \ @@ -639,6 +641,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ export sonic_asic_platform="$(patsubst %-$(CONFIGURED_ARCH),%,$(CONFIGURED_PLATFORM))" export enable_organization_extensions="$(ENABLE_ORGANIZATION_EXTENSIONS)" export enable_dhcp_graph_service="$(ENABLE_DHCP_GRAPH_SERVICE)" + export enable_ztp="$(ENABLE_ZTP)" export shutdown_bgp_on_start="$(SHUTDOWN_BGP_ON_START)" export enable_pfcwd_on_start="$(ENABLE_PFCWD_ON_START)" export installer_debs="$(addprefix $(STRETCH_DEBS_PATH)/,$($*_INSTALLS))" From cda61290ac01d0e3231dad513e5cec4b29e0cf21 Mon Sep 17 00:00:00 2001 From: rajendra-dendukuri <47423477+rajendra-dendukuri@users.noreply.github.com> Date: Wed, 4 Dec 2019 10:15:58 -0500 Subject: [PATCH 222/278] [config-setup]: create a SONiC configuration management service (#3227) * Create a SONiC configuration management service * Perform config db migration after loading config_db.json to redis DB * Migrate config-setup post migration hooks on image upgrade config-setup post migration hooks help user to migrate configurations from old image to new image. If the installed hooks are user defined they will not be part of the newly installed image. So these hooks have to be migrated to new image and only then they can be executing when the new image is booting. The changes in this fix migrate config-setup post-migration hooks and ensure that any hooks with the same filename in newly installed image are not overwritten. It is expected that users install new hooks as per their requirement and not edit existing hooks. Any changes to existing hooks need to be done as part of new image and not post bootup. --- files/build_templates/config-setup.service.j2 | 18 + .../build_templates/sonic_debian_extension.j2 | 5 + files/build_templates/updategraph.service.j2 | 9 +- files/image_config/config-setup/config-setup | 399 ++++++++++++++++++ files/image_config/updategraph/updategraph | 72 +--- 5 files changed, 430 insertions(+), 73 deletions(-) create mode 100644 files/build_templates/config-setup.service.j2 create mode 100755 files/image_config/config-setup/config-setup diff --git a/files/build_templates/config-setup.service.j2 b/files/build_templates/config-setup.service.j2 new file mode 100644 index 000000000000..a4b614a5f7fb --- /dev/null +++ b/files/build_templates/config-setup.service.j2 @@ -0,0 +1,18 @@ +[Unit] +Description=Config initialization and migration service +After=rc-local.service +After=database.service +Requires=database.service +{% if sonic_asic_platform == 'mellanox' -%} +Requires=hw-management.service +{% endif -%} + + +[Service] +Type=oneshot +ExecStart=/usr/bin/config-setup boot +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target + diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index 58ebf24bdf7c..209bc19971b3 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -244,6 +244,11 @@ sudo bash -c "echo '{ \"DEVICE_METADATA\": { \"localhost\": { \"default_bgp_stat \"{{crm_res}}_threshold_type\": \"percentage\", \"{{crm_res}}_low_threshold\": \"70\", \"{{crm_res}}_high_threshold\": \"85\"{% if not loop.last %}, {% endif %} {%- endfor %} } } }' >> $FILESYSTEM_ROOT/etc/sonic/init_cfg.json" +# Copy config-setup script and service file +j2 files/build_templates/config-setup.service.j2 | sudo tee $FILESYSTEM_ROOT/etc/systemd/system/config-setup.service +sudo cp $IMAGE_CONFIGS/config-setup/config-setup $FILESYSTEM_ROOT/usr/bin/config-setup +sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable config-setup.service + # Copy SNMP configuration files sudo cp $IMAGE_CONFIGS/snmp/snmp.yml $FILESYSTEM_ROOT/etc/sonic/ diff --git a/files/build_templates/updategraph.service.j2 b/files/build_templates/updategraph.service.j2 index 8039f42531cd..0e05cbf147d6 100644 --- a/files/build_templates/updategraph.service.j2 +++ b/files/build_templates/updategraph.service.j2 @@ -1,12 +1,7 @@ [Unit] Description=Update minigraph and set configuration based on minigraph -After=rc-local.service -After=database.service -Requires=database.service -{% if sonic_asic_platform == 'mellanox' -%} -Requires=hw-management.service -{% endif -%} - +After=config-setup.service +Requires=config-setup.service [Service] Type=oneshot diff --git a/files/image_config/config-setup/config-setup b/files/image_config/config-setup/config-setup new file mode 100755 index 000000000000..bd497d06b257 --- /dev/null +++ b/files/image_config/config-setup/config-setup @@ -0,0 +1,399 @@ +#!/bin/bash +########################################################################### +# Copyright 2019 Broadcom. The term "Broadcom" refers to Broadcom Inc. # +# and/or its subsidiaries. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# +# See the License for the specific language governing permissions and # +# limitations under the License. # +# # +########################################################################### +# SONiC Configuration Setup # +# # +# This script is used to initialize configuration used # +# by SONiC SWSS. It also performs configuration # +# migration. # +# # +########################################################################### + +# Initialize constants +CONFIG_DB_INDEX=4 +UPDATEGRAPH_CONF=/etc/sonic/updategraph.conf +CONFIG_DB_JSON=/etc/sonic/config_db.json +MINGRAPH_FILE=/etc/sonic/minigraph.xml +TMP_ZTP_CONFIG_DB_JSON=/tmp/ztp_config_db.json +FACTORY_DEFAULT_HOOKS=/etc/config-setup/factory-default-hooks.d +CONFIG_PRE_MIGRATION_HOOKS=/etc/config-setup/config-migration-pre-hooks.d +CONFIG_POST_MIGRATION_HOOKS=/etc/config-setup/config-migration-post-hooks.d +CONFIG_SETUP_VAR_DIR=/var/lib/config-setup +CONFIG_SETUP_PRE_MIGRATION_FLAG=${CONFIG_SETUP_VAR_DIR}/pending_pre_migration +CONFIG_SETUP_POST_MIGRATION_FLAG=${CONFIG_SETUP_VAR_DIR}/pending_post_migration +CONFIG_SETUP_INITIALIZATION_FLAG=${CONFIG_SETUP_VAR_DIR}/pending_initialization + +# Command usage and help +usage() +{ + cat << EOF + Usage: config-setup < backup | boot | factory > + + backup - Take a backup copy of SONiC configuration. + boot - Initialize/migrate SONiC configuration during system boot. + factory - Create factory default SONiC configuration and save it to + to ${CONFIG_DB_JSON}. +EOF +} + +# run given script +run_hook() { + local script="$1" + local exit_status=0 + + if [ -f $script ]; then + # Check hook for syntactical correctness before executing it + /bin/bash -n $script + exit_status=$? + if [ "$exit_status" -eq 0 ]; then + . $script + fi + exit_status=$? + fi + + if [ -n "$exit_status" ] && [ "$exit_status" -ne 0 ]; then + echo "$script returned non-zero exit status $exit_status" + fi + + return $exit_status +} + +# run scripts in given directory +run_hookdir() { + local dir="$1" + local progress_file="$2" + local exit_status=0 + + if [ -d "$dir" ]; then + if [ -n $progress_file ]; then + [ ! -d $(dirname $progress_file) ] && mkdir -p $(dirname $progress_file) + [ ! -e $progress_file ] && run-parts --list $dir > $progress_file + SCRIPT_LIST=$(cat $progress_file) + else + SCRIPT_LIST=$(run-parts --list $dir) + fi + + for script in $SCRIPT_LIST; do + run_hook $script + exit_status=$((exit_status|$?)) + script_name=$(basename $script) + sed -i "/$script_name/d" $progress_file + done + [ -n $progress_file ] && [ "$(cat ${progress_file})" = "" ] && rm -f ${progress_file} + fi + + return $exit_status +} + +# Reload minigraph.xml file on disk +reload_minigraph() +{ + echo "Reloading minigraph..." + if [ ! -f /etc/sonic/init_cfg.json ]; then + echo "{}" > /etc/sonic/init_cfg.json + fi + redis-cli -n $CONFIG_DB_INDEX FLUSHDB + sonic-cfggen -H -m -j /etc/sonic/init_cfg.json --write-to-db + redis-cli -n $CONFIG_DB_INDEX SET "CONFIG_DB_INITIALIZED" "1" + if [ -f /etc/sonic/acl.json ]; then + acl-loader update full /etc/sonic/acl.json + fi + config qos reload + pfcwd start_default + + if [[ -x /usr/bin/db_migrator.py ]]; then + # Set latest version number + /usr/bin/db_migrator.py -o set_version + fi +} + +# Restore SONiC configuration from a backup copy +function copy_config_files_and_directories() +{ + for file_dir in $@; do + if [ -f /etc/sonic/old_config/${file_dir} ] || [ -d /etc/sonic/old_config/${file_dir} ]; then + echo "Copying SONiC configuration ${file_dir} ..." + cp -ar /etc/sonic/old_config/${file_dir} /etc/sonic/ + else + echo "Missing SONiC configuration ${file_dir} ..." + fi + done +} + +# Check if SONiC swich has booted after a warm reboot request +check_system_warm_boot() +{ + SYSTEM_WARM_START=`/usr/bin/redis-cli -n 6 hget "WARM_RESTART_ENABLE_TABLE|system" enable` + # SYSTEM_WARM_START could be empty, always make WARM_BOOT meaningful. + if [[ x"$SYSTEM_WARM_START" == x"true" ]]; then + WARM_BOOT="true" + else + WARM_BOOT="false" + fi +} + +# Check if updategraph service is administratively enabled +updategraph_is_enabled() +{ + rv=1 + if [ -e ${UPDATEGRAPH_CONF} ]; then + updategraph_mode=$(grep enabled ${UPDATEGRAPH_CONF} | head -n 1 | cut -f2 -d=) + [ "${updategraph_mode}" = "true" ] && rv = 0 + fi + return $rv +} + +# Disable updategraph admininistratively +disable_updategraph() +{ + sed -i "/enabled=/d" ${UPDATEGRAPH_CONF} + echo "enabled=false" >> ${UPDATEGRAPH_CONF} +} + +# Check if Zero Touch Provisioning is available and is administratively enabled +ztp_is_enabled() +{ + rv=1 + if [ -e /usr/bin/ztp ]; then + status=$(ztp status -c) + [ "$status" != "0:DISABLED" ] && [ "$status" != "" ] && rv=0 + fi + return $rv +} + +# Load requested SONiC configuration into config DB and initialize it +# Usage: load_config +# +# +load_config() +{ + CONFIG_FILE=${1} + if [ "${CONFIG_FILE}" = "" ]; then + return 1 + fi + + redis-cli -n $CONFIG_DB_INDEX FLUSHDB + sonic-cfggen -j ${CONFIG_FILE} --write-to-db + if [ $? -ne 0 ]; then + return $? + fi + + if [[ -x /usr/bin/db_migrator.py ]]; then + # Migrate the DB to the latest schema version if needed + /usr/bin/db_migrator.py -o migrate + fi + + redis-cli -n $CONFIG_DB_INDEX SET "CONFIG_DB_INITIALIZED" "1" + return 0 +} + + +# Generate requested SONiC configuration and save it as destination file +# Usage: generate_config < factory | ztp > +# +# factory - Create factory default configuration +# ztp - Create Zero Touch Provisioning Configuration +# used for provisioning data discovery. +# +generate_config() +{ + # Collect all information needed to generate configuration + PLATFORM=`sonic-cfggen -H -v DEVICE_METADATA.localhost.platform` + PRESET=(`head -n 1 /usr/share/sonic/device/$PLATFORM/default_sku`) + HW_KEY=${PRESET[0]} + DEFAULT_PRESET=${PRESET[1]} + + # Parse arguments passed + CONFIG_TYPE=$1 + DEST_FILE=$2 + + if [ "$1" = "ztp" ]; then + /usr/lib/ztp/ztp-profile.sh create ${DEST_FILE} + elif [ "$1" = "factory" ]; then + rv=1 + + # Execute config initialization hooks + run_hookdir ${FACTORY_DEFAULT_HOOKS} ${CONFIG_SETUP_INITIALIZATION_FLAG} + + # Use preset defined in default_sku + if [ ! -e ${DEST_FILE} ]; then + sonic-cfggen -H -k ${HW_KEY} --preset ${DEFAULT_PRESET} > ${DEST_FILE} + rv=$? + if [ $rv -ne 0 ]; then + return $rv + fi + fi + fi + return 0 +} + +# Create SONiC configuration for first time bootup +# - If ZTP is enabled, ZTP configuraion is created +# - If ZTP is disabled and updategraph is disabled, factory default configuration +# is created +# - If updategraph is enabled and ZTP is disabled, updategraph initializes +# configuration +do_config_intialization() +{ + if ! updategraph_is_enabled ; then + if ! ztp_is_enabled ; then + echo "No configuration detected, generating factory default configuration..." + generate_config factory ${CONFIG_DB_JSON} + load_config ${CONFIG_DB_JSON} + fi + fi + + if ztp_is_enabled ; then + echo "No configuration detected, initiating zero touch provisioning..." + generate_config ztp ${TMP_ZTP_CONFIG_DB_JSON} + load_config ${TMP_ZTP_CONFIG_DB_JSON} + rm -f ${TMP_ZTP_CONFIG_DB_JSON} + fi + + rm -f /tmp/pending_config_initialization +} + +# Restore config-setup post migration hooks from a backup copy +copy_post_migration_hooks() +{ + BACKUP_DIR=/etc/sonic/old_config/config-migration-post-hooks.d + if [ -d ${BACKUP_DIR} ]; then + [ -d ${CONFIG_POST_MIGRATION_HOOKS} ] || mkdir -p ${CONFIG_POST_MIGRATION_HOOKS} + for hook in $(ls -1 ${BACKUP_DIR}) ; do + if [ ! -e ${CONFIG_POST_MIGRATION_HOOKS}/$hook ]; then + cp -ar ${BACKUP_DIR}/$hook ${CONFIG_POST_MIGRATION_HOOKS} + fi + done + fi +} + +# Perform configuration migration from backup copy. +# - This step is performed when a new image is installed and SONiC switch boots into it +do_config_migration() +{ + # Identify list of files to migrate + copy_list="minigraph.xml snmp.yml acl.json config_db.json frr" + + # Migrate all configuration files from old to new + copy_config_files_and_directories $copy_list + + # Migrate post-migration hooks + copy_post_migration_hooks + + # Execute custom hooks if present + run_hookdir ${CONFIG_POST_MIGRATION_HOOKS} ${CONFIG_SETUP_POST_MIGRATION_FLAG} + + if [ x"${WARM_BOOT}" == x"true" ]; then + echo "Warm reboot detected..." + disable_updategraph + rm -f /tmp/pending_config_migration + exit 0 + elif [ -r ${CONFIG_DB_JSON} ]; then + echo "Use config_db.json from old system..." + sonic-cfggen -j ${CONFIG_DB_JSON} --write-to-db + + if [[ -x /usr/bin/db_migrator.py ]]; then + # Migrate the DB to the latest schema version if needed + /usr/bin/db_migrator.py -o migrate + fi + elif [ -r ${MINGRAPH_FILE} ]; then + echo "Use minigraph.xml from old system..." + reload_minigraph + sonic-cfggen -d --print-data > ${CONFIG_DB_JSON} + + # Disable updategraph + disable_updategraph + else + echo "Didn't found neither config_db.json nor minigraph.xml ..." + fi + + rm -f /tmp/pending_config_migration +} + +# Take a backup of current SONiC configuration +do_config_backup() +{ + echo "Taking backup of curent configuration" + rm -rf /host/old_config + cp -ar /etc/sonic /host/old_config + [ -d ${CONFIG_POST_MIGRATION_HOOKS} ] && cp -arL ${CONFIG_POST_MIGRATION_HOOKS} /host/old_config + + # Execute custom hooks if present + run_hookdir ${CONFIG_PRE_MIGRATION_HOOKS} ${CONFIG_SETUP_PRE_MIGRATION_FLAG} +} + +# Process switch bootup event +# - Check if it is warm boot and take no further action +# - Perform configuration migration if requested +# - Perform configuration initialization if requested +# - If no saved SONiC configuration is found and ZTP is enabled, +# start ZTP +boot_config() +{ + check_system_warm_boot + if [ -e /tmp/pending_config_migration ] || [ -e ${CONFIG_SETUP_POST_MIGRATION_FLAG} ]; then + do_config_migration + fi + + if [ -e /tmp/pending_config_initialization ] || [ -e ${CONFIG_SETUP_INITIALIZATION_FLAG} ]; then + do_config_intialization + fi + + # If no startup configuration is found, create a configuration to be used + if [ ! -e ${CONFIG_DB_JSON} ]; then + do_config_intialization + # force ZTP to restart + if ztp_is_enabled ; then + ztp_status=$(ztp status -c) + if [ "$ztp_status" = "5:SUCCESS" ] || \ + [ "$ztp_status" = "6:FAILED" ]; then + # Clear completed ztp information, before starting a new one + ztp erase -y + else + touch /tmp/pending_ztp_restart + fi + fi + fi +} + +### Execution starts here ### + +CMD=$1 +# Default command is boot +if [ "$CMD" = "" ] || [ "$CMD" = "help" ] || \ + [ "$CMD" = "-h" ] || [ "$CMD" = "--help" ]; then + usage + exit 1 +fi + +# Process switch bootup event +if [ "$CMD" = "boot" ]; then + boot_config +fi + +# Process factory default configuration creation request +if [ "$CMD" = "factory" ]; then + generate_config factory ${CONFIG_DB_JSON} +fi + +# Take a backup of current configuration +if [ "$CMD" = "backup" ]; then + do_config_backup +fi + +exit 0 diff --git a/files/image_config/updategraph/updategraph b/files/image_config/updategraph/updategraph index 2eb510afa4e1..b2bd027e82e7 100755 --- a/files/image_config/updategraph/updategraph +++ b/files/image_config/updategraph/updategraph @@ -26,32 +26,6 @@ reload_minigraph() fi } -function copy_config_files_and_directories() -{ - for file_dir in $@; do - if [ -f /etc/sonic/old_config/${file_dir} ] || [ -d /etc/sonic/old_config/${file_dir} ]; then - logger "Copying SONiC configuration ${file_dir} ..." - cp -ar /etc/sonic/old_config/${file_dir} /etc/sonic/ - else - logger "Missing SONiC configuration ${file_dir} ..." - fi - done - - sync -} - -function check_system_warm_boot() -{ - SYSTEM_WARM_START=`/usr/bin/redis-cli -n 6 hget "WARM_RESTART_ENABLE_TABLE|system" enable` - # SYSTEM_WARM_START could be empty, always make WARM_BOOT meaningful. - if [[ x"$SYSTEM_WARM_START" == x"true" ]]; then - WARM_BOOT="true" - else - WARM_BOOT="false" - fi -} - - if [ ! -f /etc/sonic/updategraph.conf ]; then echo "No updategraph.conf found, generating a default one." echo "enabled=false" >/etc/sonic/updategraph.conf @@ -59,46 +33,6 @@ fi . /etc/sonic/updategraph.conf -check_system_warm_boot -copy_list="minigraph.xml snmp.yml acl.json config_db.json frr" -if [ -f /tmp/pending_config_migration ]; then - copy_config_files_and_directories $copy_list - if [ x"${WARM_BOOT}" == x"true" ]; then - echo "Warm reboot detected..." - elif [ -r /etc/sonic/config_db.json ]; then - echo "Use config_db.json from old system..." - sonic-cfggen -j /etc/sonic/config_db.json --write-to-db - - if [[ -x /usr/bin/db_migrator.py ]]; then - # Migrate the DB to the latest schema version if needed - /usr/bin/db_migrator.py -o migrate - fi - elif [ -r /etc/sonic/minigraph.xml ]; then - echo "Use minigraph.xml from old system..." - reload_minigraph - sonic-cfggen -d --print-data > /etc/sonic/config_db.json - else - echo "Didn't found neither config_db.json nor minigraph.xml ..." - fi - rm -f /tmp/pending_config_migration - sed -i "/enabled=/d" /etc/sonic/updategraph.conf - echo "enabled=false" >> /etc/sonic/updategraph.conf - exit 0 -fi - -if [ -f /tmp/pending_config_initialization ]; then - rm -f /tmp/pending_config_initialization - if [ "$enabled" != "true" ]; then - PLATFORM=`sonic-cfggen -H -v DEVICE_METADATA.localhost.platform` - PRESET=(`head -n 1 /usr/share/sonic/device/$PLATFORM/default_sku`) - sonic-cfggen -H -k ${PRESET[0]} --preset ${PRESET[1]} > /etc/sonic/config_db.json - redis-cli -n $CONFIG_DB_INDEX FLUSHDB - sonic-cfggen -j /etc/sonic/config_db.json --write-to-db - redis-cli -n $CONFIG_DB_INDEX SET "CONFIG_DB_INITIALIZED" "1" - exit 0 - fi -fi - if [ "$enabled" = "reload_only" ]; then reload_minigraph sed -i "/enabled=/d" /etc/sonic/updategraph.conf @@ -111,6 +45,12 @@ if [ "$enabled" != "true" ]; then exit 0 fi +# If ZTP package is available and enabled, use ZTP to download and load the graph. +if [ -e /usr/bin/ztp ] && [ "$(ztp status -c)" != "0:DISABLED" ]; then + echo "ZTP is available and enabled. Skipping graph update." + exit 0 +fi + ACL_URL=$acl_src if [ "$src" = "dhcp" ]; then From d5aa0d438219d5c84bbc4ad3bfb6fdfa46ef425c Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Thu, 5 Dec 2019 03:40:42 +0800 Subject: [PATCH 223/278] [Mellanox]support led for fan/psu and fan's direction (#3795) --- .../sonic_platform/chassis.py | 19 ++- .../mlnx-platform-api/sonic_platform/fan.py | 134 +++++++++++++++--- .../mlnx-platform-api/sonic_platform/psu.py | 116 ++++++++++++++- 3 files changed, 244 insertions(+), 25 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index 44ef8981281f..d34245390c59 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -14,6 +14,7 @@ from sonic_daemon_base.daemon_base import Logger from os import listdir from os.path import isfile, join + from glob import glob import sys import io import re @@ -33,6 +34,10 @@ HWMGMT_SYSTEM_ROOT = '/var/run/hw-management/system/' +MST_DEVICE_NAME_PATTERN = '/dev/mst/mt[0-9]*_pciconf0' +MST_DEVICE_RE_PATTERN = '/dev/mst/mt([0-9]*)_pciconf0' +SPECTRUM1_CHIP_ID = '52100' + #reboot cause related definitions REBOOT_CAUSE_ROOT = HWMGMT_SYSTEM_ROOT @@ -87,11 +92,21 @@ def initialize_fan(self): num_of_fan, num_of_drawer = self._extract_num_of_fans_and_fan_drawers() multi_rotor_in_drawer = num_of_fan > num_of_drawer + # Fan's direction isn't supported on spectrum 1 devices for now + mst_dev_list = glob(MST_DEVICE_NAME_PATTERN) + if not mst_dev_list: + raise RuntimeError("Can't get chip type due to {} not found".format(MST_DEVICE_NAME_PATTERN)) + m = re.search(MST_DEVICE_RE_PATTERN, mst_dev_list[0]) + if m.group(1) == SPECTRUM1_CHIP_ID: + has_fan_dir = False + else: + has_fan_dir = True + for index in range(num_of_fan): if multi_rotor_in_drawer: - fan = Fan(index, index/2) + fan = Fan(has_fan_dir, index, index/2) else: - fan = Fan(index, index) + fan = Fan(has_fan_dir, index, index) self._fan_list.append(fan) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py b/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py index 8b057e4123a2..818aa0f0110b 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py @@ -15,23 +15,28 @@ except ImportError as e: raise ImportError (str(e) + "- required module not found") -LED_ON = 1 -LED_OFF = 0 +LED_ON = '1' +LED_OFF = '0' PWM_MAX = 255 FAN_PATH = "/var/run/hw-management/thermal/" LED_PATH = "/var/run/hw-management/led/" +# fan_dir isn't supported on Spectrum 1. It is supported on Spectrum 2 and later switches +FAN_DIR = "/var/run/hw-management/system/fan_dir" class Fan(FanBase): """Platform-specific Fan class""" - def __init__(self, fan_index, drawer_index = 1, psu_fan = False): + + STATUS_LED_COLOR_ORANGE = "orange" + + def __init__(self, has_fan_dir, fan_index, drawer_index = 1, psu_fan = False): # API index is starting from 0, Mellanox platform index is starting from 1 self.index = fan_index + 1 self.drawer_index = drawer_index + 1 self.is_psu_fan = psu_fan - + self.fan_min_speed_path = "fan{}_min".format(self.index) if not self.is_psu_fan: self.fan_speed_get_path = "fan{}_speed_get".format(self.index) @@ -48,6 +53,45 @@ def __init__(self, fan_index, drawer_index = 1, psu_fan = False): self.fan_orange_led_path = "led_fan{}_orange".format(self.drawer_index) self.fan_pwm_path = "pwm1" self.fan_led_cap_path = "led_fan{}_capability".format(self.drawer_index) + if has_fan_dir: + self.fan_dir = FAN_DIR + else: + self.fan_dir = None + + + def get_direction(self): + """ + Retrieves the fan's direction + + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + + Notes: + What Mellanox calls forward: + Air flows from fans side to QSFP side, for example: MSN2700-CS2F + which means intake in community + What Mellanox calls reverse: + Air flow from QSFP side to fans side, for example: MSN2700-CS2R + which means exhaust in community + According to hw-mgmt: + 1 stands for forward, in other words intake + 0 stands for reverse, in other words exhaust + """ + if not self.fan_dir or self.is_psu_fan: + return self.FAN_DIRECTION_NOT_APPLICABLE + + try: + with open(os.path.join(self.fan_dir), 'r') as fan_dir: + fan_dir_bits = int(fan_dir.read()) + fan_mask = 1 << self.index - 1 + if fan_dir_bits & fan_mask: + return self.FAN_DIRECTION_INTAKE + else: + return self.FAN_DIRECTION_EXHAUST + except (ValueError, IOError) as e: + raise RuntimeError("Failed to read fan direction status to {}".format(repr(e))) + def get_status(self): """ @@ -68,6 +112,7 @@ def get_status(self): return status == 1 + def get_presence(self): """ Retrieves the presence status of fan @@ -89,7 +134,8 @@ def get_presence(self): status = 0 return status == 1 - + + def _get_min_speed_in_rpm(self): speed = 0 try: @@ -99,7 +145,8 @@ def _get_min_speed_in_rpm(self): speed = 0 return speed - + + def _get_max_speed_in_rpm(self): speed = 0 try: @@ -110,6 +157,7 @@ def _get_max_speed_in_rpm(self): return speed + def get_speed(self): """ Retrieves the speed of fan @@ -129,6 +177,7 @@ def get_speed(self): return speed + def get_target_speed(self): """ Retrieves the expected speed of fan @@ -151,6 +200,7 @@ def get_target_speed(self): return speed + def set_speed(self, speed): """ Set fan speed to expected value @@ -176,7 +226,8 @@ def set_speed(self, speed): status = False return status - + + def _get_led_capability(self): cap_list = None try: @@ -188,6 +239,7 @@ def _get_led_capability(self): return cap_list + def set_status_led(self, color): """ Set led to expected color @@ -208,32 +260,70 @@ def set_status_led(self, color): return False status = False try: - if color == 'green': + if color == self.STATUS_LED_COLOR_GREEN: with open(os.path.join(LED_PATH, self.fan_green_led_path), 'w') as fan_led: - fan_led.write(str(LED_ON)) - elif color == 'red': + fan_led.write(LED_ON) + status = True + elif color == self.STATUS_LED_COLOR_RED: # Some fan don't support red led but support orange led, in this case we set led to orange - if 'red' in led_cap_list: + if self.STATUS_LED_COLOR_RED in led_cap_list: led_path = os.path.join(LED_PATH, self.fan_red_led_path) - elif 'orange' in led_cap_list: + elif self.STATUS_LED_COLOR_ORANGE in led_cap_list: led_path = os.path.join(LED_PATH, self.fan_orange_led_path) else: return False with open(led_path, 'w') as fan_led: - fan_led.write(str(LED_ON)) - - elif color == 'off': - with open(os.path.join(LED_PATH, self.fan_green_led_path), 'w') as fan_led: - fan_led.write(str(LED_OFF)) - - with open(os.path.join(LED_PATH, self.fan_red_led_path), 'w') as fan_led: - fan_led.write(str(LED_OFF)) + fan_led.write(LED_ON) + status = True + elif color == self.STATUS_LED_COLOR_OFF: + if self.STATUS_LED_COLOR_GREEN in led_cap_list: + with open(os.path.join(LED_PATH, self.fan_green_led_path), 'w') as fan_led: + fan_led.write(str(LED_OFF)) + if self.STATUS_LED_COLOR_RED in led_cap_list: + with open(os.path.join(LED_PATH, self.fan_red_led_path), 'w') as fan_led: + fan_led.write(str(LED_OFF)) + if self.STATUS_LED_COLOR_ORANGE in led_cap_list: + with open(os.path.join(LED_PATH, self.fan_orange_led_path), 'w') as fan_led: + fan_led.write(str(LED_OFF)) + + status = True else: status = False except (ValueError, IOError): - status = False + status = False + return status + + 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 + """ + led_cap_list = self._get_led_capability() + if led_cap_list is None: + return self.STATUS_LED_COLOR_OFF + + try: + with open(os.path.join(LED_PATH, self.fan_green_led_path), 'r') as fan_led: + if LED_OFF != fan_led.read().rstrip('\n'): + return self.STATUS_LED_COLOR_GREEN + if self.STATUS_LED_COLOR_RED in led_cap_list: + with open(os.path.join(LED_PATH, self.fan_red_led_path), 'r') as fan_led: + if LED_OFF != fan_led.read().rstrip('\n'): + return self.STATUS_LED_COLOR_RED + if self.STATUS_LED_COLOR_ORANGE in led_cap_list: + with open(os.path.join(LED_PATH, self.fan_orange_led_path), 'r') as fan_led: + if LED_OFF != fan_led.read().rstrip('\n'): + return self.STATUS_LED_COLOR_RED + except (ValueError, IOError) as e: + raise RuntimeError("Failed to read led status for fan {} due to {}".format(self.index, repr(e))) + + return self.STATUS_LED_COLOR_OFF + + def get_speed_tolerance(self): """ Retrieves the speed tolerance of the fan @@ -243,4 +333,4 @@ def get_speed_tolerance(self): considered tolerable """ # The tolerance value is fixed as 20% for all the Mellanox platform - return 20 \ No newline at end of file + return 20 diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/psu.py b/platform/mellanox/mlnx-platform-api/sonic_platform/psu.py index 0789f67e4f09..0e4c3fd50f7a 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/psu.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/psu.py @@ -16,6 +16,9 @@ except ImportError as e: raise ImportError (str(e) + "- required module not found") +LED_ON = '1' +LED_OFF = '0' + # Global logger class instance logger = Logger() @@ -25,6 +28,8 @@ PSU_VOLTAGE = "voltage" PSU_POWER = "power" +LED_PATH = "/var/run/hw-management/led/" + # SKUs with unplugable PSUs: # 1. don't have psuX_status and should be treated as always present # 2. don't have voltage, current and power values @@ -50,6 +55,9 @@ class Psu(PsuBase): """Platform-specific Psu class""" + + STATUS_LED_COLOR_ORANGE = "orange" + def __init__(self, psu_index, sku): global psu_list PsuBase.__init__(self) @@ -90,10 +98,16 @@ def __init__(self, psu_index, sku): psu_presence = os.path.join(self.psu_path, psu_presence) self.psu_presence = psu_presence - fan = Fan(psu_index, psu_index, True) + fan = Fan(sku, psu_index, psu_index, True) if fan.get_presence(): self._fan = fan + self.psu_green_led_path = "led_psu_green" + self.psu_red_led_path = "led_psu_red" + self.psu_orange_led_path = "led_psu_orange" + self.psu_led_cap_path = "led_psu_capability" + + def _read_generic_file(self, filename, len): """ Read a generic file, returns the contents of the file @@ -106,6 +120,7 @@ def _read_generic_file(self, filename, len): logger.log_info("Fail to read file {} due to {}".format(filename, repr(e))) return result + def get_powergood_status(self): """ Retrieves the operational status of power supply unit (PSU) defined @@ -117,6 +132,7 @@ def get_powergood_status(self): return status == 1 + def get_presence(self): """ Retrieves the presence status of power supply unit (PSU) defined @@ -130,6 +146,7 @@ def get_presence(self): status = self._read_generic_file(self.psu_presence, 0) return status == 1 + def get_voltage(self): """ Retrieves current PSU voltage output @@ -144,6 +161,7 @@ def get_voltage(self): else: return None + def get_current(self): """ Retrieves present electric current supplied by PSU @@ -169,3 +187,99 @@ def get_power(self): return float(power) / 1000000 else: return None + + + def _get_led_capability(self): + cap_list = None + try: + with open(os.path.join(LED_PATH, self.psu_led_cap_path), 'r') as psu_led_cap: + caps = psu_led_cap.read() + cap_list = caps.split() + except (ValueError, IOError): + status = 0 + + return cap_list + + + 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 + + Notes: + Only one led for all PSUs. + """ + led_cap_list = self._get_led_capability() + if led_cap_list is None: + return False + + status = False + try: + if color == self.STATUS_LED_COLOR_GREEN: + with open(os.path.join(LED_PATH, self.psu_green_led_path), 'w') as psu_led: + psu_led.write(LED_ON) + status = True + elif color == self.STATUS_LED_COLOR_RED: + # Some fan don't support red led but support orange led, in this case we set led to orange + if self.STATUS_LED_COLOR_RED in led_cap_list: + led_path = os.path.join(LED_PATH, self.psu_red_led_path) + elif self.STATUS_LED_COLOR_ORANGE in led_cap_list: + led_path = os.path.join(LED_PATH, self.psu_orange_led_path) + else: + return False + with open(led_path, 'w') as psu_led: + psu_led.write(LED_ON) + status = True + elif color == self.STATUS_LED_COLOR_OFF: + if self.STATUS_LED_COLOR_GREEN in led_cap_list: + with open(os.path.join(LED_PATH, self.psu_green_led_path), 'w') as psu_led: + psu_led.write(str(LED_OFF)) + if self.STATUS_LED_COLOR_RED in led_cap_list: + with open(os.path.join(LED_PATH, self.psu_red_led_path), 'w') as psu_led: + psu_led.write(str(LED_OFF)) + if self.STATUS_LED_COLOR_ORANGE in led_cap_list: + with open(os.path.join(LED_PATH, self.psu_orange_led_path), 'w') as psu_led: + psu_led.write(str(LED_OFF)) + + status = True + else: + status = False + except (ValueError, IOError): + status = False + + return status + + + def get_status_led(self): + """ + Gets the state of the PSU status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + led_cap_list = self._get_led_capability() + if led_cap_list is None: + return self.STATUS_LED_COLOR_OFF + + try: + with open(os.path.join(LED_PATH, self.psu_green_led_path), 'r') as psu_led: + if LED_OFF != psu_led.read().rstrip('\n'): + return self.STATUS_LED_COLOR_GREEN + if self.STATUS_LED_COLOR_RED in led_cap_list: + with open(os.path.join(LED_PATH, self.psu_red_led_path), 'r') as psu_led: + if LED_OFF != psu_led.read().rstrip('\n'): + return self.STATUS_LED_COLOR_RED + if self.STATUS_LED_COLOR_ORANGE in led_cap_list: + with open(os.path.join(LED_PATH, self.psu_orange_led_path), 'r') as psu_led: + if LED_OFF != psu_led.read().rstrip('\n'): + return self.STATUS_LED_COLOR_RED + except (ValueError, IOError) as e: + raise RuntimeError("Failed to read led status for psu due to {}".format(repr(e))) + + return self.STATUS_LED_COLOR_OFF From 1848fb262b0ad24a8791d9ff8aa8d95764b470c8 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Wed, 4 Dec 2019 14:10:19 -0800 Subject: [PATCH 224/278] [fast-reboot]: Save fast-reboot state into the db (#3741) Put a flag for fast-reboot to the db using EXPIRE feature. Using this flag in other part of SONiC to start in Fast-reboot mode. If we reload a config, the state in the db will be removed. --- dockers/docker-base-stretch/Dockerfile.j2 | 8 +++++++- dockers/docker-orchagent/Dockerfile.j2 | 7 ------- dockers/docker-sonic-telemetry/Dockerfile.j2 | 9 +-------- dockers/docker-teamd/Dockerfile.j2 | 9 +-------- files/build_templates/docker_image_ctl.j2 | 5 +++++ files/scripts/syncd.sh | 7 ++++++- rules/docker-base-stretch.mk | 2 +- src/sonic-quagga | 2 +- 8 files changed, 22 insertions(+), 27 deletions(-) diff --git a/dockers/docker-base-stretch/Dockerfile.j2 b/dockers/docker-base-stretch/Dockerfile.j2 index 95272e2322ce..3b3ede376d12 100644 --- a/dockers/docker-base-stretch/Dockerfile.j2 +++ b/dockers/docker-base-stretch/Dockerfile.j2 @@ -47,7 +47,13 @@ RUN apt-get update && \ vim-tiny \ # Install dependencies of supervisor python-pkg-resources \ - python-meld3 + python-meld3 \ +# dependencies of redis-tools + libatomic1 \ + libjemalloc1 \ + liblua5.1-0 \ + lua-bitop \ + lua-cjson {% if CONFIGURED_ARCH == "armhf" %} # ip and ifconfig utility missing in docker for armhf diff --git a/dockers/docker-orchagent/Dockerfile.j2 b/dockers/docker-orchagent/Dockerfile.j2 index f01bca724094..8a66e2adbe43 100755 --- a/dockers/docker-orchagent/Dockerfile.j2 +++ b/dockers/docker-orchagent/Dockerfile.j2 @@ -18,13 +18,6 @@ RUN apt-get update && \ iproute2 \ ndisc6 \ tcpdump \ - # Install redis-tools dependencies - # TODO: implicitly install dependencies - libatomic1 \ - libjemalloc1 \ - liblua5.1-0 \ - lua-bitop \ - lua-cjson \ libelf1 \ libmnl0 \ bridge-utils diff --git a/dockers/docker-sonic-telemetry/Dockerfile.j2 b/dockers/docker-sonic-telemetry/Dockerfile.j2 index 3a5716001ca5..e94441b4f066 100644 --- a/dockers/docker-sonic-telemetry/Dockerfile.j2 +++ b/dockers/docker-sonic-telemetry/Dockerfile.j2 @@ -11,14 +11,7 @@ RUN apt-get update && \ apt-get install -f -y \ libdbus-1-3 \ libdaemon0 \ - libjansson4 \ - # Install redis-tools dependencies - # TODO: implicitly install dependencies - libatomic1 \ - libjemalloc1 \ - liblua5.1-0 \ - lua-bitop \ - lua-cjson + libjansson4 {% if docker_sonic_telemetry_debs.strip() -%} # Copy locally-built Debian package dependencies diff --git a/dockers/docker-teamd/Dockerfile.j2 b/dockers/docker-teamd/Dockerfile.j2 index fc8626e77229..4282a10d0c86 100644 --- a/dockers/docker-teamd/Dockerfile.j2 +++ b/dockers/docker-teamd/Dockerfile.j2 @@ -12,14 +12,7 @@ RUN apt-get update && \ libdbus-1-3 \ libdaemon0 \ libjansson4 \ - libpython2.7 \ - # Install redis-tools dependencies - # TODO: implicitly install dependencies - libatomic1 \ - libjemalloc1 \ - liblua5.1-0 \ - lua-bitop \ - lua-cjson + libpython2.7 {% if docker_teamd_debs.strip() -%} # Copy locally-built Debian package dependencies diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 index c485254647b8..167a392730e4 100644 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -149,6 +149,11 @@ function postStartAction() sonic-cfggen -j /etc/sonic/config_db.json --write-to-db fi + if [[ "$BOOT_TYPE" == "fast" ]]; then + # set the key to expire in 3 minutes + redis-cli -n 6 SET "FAST_REBOOT|system" "1" "EX" "180" + fi + redis-cli -n 4 SET "CONFIG_DB_INITIALIZED" "1" fi diff --git a/files/scripts/syncd.sh b/files/scripts/syncd.sh index 2b7c76263d8a..89f15f0f413f 100755 --- a/files/scripts/syncd.sh +++ b/files/scripts/syncd.sh @@ -64,7 +64,12 @@ function getBootType() TYPE='fastfast' ;; *SONIC_BOOT_TYPE=fast*|*fast-reboot*) - TYPE=$(awk '{ if ($1 <= 180) print "fast"; else print "cold" }' /proc/uptime) + # check that the key exists + if [[ $(redis-cli -n 6 GET "FAST_REBOOT|system") == "1" ]]; then + TYPE='fast' + else + TYPE='cold' + fi ;; *) TYPE='cold' diff --git a/rules/docker-base-stretch.mk b/rules/docker-base-stretch.mk index 55b7fd9f8661..a54f4ec092aa 100644 --- a/rules/docker-base-stretch.mk +++ b/rules/docker-base-stretch.mk @@ -2,7 +2,7 @@ DOCKER_BASE_STRETCH = docker-base-stretch.gz $(DOCKER_BASE_STRETCH)_PATH = $(DOCKERS_PATH)/docker-base-stretch -$(DOCKER_BASE_STRETCH)_DEPENDS += $(SUPERVISOR) +$(DOCKER_BASE_STRETCH)_DEPENDS += $(SUPERVISOR) $(REDIS_TOOLS) $(DOCKER_BASE_STRETCH)_DEPENDS += $(SOCAT) GDB = gdb diff --git a/src/sonic-quagga b/src/sonic-quagga index 904a35010779..7101eeda1a1c 160000 --- a/src/sonic-quagga +++ b/src/sonic-quagga @@ -1 +1 @@ -Subproject commit 904a350107793d44be7167500fcec9087ca3243b +Subproject commit 7101eeda1a1ccef2e951e4bea5a2f15d9a43e3b5 From 77b8e74fc0283ff41b60225a172596bb0e93bea8 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Thu, 5 Dec 2019 10:00:13 +0700 Subject: [PATCH 225/278] [platform/device] - Implement Silverstone platform API [PSU] (#3784) Implement part of the Chassis and Fan related APIs. Psu APIs get_voltage() get_current() get_power() get_powergood_status() set_status_led() get_status_led() Update Fan APIs to support PSU FAN get_direction() get_speed() get_target_speed() get_speed_tolerance() get_target_speed() PSU APIs base on Device API get_name() get_presence() get_model() get_serial() get_status() - How I did it Implement PSU APIs Update FAN API to support PSU Fans Add PSU object to Chassis API --- .../sonic_platform/chassis.py | 4 + .../sonic_platform/fan.py | 36 ++- .../sonic_platform/psu.py | 243 ++++++++++++++++++ 3 files changed, 278 insertions(+), 5 deletions(-) create mode 100644 device/celestica/x86_64-cel_silverstone-r0/sonic_platform/psu.py diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py index dc622016cbb2..d984b3578b27 100644 --- a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py @@ -18,6 +18,7 @@ from sonic_platform_base.chassis_base import ChassisBase from sonic_platform.eeprom import Tlv from sonic_platform.fan import Fan + from sonic_platform.psu import Psu from helper import APIHelper except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -46,6 +47,9 @@ def __init__(self): for fan_index in range(0, NUM_FAN): fan = Fan(fant_index, fan_index) self._fan_list.append(fan) + for index in range(0, NUM_PSU): + psu = Psu(index) + self._psu_list.append(psu) def get_base_mac(self): """ diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py index 902de261f8cb..d1b36effc1ac 100644 --- a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py @@ -30,7 +30,7 @@ IPMI_SET_FAN_LED_CMD = "0x07 {} {}" IPMI_GET_FAN_LED_CMD = "0x08 {}" IPMI_SET_PWM = "0x03 0x01 0x02 {} {}" -IPMI_FRU_PRINT_ID = "ipmitool fru print {}" + IPMI_FRU_MODEL_KEY = "Board Part Number" IPMI_FRU_SERIAL_KEY = "Board Serial" @@ -48,6 +48,9 @@ FAN_PWM_REGISTER_STEP = 0x10 FAN1_FRU_ID = 6 +NUM_OF_FAN_TRAY = 7 +PSU_FAN1_FRONT_SS_ID = "0x33" + class Fan(FanBase): """Platform-specific Fan class""" @@ -69,8 +72,10 @@ def get_direction(self): depending on fan direction """ direction = self.FAN_DIRECTION_EXHAUST + fan_direction_key = hex(self.fan_tray_index) if not self.is_psu_fan else hex( + self.psu_index + NUM_OF_FAN_TRAY) status, raw_flow = self._api_helper.ipmi_raw( - IPMI_OEM_NETFN, IPMI_AIR_FLOW_CMD.format(hex(self.fan_tray_index))) + IPMI_OEM_NETFN, IPMI_AIR_FLOW_CMD.format(fan_direction_key)) if status and raw_flow == "01": direction = self.FAN_DIRECTION_INTAKE @@ -88,13 +93,12 @@ def get_speed(self): Max F2B = 24700 RPM Max B2F = 29700 RPM """ - # ipmitool raw 0x3a 0x03 0x01 0x01 {register} - # register = 22 32 42 52 62 72 82 max_rpm = MAX_OUTLET if self.fan_index % 2 == 0 else MAX_INLET fan1_ss_start = FAN1_FRONT_SS_ID if self.fan_index % 2 == 0 else FAN1_REAR_SS_ID - ss_id = hex(int(fan1_ss_start, 16) + self.fan_tray_index) + ss_id = hex(int(fan1_ss_start, 16) + self.fan_tray_index) if not self.psu_index else hex( + int(PSU_FAN1_FRONT_SS_ID, 16) + self.fan_tray_index) status, raw_ss_read = self._api_helper.ipmi_raw( IPMI_SENSOR_NETFN, IPMI_FAN_SPEED_CMD.format(ss_id)) @@ -145,6 +149,10 @@ def set_speed(self, speed): # ipmitool raw 0x3a 0x03 0x01 0x02 {register} {pwm_speed} # register = 22 32 42 52 62 72 82 + if self.is_psu_fan: + ## TODO + return False + speed_hex = hex(int(float(speed)/100 * 255)) fan_register_hex = hex(FAN_PWM_REGISTER_START + (self.fan_tray_index*FAN_PWM_REGISTER_STEP)) @@ -171,6 +179,11 @@ def set_status_led(self, color): manual: ipmitool raw 0x3A 0x09 0x02 0x00 auto: ipmitool raw 0x3A 0x09 0x02 0x01 """ + + if self.is_psu_fan: + # Not support + return False + led_cmd = { self.STATUS_LED_COLOR_GREEN: FAN_LED_GREEN_CMD, self.STATUS_LED_COLOR_RED: FAN_LED_RED_CMD, @@ -196,6 +209,10 @@ def get_status_led(self): STATUS_LED_COLOR_RED = "red" STATUS_LED_COLOR_OFF = "off" """ + if self.is_psu_fan: + # Not support + return self.STATUS_LED_COLOR_OFF + fan_selector = hex(int(FAN1_LED_CMD, 16) + self.fan_tray_index) status, hx_color = self._api_helper.ipmi_raw( IPMI_OEM_NETFN, IPMI_GET_FAN_LED_CMD.format(fan_selector)) @@ -225,6 +242,9 @@ def get_presence(self): Returns: bool: True if FAN is present, False if not """ + if self.is_psu_fan: + return True + presence = False status, raw_present = self._api_helper.ipmi_raw( IPMI_OEM_NETFN, IPMI_FAN_PRESENT_CMD.format(hex(self.index))) @@ -239,6 +259,9 @@ def get_model(self): Returns: string: Model/part number of device """ + if self.is_psu_fan: + return "Unknown" + model = "Unknown" ipmi_fru_idx = self.fan_tray_index + FAN1_FRU_ID status, raw_model = self._api_helper.ipmi_fru_id( @@ -256,6 +279,9 @@ def get_serial(self): Returns: string: Serial number of device """ + if self.is_psu_fan: + return "Unknown" + serial = "Unknown" ipmi_fru_idx = self.fan_tray_index + FAN1_FRU_ID status, raw_model = self._api_helper.ipmi_fru_id( diff --git a/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/psu.py b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/psu.py new file mode 100644 index 000000000000..c5d2270d2657 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone-r0/sonic_platform/psu.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +import os +import re +import math +import sonic_platform + +try: + from sonic_platform_base.psu_base import PsuBase + from helper import APIHelper + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PSU_NAME_LIST = ["PSU-1", "PSU-2"] +PSU_NUM_FAN = [1, 1] + +IPMI_SENSOR_NETFN = "0x04" +IPMI_OEM_NETFN = "0x3A" +IPMI_SS_READ_CMD = "0x2D {}" +IPMI_SET_PSU_LED_CMD = "0x07 0x02 {}" +IPMI_GET_PSU_LED_CMD = "0x08 0x02" +IPMI_FRU_MODEL_KEY = "Board Part Number" +IPMI_FRU_SERIAL_KEY = "Board Serial" + +PSU_LED_OFF_CMD = "0x00" +PSU_LED_GREEN_CMD = "0x01" +PSU_LED_AMBER_CMD = "0x02" + +PSU1_VOUT_SS_ID = "0x36" +PSU1_COUT_SS_ID = "0x37" +PSU1_POUT_SS_ID = "0x38" +PSU1_STATUS_REG = "0x39" + +PSU2_VOUT_SS_ID = "0x40" +PSU2_COUT_SS_ID = "0x41" +PSU2_POUT_SS_ID = "0x42" +PSU2_STATUS_REG = "0x2f" + +PSU1_FRU_ID = 3 + +SS_READ_OFFSET = 0 + + +class Psu(PsuBase): + """Platform-specific Psu class""" + + def __init__(self, psu_index): + PsuBase.__init__(self) + self.index = psu_index + for fan_index in range(0, PSU_NUM_FAN[self.index]): + fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) + self._fan_list.append(fan) + self._api_helper = APIHelper() + + def find_value(self, in_string): + result = re.search("^.+ ([0-9a-f]{2}) .+$", in_string) + return result.group(1) if result else result + + def get_voltage(self): + """ + Retrieves current PSU voltage output + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + psu_voltage = 0.0 + psu_vout_key = globals()['PSU{}_VOUT_SS_ID'.format(self.index+1)] + status, raw_ss_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_vout_key)) + ss_read = raw_ss_read.split()[SS_READ_OFFSET] + # Formula: Rx1x10^-1 + psu_voltage = int(ss_read, 16) * math.pow(10, -1) + + return psu_voltage + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + psu_current = 0.0 + psu_cout_key = globals()['PSU{}_COUT_SS_ID'.format(self.index+1)] + status, raw_ss_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_cout_key)) + ss_read = raw_ss_read.split()[SS_READ_OFFSET] + # Formula: Rx5x10^-1 + psu_current = int(ss_read, 16) * 5 * math.pow(10, -1) + + return psu_current + + def get_power(self): + """ + Retrieves current energy supplied by PSU + Returns: + A float number, the power in watts, e.g. 302.6 + """ + psu_power = 0.0 + psu_pout_key = globals()['PSU{}_POUT_SS_ID'.format(self.index+1)] + status, raw_ss_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_pout_key)) + ss_read = raw_ss_read.split()[SS_READ_OFFSET] + # Formula: Rx6x10^0 + psu_power = int(ss_read, 16) * 6 + return psu_power + + def get_powergood_status(self): + """ + Retrieves the powergood status of PSU + Returns: + A boolean, True if PSU has stablized its output voltages and passed all + its internal self-tests, False if not. + """ + 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 + Note: Only support green and off + Returns: + bool: True if status LED state is set successfully, False if not + Note + Set manual + ipmitool raw 0x3a 0x09 0x2 0x0 + """ + led_cmd = { + self.STATUS_LED_COLOR_GREEN: PSU_LED_GREEN_CMD, + self.STATUS_LED_COLOR_AMBER: PSU_LED_AMBER_CMD, + self.STATUS_LED_COLOR_OFF: PSU_LED_OFF_CMD + }.get(color) + + status, set_led = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_SET_PSU_LED_CMD.format(led_cmd)) + set_status_led = False if not status else True + + return set_status_led + + 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 + """ + status, hx_color = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_GET_PSU_LED_CMD) + + status_led = { + "00": self.STATUS_LED_COLOR_OFF, + "01": self.STATUS_LED_COLOR_GREEN, + "02": self.STATUS_LED_COLOR_AMBER, + }.get(hx_color, self.STATUS_LED_COLOR_OFF) + + return status_led + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return PSU_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + psu_presence = False + psu_pstatus_key = globals()['PSU{}_STATUS_REG'.format(self.index+1)] + status, raw_status_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_pstatus_key)) + status_byte = self.find_value(raw_status_read) + + if status: + presence_int = (int(status_byte, 16) >> 0) & 1 + psu_presence = True if presence_int else False + + return psu_presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + model = "Unknown" + ipmi_fru_idx = self.index + PSU1_FRU_ID + status, raw_model = self._api_helper.ipmi_fru_id( + ipmi_fru_idx, IPMI_FRU_MODEL_KEY) + + fru_pn_list = raw_model.split() + if len(fru_pn_list) > 4: + model = fru_pn_list[4] + + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + serial = "Unknown" + ipmi_fru_idx = self.index + PSU1_FRU_ID + status, raw_model = self._api_helper.ipmi_fru_id( + ipmi_fru_idx, IPMI_FRU_SERIAL_KEY) + + fru_sr_list = raw_model.split() + if len(fru_sr_list) > 3: + serial = fru_sr_list[3] + + 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 + """ + psu_status = False + psu_pstatus_key = globals()['PSU{}_STATUS_REG'.format(self.index+1)] + status, raw_status_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_pstatus_key)) + status_byte = self.find_value(raw_status_read) + + if status: + failure_detected = (int(status_byte, 16) >> 1) & 1 + input_lost = (int(status_byte, 16) >> 3) & 1 + psu_status = False if (input_lost or failure_detected) else True + + return psu_status From 157317d7105351225151c51abc71fb35d01beb2a Mon Sep 17 00:00:00 2001 From: Sujin Kang <54082335+sujinmkang@users.noreply.github.com> Date: Wed, 4 Dec 2019 20:27:39 -0800 Subject: [PATCH 226/278] [doc]: Remove all non-existing build jobs from README.md (#3844) --- README.md | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/README.md b/README.md index 1ab18f5e646f..a1de15524b63 100644 --- a/README.md +++ b/README.md @@ -9,35 +9,21 @@ VS: [![VS](https://sonic-jenkins.westus2.cloudapp.azure.com/job/vs/job/buildimag *201904*: Broadcom: [![Broadcom](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201904/) -Barefoot: [![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201904/) -Centec: [![Centec](https://sonic-jenkins.westus2.cloudapp.azure.com/job/centec/job/buildimage-centec-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/centec/job/buildimage-centec-201904/) -Nephos: [![Nephos](https://sonic-jenkins.westus2.cloudapp.azure.com/job/nephos/job/buildimage-nephos-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/nephos/job/buildimage-nephos-201904/) -Marvell: [![Marvell](https://sonic-jenkins.westus2.cloudapp.azure.com/job/marvell/job/buildimage-mrvl-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/marvell/job/buildimage-mrvl-201904/) Mellanox: [![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-201904/) -VS: [![VS](https://sonic-jenkins.westus2.cloudapp.azure.com/job/vs/job/buildimage-vs-201904/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/vs/job/buildimage-vs-201904) *201811*: Innovium: [![Innovium](https://sonic-jenkins.westus2.cloudapp.azure.com/job/innovium/job/buildimage-invm-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/innovium/job/buildimage-invm-201811/) Broadcom: [![Broadcom](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201811/) -Barefoot: [![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201811/) -Centec: [![Centec](https://sonic-jenkins.westus2.cloudapp.azure.com/job/centec/job/buildimage-centec-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/centec/job/buildimage-centec-201811/) -Nephos: [![Nephos](https://sonic-jenkins.westus2.cloudapp.azure.com/job/nephos/job/buildimage-nephos-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/nephos/job/buildimage-nephos-201811/) -Marvell: [![Marvell](https://sonic-jenkins.westus2.cloudapp.azure.com/job/marvell/job/buildimage-mrvl-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/marvell/job/buildimage-mrvl-201811/) Mellanox: [![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-201811/) VS: [![VS](https://sonic-jenkins.westus2.cloudapp.azure.com/job/vs/job/buildimage-vs-201811/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/vs/job/buildimage-vs-201811) *201807*: Broadcom: [![Broadcom](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201807/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201807/) -Barefoot: [![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201807/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201807/) -Centec: [![Centec](https://sonic-jenkins.westus2.cloudapp.azure.com/job/centec/job/buildimage-centec-201807/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/centec/job/buildimage-centec-201807/) -Nephos: [![Nephos](https://sonic-jenkins.westus2.cloudapp.azure.com/job/nephos/job/buildimage-nephos-201807/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/nephos/job/buildimage-nephos-201807/) -Marvell: [![Marvell](https://sonic-jenkins.westus2.cloudapp.azure.com/job/marvell/job/buildimage-mrvl-201807/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/marvell/job/buildimage-mrvl-201807/) +Barefoot: [![Barefoot](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201807/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/barefoot/job/buildimage-bf-201807/) Mellanox: [![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-201807/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-201807/) *201803*: Broadcom: [![Broadcom](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201803/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-201803/) -Cavium: [![Cavium](https://sonic-jenkins.westus2.cloudapp.azure.com/job/cavium/job/buildimage-cavm-201803/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/cavium/job/buildimage-cavm-201803/) -Centec: [![Centec](https://sonic-jenkins.westus2.cloudapp.azure.com/job/centec/job/buildimage-centec-201803/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/centec/job/buildimage-centec-201803/) Nephos: [![Nephos](https://sonic-jenkins.westus2.cloudapp.azure.com/job/nephos/job/buildimage-nephos-201803/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/nephos/job/buildimage-nephos-201803/) Marvell: [![Marvell](https://sonic-jenkins.westus2.cloudapp.azure.com/job/marvell/job/buildimage-mrvl-201803/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/marvell/job/buildimage-mrvl-201803/) Mellanox: [![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-201803/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-201803/) From f345935aec5325c76d34d1fa38f158a9171dbbe9 Mon Sep 17 00:00:00 2001 From: Nazarii Hnydyn Date: Thu, 5 Dec 2019 21:23:16 +0200 Subject: [PATCH 227/278] [submodule]: Advance sonic-platform-common. (#3848) Signed-off-by: Nazarii Hnydyn --- src/sonic-platform-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-platform-common b/src/sonic-platform-common index d22f0a0e64f3..6ad48b87eb96 160000 --- a/src/sonic-platform-common +++ b/src/sonic-platform-common @@ -1 +1 @@ -Subproject commit d22f0a0e64f30e9e26064824fb11f27b2d636850 +Subproject commit 6ad48b87eb9654daa3f3c854134434d14572573f From 8ab75e0e90879a8b59a55b16f89ca4f4c2439d55 Mon Sep 17 00:00:00 2001 From: Joe LeVeque Date: Sat, 7 Dec 2019 11:26:29 -0800 Subject: [PATCH 228/278] [isc-dhcp-relay] Patch to allow relay to discover interfaces even if (#3851) Patch isc-dhcp-relay in order to allow the relay agent to discover configured interfaces even if they are down. Without this patch, the relay agent will not discover configured interfaces if they are down when the relay agent starts up. If the interface(s) then get brought up after the relay started, the relay will discard packets received on these interfaces and log the message, Discarding packet received on interface that has no IPv4 address assigned. This led to race conditions when starting SONiC (or loading configuration). To resolve this, the relay agent would need to be restarted with all configured interfaces up. With this patch, the relay agent will discover all configured interfaces, whether or not they are up at the time the relay agent starts. Thus, the state of the configured interfaces can be down when the relay agent starts and brought up during the lifetime of the relay agent process, and the relay agent will relay packets as expected; it will not discard them. --- ...interfaces-when-discovering-interfac.patch | 32 +++++++++++++++++++ src/isc-dhcp/patch/series | 1 + 2 files changed, 33 insertions(+) create mode 100644 src/isc-dhcp/patch/0012-Don-t-skip-down-interfaces-when-discovering-interfac.patch diff --git a/src/isc-dhcp/patch/0012-Don-t-skip-down-interfaces-when-discovering-interfac.patch b/src/isc-dhcp/patch/0012-Don-t-skip-down-interfaces-when-discovering-interfac.patch new file mode 100644 index 000000000000..f088b035edb4 --- /dev/null +++ b/src/isc-dhcp/patch/0012-Don-t-skip-down-interfaces-when-discovering-interfac.patch @@ -0,0 +1,32 @@ +From 06850e9beb2c50b5cc23fc94168acd9ae58d8ef8 Mon Sep 17 00:00:00 2001 +From: Joe LeVeque +Date: Fri, 6 Dec 2019 05:53:09 +0000 +Subject: [PATCH] Don't skip down interfaces when discovering interfaces in + relay mode + +When discovering interfaces in relay mode, don't skip interfaces just +because they're down. If we fail to discover the interfaces because they +are down when the relay starts, but then are brought up at a later point +in time, the relay will discard any packets received on them because it +didn't discover the interface(s) when it started up. +--- + common/discover.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/common/discover.c b/common/discover.c +index 8d5b958..5efff49 100644 +--- a/common/discover.c ++++ b/common/discover.c +@@ -1016,7 +1016,8 @@ discover_interfaces(int state) { + info.flags & IFF_LOOPBACK || + info.flags & IFF_POINTOPOINT) && !tmp) || + (!(info.flags & IFF_UP) && +- state != DISCOVER_UNCONFIGURED)) ++ state != DISCOVER_UNCONFIGURED && ++ state != DISCOVER_RELAY)) + continue; + + /* If there isn't already an interface by this name, +-- +2.17.1 + diff --git a/src/isc-dhcp/patch/series b/src/isc-dhcp/patch/series index 1b83f2166b96..ec68967e28b9 100644 --- a/src/isc-dhcp/patch/series +++ b/src/isc-dhcp/patch/series @@ -10,3 +10,4 @@ 0009-CVE-2018-5733.patch 0010-CVE-2018-5732.patch 0008-interface-name-maxlen-crash.patch +0012-Don-t-skip-down-interfaces-when-discovering-interfac.patch From 90ddad48d1ff0a1482867b12b7552e1d774a6fd7 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Sun, 8 Dec 2019 03:28:49 +0800 Subject: [PATCH 229/278] [mellanox ]improve the method the type of sfp module is detected (#3846) Fix the issue when an SFP module is plugged into a QSFP port via an adapter. - How I did it Originally the type of an SFP module is determined according to the SKU dictionary. However, it's possible that as SFP module is plugged into a QSFP port via an adapter. In this case, the EEPROM content will be parsed in the wrong format. To address that we fetch the identifier value of an xSFP module and then get the type by parsing it. --- .../mlnx-platform-api/sonic_platform/sfp.py | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py index 845f355e28f1..254d9c2e3e58 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py @@ -136,6 +136,26 @@ SFP_CHANNL_STATUS_OFFSET = 110 SFP_CHANNL_STATUS_WIDTH = 1 +# identifier value of xSFP module which is in the first byte of the EEPROM +# if the identifier value falls into SFP_TYPE_CODE_LIST the module is treated as a SFP module and parsed according to 8472 +# for QSFP_TYPE_CODE_LIST the module is treated as a QSFP module and parsed according to 8436/8636 +# Originally the type (SFP/QSFP) of each module is determined according to the SKU dictionary +# where the type of each FP port is defined. The content of EEPROM is parsed according to its type. +# However, sometimes the SFP module can be fit in an adapter and then pluged into a QSFP port. +# In this case the EEPROM content is in format of SFP but parsed as QSFP, causing failure. +# To resolve that issue the type field of the xSFP module is also fetched so that we can know exectly what type the +# module is. Currently only the following types are recognized as SFP/QSFP module. +# Meanwhile, if the a module's identifier value can't be recognized, it will be parsed according to the SKU dictionary. +# This is because in the future it's possible that some new identifier value which is not regonized but backward compatible +# with the current format and by doing so it can be parsed as much as possible. +SFP_TYPE_CODE_LIST = [ + '03' # SFP/SFP+/SFP28 +] +QSFP_TYPE_CODE_LIST = [ + '0d', # QSFP+ or later + '11' # QSFP28 or later +] + qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', 'Length OM2(m)', 'Length OM1(m)', 'Length Cable Assembly(m)') @@ -206,7 +226,7 @@ def __init__(self, sfp_index, sfp_type): self.index = sfp_index + 1 self.sfp_eeprom_path = "qsfp{}".format(self.index) self.sfp_status_path = "qsfp{}_status".format(self.index) - self.sfp_type = sfp_type + self._detect_sfp_type(sfp_type) self.dom_tx_disable_supported = False self._dom_capability_detect() self.sdk_handle = None @@ -293,6 +313,26 @@ def _read_eeprom_specific_bytes(self, offset, num_bytes): return eeprom_raw + def _detect_sfp_type(self, sfp_type): + eeprom_raw = [] + eeprom_raw = self._read_eeprom_specific_bytes(XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH) + if eeprom_raw: + if eeprom_raw[0] in SFP_TYPE_CODE_LIST: + self.sfp_type = SFP_TYPE + elif eeprom_raw[0] in QSFP_TYPE_CODE_LIST: + self.sfp_type = QSFP_TYPE + else: + # we don't regonize this identifier value, treat the xSFP module as the default type + self.sfp_type = sfp_type + logger.log_info("Identifier value of {} module {} is {} which isn't regonized and will be treated as default type ({})".format( + sfp_type, self.index, eeprom_raw[0], sfp_type + )) + else: + # eeprom_raw being None indicates the module is not present. + # in this case we treat it as the default type according to the SKU + self.sfp_type = sfp_type + + def _dom_capability_detect(self): if not self.get_presence(): self.dom_supported = False @@ -303,7 +343,7 @@ def _dom_capability_detect(self): self.calibration = 0 return - if self.sfp_type == "QSFP": + if self.sfp_type == QSFP_TYPE: self.calibration = 1 sfpi_obj = sff8436InterfaceId() if sfpi_obj is None: @@ -348,7 +388,7 @@ def _dom_capability_detect(self): self.dom_tx_power_supported = False self.calibration = 0 self.qsfp_page3_available = False - elif self.sfp_type == "SFP": + elif self.sfp_type == SFP_TYPE: sfpi_obj = sff8472InterfaceId() if sfpi_obj is None: return None From d39f10b31fafeb4ca55d6551bfa1cba26e384306 Mon Sep 17 00:00:00 2001 From: Joe LeVeque Date: Sat, 7 Dec 2019 20:18:49 -0800 Subject: [PATCH 230/278] Revert "[dhcp_relay] Add extra sleep before starting relay agent processes (#3824)" (#3857) This reverts commit 7622a30d98553288ca5cb53bb3b1eff210d40a77. --- dockers/docker-dhcp-relay/start.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dockers/docker-dhcp-relay/start.sh b/dockers/docker-dhcp-relay/start.sh index 54e58dd42a07..0ac5ea1a10ec 100755 --- a/dockers/docker-dhcp-relay/start.sh +++ b/dockers/docker-dhcp-relay/start.sh @@ -16,12 +16,6 @@ if [ $(supervisorctl status | grep -c "^isc-dhcp-relay:") -gt 0 ]; then # lifetime of the process. /usr/bin/wait_for_intf.sh - # Allow a bit more time for interfaces to settle before starting the - # relay agent processes. - # FIXME: Remove/decrease this once we determine how to prevent future race - # conditions here. - sleep 180 - # Start all DHCP relay agent(s) supervisorctl start isc-dhcp-relay:* fi From 335514bf87ee93f6d4c381192574dc82ae6547c4 Mon Sep 17 00:00:00 2001 From: Dong Zhang <41927498+dzhangalibaba@users.noreply.github.com> Date: Mon, 9 Dec 2019 18:42:29 -0800 Subject: [PATCH 231/278] [swss-common] update submodule for sonic-swss-common (#3863) --- src/sonic-swss-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-swss-common b/src/sonic-swss-common index a4a1e108afb3..29a2cdfe9ea9 160000 --- a/src/sonic-swss-common +++ b/src/sonic-swss-common @@ -1 +1 @@ -Subproject commit a4a1e108afb3e75717e204da49a975681d964e8c +Subproject commit 29a2cdfe9ea9bb0c4d2d82be9428228a8ab6b9d4 From fec80293dd22c358b5ccc68eedc23d9feb15aca5 Mon Sep 17 00:00:00 2001 From: rajendra-dendukuri <47423477+rajendra-dendukuri@users.noreply.github.com> Date: Tue, 10 Dec 2019 11:16:56 -0500 Subject: [PATCH 232/278] ZTP infrastructure changes to support DHCP discovery provisioning data (#3298) * ZTP infrastructure changes to support DHCP discovery provisioning data - Dynamically generate DHCP client configuration based on current ZTP state - Added support to request and process hostname when using DHCPv6 - Do not process graphservice url dhcp option if ZTP is enabled, ZTP service will process it - Generate /e/n/i file with all active interfaces seeking address assignment via DHCP. Only interfaces that are created in Linux will be added to /e/n/i. Also DHCP is started only on linked up in-band interfaces. Signed-off-by: Rajendra Dendukuri --- build_debian.sh | 5 +-- .../build_templates/sonic_debian_extension.j2 | 6 +++ files/dhcp/90-dhcp6-systcl.conf.j2 | 7 +++ files/dhcp/dhclient.conf | 24 ---------- files/dhcp/dhclient.conf.j2 | 45 +++++++++++++++++++ files/dhcp/graphserviceurl | 26 ++++++----- files/dhcp/ifupdown2_policy.json | 12 +++++ files/dhcp/rfc3442-classless-routes | 7 ++- files/dhcp/sethostname6 | 14 ++++++ .../interfaces/interfaces-config.sh | 32 ++++++++++++- files/image_config/interfaces/interfaces.j2 | 36 +++++++++++++++ 11 files changed, 172 insertions(+), 42 deletions(-) create mode 100644 files/dhcp/90-dhcp6-systcl.conf.j2 delete mode 100644 files/dhcp/dhclient.conf create mode 100644 files/dhcp/dhclient.conf.j2 create mode 100644 files/dhcp/ifupdown2_policy.json create mode 100644 files/dhcp/sethostname6 diff --git a/build_debian.sh b/build_debian.sh index fb3ecfef6ce6..666e140416c9 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -392,9 +392,6 @@ set /files/etc/sysctl.conf/net.ipv6.conf.default.keep_addr_on_down 1 set /files/etc/sysctl.conf/net.ipv6.conf.all.keep_addr_on_down 1 set /files/etc/sysctl.conf/net.ipv6.conf.eth0.keep_addr_on_down 1 -set /files/etc/sysctl.conf/net.ipv6.conf.eth0.accept_ra_defrtr 0 -set /files/etc/sysctl.conf/net.ipv6.conf.eth0.accept_ra 0 - set /files/etc/sysctl.conf/net.ipv4.tcp_l3mdev_accept 1 set /files/etc/sysctl.conf/net.ipv4.udp_l3mdev_accept 1 @@ -429,10 +426,10 @@ EOF sudo cp files/dhcp/rfc3442-classless-routes $FILESYSTEM_ROOT/etc/dhcp/dhclient-exit-hooks.d sudo cp files/dhcp/sethostname $FILESYSTEM_ROOT/etc/dhcp/dhclient-exit-hooks.d/ +sudo cp files/dhcp/sethostname6 $FILESYSTEM_ROOT/etc/dhcp/dhclient-exit-hooks.d/ sudo cp files/dhcp/graphserviceurl $FILESYSTEM_ROOT/etc/dhcp/dhclient-exit-hooks.d/ sudo cp files/dhcp/snmpcommunity $FILESYSTEM_ROOT/etc/dhcp/dhclient-exit-hooks.d/ sudo cp files/dhcp/vrf $FILESYSTEM_ROOT/etc/dhcp/dhclient-exit-hooks.d/ -sudo cp files/dhcp/dhclient.conf $FILESYSTEM_ROOT/etc/dhcp/ if [ -f files/image_config/ntp/ntp ]; then sudo cp ./files/image_config/ntp/ntp $FILESYSTEM_ROOT/etc/init.d/ fi diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index 209bc19971b3..4e81593298f6 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -203,6 +203,12 @@ sudo cp $IMAGE_CONFIGS/interfaces/interfaces-config.sh $FILESYSTEM_ROOT/usr/bin/ sudo cp $IMAGE_CONFIGS/interfaces/*.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/ echo "interfaces-config.service" | sudo tee -a $GENERATED_SERVICE_FILE +# Copy dhcp client configuration template and create an initial configuration +sudo cp files/dhcp/dhclient.conf.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/ +j2 files/dhcp/dhclient.conf.j2 | sudo tee $FILESYSTEM_ROOT/etc/dhcp/dhclient.conf +sudo cp files/dhcp/ifupdown2_policy.json $FILESYSTEM_ROOT/etc/network/ifupdown2/policy.d +sudo cp files/dhcp/90-dhcp6-systcl.conf.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/ + # Copy initial interfaces configuration file, will be overwritten on first boot sudo cp $IMAGE_CONFIGS/interfaces/init_interfaces $FILESYSTEM_ROOT/etc/network/interfaces sudo mkdir -p $FILESYSTEM_ROOT/etc/network/interfaces.d diff --git a/files/dhcp/90-dhcp6-systcl.conf.j2 b/files/dhcp/90-dhcp6-systcl.conf.j2 new file mode 100644 index 000000000000..addb94675258 --- /dev/null +++ b/files/dhcp/90-dhcp6-systcl.conf.j2 @@ -0,0 +1,7 @@ +{% if MGMT_INTERFACE %} +net.ipv6.conf.eth0.accept_ra_defrtr = 0 +net.ipv6.conf.eth0.accept_ra = 0 +{% else %} +net.ipv6.conf.eth0.accept_ra_defrtr = 1 +net.ipv6.conf.eth0.accept_ra = 1 +{% endif %} diff --git a/files/dhcp/dhclient.conf b/files/dhcp/dhclient.conf deleted file mode 100644 index 6a542e069fab..000000000000 --- a/files/dhcp/dhclient.conf +++ /dev/null @@ -1,24 +0,0 @@ -# Configuration file for /sbin/dhclient, which is included in Debian's -# dhcp3-client package. -# -# This is a sample configuration file for dhclient. See dhclient.conf's -# man page for more information about the syntax of this file -# and a more comprehensive list of the parameters understood by -# dhclient. -# -# Normally, if the DHCP server provides reasonable information and does -# not leave anything out (like the domain name, for example), then -# few changes must be made to this file, if any. -# - -option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; -option snmp-community code 224 = text; -option minigraph-url code 225 = text; -option acl-url code 226 = text; - -send host-name = gethostname(); -request subnet-mask, broadcast-address, time-offset, routers, - domain-name, domain-name-servers, domain-search, host-name, - dhcp6.name-servers, dhcp6.domain-search, interface-mtu, - rfc3442-classless-static-routes, ntp-servers, - snmp-community, minigraph-url, acl-url; diff --git a/files/dhcp/dhclient.conf.j2 b/files/dhcp/dhclient.conf.j2 new file mode 100644 index 000000000000..2a6f6fa84fbd --- /dev/null +++ b/files/dhcp/dhclient.conf.j2 @@ -0,0 +1,45 @@ +{% block banner %} +# =============== Managed by SONiC Config Engine DO NOT EDIT! =============== +# generated from /usr/share/sonic/templates/dhclient.conf.j2 using sonic-cfggen +# file: /etc/dhcp/dhclient.conf +# +{% endblock banner %} +# Configuration file for /sbin/dhclient, which is included in Debian's +# dhcp3-client package. +# +# This is a sample configuration file for dhclient. See dhclient.conf's +# man page for more information about the syntax of this file +# and a more comprehensive list of the parameters understood by +# dhclient. +# +# Normally, if the DHCP server provides reasonable information and does +# not leave anything out (like the domain name, for example), then +# few changes must be made to this file, if any. +# + +option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; +option snmp-community code 224 = text; +option minigraph-url code 225 = text; +option acl-url code 226 = text; +option tftp-server-name code 66 = text; +option bootfile-name code 67 = text; +option user-class code 77 = text; +option provisioning-script-url code 239 = text; +option dhcp6.user-class code 15 = text; +option dhcp6.provisioning-script-url code 239 = text; +option dhcp6.boot-file-url code 59 = text; + +send host-name = gethostname(); +request subnet-mask, broadcast-address, time-offset, routers, + domain-name, domain-name-servers, domain-search, host-name, + dhcp6.name-servers, dhcp6.domain-search, interface-mtu, dhcp6.fqdn, + rfc3442-classless-static-routes, ntp-servers, log-servers, +{%- if ZTP is defined and ZTP_DHCP_DISABLED is not defined -%}bootfile-name, provisioning-script-url, tftp-server-name, + dhcp6.provisioning-script-url, dhcp6.boot-file-url,{%- endif -%} + snmp-community, minigraph-url, acl-url; +{% if ZTP is defined and ZTP_DHCP_DISABLED is not defined %} +send user-class "SONiC-ZTP"; +send dhcp6.user-class "SONiC-ZTP"; +send dhcp-client-identifier "SONiC##{{ ZTP['mode']['product-name'] }}##{{ ZTP['mode']['serial-no'] }}"; +retry 60; +{% endif %} diff --git a/files/dhcp/graphserviceurl b/files/dhcp/graphserviceurl index f255cdff9877..9bd5fded4b8f 100644 --- a/files/dhcp/graphserviceurl +++ b/files/dhcp/graphserviceurl @@ -1,12 +1,14 @@ -case $reason in - BOUND|RENEW|REBIND|REBOOT) - if [ -n "$new_minigraph_url" ]; then - echo $new_minigraph_url > /tmp/dhcp_graph_url - else - echo "N/A" > /tmp/dhcp_graph_url - fi - if [ -n "$new_acl_url" ]; then - echo $new_acl_url > /tmp/dhcp_acl_url - fi - ;; -esac +if [ ! -e /usr/bin/ztp ] || [ "$(ztp status -c)" = "0:DISABLED" ]; then + case $reason in + BOUND|RENEW|REBIND|REBOOT) + if [ -n "$new_minigraph_url" ]; then + echo $new_minigraph_url > /tmp/dhcp_graph_url + else + echo "N/A" > /tmp/dhcp_graph_url + fi + if [ -n "$new_acl_url" ]; then + echo $new_acl_url > /tmp/dhcp_acl_url + fi + ;; + esac +fi diff --git a/files/dhcp/ifupdown2_policy.json b/files/dhcp/ifupdown2_policy.json new file mode 100644 index 000000000000..9a5010dead8a --- /dev/null +++ b/files/dhcp/ifupdown2_policy.json @@ -0,0 +1,12 @@ +{ + "dhcp" : { + "defaults" : { + "dhcp-wait" : "no" + }, + "iface_defaults" : { + "eth0" : { + "dhcp6-duid" : "LL" + } + } + } +} diff --git a/files/dhcp/rfc3442-classless-routes b/files/dhcp/rfc3442-classless-routes index 64e24192816b..797a0d24429f 100644 --- a/files/dhcp/rfc3442-classless-routes +++ b/files/dhcp/rfc3442-classless-routes @@ -55,8 +55,13 @@ if [ "$RUN" = "yes" ]; then fi # set route (ip detects host routes automatically) - ip -4 route add "${net_address}/${net_length}" \ + if echo $interface | grep -v Ethernet ; then + ip -4 route add "${net_address}/${net_length}" \ ${via_arg} dev "${interface}" table default >/dev/null 2>&1 + else + ip -4 route add "${net_address}/${net_length}" \ + ${via_arg} dev "${interface}" >/dev/null 2>&1 + fi done fi fi diff --git a/files/dhcp/sethostname6 b/files/dhcp/sethostname6 new file mode 100644 index 000000000000..6ca5d8dbc995 --- /dev/null +++ b/files/dhcp/sethostname6 @@ -0,0 +1,14 @@ +case $reason in + BOUND6|RENEW6|REBIND6|REBOOT) + current_dhcp6_fqdn=`hostname` + if [ "$current_dhcp6_fqdn" != "$new_dhcp6_fqdn" ] && [ -n "$new_dhcp6_fqdn" ] + then + echo $new_dhcp6_fqdn > /etc/hostname + hostname -F /etc/hostname + sed -i "/\s$current_dhcp6_fqdn$/d" /etc/hosts + sed -i "/\s$new_dhcp6_fqdn$/d" /etc/hosts + echo "127.0.0.1 $new_dhcp6_fqdn" >> /etc/hosts + echo ":: $new_dhcp6_fqdn" >> /etc/hosts + fi + ;; +esac diff --git a/files/image_config/interfaces/interfaces-config.sh b/files/image_config/interfaces/interfaces-config.sh index a702917419ca..8dddc215bbd9 100755 --- a/files/image_config/interfaces/interfaces-config.sh +++ b/files/image_config/interfaces/interfaces-config.sh @@ -2,10 +2,40 @@ ifdown --force eth0 -sonic-cfggen -d -t /usr/share/sonic/templates/interfaces.j2 > /etc/network/interfaces +# Check if ZTP DHCP policy has been installed +if [ -e /etc/network/ifupdown2/policy.d/ztp_dhcp.json ]; then + # Obtain port operational state information + redis-dump -d 0 -k "PORT_TABLE:Ethernet*" -y > /tmp/ztp_port_data.json + + if [ $? -ne 0 ] || [ ! -e /tmp/ztp_port_data.json ] || [ "$(cat /tmp/ztp_port_data.json)" = "" ]; then + echo "{}" > /tmp/ztp_port_data.json + fi + + # Create an input file with ztp input information + echo "{ \"PORT_DATA\" : $(cat /tmp/ztp_port_data.json) }" > \ + /tmp/ztp_input.json +else + echo "{ \"ZTP_DHCP_DISABLED\" : \"true\" }" > /tmp/ztp_input.json +fi + +# Create /e/n/i file for existing and active interfaces +sonic-cfggen -d -j /tmp/ztp_input.json -t /usr/share/sonic/templates/interfaces.j2 > /etc/network/interfaces [ -f /var/run/dhclient.eth0.pid ] && kill `cat /var/run/dhclient.eth0.pid` && rm -f /var/run/dhclient.eth0.pid +[ -f /var/run/dhclient6.eth0.pid ] && kill `cat /var/run/dhclient6.eth0.pid` && rm -f /var/run/dhclient6.eth0.pid +for intf_pid in $(ls -1 /var/run/dhclient*.Ethernet*.pid 2> /dev/null); do + [ -f ${intf_pid} ] && kill `cat ${intf_pid}` && rm -f ${intf_pid} +done + +sonic-cfggen -d -j /tmp/ztp_input.json -t /usr/share/sonic/templates/90-dhcp6-systcl.conf.j2 > /etc/sysctl.d/90-dhcp6-systcl.conf +# Read sysctl conf files again +sysctl -p /etc/sysctl.d/90-dhcp6-systcl.conf + +sonic-cfggen -d -j /tmp/ztp_input.json -t /usr/share/sonic/templates/dhclient.conf.j2 > /etc/dhcp/dhclient.conf systemctl restart networking +# Clean-up created files +rm -f /tmp/ztp_input.json /tmp/ztp_port_data.json + ifdown lo && ifup lo diff --git a/files/image_config/interfaces/interfaces.j2 b/files/image_config/interfaces/interfaces.j2 index 91be4437fc06..8b8ea0b52bc8 100644 --- a/files/image_config/interfaces/interfaces.j2 +++ b/files/image_config/interfaces/interfaces.j2 @@ -27,6 +27,38 @@ iface lo inet loopback # The management network interface auto eth0 +{% if (ZTP_DHCP_DISABLED is not defined) and (ZTP is defined) and (ZTP['mode'] is defined and ZTP['mode']['profile'] == 'active') %} + + +# ZTP out-of-band interface +allow-hotplug eth0 +{% if ZTP['mode']['ipv4'] == 'true' %} +iface eth0 inet dhcp +{% endif %} +{% if ZTP['mode']['ipv6'] == 'true' %} +iface eth0 inet6 dhcp + up sysctl net.ipv6.conf.eth0.accept_ra=1 + down sysctl net.ipv6.conf.eth0.accept_ra=0 +{% endif %} + +{% if ZTP['mode']['inband'] == 'true' %} +{% for port in PORT %} + +# ZTP in-band interface {{ port }} +auto {{ port }} +allow-hotplug {{ port }} +{% if PORT_DATA['PORT_TABLE:'+port] is defined and PORT_DATA['PORT_TABLE:'+port]['value']['oper_status'] == 'up' %} +{% if ZTP['mode']['ipv4'] == 'true' %} +iface {{ port }} inet dhcp +{% endif %} +{% if ZTP['mode']['ipv6'] == 'true' %} +iface {{ port }} inet6 dhcp +{% endif %} +{% endif %} +{% endfor %} +{% endif %} + +{% else %} {% if MGMT_INTERFACE %} {% for (name, prefix) in MGMT_INTERFACE|pfx_filter %} iface eth0 {{ 'inet' if prefix | ipv4 else 'inet6' }} static @@ -70,6 +102,10 @@ iface eth0 inet dhcp up cgset -r l3mdev.master-device=mgmt mgmt down cgdelete -g l3mdev:mgmt {% endif %} +iface eth0 inet6 dhcp + up sysctl net.ipv6.conf.eth0.accept_ra=1 + down sysctl net.ipv6.conf.eth0.accept_ra=0 +{% endif %} {% endif %} # source /etc/network/interfaces.d/* From 9b8c59f4090d462ccc89a31e2951a10a664b4413 Mon Sep 17 00:00:00 2001 From: Dong Zhang <41927498+dzhangalibaba@users.noreply.github.com> Date: Tue, 10 Dec 2019 09:45:32 -0800 Subject: [PATCH 233/278] [swss] update submodule for sonic-swss (#3864) update multiDB changes in sonic-swss to include multiDB API changes: - [MultiDB]: using new APIs in orch agents and mocktest (#1138) - [vstest]: gather logs when dvs fail to start (#1140) --- src/sonic-swss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-swss b/src/sonic-swss index c3b8fe10b156..fc085ee70df1 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit c3b8fe10b1568022fa025ef4be9cb063bfe49df4 +Subproject commit fc085ee70df1b6e4edf512bcfac212be429ab021 From dd322270cba96dbb766688b899167c01f485ef73 Mon Sep 17 00:00:00 2001 From: srideepDell Date: Tue, 10 Dec 2019 16:13:25 -0700 Subject: [PATCH 234/278] [DellEMC]: utility to set onie modes from NOS (#3860) This common utility would set next boot option as onie mode and when reboot is triggered it would reboot the box into that specific onie mode. Current support modes are rescue/install/uninstall --- .../common/onie_mode_set | 90 +++++++++++++++++++ .../debian/platform-modules-s5232f.install | 1 + .../debian/platform-modules-s5248f.install | 1 + .../debian/platform-modules-s6100.install | 1 + .../debian/platform-modules-z9100.install | 1 + .../debian/platform-modules-z9264f.install | 1 + 6 files changed, 95 insertions(+) create mode 100755 platform/broadcom/sonic-platform-modules-dell/common/onie_mode_set diff --git a/platform/broadcom/sonic-platform-modules-dell/common/onie_mode_set b/platform/broadcom/sonic-platform-modules-dell/common/onie_mode_set new file mode 100755 index 000000000000..247dda5dcc8e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/common/onie_mode_set @@ -0,0 +1,90 @@ +#!/bin/bash +#scrit to set onie boot modes from NOS +# modes supported rescue/install/uninstall + +VERBOSE=no +ONIEPATH="/mnt/onie-boot" + +unset ONIE_MODE + +function set_onie_boot() +{ + # If reboot to ONIE is requested, set the ONIE boot mode (update/install/uninstall/rescue) + # and reboot. + + # Exit if not superuser + if [[ "$EUID" -ne 0 ]]; then + echo "This command must be run as root" >&2 + exit 1 + fi + + # Mount ONIE partition if not already mounted + if ! grep -qs '/mnt/onie-boot ' /proc/mounts; then + mkdir -p ${ONIEPATH} + mount LABEL=ONIE-BOOT ${ONIEPATH} || ERR=$? + if [[ ${ERR} -ne 0 ]]; then + VERBOSE=yes debug "Failed to mount ONIE partition." + exit 1 + fi + fi + + # Set mode + ${ONIEPATH}/onie/tools/bin/onie-boot-mode -o ${ONIE_MODE} || ERR=$? + if [[ ${ERR} -ne 0 ]]; then + VERBOSE=yes debug "Failed to set ONIE boot mode. Ensure that mode is valid" + exit 1 + fi + + # Set next boot to ONIE + grub-editenv /host/grub/grubenv set next_entry=ONIE || ERR=$? + if [[ ${ERR} -ne 0 ]]; then + VERBOSE=yes debug "Failed to set next boot to ONIE." + exit 1 + fi + echo "next boot mode set to onie - ${ONIE_MODE}" + +} + + +function debug() +{ + if [[ x"${VERBOSE}" == x"yes" ]]; then + echo `date` $@ + fi + logger "$@" +} + + +SCRIPT=$0 + +function show_help_and_exit() +{ + echo "Usage ${SCRIPT} [options]" + echo " This script will set modes in onie rescue/uninstall/install." + echo " " + echo " Available options:" + echo " -h, -? : getting this help" + echo " -o [mode] : boot into ONIE" + + exit 0 +} + +function parse_options() +{ + while getopts "h?vo:" opt; do + case $opt in + h|\? ) + show_help_and_exit + ;; + o ) + ONIE_MODE=$OPTARG + set_onie_boot + ;; + v ) + VERBOSE=yes + ;; + esac + done +} + +parse_options $@ diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5232f.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5232f.install index b577c5cd5b10..303e978848db 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5232f.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5232f.install @@ -8,3 +8,4 @@ s5232f/cfg/s5232f-modules.conf etc/modules-load.d s5232f/systemd/platform-modules-s5232f.service etc/systemd/system common/platform_reboot usr/share/sonic/device/x86_64-dellemc_s5232f_c3538-r0 common/fw-updater usr/local/bin +common/onie_mode_set usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.install index 7aa27d23b536..e87ea7e37b4e 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5248f.install @@ -8,3 +8,4 @@ s5248f/cfg/s5248f-modules.conf etc/modules-load.d s5248f/systemd/platform-modules-s5248f.service etc/systemd/system common/platform_reboot usr/share/sonic/device/x86_64-dellemc_s5248f_c3538-r0 common/fw-updater usr/local/bin +common/onie_mode_set usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install index 5d1cb6341fc7..eb0211b3afde 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install @@ -14,3 +14,4 @@ s6100/systemd/platform-modules-s6100.service etc/systemd/system s6100/systemd/s6100-lpc-monitor.service etc/systemd/system tools/flashrom/flashrom usr/local/bin/ common/fw-updater usr/local/bin +common/onie_mode_set usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.install index 5c5c4cc55be2..a4dffe0d023c 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.install @@ -12,3 +12,4 @@ z9100/cfg/z9100-modules.conf etc/modules-load.d z9100/systemd/platform-modules-z9100.service etc/systemd/system z9100/systemd/z9100-lpc-monitor.service etc/systemd/system common/fw-updater usr/local/bin +common/onie_mode_set usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.install index 29e8b1df2e36..e7d589f14e0c 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.install @@ -8,3 +8,4 @@ z9264f/cfg/z9264f-modules.conf etc/modules-load.d z9264f/systemd/platform-modules-z9264f.service etc/systemd/system common/platform_reboot usr/share/sonic/device/x86_64-dellemc_z9264f_c3538-r0 common/fw-updater usr/local/bin +common/onie_mode_set usr/local/bin From 7ef57f92e1479b382fce962b2ea8c0346d0550b5 Mon Sep 17 00:00:00 2001 From: Myron Sosyak <49795530+msosyak@users.noreply.github.com> Date: Tue, 10 Dec 2019 18:03:55 -0800 Subject: [PATCH 235/278] [docker-sonic-mgmt]: Add docker-ce-cli to sonic-mgmt container (#3868) In the scope of migration from docker shell plugin to docker connection plugin, we need to have docker-ce-cli installed in docker-sonic-mgmt. Azure/sonic-mgmt#1269 Added docker-ce-cli package to docker-sonic-mgmt. --- dockers/docker-sonic-mgmt/Dockerfile.j2 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dockers/docker-sonic-mgmt/Dockerfile.j2 b/dockers/docker-sonic-mgmt/Dockerfile.j2 index d24df1ca5d77..4c53baf7c485 100644 --- a/dockers/docker-sonic-mgmt/Dockerfile.j2 +++ b/dockers/docker-sonic-mgmt/Dockerfile.j2 @@ -71,6 +71,19 @@ RUN pip install ipaddr \ && pip install nnpy \ && pip install dpkt +# Install docker-ce-cli +RUN apt-get update \ + && apt-get install -y \ + apt-transport-https \ + ca-certificates \ + curl \ + gnupg-agent \ + software-properties-common \ + && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - \ + && add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \ + && apt-get update \ + && apt-get install -y docker-ce-cli + # Install Microsoft Azure Kusto Library for Python RUN pip install azure-kusto-data==0.0.13 \ azure-kusto-ingest==0.0.13 From 979b0dd4a2e051a2226aac3f5daa4c8be11bfa94 Mon Sep 17 00:00:00 2001 From: kannankvs Date: Wed, 11 Dec 2019 13:18:18 +0530 Subject: [PATCH 236/278] [doc]: Added one extra sentence to give example for check out 201911 branch (#3867) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a1de15524b63..301bff39547e 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ To build SONiC installer image and docker images, run the following commands: # Enter the source directory cd sonic-buildimage - # (Optional) Checkout a specific branch. By default, it uses master branch + # (Optional) Checkout a specific branch. By default, it uses master branch. For example, to checkout the branch 201911, use "git checkout 201911" git checkout [branch_name] # Execute make init once after cloning the repo, or after fetching remote repo with submodule updates From 3b0c51f423637aafb0c0c42c98c6729e1609468a Mon Sep 17 00:00:00 2001 From: Kebo Liu Date: Thu, 12 Dec 2019 01:41:29 +0800 Subject: [PATCH 237/278] [sub module] Update sonic-platform-common pointer to pick up fix (#3859) Azure/sonic-platform-common#71 [Bug fix] fix a syntax error which was introduced by last commit Azure/sonic-platform-common#70 Fix EEPROM vendor extension TLV number counting issue Azure/sonic-platform-common#62 Platform Driver Development Framework (PDDF): 1) Changes to psu base class (1.0 APIs) to support PDDF CLI utils, 2) Adding fan_base class to support PDDF fan CLI utils (comments incorporated) Azure/sonic-platform-common#68 DeviceBase.get_name should raise NotImplementedError like other member --- src/sonic-platform-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-platform-common b/src/sonic-platform-common index 6ad48b87eb96..6f74dd3f4f42 160000 --- a/src/sonic-platform-common +++ b/src/sonic-platform-common @@ -1 +1 @@ -Subproject commit 6ad48b87eb9654daa3f3c854134434d14572573f +Subproject commit 6f74dd3f4f42bc945467cffa4f889b50e4b1468a From ef26ba024d73996073ff9afc2fc15d8da0802d7e Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Fri, 13 Dec 2019 03:09:28 +0800 Subject: [PATCH 238/278] [Mellanox]Update hw-mgmt to V7.0000.2308 (#3858) * [Mellanox]Update hw-mgmt to V7.0000.2308 sonic-linux-kernel should be updated accordingly with necessary patches uploaded. * [sub-module]Advance submodule head for sonic-linux-kernel --- platform/mellanox/hw-management.mk | 2 +- platform/mellanox/hw-management/hw-mgmt | 2 +- src/sonic-linux-kernel | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/mellanox/hw-management.mk b/platform/mellanox/hw-management.mk index f41c2b9a25ce..ff1ea207572d 100644 --- a/platform/mellanox/hw-management.mk +++ b/platform/mellanox/hw-management.mk @@ -1,6 +1,6 @@ # Mellanox HW Management -MLNX_HW_MANAGEMENT_VERSION = 7.0000.2303 +MLNX_HW_MANAGEMENT_VERSION = 7.0000.2308 export MLNX_HW_MANAGEMENT_VERSION diff --git a/platform/mellanox/hw-management/hw-mgmt b/platform/mellanox/hw-management/hw-mgmt index 7c26a8f6a520..28d83cdb3565 160000 --- a/platform/mellanox/hw-management/hw-mgmt +++ b/platform/mellanox/hw-management/hw-mgmt @@ -1 +1 @@ -Subproject commit 7c26a8f6a520b06663992afe874bc56b1fcd9311 +Subproject commit 28d83cdb3565d3b0352cc718fe82a14cacd1d4a5 diff --git a/src/sonic-linux-kernel b/src/sonic-linux-kernel index feb42b05eb91..87576c061d10 160000 --- a/src/sonic-linux-kernel +++ b/src/sonic-linux-kernel @@ -1 +1 @@ -Subproject commit feb42b05eb912ea64f0b4ce17f4bc890929eb57e +Subproject commit 87576c061d10dfe7de8e8e5cc1bae6bd29b0143b From 13eec88732835b82802721deed72c2c43f3751bc Mon Sep 17 00:00:00 2001 From: Qi Luo Date: Thu, 12 Dec 2019 18:46:35 -0800 Subject: [PATCH 239/278] Change the dpkg default behavior in slave, and docker-base, in order to prevent prompt (#3879) * Change the dpkg default behavior in slave, and docker-base, in order to prevent prompt * Move to right place --- dockers/docker-base-stretch/dpkg_01_drop | 8 ++++++++ dockers/docker-base/dpkg_01_drop | 8 ++++++++ sonic-slave-stretch/Dockerfile.j2 | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/dockers/docker-base-stretch/dpkg_01_drop b/dockers/docker-base-stretch/dpkg_01_drop index e75ef3147158..d749943797d9 100644 --- a/dockers/docker-base-stretch/dpkg_01_drop +++ b/dockers/docker-base-stretch/dpkg_01_drop @@ -20,3 +20,11 @@ path-exclude /usr/share/pyshared/twisted/test* path-exclude /usr/lib/python*/dist-packages/twisted/test* path-exclude /usr/share/pyshared/twisted/*/test* path-exclude /usr/lib/python*/dist-packages/twisted/*/test* + +## install the configuration file if it’s currently missing +force-confmiss +## combined with confold: overwrite configuration files that you have not modified +force-confdef +## do not modify the current configuration file, the new version is installed with a .dpkg-dist suffix +force-confold + diff --git a/dockers/docker-base/dpkg_01_drop b/dockers/docker-base/dpkg_01_drop index e75ef3147158..d749943797d9 100644 --- a/dockers/docker-base/dpkg_01_drop +++ b/dockers/docker-base/dpkg_01_drop @@ -20,3 +20,11 @@ path-exclude /usr/share/pyshared/twisted/test* path-exclude /usr/lib/python*/dist-packages/twisted/test* path-exclude /usr/share/pyshared/twisted/*/test* path-exclude /usr/lib/python*/dist-packages/twisted/*/test* + +## install the configuration file if it’s currently missing +force-confmiss +## combined with confold: overwrite configuration files that you have not modified +force-confdef +## do not modify the current configuration file, the new version is installed with a .dpkg-dist suffix +force-confold + diff --git a/sonic-slave-stretch/Dockerfile.j2 b/sonic-slave-stretch/Dockerfile.j2 index f52bd943b0a7..133238622f76 100644 --- a/sonic-slave-stretch/Dockerfile.j2 +++ b/sonic-slave-stretch/Dockerfile.j2 @@ -293,6 +293,14 @@ RUN apt-get update && apt-get install -y \ # For kdump-tools liblzo2-dev +## Config dpkg +## install the configuration file if it’s currently missing +RUN sudo augtool --autosave "set /files/etc/dpkg/dpkg.cfg/force-confmiss" +## combined with confold: overwrite configuration files that you have not modified +RUN sudo augtool --autosave "set /files/etc/dpkg/dpkg.cfg/force-confdef" +## do not modify the current configuration file, the new version is installed with a .dpkg-dist suffix +RUN sudo augtool --autosave "set /files/etc/dpkg/dpkg.cfg/force-confold" + # For smartmontools 6.6-1 RUN apt-get -t stretch-backports install -y debhelper From f126258d5fa40406b5412cb6afff7eeb6529b224 Mon Sep 17 00:00:00 2001 From: ciju-juniper <53076238+ciju-juniper@users.noreply.github.com> Date: Fri, 13 Dec 2019 22:36:05 +0530 Subject: [PATCH 240/278] [Juniper][QFX5210] Platform monitoring updates (#3899) As part of this commit, there are a few enhancements being made for EM policy implementation: a) Introduced hysteresis algorithm to prevent fan hunting b) Reading ASIC temperature to make decision for fan speed. As part of the PR# 3599, Workaround for the boot problem from secondary bios was addressed. When the SONiC image is upgraded, this resulted in creating multiple entries for BOOTX64.EFI. To fix the problem, as part of this changeset, introducing a check to see if there is already an UEFI entry for BOOTX64.EFI and accordingly creating / skipping the UEFI entry. Signed-off-by: Ciju Rajan K --- .../sonic-platform-juniper-qfx5210.postinst | 11 +- .../qfx5210/utils/juniper_qfx5210_monitor.py | 221 ++++++++++++++---- 2 files changed, 181 insertions(+), 51 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.postinst b/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.postinst index dcff39f53799..97b66fb44e4c 100644 --- a/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.postinst +++ b/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.postinst @@ -1,3 +1,5 @@ +#!/bin/bash + systemctl enable qfx5210-platform-init.service systemctl start qfx5210-platform-init.service @@ -18,5 +20,12 @@ if [ -f $FIRST_BOOT_FILE ]; then cp SONiC-OS/grubx64.efi BOOT/BOOTX64.EFI cd /tmp umount sda1 - efibootmgr -c -L "SONiC" -l "\EFI\BOOT\BOOTX64.EFI" > /dev/null 2>&1 + # This code block ensures that no additional entries + # are added. This is applicable during SONiC image + # upgrades. + entries=`efibootmgr -v | grep "BOOTX64"` + if [ -z "$entries" ]; then + # Creating the UEFI entry for the first time. + efibootmgr -c -L "SONiC" -l "\EFI\BOOT\BOOTX64.EFI" > /var/tmp/efi_log 2>&1 + fi fi diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py index d225400121b8..97adf9588f9f 100755 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py @@ -47,6 +47,7 @@ import traceback import glob import collections + import StringIO from tabulate import tabulate except ImportError as e: raise ImportError('%s - required module not found' % str(e)) @@ -54,15 +55,20 @@ # Deafults VERSION = '1.0' FUNCTION_NAME = '/var/log/juniper_qfx5210_monitor' - +verbose = False +DEBUG = False global log_file global log_level global isPlatformAFI +global is80PerFlag +global is60PerFlag global isFireThresholdReached -FireThresholdSecsRemaining = 120 +global isFireThresholdPrint +global PrevASICValue +global FireThresholdSecsRemaining temp_policy_AFI = { 0: [[70, 0, 48000], [70, 48000, 53000], [80, 53000, 0], [80, 53000, 58000], [100, 58000, 0], ['Yellow Alarm', 64000, 70000], ['Red Alarm', 70000, 75000], ['Fire Shut Alarm', 75000, 0]], @@ -72,6 +78,7 @@ 4: [[70, 0, 31000], [70, 31000, 36000], [80, 36000, 0], [80, 36000, 42000], [100, 42000, 0], ['Yellow Alarm', 48000, 55000], ['Red Alarm', 55000, 60000], ['Fire Shut Alarm', 60000, 0]], 5: [[70, 0, 31000], [70, 31000, 36000], [80, 36000, 0], [80, 36000, 43000], [100, 43000, 0], ['Yellow Alarm', 49000, 56000], ['Red Alarm', 56000, 61000], ['Fire Shut Alarm', 61000, 0]], 6: [[70, 0, 70000], [70, 70000, 78000], [80, 78000, 0], [80, 78000, 86000], [100, 86000, 0], ['Yellow Alarm', 91000, 96000], ['Red Alarm', 96000, 102000], ['Fire Shut Alarm', 102000, 0]], + 7: [[70, 0, 84000], [70, 84000, 91000], [80, 91000, 0], [80, 91000, 98000], [100, 98000, 0], ['Yellow Alarm', 103000, 108000], ['Red Alarm', 108000, 120000], ['Fire Shut Alarm', 120000, 0]], } temp_policy_AFO = { @@ -82,6 +89,7 @@ 4: [[60, 0, 39000], [60, 39000, 45000], [80, 45000, 0], [80, 45000, 52000], [100, 52000, 0], ['Yellow Alarm', 59000, 65000], ['Red Alarm', 65000, 69000], ['Fire Shut Alarm', 69000, 0]], 5: [[60, 0, 37000], [60, 37000, 43000], [80, 43000, 0], [80, 43000, 50000], [100, 50000, 0], ['Yellow Alarm', 57000, 63000], ['Red Alarm', 63000, 67000], ['Fire Shut Alarm', 67000, 0]], 6: [[60, 0, 70000], [60, 70000, 78000], [80, 78000, 0], [80, 78000, 86000], [100, 86000, 0], ['Yellow Alarm', 91000, 96000], ['Red Alarm', 96000, 102000], ['Fire Shut Alarm', 102000, 0]], + 7: [[60, 0, 84000], [60, 84000, 91000], [80, 91000, 0], [80, 91000, 98000], [100, 98000, 0], ['Yellow Alarm', 103000, 108000], ['Red Alarm', 108000, 120000], ['Fire Shut Alarm', 120000, 0]], } class QFX5210_FanUtil(object): @@ -97,7 +105,7 @@ def get_fan_duty_cycle(self): try: val_file = open(self.FAN_DUTY_PATH) except IOError as e: - print "Error: unable to open file: %s" % str(e) + logging.error('get_fan_duty_cycle: unable to open file: %s', str(e)) return False content = val_file.readline().rstrip() @@ -110,7 +118,7 @@ def set_fan_duty_cycle(self, val): try: fan_file = open(self.FAN_DUTY_PATH, 'r+') except IOError as e: - print "Error: unable to open file: %s" % str(e) + logging.error('set_fan_duty_cycle: unable to open file: %s', str(e)) return False fan_file.write(str(val)) fan_file.close() @@ -120,7 +128,8 @@ class QFX5210_ThermalUtil(object): """QFX5210 Platform ThermalUtil class""" SENSOR_NUM_ON_MAIN_BOARD = 6 - SENSOR_CORETEMP_NUM_ON_MAIN_BOARD = 7 + CORETEMP_INDEX_ON_MAIN_BOARD = 6 + SENSOR_CORETEMP_NUM_ON_MAIN_BOARD = 8 CORETEMP_NUM_ON_MAIN_BOARD = 5 THERMAL_NUM_RANGE = 8 SENSOR_NUM_1_IDX = 1 @@ -181,19 +190,19 @@ def _get_sensor_node_val(self, thermal_num): try: val_file = open(filename, 'r') except IOError as e: - logging.error('GET. unable to open file: %s', str(e)) + logging.error('get_sensor_node_val: unable to open file: %s', str(e)) return None content = val_file.readline().rstrip() if content == '': - logging.debug('GET. content is NULL. device_path:%s', device_path) + logging.debug('get_sensor_node_val: content is NULL. device_path:%s', device_path) return None try: - val_file.close() + val_file.close() except: - logging.debug('GET. unable to close file. device_path:%s', device_path) + logging.debug('get_sensor_node_val: unable to close file. device_path:%s', device_path) return None return int(content) @@ -208,19 +217,19 @@ def _get_coretemp_node_val(self, thermal_num): try: val_file = open(filename, 'r') except IOError as e: - logging.error('GET. unable to open file: %s', str(e)) + logging.error('get_coretemp_node_val: unable to open file: %s', str(e)) return None content = val_file.readline().rstrip() if content == '': - logging.debug('GET. content is NULL. device_path:%s', device_path) + logging.debug('get_coretemp_node_val: content is NULL. device_path:%s', device_path) return None try: val_file.close() except: - logging.debug('GET. unable to close file. device_path:%s', device_path) + logging.debug('get_coretemp_node_val: unable to close file. device_path:%s', device_path) return None return int(content) @@ -243,7 +252,7 @@ def get_alarm_led_brightness(self): try: val_file = open(self.ALARM_LED_PATH) except IOError as e: - print "Error: unable to open file: %s" % str(e) + logging.error('get_alarm_led_brightness: unable to open file: %s', str(e)) return False content = val_file.readline().rstrip() @@ -260,7 +269,7 @@ def set_alarm_led_brightness(self, val): try: val_file = open(self.ALARM_LED_PATH, 'r+') except IOError as e: - print "Error: unable to open file: %s" % str(e) + logging.error('set_alarm_led_brightness: unable to open file: %s', str(e)) return False val_file.write(str(val)) val_file.close() @@ -274,8 +283,12 @@ def set_alarm_led_brightness(self, val): def getSensorTemp(self): sum = 0 global isPlatformAFI + global is80PerFlag + global is60PerFlag global isFireThresholdReached - global FireThresholdSecsRemaining + global FireThresholdSecsRemaining + global isFireThresholdPrint + global PrevASICValue #AFI if (isPlatformAFI == True): temp_policy = temp_policy_AFI @@ -294,14 +307,22 @@ def getSensorTemp(self): 4: [0,0,0,0,0,0,0,0], 5: [0,0,0,0,0,0,0,0], 6: [0,0,0,0,0,0,0,0], + 7: [0,0,0,0,0,0,0,0], } # if the Firethreshold Flag is set and 120 seconds have elapsed, invoking the "poweroff" to shutdown the box if (isFireThresholdReached == True): firethr = FireThresholdSecsRemaining - 20 - logging.critical('CRITICAL: Fire Threshold reached: System is going to shutdown in %s seconds', firethr) - print "Fire Threshold reached: System is going to shutdown in %s seconds\n" % firethr + if firethr == 0: + logging.critical('CRITICAL: Fire Threshold reached: System is going to shutdown now') + os.system("echo 'CRITICAL: Fire Threshold reached: System is going to shutdown now' > /dev/console") + else: + logging.critical('CRITICAL: Fire Threshold reached: System is going to shutdown in %s seconds', firethr) + os.system("echo 'CRITICAL: Fire Threshold reached: System is going to shutdown in %s seconds' > /dev/console" % firethr) + FireThresholdSecsRemaining = FireThresholdSecsRemaining - 20 - if (FireThresholdSecsRemaining == 20): + logging.critical('CRITICAL: Value of FireThresholdSecsRemaining %s seconds', FireThresholdSecsRemaining) + + if (FireThresholdSecsRemaining == 0): isFireThresholdReached == False time.sleep(20) cmd = "poweroff" @@ -310,9 +331,32 @@ def getSensorTemp(self): for x in range(self.SENSOR_CORETEMP_NUM_ON_MAIN_BOARD): if x < self.SENSOR_NUM_ON_MAIN_BOARD: value = self._get_sensor_node_val(x+1) + logging.debug('Sensor value %d : %s', x, value) + elif x == self.CORETEMP_INDEX_ON_MAIN_BOARD: + value = self.get_coretempValue() + logging.debug('Main Board CORE temp: %s', value) else: - value = self.get_coretempValue() - + logging.debug('Reading ASIC Temp value using bcmcmd') + proc = subprocess.Popen("bcmcmd \"show temp\" | grep \"maximum peak temperature\" | awk '{ print $5 }' > /var/log/asic_value 2>&1 & ",shell=True) + time.sleep(2) + cmd = "kill -9 %s"%(proc.pid) + status, cmd_out = commands.getstatusoutput(cmd) + + if os.stat("/var/log/asic_value").st_size == 0: + value = PrevASICValue + logging.debug('No ASIC Temp file, Prev ASIC Temp Value: %s', PrevASICValue) + else: + with open('/var/log/asic_value', 'r') as f: + value1 = f.readline() + value2 = float(value1) + value1 = value2 * 1000 + value = int(value1) + PrevASICValue = value + logging.debug('Reading from ASIC Temp file: %s', value) + logging.debug('Reading from Prev ASIC Temp Value: %s', PrevASICValue) + + os.system('rm /var/log/asic_value') + # 60% Duty Cycle for AFO and 70% Duty Cycle for AFI if value > temp_policy[x][0][1] and value <= temp_policy[x][0][2]: SensorFlag[x][0] = True @@ -350,57 +394,113 @@ def getSensorTemp(self): fan = QFX5210_FanUtil() # CHECK IF ANY TEMPERATURE SENSORS HAS SET FIRE SHUTDOWN FLAG - if SensorFlag[0][7] or SensorFlag[1][7] or SensorFlag[2][7] or SensorFlag[3][7] or SensorFlag[4][7] or SensorFlag[5][7] or SensorFlag[6][7]: + if SensorFlag[0][7] or SensorFlag[1][7] or SensorFlag[2][7] or SensorFlag[3][7] or SensorFlag[4][7] or SensorFlag[5][7] or SensorFlag[6][7] or SensorFlag[7][7]: isFireThresholdReached = True - logging.critical('CRITICAL: Fire Threshold reached: System is going to shutdown in 120 seconds') - print "CRITICAL: Fire Threshold reached: System is going to shutdown in 120 seconds\n" - value = self.get_alarm_led_brightness() - if ( value > 0): - self.set_alarm_led_brightness(0) + if (isFireThresholdPrint == True): + logging.critical('CRITICAL: Fire Threshold reached: System is going to shutdown in 120 seconds') + os.system("echo 'CRITICAL: Fire Threshold reached: System is going to shutdown in 120 seconds' > /dev/console") + isFireThresholdPrint = False + + logging.debug('Temp Sensor is set to FIRE SHUTDOWN Flag') + fan.set_fan_duty_cycle(100) + self.set_alarm_led_brightness(2) # CHECK IF ANY TEMPERATURE SENSORS HAS SET 'RED' ALARM FLAG, IF YES, SET THE ALARM LED TO 'RED' - elif SensorFlag[0][6] or SensorFlag[1][6] or SensorFlag[2][6] or SensorFlag[3][6] or SensorFlag[4][6] or SensorFlag[5][6] or SensorFlag[6][6]: + elif SensorFlag[0][6] or SensorFlag[1][6] or SensorFlag[2][6] or SensorFlag[3][6] or SensorFlag[4][6] or SensorFlag[5][6] or SensorFlag[6][6] or SensorFlag[7][6]: + fan.set_fan_duty_cycle(100) self.set_alarm_led_brightness(2) + logging.debug('Temp Sensor is set to Red Alarm Flag') + if (isFireThresholdReached == True): + logging.critical('CRITICAL: System Stabilized, not shutting down') + os.system("echo 'CRITICAL: System Stabilized, not shutting down' > /dev/console") + FireThresholdSecsRemaining = 120 + isFireThresholdReached = False # CHECK IF ANY TEMPERATURE SENSORS HAS SET 'YELLOW' ALARM FLAG, IF YES, SET THE ALARM LED TO 'YELLOW' - elif SensorFlag[0][5] or SensorFlag[1][5] or SensorFlag[2][5] or SensorFlag[3][5] or SensorFlag[4][5] or SensorFlag[5][5] or SensorFlag[6][5]: + elif SensorFlag[0][5] or SensorFlag[1][5] or SensorFlag[2][5] or SensorFlag[3][5] or SensorFlag[4][5] or SensorFlag[5][5] or SensorFlag[6][5] or SensorFlag[7][5]: + fan.set_fan_duty_cycle(100) self.set_alarm_led_brightness(1) + logging.debug('Temp Sensor is set to Yellow Alarm Flag') + if (isFireThresholdReached == True): + logging.critical('CRITICAL: System Stabilized, not shutting down') + os.system("echo 'CRITICAL: System Stabilized, not shutting down' > /dev/console") + FireThresholdSecsRemaining = 120 + isFireThresholdReached = False # CHECK IF ANY TEMPERATURE SENSORS HAS SET 100% DUTY CYCLE FLAG, IF YES, SET THE FAN DUTY CYCLE TO 100% - elif SensorFlag[0][4] or SensorFlag[1][4] or SensorFlag[2][4] or SensorFlag[3][4] or SensorFlag[4][4] or SensorFlag[5][4] or SensorFlag[6][4]: + elif SensorFlag[0][4] or SensorFlag[1][4] or SensorFlag[2][4] or SensorFlag[3][4] or SensorFlag[4][4] or SensorFlag[5][4] or SensorFlag[6][4] or SensorFlag[7][4]: fan.set_fan_duty_cycle(100) value = self.get_alarm_led_brightness() if ( value > 0): self.set_alarm_led_brightness(0) + is80PerFlag = False + is60PerFlag = False + logging.debug('Temp Sensor is set to 100% Duty Cycle Flag') # CHECK IF ANY TEMPERATURE SENSORS HAS SET 80% DUTY CYCLE PREV FLAG, IF YES, SET THE FAN DUTY CYCLE TO 80% - elif SensorFlag[0][3] or SensorFlag[1][3] or SensorFlag[2][3] or SensorFlag[3][3] or SensorFlag[4][3] or SensorFlag[5][3] or SensorFlag[6][3]: - fan.set_fan_duty_cycle(80) + elif SensorFlag[0][3] or SensorFlag[1][3] or SensorFlag[2][3] or SensorFlag[3][3] or SensorFlag[4][3] or SensorFlag[5][3] or SensorFlag[6][3] or SensorFlag[7][3]: + if (is80PerFlag == True): + fan.set_fan_duty_cycle(80) + is80PerFlag = False + else: + pass + value = self.get_alarm_led_brightness() if ( value > 0): self.set_alarm_led_brightness(0) + if (isFireThresholdReached == True): + logging.critical('CRITICAL: System Stabilized, not shutting down') + os.system("echo 'CRITICAL: System Stabilized, not shutting down' > /dev/console") + FireThresholdSecsRemaining = 120 + isFireThresholdReached = False + logging.debug('Temp Sensor is set to 80% Prev Duty Cycle Flag') + # CHECK IF ANY TEMPERATURE SENSORS HAS SET 80% DUTY CYCLE FLAG, IF YES, SET THE FAN DUTY CYCLE TO 80% - elif SensorFlag[0][2] or SensorFlag[1][2] or SensorFlag[2][2] or SensorFlag[3][2] or SensorFlag[4][2] or SensorFlag[5][2] or SensorFlag[6][2]: + elif SensorFlag[0][2] or SensorFlag[1][2] or SensorFlag[2][2] or SensorFlag[3][2] or SensorFlag[4][2] or SensorFlag[5][2] or SensorFlag[6][2] or SensorFlag[7][2]: fan.set_fan_duty_cycle(80) value = self.get_alarm_led_brightness() if ( value > 0): self.set_alarm_led_brightness(0) + is80PerFlag = True + + if (isFireThresholdReached == True): + logging.critical('CRITICAL: System Stabilized, not shutting down') + os.system("echo 'CRITICAL: System Stabilized, not shutting down' > /dev/console") + FireThresholdSecsRemaining = 120 + isFireThresholdReached = False + + logging.debug('Temp Sensor is set to 80% Duty Cycle Flag') # FOR "AFO" Platform CHECK IF ANY TEMPERATURE SENSORS HAS SET 60% DUTY CYCLE PREV FLAG, IF YES, SET THE FAN DUTY CYCLE TO 60% # FOR "AFI" Platform CHECK IF ANY TEMPERATURE SENSORS HAS SET 70% DUTY CYCLE PREV FLAG, IF YES, SET THE FAN DUTY CYCLE TO 70% - elif SensorFlag[0][1] or SensorFlag[1][1] or SensorFlag[2][1] or SensorFlag[3][1] or SensorFlag[4][1] or SensorFlag[5][1] or SensorFlag[6][1]: - if (isPlatformAFI == True): - fan.set_fan_duty_cycle(70) + elif SensorFlag[0][1] or SensorFlag[1][1] or SensorFlag[2][1] or SensorFlag[3][1] or SensorFlag[4][1] or SensorFlag[5][1] or SensorFlag[6][1] or SensorFlag[7][1]: + if (is60PerFlag == True): + if (isPlatformAFI == True): + fan.set_fan_duty_cycle(70) + else: + fan.set_fan_duty_cycle(60) + + is60PerFlag = False + is80PerFlag = True else: - fan.set_fan_duty_cycle(60) + pass + value = self.get_alarm_led_brightness() if ( value > 0): self.set_alarm_led_brightness(0) + if (isFireThresholdReached == True): + logging.critical('CRITICAL: System Stabilized, not shutting down') + os.system("echo 'CRITICAL: System Stabilized, not shutting down' > /dev/console") + FireThresholdSecsRemaining = 120 + isFireThresholdReached = False + + logging.debug('Temp Sensor is set to 60% Prev Duty Cycle Flag') + # FOR "AFO" Platform CHECK IF ANY TEMPERATURE SENSORS HAS SET 60% DUTY CYCLE FLAG, IF YES, SET THE FAN DUTY CYCLE TO 60% # FOR "AFI" Platform CHECK IF ANY TEMPERATURE SENSORS HAS SET 70% DUTY CYCLE FLAG, IF YES, SET THE FAN DUTY CYCLE TO 70% - elif SensorFlag[0][0] or SensorFlag[1][0] or SensorFlag[2][0] or SensorFlag[3][0] or SensorFlag[4][0] or SensorFlag[5][0] or SensorFlag[6][0]: + elif SensorFlag[0][0] or SensorFlag[1][0] or SensorFlag[2][0] or SensorFlag[3][0] or SensorFlag[4][0] or SensorFlag[5][0] or SensorFlag[6][0] or SensorFlag[7][0]: if (isPlatformAFI == True): fan.set_fan_duty_cycle(70) else: @@ -408,6 +508,15 @@ def getSensorTemp(self): value = self.get_alarm_led_brightness() if ( value > 0): self.set_alarm_led_brightness(0) + is60PerFlag = True + is80PerFlag = True + + if (isFireThresholdReached == True): + logging.critical('CRITICAL: System Stabilized, not shutting down') + os.system("echo 'CRITICAL: System Stabilized, not shutting down' > /dev/console") + FireThresholdSecsRemaining = 120 + isFireThresholdReached = False + logging.debug('Temp Sensor is set to 60% Duty Cycle Flag') else: pass @@ -417,14 +526,18 @@ def getSensorTemp(self): for x in range(self.SENSOR_CORETEMP_NUM_ON_MAIN_BOARD): for y in range(self.THERMAL_NUM_RANGE): SensorFlag[x][y] = 0 - class device_monitor(object): def __init__(self, log_file, log_level): - + global DEBUG global isPlatformAFI global isFireThresholdReached + global is80PerFlag + global is60PerFlag + global isFireThresholdPrint + global PrevASICValue + global FireThresholdSecsRemaining MASTER_LED_PATH = '/sys/class/leds/master/brightness' SYSTEM_LED_PATH = '/sys/class/leds/system/brightness' FANTYPE_PATH = '/sys/bus/i2c/devices/17-0068/fan1_direction' @@ -439,13 +552,14 @@ def __init__(self, log_file, log_level): datefmt='%H:%M:%S' ) + if DEBUG == True: # set up logging to console - if log_level == logging.DEBUG: - console = logging.StreamHandler() - console.setLevel(log_level) - formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') - console.setFormatter(formatter) - logging.getLogger('').addHandler(console) + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) import sonic_platform platform = sonic_platform.platform.Platform() @@ -454,20 +568,25 @@ def __init__(self, log_file, log_level): # the return value of get_fan_type is AFO = 0, AFI = 1 and for error condition it is -1 # In the error condition also, we are making default platform as AFO, to continue with Energy Monitoring - if (fan_type == -1 or fan_type == 0): - if (fan_type == -1): - print "Error: unable to open sys file for fan handling, defaulting it to AFO" + if (int(fan_type) == -1 or int(fan_type) == 0): + if (int(fan_type) == -1): + logging.error('device_monitor: unable to open sys file for fan handling, defaulting it to AFO') isPlatformAFI = False else: isPlatformAFI = True isFireThresholdReached = False + is80PerFlag = True + is60PerFlag = True + isFireThresholdPrint = True + FireThresholdSecsRemaining = 120 + PrevASICValue = 0 master_led_value = 1 try: masterLED_file = open(MASTER_LED_PATH, 'r+') except IOError as e: - print "Error: unable to open file: %s" % str(e) + logging.error('device_monitor: unable to open Master LED file: %s', str(e)) return False masterLED_file.write(str(master_led_value)) masterLED_file.close() @@ -476,7 +595,7 @@ def __init__(self, log_file, log_level): try: systemLED_file = open(SYSTEM_LED_PATH, 'r+') except IOError as e: - print "Error: unable to open file: %s" % str(e) + logging.error('device_monitor: unable to open System LED file: %s', str(e)) return False systemLED_file.write(str(system_led_value)) systemLED_file.close() @@ -490,6 +609,8 @@ def main(): log_file = '%s.log' % FUNCTION_NAME log_level = logging.DEBUG + #Introducing sleep of 150 seconds to wait for all the docker containers to start before starting the EM policy. + time.sleep(150) monitor = device_monitor(log_file, log_level) while True: monitor.manage_device() From 86e23f9ededb0b56d55bdad09e4d9c91b20aaee4 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Fri, 13 Dec 2019 13:46:48 -0800 Subject: [PATCH 241/278] [lldpd]: Ports few fixes from lldpd master (#3889) * lldpctl: put a lock around some commands to avoid race conditions * Read all notifications in lldpctl_recv * lib: fix memory leak * lib: fix memory leak when handling I/O * Update series --- ...ck-around-some-commands-to-avoid-rac.patch | 169 ++++++++++++++++++ ...ad-all-notifications-in-lldpctl_recv.patch | 27 +++ .../patch/0006-lib-fix-memory-leak.patch | 24 +++ ...ib-fix-memory-leak-when-handling-I-O.patch | 85 +++++++++ src/lldpd/patch/series | 4 + 5 files changed, 309 insertions(+) create mode 100644 src/lldpd/patch/0004-lldpctl-put-a-lock-around-some-commands-to-avoid-rac.patch create mode 100644 src/lldpd/patch/0005-Read-all-notifications-in-lldpctl_recv.patch create mode 100644 src/lldpd/patch/0006-lib-fix-memory-leak.patch create mode 100644 src/lldpd/patch/0007-lib-fix-memory-leak-when-handling-I-O.patch diff --git a/src/lldpd/patch/0004-lldpctl-put-a-lock-around-some-commands-to-avoid-rac.patch b/src/lldpd/patch/0004-lldpctl-put-a-lock-around-some-commands-to-avoid-rac.patch new file mode 100644 index 000000000000..df7f26131dd4 --- /dev/null +++ b/src/lldpd/patch/0004-lldpctl-put-a-lock-around-some-commands-to-avoid-rac.patch @@ -0,0 +1,169 @@ +From 46aa45d0fa3e8879ecdca1c156cb2d91194c45e9 Mon Sep 17 00:00:00 2001 +From: Pavel Shirshov +Date: Thu, 12 Dec 2019 13:47:17 -0800 +Subject: [PATCH 1/1] lldpctl: put a lock around some commands to avoid race + conditions + +--- + src/client/client.h | 3 +++ + src/client/commands.c | 58 ++++++++++++++++++++++++++++++++++++++++--- + src/client/conf.c | 4 +-- + 3 files changed, 60 insertions(+), 5 deletions(-) + +diff --git a/src/client/client.h b/src/client/client.h +index e3ee352..6c3e30d 100644 +--- a/src/client/client.h ++++ b/src/client/client.h +@@ -62,6 +62,8 @@ extern void add_history (); + #endif + #undef NEWLINE + ++extern const char *ctlname; ++ + /* commands.c */ + #define NEWLINE "" + struct cmd_node; +@@ -76,6 +78,7 @@ struct cmd_node *commands_new( + struct cmd_env*, void *), + void *); + struct cmd_node* commands_privileged(struct cmd_node *); ++struct cmd_node* commands_lock(struct cmd_node *); + struct cmd_node* commands_hidden(struct cmd_node *); + void commands_free(struct cmd_node *); + const char *cmdenv_arg(struct cmd_env*); +diff --git a/src/client/commands.c b/src/client/commands.c +index beedbf1..58df4a7 100644 +--- a/src/client/commands.c ++++ b/src/client/commands.c +@@ -18,6 +18,9 @@ + #include "client.h" + #include + #include ++#include ++#include ++#include + + /** + * An element of the environment (a key and a value). +@@ -68,6 +71,7 @@ struct cmd_node { + const char *token; /**< Token to enter this cnode */ + const char *doc; /**< Documentation string */ + int privileged; /**< Privileged command? */ ++ int lock; /**< Lock required for execution? */ + int hidden; /**< Hidden command? */ + + /** +@@ -113,6 +117,21 @@ commands_privileged(struct cmd_node *node) + return node; + } + ++/** ++ * Make a node accessible only with a lock. ++ * ++ * @param node node to use lock to execute ++ * @return the modified node ++ * ++ * The node is modified. It is returned to ease chaining. ++ */ ++struct cmd_node* ++commands_lock(struct cmd_node *node) ++{ ++ if (node) node->lock = 1; ++ return node; ++} ++ + /** + * Hide a node from help or completion. + * +@@ -344,6 +363,7 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w, + int n, rc = 0, completion = (word != NULL); + int help = 0; /* Are we asking for help? */ + int complete = 0; /* Are we asking for possible completions? */ ++ int needlock = 0; /* Do we need a lock? */ + struct cmd_env env = { + .elements = TAILQ_HEAD_INITIALIZER(env.elements), + .stack = TAILQ_HEAD_INITIALIZER(env.stack), +@@ -351,6 +371,7 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w, + .argv = argv, + .argp = 0 + }; ++ static int lockfd = -1; + cmdenv_push(&env, root); + if (!completion) + for (n = 0; n < argc; n++) +@@ -388,6 +409,7 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w, + !strcmp(candidate->token, token)) { + /* Exact match */ + best = candidate; ++ needlock = needlock || candidate->lock; + break; + } + if (!best) best = candidate; +@@ -406,6 +428,7 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w, + if (!candidate->token && + CAN_EXECUTE(candidate)) { + best = candidate; ++ needlock = needlock || candidate->lock; + break; + } + } +@@ -421,9 +444,38 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w, + + /* Push and execute */ + cmdenv_push(&env, best); +- if (best->execute && best->execute(conn, w, &env, best->arg) != 1) { +- rc = -1; +- goto end; ++ if (best->execute) { ++ struct sockaddr_un su; ++ if (needlock) { ++ if (lockfd == -1) { ++ log_debug("lldpctl", "reopen %s for locking", ctlname); ++ if ((lockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) { ++ log_warn("lldpctl", "cannot open for lock %s", ctlname); ++ rc = -1; ++ goto end; ++ } ++ su.sun_family = AF_UNIX; ++ strlcpy(su.sun_path, ctlname, sizeof(su.sun_path)); ++ if (connect(lockfd, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) { ++ log_warn("lldpctl", "cannot connect to socket %s", ctlname); ++ rc = -1; ++ close(lockfd); lockfd = -1; ++ goto end; ++ } ++ } ++ if (lockf(lockfd, F_LOCK, 0) == -1) { ++ log_warn("lldpctl", "cannot get lock on %s", ctlname); ++ rc = -1; ++ close(lockfd); lockfd = -1; ++ goto end; ++ } ++ } ++ rc = best->execute(conn, w, &env, best->arg) != 1 ? -1 : rc; ++ if (needlock && lockf(lockfd, F_ULOCK, 0) == -1) { ++ log_warn("lldpctl", "cannot unlock %s", ctlname); ++ close(lockfd); lockfd = -1; ++ } ++ if (rc == -1) goto end; + } + env.argp++; + } +diff --git a/src/client/conf.c b/src/client/conf.c +index 1a14981..ba5743f 100644 +--- a/src/client/conf.c ++++ b/src/client/conf.c +@@ -37,8 +37,8 @@ register_commands_configure(struct cmd_node *root) + "unconfigure", + "Unconfigure system settings", + NULL, NULL, NULL); +- commands_privileged(configure); +- commands_privileged(unconfigure); ++ commands_privileged(commands_lock(configure)); ++ commands_privileged(commands_lock(unconfigure)); + cmd_restrict_ports(configure); + cmd_restrict_ports(unconfigure); + +-- +2.17.1.windows.2 + diff --git a/src/lldpd/patch/0005-Read-all-notifications-in-lldpctl_recv.patch b/src/lldpd/patch/0005-Read-all-notifications-in-lldpctl_recv.patch new file mode 100644 index 000000000000..1c3781da67ce --- /dev/null +++ b/src/lldpd/patch/0005-Read-all-notifications-in-lldpctl_recv.patch @@ -0,0 +1,27 @@ +From b8e66b52f40103fd3abea77031c4634742c31860 Mon Sep 17 00:00:00 2001 +From: Pavel Shirshov +Date: Thu, 12 Dec 2019 12:47:42 -0800 +Subject: [PATCH 1/1] Read all notifications in lldpctl_recv + +--- + src/lib/connection.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/lib/connection.c b/src/lib/connection.c +index 591d9e9..88bbc99 100644 +--- a/src/lib/connection.c ++++ b/src/lib/connection.c +@@ -253,8 +253,8 @@ lldpctl_recv(lldpctl_conn_t *conn, const uint8_t *data, size_t length) + memcpy(conn->input_buffer + conn->input_buffer_len, data, length); + conn->input_buffer_len += length; + +- /* Is it a notification? */ +- check_for_notification(conn); ++ /* Read all notifications */ ++ while(!check_for_notification(conn)); + + RESET_ERROR(conn); + +-- +2.17.1.windows.2 + diff --git a/src/lldpd/patch/0006-lib-fix-memory-leak.patch b/src/lldpd/patch/0006-lib-fix-memory-leak.patch new file mode 100644 index 000000000000..765b5fb751e7 --- /dev/null +++ b/src/lldpd/patch/0006-lib-fix-memory-leak.patch @@ -0,0 +1,24 @@ +From 833653dffb9be40110142af2a7cb4076a0dd24f5 Mon Sep 17 00:00:00 2001 +From: Pavel Shirshov +Date: Thu, 12 Dec 2019 12:48:47 -0800 +Subject: [PATCH 1/1] lib: fix memory leak + +--- + src/lib/connection.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/lib/connection.c b/src/lib/connection.c +index 88bbc99..aa88dad 100644 +--- a/src/lib/connection.c ++++ b/src/lib/connection.c +@@ -114,6 +114,7 @@ lldpctl_new_name(const char *ctlname, lldpctl_send_callback send, lldpctl_recv_c + } + if (!send && !recv) { + if ((data = malloc(sizeof(struct lldpctl_conn_sync_t))) == NULL) { ++ free(conn->ctlname); + free(conn); + return NULL; + } +-- +2.17.1.windows.2 + diff --git a/src/lldpd/patch/0007-lib-fix-memory-leak-when-handling-I-O.patch b/src/lldpd/patch/0007-lib-fix-memory-leak-when-handling-I-O.patch new file mode 100644 index 000000000000..cad8bf2fd48a --- /dev/null +++ b/src/lldpd/patch/0007-lib-fix-memory-leak-when-handling-I-O.patch @@ -0,0 +1,85 @@ +From f6086575e63b5e089814ca116aa637d7588bfcd3 Mon Sep 17 00:00:00 2001 +From: Pavel Shirshov +Date: Thu, 12 Dec 2019 13:52:42 -0800 +Subject: [PATCH 1/1] lib: fix memory leak when handling I/O. + +--- + src/lib/atom.c | 11 ++++++----- + src/lib/atom.h | 9 ++++----- + src/lib/atoms/port.c | 2 +- + 3 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/src/lib/atom.c b/src/lib/atom.c +index 955f434..f81d3bb 100644 +--- a/src/lib/atom.c ++++ b/src/lib/atom.c +@@ -322,10 +322,12 @@ _lldpctl_do_something(lldpctl_conn_t *conn, + return SET_ERROR(conn, LLDPCTL_ERR_SERIALIZATION); + conn->state = state_send; + if (state_data) +- conn->state_data = strdup(state_data); ++ strlcpy(conn->state_data, state_data, sizeof(conn->state_data)); ++ else ++ conn->state_data[0] = 0; + } + if (conn->state == state_send && +- (state_data == NULL || !strcmp(conn->state_data, state_data))) { ++ (state_data == NULL || !strncmp(conn->state_data, state_data, sizeof(conn->state_data)))) { + /* We need to send the currently built message */ + rc = lldpctl_send(conn); + if (rc < 0) +@@ -333,7 +335,7 @@ _lldpctl_do_something(lldpctl_conn_t *conn, + conn->state = state_recv; + } + if (conn->state == state_recv && +- (state_data == NULL || !strcmp(conn->state_data, state_data))) { ++ (state_data == NULL || !strncmp(conn->state_data, state_data, sizeof(conn->state_data)))) { + /* We need to receive the answer */ + while ((rc = ctl_msg_recv_unserialized(&conn->input_buffer, + &conn->input_buffer_len, +@@ -347,8 +349,7 @@ _lldpctl_do_something(lldpctl_conn_t *conn, + return SET_ERROR(conn, LLDPCTL_ERR_SERIALIZATION); + /* rc == 0 */ + conn->state = CONN_STATE_IDLE; +- free(conn->state_data); +- conn->state_data = NULL; ++ conn->state_data[0] = 0; + return 0; + } else + return SET_ERROR(conn, LLDPCTL_ERR_INVALID_STATE); +diff --git a/src/lib/atom.h b/src/lib/atom.h +index 265c0a7..ab7037d 100644 +--- a/src/lib/atom.h ++++ b/src/lib/atom.h +@@ -55,11 +55,10 @@ struct lldpctl_conn_t { + #define CONN_STATE_GET_DEFAULT_PORT_SEND 14 + #define CONN_STATE_GET_DEFAULT_PORT_RECV 15 + int state; /* Current state */ +- char *state_data; /* Data attached to the state. It is used to +- * check that we are using the same data as a +- * previous call until the state machine goes to +- * CONN_STATE_IDLE. */ +- ++ /* Data attached to the state. It is used to check that we are using the ++ * same data as a previous call until the state machine goes to ++ * CONN_STATE_IDLE. */ ++ char state_data[IFNAMSIZ + 64]; + /* Error handling */ + lldpctl_error_t error; /* Last error */ + +diff --git a/src/lib/atoms/port.c b/src/lib/atoms/port.c +index 545155c..d902188 100644 +--- a/src/lib/atoms/port.c ++++ b/src/lib/atoms/port.c +@@ -329,7 +329,7 @@ _lldpctl_atom_set_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key, lldpctl_ato + struct lldpd_hardware *hardware = p->hardware; + struct lldpd_port_set set = {}; + int rc; +- char *canary; ++ char *canary = NULL; + + #ifdef ENABLE_DOT3 + struct _lldpctl_atom_dot3_power_t *dpow; +-- +2.17.1.windows.2 + diff --git a/src/lldpd/patch/series b/src/lldpd/patch/series index 5e5e8bc99714..626c5d59751b 100644 --- a/src/lldpd/patch/series +++ b/src/lldpd/patch/series @@ -2,3 +2,7 @@ 0001-return-error-when-port-does-not-exist.patch 0002-Let-linux-kernel-to-find-appropriate-nl_pid-automa.patch 0003-update-tx-interval-immediately.patch +0004-lldpctl-put-a-lock-around-some-commands-to-avoid-rac.patch +0005-Read-all-notifications-in-lldpctl_recv.patch +0006-lib-fix-memory-leak.patch +0007-lib-fix-memory-leak-when-handling-I-O.patch From fbcaaa498e2dd87fbeb9e519a0f706133e477e48 Mon Sep 17 00:00:00 2001 From: Mykola F <37578614+mykolaf@users.noreply.github.com> Date: Sat, 14 Dec 2019 00:30:52 +0200 Subject: [PATCH 242/278] [config engine] For l2 preset, use admin_status: up by default (#3902) Updated the l2 preset config generator to specify 'admin_status': 'up' for every port by default. The use of setdefault() ensures that if port already has some admin_status set, the original value will not be overwritten. Signed-off-by: Mykola Faryma --- src/sonic-config-engine/config_samples.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sonic-config-engine/config_samples.py b/src/sonic-config-engine/config_samples.py index adaea0c4532c..1b38276524c0 100644 --- a/src/sonic-config-engine/config_samples.py +++ b/src/sonic-config-engine/config_samples.py @@ -51,6 +51,7 @@ def generate_l2_config(data): data['VLAN']['Vlan1000'].setdefault('members', vp) data['VLAN_MEMBER'] = {} for port in natsorted(data['PORT'].keys()): + data['PORT'][port].setdefault('admin_status', 'up') data['VLAN_MEMBER']['Vlan1000|{}'.format(port)] = {'tagging_mode': 'untagged'} return data From e8f3bee0b4ef54cf3d903d94083dfc6a224a8ff5 Mon Sep 17 00:00:00 2001 From: Wataru Ishida <5915117+ishidawataru@users.noreply.github.com> Date: Fri, 13 Dec 2019 14:41:00 -0800 Subject: [PATCH 243/278] [broadcom]: fix KNET MTU setting with Linux Kernel > 4.10.0 (#3895) We need to set min_mtu/max_mtu properly to support MTU setting https://github.com/torvalds/linux/commit/61e84623 Signed-off-by: Wataru Ishida --- .../systems/linux/kernel/modules/bcm-knet/bcm-knet.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c index 6767090ec7bb..3559ace7a898 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c @@ -5128,6 +5128,10 @@ bkn_init_ndev(u8 *mac, char *name) if (dev->mtu == 0) { dev->mtu = rx_buffer_size; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) + dev->min_mtu = 68; + dev->max_mtu = rx_buffer_size; +#endif /* Device vectors */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) From eefa8455d73c35b41bd43d4b988b74f5c474581d Mon Sep 17 00:00:00 2001 From: Ying Xie Date: Fri, 13 Dec 2019 19:26:39 -0800 Subject: [PATCH 244/278] [hostcfgd] avoid in place editing config file contents (#3904) In place editing (sed -i) seems having some issues with filesystem interaction. It could leave 0 size file or corrupted file behind. It would be safer to sed the file contents into a new file and switch new file with the old file. Signed-off-by: Ying Xie --- files/image_config/hostcfgd/hostcfgd | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/files/image_config/hostcfgd/hostcfgd b/files/image_config/hostcfgd/hostcfgd index 7fa8ed2ba205..e10288c0dd37 100755 --- a/files/image_config/hostcfgd/hostcfgd +++ b/files/image_config/hostcfgd/hostcfgd @@ -176,6 +176,11 @@ class AaaCfg(object): if modify_conf: self.modify_conf_file() + def modify_single_file(self, filename, operations=None): + if operations: + cmd = "sed -e {0} {1} > {1}.new; mv -f {1} {1}.old; mv -f {1}.new {1}".format(' -e '.join(operations), filename) + os.system(cmd) + def modify_conf_file(self): auth = self.auth_default.copy() auth.update(self.auth) @@ -201,19 +206,19 @@ class AaaCfg(object): # Modify common-auth include file in /etc/pam.d/login and sshd if os.path.isfile(PAM_AUTH_CONF): - os.system("sed -i -e '/^@include/s/common-auth$/common-auth-sonic/' /etc/pam.d/sshd") - os.system("sed -i -e '/^@include/s/common-auth$/common-auth-sonic/' /etc/pam.d/login") + self.modify_single_file('/etc/pam.d/sshd', [ "'/^@include/s/common-auth$/common-auth-sonic/'" ]) + self.modify_single_file('/etc/pam.d/login', [ "'/^@include/s/common-auth$/common-auth-sonic/'" ]) else: - os.system("sed -i -e '/^@include/s/common-auth-sonic$/common-auth/' /etc/pam.d/sshd") - os.system("sed -i -e '/^@include/s/common-auth-sonic$/common-auth/' /etc/pam.d/login") + self.modify_single_file('/etc/pam.d/sshd', [ "'/^@include/s/common-auth-sonic$/common-auth/'" ]) + self.modify_single_file('/etc/pam.d/login', [ "'/^@include/s/common-auth-sonic$/common-auth/'" ]) # Add tacplus in nsswitch.conf if TACACS+ enable if 'tacacs+' in auth['login']: if os.path.isfile(NSS_CONF): - os.system("sed -i -e '/tacplus/b' -e '/^passwd/s/compat/tacplus &/' /etc/nsswitch.conf") + self.modify_single_file(NSS_CONF, [ "'/tacplus/b'", "'/^passwd/s/compat/tacplus &/'"]) else: if os.path.isfile(NSS_CONF): - os.system("sed -i -e '/^passwd/s/tacplus //' /etc/nsswitch.conf") + self.modify_single_file(NSS_CONF, [ "'/^passwd/s/tacplus //'" ]) # Set tacacs+ server in nss-tacplus conf template_file = os.path.abspath(NSS_TACPLUS_CONF_TEMPLATE) From 80bb7fd15a92d7f0153869854d43f9590a191572 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Sun, 15 Dec 2019 01:41:48 +0800 Subject: [PATCH 245/278] [process-reboot-cause]Address the issue: Incorrect reboot cause returned when warm reboot follows a hardware caused reboot (#3880) * [process-reboot-cause]Address the issue: Incorrect reboot cause returned when warm reboot follows a hardware caused reboot 1. check whether /proc/cmdline indicates warm/fast reboot. if yes the software reboot cause file will be treated as the reboot cause. finish 2. check whether platform api returns a reboot cause. if yes it is treated as the reboot cause. finish. 3. check whether /hosts/reboot-cause contains a cause. if yes it is treated as the cause otherwise return unknown. * [process-reboot-cause]Fix review comments * [process-reboot-cause]address comments 1. use "with" statement 2. update fast/warm reboot BOOT_ARG * [process-reboot-cause]address comments * refactor the code flow * Remove escape * Remove extra ':' --- .../process-reboot-cause/process-reboot-cause | 114 +++++++++++------- 1 file changed, 73 insertions(+), 41 deletions(-) diff --git a/files/image_config/process-reboot-cause/process-reboot-cause b/files/image_config/process-reboot-cause/process-reboot-cause index 49cfa752641f..e5d228b4c6b6 100755 --- a/files/image_config/process-reboot-cause/process-reboot-cause +++ b/files/image_config/process-reboot-cause/process-reboot-cause @@ -11,6 +11,7 @@ try: import pwd import sys import syslog + import re except ImportError as err: raise ImportError("%s - required module not found" % str(err)) @@ -22,6 +23,16 @@ REBOOT_CAUSE_DIR = "/host/reboot-cause/" REBOOT_CAUSE_FILE = REBOOT_CAUSE_DIR + "reboot-cause.txt" PREVIOUS_REBOOT_CAUSE_FILE = REBOOT_CAUSE_DIR + "previous-reboot-cause.txt" FIRST_BOOT_PLATFORM_FILE = "/tmp/notify_firstboot_to_platform" +REBOOT_TYPE_KEXEC_FILE = "/proc/cmdline" +# The following SONIC_BOOT_TYPEs come from the warm/fast reboot script which is in sonic-utilities +# Because the system can be rebooted from some old versions, we have to take all possible BOOT options into consideration. +# On 201803, 201807 we have +# BOOT_OPTIONS="$(echo $KERNEL_OPTIONS | sed -e 's/\s*linux\s*/BOOT_IMAGE=/') fast-reboot" +# On 201811 and later we have +# BOOT_OPTIONS="$(echo $KERNEL_OPTIONS | sed -e 's/\s*linux\s*/BOOT_IMAGE=/') SONIC_BOOT_TYPE=${BOOT_TYPE_ARG}" where BOOT_TYPE_ARG can be warm, fastfast or fast +# To extract the commom part of them, we should have the following PATTERN +REBOOT_TYPE_KEXEC_PATTERN_WARM = ".*SONIC_BOOT_TYPE=(warm|fastfast).*" +REBOOT_TYPE_KEXEC_PATTERN_FAST = ".*SONIC_BOOT_TYPE=(fast|fast-reboot).*" UNKNOWN_REBOOT_CAUSE = "Unknown" @@ -47,7 +58,32 @@ def log_error(msg): # ============================= Functions ============================= - +def parse_warmfast_reboot_from_proc_cmdline(): + if os.path.isfile(REBOOT_TYPE_KEXEC_FILE): + with open(REBOOT_TYPE_KEXEC_FILE, "r") as cause_file: + cause_file_kexec = cause_file.readline() + m = re.match(REBOOT_TYPE_KEXEC_PATTERN_WARM, cause_file_kexec) + if m and m.group(1): + return 'warm-reboot' + m = re.match(REBOOT_TYPE_KEXEC_PATTERN_FAST, cause_file_kexec) + if m and m.group(1): + return 'fast-reboot' + return None + + +def find_software_reboot_cause(): + software_reboot_cause = UNKNOWN_REBOOT_CAUSE + + if os.path.isfile(REBOOT_CAUSE_FILE): + with open(REBOOT_CAUSE_FILE, "r") as cause_file: + software_reboot_cause = cause_file.readline().rstrip('\n') + + if os.path.isfile(FIRST_BOOT_PLATFORM_FILE): + os.remove(FIRST_BOOT_PLATFORM_FILE) + + return software_reboot_cause + + def main(): log_info("Starting up...") @@ -73,51 +109,48 @@ def main(): try: import sonic_platform - # Check if the previous reboot was caused by hardware - platform = sonic_platform.platform.Platform() - - chassis = platform.get_chassis() - - hardware_reboot_cause, optional_details = chassis.get_reboot_cause() - - if hardware_reboot_cause == chassis.REBOOT_CAUSE_NON_HARDWARE: - # The reboot was not caused by hardware. If there is a REBOOT_CAUSE_FILE, it will - # contain any software-related reboot info. We will use it as the previous cause. + # 1. Check if the previous reboot was warm/fast reboot by testing whether there is "fast|fastfast|warm" in /proc/cmdline + # If yes, the content of /hosts/reboot-cause/reboot-cause.txt will be treated as the reboot cause + proc_cmdline_reboot_cause = parse_warmfast_reboot_from_proc_cmdline() + if proc_cmdline_reboot_cause: + log_info("/proc/cmdline indicates reboot type: {}".format(proc_cmdline_reboot_cause)) if os.path.isfile(REBOOT_CAUSE_FILE): - cause_file = open(REBOOT_CAUSE_FILE, "r") - previous_reboot_cause = cause_file.readline().rstrip('\n') - cause_file.close() - # If it is FirstTime Boot and previous_reboot_cause is unknown - # and hardware_reboot cause is non_hardware then - # Update the reboot cause as required - if os.path.isfile(FIRST_BOOT_PLATFORM_FILE): - if (previous_reboot_cause == UNKNOWN_REBOOT_CAUSE): - previous_reboot_cause = UNKNOWN_REBOOT_CAUSE - os.remove(FIRST_BOOT_PLATFORM_FILE) - elif hardware_reboot_cause == chassis.REBOOT_CAUSE_HARDWARE_OTHER: - previous_reboot_cause = "{} ({})".format(hardware_reboot_cause, optional_details) + with open(REBOOT_CAUSE_FILE, "r") as cause_file: + proc_cmdline_reboot_cause = cause_file.readline().rstrip('\n') + else: + # /proc/cmdline says it's a warm/fast reboot but /host/reboot-cause.txt doesn't exist. + # This could happen when upgrading from a version doesn't support reboot cause. + log_info("Reboot cause file {} doesn't exist".format(REBOOT_CAUSE_DIR)) + + if proc_cmdline_reboot_cause is not None: + previous_reboot_cause = proc_cmdline_reboot_cause else: - previous_reboot_cause = hardware_reboot_cause + # 2. Check if the previous reboot was caused by hardware + # If yes, the hardware reboot cause will be treated as the reboot cause + platform = sonic_platform.platform.Platform() + + chassis = platform.get_chassis() + + hardware_reboot_cause, optional_details = chassis.get_reboot_cause() + + if hardware_reboot_cause == chassis.REBOOT_CAUSE_NON_HARDWARE: + # The reboot was not caused by hardware. If there is a REBOOT_CAUSE_FILE, it will + # contain any software-related reboot info. We will use it as the previous cause. + previous_reboot_cause = find_software_reboot_cause() + elif hardware_reboot_cause == chassis.REBOOT_CAUSE_HARDWARE_OTHER: + previous_reboot_cause = "{} ({})".format(hardware_reboot_cause, optional_details) + else: + previous_reboot_cause = hardware_reboot_cause except ImportError as err: log_warning("sonic_platform package not installed. Unable to detect hardware reboot causes.") # If there is a REBOOT_CAUSE_FILE, it will contain any software-related # reboot info. We will use it as the previous cause. - if os.path.isfile(REBOOT_CAUSE_FILE): - cause_file = open(REBOOT_CAUSE_FILE, "r") - previous_reboot_cause = cause_file.readline().rstrip('\n') - cause_file.close() - - # If it is FirstTime Boot and previous_reboot_cause is unknown - # Update the reboot cause as required - if os.path.isfile(FIRST_BOOT_PLATFORM_FILE): - if (previous_reboot_cause == UNKNOWN_REBOOT_CAUSE): - previous_reboot_cause = UNKNOWN_REBOOT_CAUSE - os.remove(FIRST_BOOT_PLATFORM_FILE) + previous_reboot_cause = find_software_reboot_cause() + # Write the previous reboot cause to PREVIOUS_REBOOT_CAUSE_FILE - prev_cause_file = open(PREVIOUS_REBOOT_CAUSE_FILE, "w") - prev_cause_file.write(previous_reboot_cause) - prev_cause_file.close() + with open(PREVIOUS_REBOOT_CAUSE_FILE, "w") as prev_cause_file: + prev_cause_file.write(previous_reboot_cause) # Also log the previous reboot cause to the syslog log_info("Previous reboot cause: {}".format(previous_reboot_cause)) @@ -127,9 +160,8 @@ def main(): os.remove(REBOOT_CAUSE_FILE) # Write a new default reboot cause file for the next reboot - cause_file = open(REBOOT_CAUSE_FILE, "w") - cause_file.write(UNKNOWN_REBOOT_CAUSE) - cause_file.close() + with open(REBOOT_CAUSE_FILE, "w") as cause_file: + cause_file.write(UNKNOWN_REBOOT_CAUSE) if __name__ == "__main__": From 3ab4b71656e8cd300aab69e897de6fa7e8103e3d Mon Sep 17 00:00:00 2001 From: Renuka Manavalan <47282725+renukamanavalan@users.noreply.github.com> Date: Sun, 15 Dec 2019 16:48:48 -0800 Subject: [PATCH 246/278] Corefile uploader service (#3887) * Corefile uploader service 1) A service is added to watch /var/core and upload to Azure storage 2) The service is disabled on boot. One may enable explicitly. 3) The .rc file to be updated with acct credentials and http proxy to use. 4) If service is enabled with no credentials, it would sleep, with periodic log messages 5) For any update in .rc, the service has to be restarted to take effect. * Remove rw permission for .rc file for group & others. * Changes per review comments. Re-ordered .rc file per JSON.dump order. Added a script to enable partial update of .rc, which HWProxy would use to add acct key. * Azure storage upload requires python module futures, hence added it to install list. * Removed trailing spaces. * A mistake in name corrected. Copy the .rc updater script to /usr/bin. --- .../build_templates/sonic_debian_extension.j2 | 13 + .../corefile_uploader/core_analyzer.rc.json | 17 ++ .../corefile_uploader/core_uploader.py | 276 ++++++++++++++++++ .../corefile_uploader/core_uploader.service | 11 + .../corefile_uploader/update_json.py | 55 ++++ 5 files changed, 372 insertions(+) create mode 100644 files/image_config/corefile_uploader/core_analyzer.rc.json create mode 100755 files/image_config/corefile_uploader/core_uploader.py create mode 100644 files/image_config/corefile_uploader/core_uploader.service create mode 100755 files/image_config/corefile_uploader/update_json.py diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index 4e81593298f6..b11325e86835 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -36,6 +36,8 @@ FILESYSTEM_ROOT_USR="$FILESYSTEM_ROOT/usr" FILESYSTEM_ROOT_USR_SHARE="$FILESYSTEM_ROOT_USR/share" FILESYSTEM_ROOT_USR_SHARE_SONIC="$FILESYSTEM_ROOT_USR_SHARE/sonic" FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES="$FILESYSTEM_ROOT_USR_SHARE_SONIC/templates" +FILESYSTEM_ROOT_ETC="$FILESYSTEM_ROOT/etc" +FILESYSTEM_ROOT_ETC_SONIC="$FILESYSTEM_ROOT_ETC/sonic" GENERATED_SERVICE_FILE="$FILESYSTEM_ROOT/etc/sonic/generated_services.conf" @@ -219,6 +221,17 @@ echo "hostcfgd.service" | sudo tee -a $GENERATED_SERVICE_FILE sudo cp $IMAGE_CONFIGS/hostcfgd/hostcfgd $FILESYSTEM_ROOT/usr/bin/ sudo cp $IMAGE_CONFIGS/hostcfgd/*.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/ +# copy core file uploader files +sudo cp $IMAGE_CONFIGS/corefile_uploader/core_uploader.service $FILESYSTEM_ROOT/etc/systemd/system/ +sudo LANG=C chroot $FILESYSTEM_ROOT systemctl disable core_uploader.service +sudo cp $IMAGE_CONFIGS/corefile_uploader/core_uploader.py $FILESYSTEM_ROOT/usr/bin/ +sudo cp $IMAGE_CONFIGS/corefile_uploader/update_json.py $FILESYSTEM_ROOT/usr/bin/ +sudo cp $IMAGE_CONFIGS/corefile_uploader/core_analyzer.rc.json $FILESYSTEM_ROOT_ETC_SONIC/ +sudo chmod og-rw $FILESYSTEM_ROOT_ETC_SONIC/core_analyzer.rc.json +sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install azure-storage +sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install watchdog +sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install futures + # Copy the buffer configuration template sudo cp $BUILD_TEMPLATES/buffers_config.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/ diff --git a/files/image_config/corefile_uploader/core_analyzer.rc.json b/files/image_config/corefile_uploader/core_analyzer.rc.json new file mode 100644 index 000000000000..3ffa33fd1e1d --- /dev/null +++ b/files/image_config/corefile_uploader/core_analyzer.rc.json @@ -0,0 +1,17 @@ +{ + "local_work": { + "core_upload": "/tmp/core_upload/" + }, + "azure_sonic_core_storage": { + "account_name": "corefilecollection", + "account_key": "", + "share_name": "corefiles-root" + }, + "metadata_files_in_archive": { + "version": "/etc/sonic/sonic_version.yml", + "core_info": "core_info.json" + }, + "env": { + "https_proxy": "" + } +} diff --git a/files/image_config/corefile_uploader/core_uploader.py b/files/image_config/corefile_uploader/core_uploader.py new file mode 100755 index 000000000000..676ff9583b06 --- /dev/null +++ b/files/image_config/corefile_uploader/core_uploader.py @@ -0,0 +1,276 @@ +#!/usr/bin/env python + +import os +import time +import tarfile +import socket +import yaml +import json +import syslog +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler +from azure.storage.file import FileService + +global CORE_FILE_PATH, RC_FILE +global hostname, sonicversion, asicname, acctname, acctkey, sharename, cwd +global INIT_CWD +global log_level +global this_file + +this_file = os.path.basename(__file__) + +global cfg +cfg = "" + +CORE_FILE_PATH = "/var/core/" +RC_FILE = "/etc/sonic/core_analyzer.rc.json" +INIT_CWD = "/tmp" + +hostname = "" +sonicversion = "" +asicname = "" +acctname = "" +acctkey = "" +sharename = "" +cwd = [] + +HOURS_4 = (4 * 60 * 60) +PAUSE_ON_FAIL = (60 * 60) +MAX_RETRIES = 5 + +log_level = syslog.LOG_DEBUG + +def log_msg(lvl, fname, m): + if (lvl <= log_level): + syslog.syslog(lvl, "{}: {}".format(fname, m)) + + if log_level == syslog.LOG_DEBUG: + print("{}: {}".format(fname, m)) + +def log_err(m): + log_msg(syslog.LOG_ERR, this_file, m) + +def log_info(m): + log_msg(syslog.LOG_INFO, this_file, m) + +def log_warn(m): + log_msg(syslog.LOG_WARNING, this_file, m) + +def log_debug(m): + log_msg(syslog.LOG_DEBUG, this_file, m) + + +def make_new_dir(p): + os.system("rm -rf " + p) + os.system("mkdir -p " + p) + +def parse_a_json(data, prefix, val): + for i in data: + if type(data[i]) == dict: + parse_a_json(data[i], prefix + (i,), val) + else: + val[prefix + (i,)] = data[i] + +class config: + parsed_data = {} + cfg_data = {} + + def __init__(self): + while not os.path.exists(RC_FILE): + # Wait here until service restart + log_err("Unable to retrieve Azure storage credentials") + time.sleep (HOURS_4) + + with open(RC_FILE, 'r') as f: + self.parsed_data = json.load(f) + parse_a_json(self.parsed_data, (), self.cfg_data) + + def get_data(self, k): + return self.cfg_data[k] if self.cfg_data.has_key(k) else "" + + def get_dict(self): + return self.parsed_data + + def get_core_info(self, corepath, devicename): + info = {} + info["corefname"] = os.path.basename(corepath) + info["tstamp"] = str(os.stat(corepath).st_ctime) + info["devicename"] = devicename + + lpath = self.get_data(("metadata_files_in_archive", "core_info")) + f = open(lpath, "w+") + f.write(json.dumps(info, indent=4)) + f.close() + + return lpath + + +class Watcher: + + def __init__(self): + self.observer = Observer() + + def run(self): + event_handler = Handler() + self.observer.schedule(event_handler, CORE_FILE_PATH) + self.observer.start() + try: + while True: + time.sleep(5) + except: + self.observer.stop() + log_err("Error in watcher") + + self.observer.join() + +def set_env(lst): + for k in lst: + if lst[k]: + os.environ[k] = lst[k] + log_debug("set env {} = {}".format(k, lst[k])) + +class Handler(FileSystemEventHandler): + + @staticmethod + def init(): + global hostname, sonicversion, asicname, acctname, acctkey, sharename + global cwd, cfg + + cfg = config() + + set_env(cfg.get_dict()["env"]) + + hostname = socket.gethostname() + if not hostname: + raise Exception("Failed to read hostname") + + acctname = cfg.get_data(("azure_sonic_core_storage", "account_name")) + acctkey = cfg.get_data(("azure_sonic_core_storage", "account_key")) + sharename = cfg.get_data(("azure_sonic_core_storage", "share_name")) + + if not acctname or not acctkey or not sharename: + while True: + # Wait here until service restart + log_err("Unable to retrieve Azure storage credentials") + time.sleep (HOURS_4) + + with open("/etc/sonic/sonic_version.yml", 'r') as stream: + l = yaml.safe_load(stream) + sonicversion = l['build_version'] + asicname = l['asic_type'] + + if not sonicversion: + raise Exception("Failed to read build_version from /etc/sonic/sonic_version.yml") + + if not asicname: + raise Exception("Failed to read asic_type from /etc/sonic/sonic_version.yml") + + cwd = cfg.get_data(("local_work", "core_upload")).split("/") + if not len(cwd) > 2: + raise Exception("Invalid path for core_upload. Expect a min of two elements in path") + + os.chdir(INIT_CWD) + + @staticmethod + def on_any_event(event): + if event.is_directory: + return None + + elif event.event_type == 'created': + # Take any action here when a file is first created. + log_debug("Received create event - " + event.src_path) + Handler.handle_file(event.src_path) + + + @staticmethod + def wait_for_file_write_complete(path): + ct_size = -1 + + while ct_size != os.path.getsize(path): + ct_size = os.path.getsize(path) + time.sleep(2) + + time.sleep(2) + if ct_size != os.path.getsize(path): + raise Exception("Dump file creation is too slow: " + path) + + log_debug("File write complete - " + path) + + + @staticmethod + def handle_file(path): + + Handler.wait_for_file_write_complete(path) + + lpath = "/".join(cwd) + make_new_dir(lpath) + os.chdir(lpath) + + # Create a new archive with core & more. + metafiles = cfg.get_dict()["metadata_files_in_archive"] + + fname = os.path.basename(path) + tarf_name = fname + ".tar.gz" + + cfg.get_core_info(path, hostname) + + tar = tarfile.open(tarf_name, "w:gz") + for e in metafiles: + tar.add(metafiles[e]) + tar.add(path) + tar.close() + log_debug("Tar file for upload created: " + tarf_name) + + Handler.upload_file(tarf_name, tarf_name) + + log_debug("File uploaded - " + path) + os.chdir(INIT_CWD) + + @staticmethod + def upload_file(fname, fpath): + daemonname = fname.split(".")[0] + i = 0 + fail_msg = "" + + while i <= MAX_RETRIES: + try: + svc = FileService(account_name=acctname, account_key=acctkey) + + l = [sonicversion, asicname, daemonname, hostname] + e = [] + while len(e) != len(l): + e.append(l[len(e)]) + svc.create_directory(sharename, "/".join(e)) + + log_debug("Remote dir created: " + "/".join(e)) + + svc.create_file_from_path(sharename, "/".join(l), fname, fpath) + log_debug("Remote file created: name{} path{}".format(fname, fpath)) + break + + except Exception as e: + log_err("core uploader failed: Failed during upload (" + str(e) +")") + fail_msg = str(e) + i += 1 + if i >= MAX_RETRIES: + raise Exception("Failed while uploading. msg(" + fail_msg + ") after " + str(i) + " retries") + time.sleep(PAUSE_ON_FAIL) + + + @staticmethod + def scan(): + for e in os.listdir(CORE_FILE_PATH): + fl = CORE_FILE_PATH + e + if os.path.isfile(fl): + Handler.handle_file(fl) + + +if __name__ == '__main__': + try: + Handler.init() + w = Watcher() + Handler.scan() + w.run() + except Exception as e: + log_err("core uploader failed: " + str(e) + " Exiting ...") + diff --git a/files/image_config/corefile_uploader/core_uploader.service b/files/image_config/corefile_uploader/core_uploader.service new file mode 100644 index 000000000000..5c061e72a16e --- /dev/null +++ b/files/image_config/corefile_uploader/core_uploader.service @@ -0,0 +1,11 @@ +[Unit] +Description=Host core file uploader daemon +Requires=updategraph.service +After=updategraph.service + +[Service] +Type=simple +ExecStart=/usr/bin/core_uploader.py + +[Install] +WantedBy=multi-user.target diff --git a/files/image_config/corefile_uploader/update_json.py b/files/image_config/corefile_uploader/update_json.py new file mode 100755 index 000000000000..03bb39aa4ec8 --- /dev/null +++ b/files/image_config/corefile_uploader/update_json.py @@ -0,0 +1,55 @@ +#! /usr/bin/env python + +import os +import sys +import json +import argparse + +TMP_SUFFIX = ".tmp" +BAK_SUFFIX = ".bak" + +def dict_update(dst, patch): + for k in patch.keys(): + if type(patch[k]) == dict: + dst[k] = dict_update(dst[k], patch[k]) + else: + dst[k] = patch[k] + return dst + +def do_update(rcf, patchf): + dst = {} + patch = {} + + tmpf = rcf + TMP_SUFFIX + bakf = rcf + BAK_SUFFIX + + with open(rcf, "r") as f: + dst = json.load(f) + + with open(patchf, "r") as f: + patch = json.load(f) + + dst = dict_update(dst, patch) + + with open(tmpf, "w") as f: + json.dump(dst, f, indent = 4) + + os.rename(rcf, bakf) + os.rename(tmpf, rcf) + + +def main(): + parser=argparse.ArgumentParser(description="Update JSON based file") + parser.add_argument("-r", "--rc", help="JSON file to be updated") + parser.add_argument("-p", "--patch", help="JSON file holding patch") + args = parser.parse_args() + + if not args.rc or not args.patch: + raise Exception("check usage") + + do_update(args.rc, args.patch) + +if __name__ == '__main__': + main() + + From 1286e5ed3fada79fd81526f91ab079ea254756b8 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Mon, 16 Dec 2019 22:30:35 +0700 Subject: [PATCH 247/278] [platform/cel]: Remove afulnx_64 (#3900) remove afulnx_64 install script --- .../sonic_platform/component.py | 4 ++-- .../sonic_platform/component.py | 4 ++-- .../debian/platform-modules-dx010.install | 1 - .../debian/platform-modules-haliburton.install | 1 - .../sonic-platform-modules-cel/tools/afulnx_64 | Bin 828912 -> 0 bytes 5 files changed, 4 insertions(+), 6 deletions(-) delete mode 100755 platform/broadcom/sonic-platform-modules-cel/tools/afulnx_64 diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/component.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/component.py index ad6810b14c38..fe34bc45c670 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/component.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/component.py @@ -140,7 +140,7 @@ def install_firmware(self, image_path): new_image_path = os.path.join("/tmp", (root.lower() + ext)) shutil.copy(image_path, new_image_path) install_command = "ispvm %s" % new_image_path - elif self.name == "BIOS": - install_command = "afulnx_64 %s /p /b /n /x /r" % image_path + # elif self.name == "BIOS": + # install_command = "afulnx_64 %s /p /b /n /x /r" % image_path return self.__run_command(install_command) diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py index 67c7a9c46341..d94a93474452 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py @@ -141,7 +141,7 @@ def install_firmware(self, image_path): new_image_path = os.path.join("/tmp", (root.lower() + ext)) shutil.copy(image_path, new_image_path) install_command = "ispvm %s" % new_image_path - elif self.name == "BIOS": - install_command = "afulnx_64 %s /p /b /n /x /r" % image_path + # elif self.name == "BIOS": + # install_command = "afulnx_64 %s /p /b /n /x /r" % image_path return self.__run_command(install_command) diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install index 2ab53302a9bf..8570fa1eae84 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install @@ -3,4 +3,3 @@ dx010/cfg/dx010-modules.conf etc/modules-load.d dx010/systemd/platform-modules-dx010.service lib/systemd/system dx010/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_seastone-r0 services/platform_api/platform_api_mgnt.sh usr/local/bin -tools/afulnx_64 usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install index d50306304cd5..df78b7a34ea4 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install @@ -5,4 +5,3 @@ services/fancontrol/fancontrol.service lib/systemd/system services/fancontrol/fancontrol usr/local/bin haliburton/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_e1031-r0 services/platform_api/platform_api_mgnt.sh usr/local/bin -tools/afulnx_64 usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/afulnx_64 b/platform/broadcom/sonic-platform-modules-cel/tools/afulnx_64 deleted file mode 100755 index c32823393c0805484f1a5ef37375c0ca3384a72b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 828912 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 zⅅ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%0AW?1 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�!aAZIt39-bB2bc;J1p7Y_!T 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 Si3xq7R#~=kHl`c Date: Mon, 16 Dec 2019 07:58:16 -0800 Subject: [PATCH 248/278] [swss service] flush fast-reboot enabled flag upon swss stopping (#3908) If we need to stop swss during fast-reboot procedure on the boot up path, it means that something went wrong, like syncd/orchagent crashed already, we are stopping and restarting swss/syncd to re-initialize. In this case, we should proceed as if it is a cold reboot. Signed-off-by: Ying Xie --- files/scripts/swss.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/files/scripts/swss.sh b/files/scripts/swss.sh index 7dde4aecb365..93f311019d66 100755 --- a/files/scripts/swss.sh +++ b/files/scripts/swss.sh @@ -161,6 +161,13 @@ stop() { /usr/bin/${SERVICE}.sh stop debug "Stopped ${SERVICE} service..." + # Flush FAST_REBOOT table when swss needs to stop. The only + # time when this would take effect is when fast-reboot + # encountered error, e.g. syncd crashed. And swss needs to + # be restarted. + debug "Clearing FAST_REBOOT flag..." + clean_up_tables 6 "'FAST_REBOOT*'" + # Unlock has to happen before reaching out to peer service unlock_service_state_change From 2c6c6bb33fbc9e5b6d77d87a7c39d820e7c8c2be Mon Sep 17 00:00:00 2001 From: rajendra-dendukuri <47423477+rajendra-dendukuri@users.noreply.github.com> Date: Mon, 16 Dec 2019 11:28:29 -0500 Subject: [PATCH 249/278] [sonic-ztp]: Add Azure/sonic-ztp as a submodule to Azure/sonic-buildimage (#3903) --- .gitmodules | 3 +++ src/sonic-ztp | 1 + 2 files changed, 4 insertions(+) create mode 160000 src/sonic-ztp diff --git a/.gitmodules b/.gitmodules index cfc6878c7291..b2ffb2b26fff 100644 --- a/.gitmodules +++ b/.gitmodules @@ -69,3 +69,6 @@ [submodule "Switch-SDK-drivers"] path = platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers url = https://github.com/Mellanox/Switch-SDK-drivers +[submodule "src/sonic-ztp"] + path = src/sonic-ztp + url = https://github.com/Azure/sonic-ztp diff --git a/src/sonic-ztp b/src/sonic-ztp new file mode 160000 index 000000000000..374c9e804a9f --- /dev/null +++ b/src/sonic-ztp @@ -0,0 +1 @@ +Subproject commit 374c9e804a9f434cdb58fa7afe0c3f6201bfe56f From 9cb12e6474c263c4e5d1bb10b4e18e230a525093 Mon Sep 17 00:00:00 2001 From: Aravind Mani <53524901+aravindmani-1@users.noreply.github.com> Date: Mon, 16 Dec 2019 22:27:25 +0530 Subject: [PATCH 250/278] DellEMC: S52xx platforms optoe driver changes (#3865) used overriding method instead of making changes in sfputilbase.py and changed the sff84xx to optoe driver for both QSFP and SFP. --- .../plugins/sfputil.py | 328 ++++++++++++++++- .../plugins/sfputil.py | 329 ++++++++++++++++++ .../plugins/sfputil.py | 12 +- .../s5232f/scripts/s5232f_platform.sh | 33 +- .../s5248f/scripts/s5248f_platform.sh | 2 +- .../z9100/sonic_platform/sfp.py | 2 +- 6 files changed, 692 insertions(+), 14 deletions(-) diff --git a/device/dell/x86_64-dellemc_s5232f_c3538-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_s5232f_c3538-r0/plugins/sfputil.py index 192fb80f6c56..d09f621ee882 100644 --- a/device/dell/x86_64-dellemc_s5232f_c3538-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dellemc_s5232f_c3538-r0/plugins/sfputil.py @@ -8,13 +8,42 @@ import sys import getopt import time + import io from sonic_sfp.sfputilbase import SfpUtilBase from os import * from mmap import * - + from sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_sfp.sff8436 import sff8436Dom + from sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_sfp.sff8472 import sff8472Dom except ImportError as e: raise ImportError("%s - required module not found" % str(e)) +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_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNL_THRESHOLD_OFFSET = 176 +QSFP_CHANNL_THRESHOLD_WIDTH = 16 +QSFP_CHANNL_MON_MASK_OFFSET = 242 +QSFP_CHANNL_MON_MASK_WIDTH = 4 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 56 + +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 1 class SfpUtil(SfpUtilBase): """Platform-specific SfpUtil class""" @@ -225,3 +254,300 @@ def get_transceiver_change_event(self): return True, port_dict time.sleep(0.5) + + 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: + offset = 0 + offset_xcvr = 128 + file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + return None + + try: + sysfsfile_eeprom = io.open(file_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + return transceiver_dom_info_dict + + # 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(sysfsfile_eeprom, (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_qsfp_dom_capability(qsfp_dom_capability_raw, 0) + else: + return transceiver_dom_info_dict + + dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) + else: + return transceiver_dom_info_dict + + dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) + else: + return transceiver_dom_info_dict + + qsfp_dom_rev_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) + else: + return transceiver_dom_info_dict + + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['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 = {} + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + 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(sysfsfile_eeprom, (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: + return transceiver_dom_info_dict + + transceiver_dom_info_dict['tx1power'] = 'N/A' + transceiver_dom_info_dict['tx2power'] = 'N/A' + transceiver_dom_info_dict['tx3power'] = 'N/A' + transceiver_dom_info_dict['tx4power'] = 'N/A' + else: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) + else: + return None + + 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'] + + 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']['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'] + + else: + 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 = io.open(file_path,"rb",0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8472Dom(None,1) + if sfpd_obj is None: + return transceiver_dom_info_dict + + 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 transceiver_dom_info_dict + + 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 transceiver_dom_info_dict + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_MODULE_THRESHOLD_OFFSET), + SFP_MODULE_THRESHOLD_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 transceiver_dom_info_dict + + 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: + file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + return None + + try: + sysfsfile_eeprom = io.open(file_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + # Dom Threshold data starts from offset 384 + # Revert offset back to 0 once data is retrieved + offset = 384 + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + sysfsfile_eeprom, + (offset + QSFP_MODULE_THRESHOLD_OFFSET), + QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + else: + return transceiver_dom_threshold_info_dict + + dom_channel_threshold_raw = self._read_eeprom_specific_bytes( + sysfsfile_eeprom, + (offset + QSFP_CHANNL_THRESHOLD_OFFSET), + QSFP_CHANNL_THRESHOLD_WIDTH) + if dom_channel_threshold_raw is not None: + dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values(dom_channel_threshold_raw, 0) + else: + return transceiver_dom_threshold_info_dict + + 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['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] + + else: + 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 = io.open(file_path,"rb",0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8472Dom(None,1) + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + 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_alarm_warning_threshold(dom_module_threshold_raw, 0) + else: + return transceiver_dom_threshold_info_dict + + 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']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + return transceiver_dom_threshold_info_dict diff --git a/device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/sfputil.py index e6680dc8d919..911c04a0fe0d 100644 --- a/device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dellemc_s5248f_c3538-r0/plugins/sfputil.py @@ -9,13 +9,44 @@ import sys import getopt import time + import io from sonic_sfp.sfputilbase import SfpUtilBase from os import * from mmap import * + from sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_sfp.sff8436 import sff8436Dom + from sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_sfp.sff8472 import sff8472Dom except ImportError as e: raise ImportError("%s - required module not found" % str(e)) +#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_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNL_THRESHOLD_OFFSET = 176 +QSFP_CHANNL_THRESHOLD_WIDTH = 16 +QSFP_CHANNL_MON_MASK_OFFSET = 242 +QSFP_CHANNL_MON_MASK_WIDTH = 4 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 56 + +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 1 class SfpUtil(SfpUtilBase): """Platform-specific SfpUtil class""" @@ -287,3 +318,301 @@ def get_transceiver_change_event(self, timeout=0): return True, port_dict time.sleep(0.5) + + 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: + offset = 0 + offset_xcvr = 128 + file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + return None + + try: + sysfsfile_eeprom = io.open(file_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + return transceiver_dom_info_dict + + # 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(sysfsfile_eeprom, (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_qsfp_dom_capability(qsfp_dom_capability_raw, 0) + else: + return transceiver_dom_info_dict + + dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) + else: + return transceiver_dom_info_dict + + dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) + else: + return transceiver_dom_info_dict + + qsfp_dom_rev_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) + else: + return transceiver_dom_info_dict + + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['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 = {} + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + 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(sysfsfile_eeprom, (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: + return transceiver_dom_info_dict + + transceiver_dom_info_dict['tx1power'] = 'N/A' + transceiver_dom_info_dict['tx2power'] = 'N/A' + transceiver_dom_info_dict['tx3power'] = 'N/A' + transceiver_dom_info_dict['tx4power'] = 'N/A' + else: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) + else: + return None + + 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'] + + 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']['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'] + + else: + 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 = io.open(file_path,"rb",0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8472Dom(None,1) + if sfpd_obj is None: + return transceiver_dom_info_dict + + 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 transceiver_dom_info_dict + + 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 transceiver_dom_info_dict + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_MODULE_THRESHOLD_OFFSET), + SFP_MODULE_THRESHOLD_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 transceiver_dom_info_dict + + 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: + file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + return None + + try: + sysfsfile_eeprom = io.open(file_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + # Dom Threshold data starts from offset 384 + # Revert offset back to 0 once data is retrieved + offset = 384 + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + sysfsfile_eeprom, + (offset + QSFP_MODULE_THRESHOLD_OFFSET), + QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + else: + return transceiver_dom_threshold_info_dict + + dom_channel_threshold_raw = self._read_eeprom_specific_bytes( + sysfsfile_eeprom, + (offset + QSFP_CHANNL_THRESHOLD_OFFSET), + QSFP_CHANNL_THRESHOLD_WIDTH) + if dom_channel_threshold_raw is not None: + dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values(dom_channel_threshold_raw, 0) + else: + return transceiver_dom_threshold_info_dict + + 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['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] + + else: + 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 = io.open(file_path,"rb",0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8472Dom(None,1) + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + 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_alarm_warning_threshold(dom_module_threshold_raw, 0) + else: + return transceiver_dom_threshold_info_dict + + 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']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + return transceiver_dom_threshold_info_dict diff --git a/device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py index bb1c961ab670..70e0b26f7890 100644 --- a/device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py @@ -348,7 +348,7 @@ def get_transceiver_dom_info_dict(self, port_num): transceiver_dom_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') if port_num in self.qsfp_ports: - offset = 0 + offset = 0 offset_xcvr = 128 file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) if not self._sfp_eeprom_present(file_path, 0): @@ -415,7 +415,7 @@ def get_transceiver_dom_info_dict(self, port_num): transceiver_dom_info_dict['tx2power'] = 'N/A' transceiver_dom_info_dict['tx3power'] = 'N/A' transceiver_dom_info_dict['tx4power'] = 'N/A' - try: + try: sysfsfile_eeprom.close() except IOError: print("Error: closing sysfs file %s" % file_path) @@ -433,7 +433,7 @@ def get_transceiver_dom_info_dict(self, port_num): transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] else: - offset = 256 + 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 @@ -507,7 +507,7 @@ def get_transceiver_dom_threshold_info_dict(self, port_num): transceiver_dom_threshold_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') if port_num in self.qsfp_ports: - file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) + file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) if not self._sfp_eeprom_present(file_path, 0): return None @@ -578,7 +578,7 @@ def get_transceiver_dom_threshold_info_dict(self, port_num): print("Error: reading sysfs file %s" % file_path) return None - sfpd_obj = sff8472Dom(None,1) + sfpd_obj = sff8472Dom(None,1) if sfpd_obj is None: return transceiver_dom_threshold_info_dict @@ -608,7 +608,7 @@ def get_transceiver_dom_threshold_info_dict(self, port_num): 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['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'] diff --git a/platform/broadcom/sonic-platform-modules-dell/s5232f/scripts/s5232f_platform.sh b/platform/broadcom/sonic-platform-modules-dell/s5232f/scripts/s5232f_platform.sh index 18e5ca2d5159..6923c9f4b353 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s5232f/scripts/s5232f_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/s5232f/scripts/s5232f_platform.sh @@ -51,19 +51,41 @@ switch_board_qsfp_mux() { sleep 2 } -#Attach/Detach 64 instances of EEPROM driver QSFP ports +#Attach/Detach 32 instances of EEPROM driver QSFP ports #eeprom can dump data using below command switch_board_qsfp() { case $1 in "new_device") - for ((i=2;i<=41;i++)); + for ((i=2;i<=33;i++)); do - echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 done ;; "delete_device") - for ((i=2;i<=41;i++)); + for ((i=2;i<=33;i++)); + do + echo 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + done + ;; + + *) echo "s5232f_platform: switch_board_qsfp: invalid command !" + ;; + esac +} + +#Attach 2 instances of EEPROM driver SFP ports +switch_board_sfp() { + case $1 in + "new_device") + for ((i=34;i<=35;i++)); + do + echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + done + ;; + + "delete_device") + for ((i=34;i<=35;i++)); do echo 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 done @@ -103,6 +125,7 @@ if [ "$1" == "init" ]; then sys_eeprom "new_device" switch_board_qsfp_mux "new_device" switch_board_qsfp "new_device" + switch_board_sfp "new_device" switch_board_modsel switch_board_led_default python /usr/bin/qsfp_irq_enable.py @@ -111,7 +134,7 @@ elif [ "$1" == "deinit" ]; then sys_eeprom "delete_device" switch_board_qsfp "delete_device" switch_board_qsfp_mux "delete_device" - + switch_board_sfp "delete_device" modprobe -r i2c-mux-pca954x modprobe -r i2c-dev else diff --git a/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/s5248f_platform.sh b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/s5248f_platform.sh index e74a3d6c40de..094c88eeaba6 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/s5248f_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/s5248f/scripts/s5248f_platform.sh @@ -58,7 +58,7 @@ switch_board_qsfp() { "new_device") for ((i=2;i<=57;i++)); do - echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 done ;; diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py index 87057545cbb7..9f5844d2058c 100644 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py @@ -44,7 +44,7 @@ 'manufacturename', 'modelname', 'Connector', 'encoding', 'ext_identifier', 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', - 'specification_compliance', ,'type_abbrv_name','vendor_date', 'vendor_oui'] + 'specification_compliance','type_abbrv_name','vendor_date', 'vendor_oui'] dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', From 1e5d25b48e896c46ae31a10d2ebeef7dafde40a0 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Tue, 17 Dec 2019 00:04:42 +0700 Subject: [PATCH 251/278] [platform-celestica]: Update fancontrol service for Seastone-DX010 device (#3690) * [platform/cel]: add fancontrol service support for dx010 * [device/celestica]: add hysteresis temp to dx010 fancontrol configuration --- .../x86_64-cel_seastone-r0/fancontrol | 12 --- .../x86_64-cel_seastone-r0/fancontrol-B2F | 11 +++ .../x86_64-cel_seastone-r0/fancontrol-F2B | 12 +++ .../debian/platform-modules-dx010.install | 3 + .../debian/platform-modules-dx010.postinst | 3 + .../dx010/scripts/fancontrol.sh | 81 +++++++++++++++++++ .../services/fancontrol/fancontrol | 11 +-- 7 files changed, 116 insertions(+), 17 deletions(-) delete mode 100644 device/celestica/x86_64-cel_seastone-r0/fancontrol create mode 100644 device/celestica/x86_64-cel_seastone-r0/fancontrol-B2F create mode 100644 device/celestica/x86_64-cel_seastone-r0/fancontrol-F2B create mode 100644 platform/broadcom/sonic-platform-modules-cel/dx010/scripts/fancontrol.sh diff --git a/device/celestica/x86_64-cel_seastone-r0/fancontrol b/device/celestica/x86_64-cel_seastone-r0/fancontrol deleted file mode 100644 index 8d5cbccb9d00..000000000000 --- a/device/celestica/x86_64-cel_seastone-r0/fancontrol +++ /dev/null @@ -1,12 +0,0 @@ -# Configuration file generated by pwmconfig, changes will be lost -INTERVAL=10 -DEVPATH=hwmon6=devices/pci0000:00/0000:00:13.0/i2c-1/i2c-13/13-002e hwmon7=devices/pci0000:00/0000:00:13.0/i2c-1/i2c-13/13-004d -DEVNAME=hwmon6=emc2305 hwmon7=emc2305 -FCTEMPS=hwmon6/device/pwm1=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-0048/hwmon/hwmon1/temp1_input hwmon6/device/pwm2=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-0048/hwmon/hwmon1/temp1_input hwmon6/device/pwm3=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-0048/hwmon/hwmon1/temp1_input hwmon6/device/pwm4=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-0048/hwmon/hwmon1/temp1_input hwmon6/device/pwm5=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-0048/hwmon/hwmon1/temp1_input hwmon7/device/pwm1=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-0048/hwmon/hwmon1/temp1_input hwmon7/device/pwm2=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-0048/hwmon/hwmon1/temp1_input hwmon7/device/pwm3=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-0048/hwmon/hwmon1/temp1_input hwmon7/device/pwm4=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-0048/hwmon/hwmon1/temp1_input hwmon7/device/pwm5=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-0048/hwmon/hwmon1/temp1_input -FCFANS=hwmon7/device/pwm5=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-13/13-004d/pwm5 hwmon7/device/pwm4=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-13/13-004d/pwm4 hwmon7/device/pwm3=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-13/13-004d/pwm3 hwmon7/device/pwm2=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-13/13-004d/pwm2 hwmon7/device/pwm1=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-13/13-004d/pwm1 hwmon6/device/pwm5=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-13/13-002e/pwm5 hwmon6/device/pwm4=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-13/13-002e/pwm4 hwmon6/device/pwm3=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-13/13-002e/pwm3 hwmon6/device/pwm2=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-13/13-002e/pwm2 hwmon6/device/pwm1=/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-13/13-002e/pwm1 -MINTEMP=hwmon6/device/pwm1=26 hwmon6/device/pwm2=26 hwmon6/device/pwm3=26 hwmon6/device/pwm4=26 hwmon6/device/pwm5=26 hwmon7/device/pwm1=26 hwmon7/device/pwm2=26 hwmon7/device/pwm3=26 hwmon7/device/pwm4=26 hwmon7/device/pwm5=26 -MAXTEMP=hwmon6/device/pwm1=45 hwmon6/device/pwm2=45 hwmon6/device/pwm3=45 hwmon6/device/pwm4=45 hwmon6/device/pwm5=45 hwmon7/device/pwm1=45 hwmon7/device/pwm2=45 hwmon7/device/pwm3=45 hwmon7/device/pwm4=45 hwmon7/device/pwm5=45 -MINSTART=hwmon6/device/pwm1=89 hwmon6/device/pwm2=89 hwmon6/device/pwm3=89 hwmon6/device/pwm4=89 hwmon6/device/pwm5=89 hwmon7/device/pwm1=89 hwmon7/device/pwm2=89 hwmon7/device/pwm3=89 hwmon7/device/pwm4=89 hwmon7/device/pwm5=89 -MINSTOP=hwmon6/device/pwm1=89 hwmon6/device/pwm2=89 hwmon6/device/pwm3=89 hwmon6/device/pwm4=89 hwmon6/device/pwm5=89 hwmon7/device/pwm1=89 hwmon7/device/pwm2=89 hwmon7/device/pwm3=89 hwmon7/device/pwm4=89 hwmon7/device/pwm5=89 -MINPWM=hwmon6/device/pwm1=89 hwmon6/device/pwm2=89 hwmon6/device/pwm3=89 hwmon6/device/pwm4=89 hwmon6/device/pwm5=89 hwmon7/device/pwm1=89 hwmon7/device/pwm2=89 hwmon7/device/pwm3=89 hwmon7/device/pwm4=89 hwmon7/device/pwm5=89 -MAXPWM=hwmon6/device/pwm1=255 hwmon6/device/pwm2=255 hwmon6/device/pwm3=255 hwmon6/device/pwm4=255 hwmon6/device/pwm5=255 hwmon7/device/pwm1=255 hwmon7/device/pwm2=255 hwmon7/device/pwm3=255 hwmon7/device/pwm4=255 hwmon7/device/pwm5=255 diff --git a/device/celestica/x86_64-cel_seastone-r0/fancontrol-B2F b/device/celestica/x86_64-cel_seastone-r0/fancontrol-B2F new file mode 100644 index 000000000000..c2132d7f2806 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/fancontrol-B2F @@ -0,0 +1,11 @@ +# Configuration file generated by pwmconfig, changes will be lost +INTERVAL=2 +FCTEMPS=13-002e/pwm1=/sys/bus/i2c/devices/15-004e/hwmon/hwmon*/temp1_input 13-002e/pwm2=/sys/bus/i2c/devices/15-004e/hwmon/hwmon*/temp1_input 13-002e/pwm3=/sys/bus/i2c/devices/15-004e/hwmon/hwmon*/temp1_input 13-002e/pwm4=/sys/bus/i2c/devices/15-004e/hwmon/hwmon*/temp1_input 13-002e/pwm5=/sys/bus/i2c/devices/15-004e/hwmon/hwmon*/temp1_input 13-004d/pwm1=/sys/bus/i2c/devices/15-004e/hwmon/hwmon*/temp1_input 13-004d/pwm2=/sys/bus/i2c/devices/15-004e/hwmon/hwmon*/temp1_input 13-004d/pwm3=/sys/bus/i2c/devices/15-004e/hwmon/hwmon*/temp1_input 13-004d/pwm4=/sys/bus/i2c/devices/15-004e/hwmon/hwmon*/temp1_input 13-004d/pwm5=/sys/bus/i2c/devices/15-004e/hwmon/hwmon*/temp1_input +FCFANS=13-004d/pwm5=13-004d/fan5_input 13-004d/pwm4=13-004d/fan4_input 13-004d/pwm3=13-004d/fan3_input 13-004d/pwm2=13-004d/fan2_input 13-004d/pwm1=13-004d/fan1_input 13-002e/pwm5=13-002e/fan5_input 13-002e/pwm4=13-002e/fan4_input 13-002e/pwm3=13-002e/fan3_input 13-002e/pwm2=13-002e/fan2_input 13-002e/pwm1=13-002e/fan1_input +MINTEMP=13-002e/pwm1=27 13-002e/pwm2=27 13-002e/pwm3=27 13-002e/pwm4=27 13-002e/pwm5=27 13-004d/pwm1=27 13-004d/pwm2=27 13-004d/pwm3=27 13-004d/pwm4=27 13-004d/pwm5=27 +MAXTEMP=13-002e/pwm1=46 13-002e/pwm2=46 13-002e/pwm3=46 13-002e/pwm4=46 13-002e/pwm5=46 13-004d/pwm1=46 13-004d/pwm2=46 13-004d/pwm3=46 13-004d/pwm4=46 13-004d/pwm5=46 +MINSTART=13-002e/pwm1=89 13-002e/pwm2=89 13-002e/pwm3=89 13-002e/pwm4=89 13-002e/pwm5=89 13-004d/pwm1=89 13-004d/pwm2=89 13-004d/pwm3=89 13-004d/pwm4=89 13-004d/pwm5=89 +MINSTOP=13-002e/pwm1=89 13-002e/pwm2=89 13-002e/pwm3=89 13-002e/pwm4=89 13-002e/pwm5=89 13-004d/pwm1=89 13-004d/pwm2=89 13-004d/pwm3=89 13-004d/pwm4=89 13-004d/pwm5=89 +MINPWM=13-002e/pwm1=89 13-002e/pwm2=89 13-002e/pwm3=89 13-002e/pwm4=89 13-002e/pwm5=89 13-004d/pwm1=89 13-004d/pwm2=89 13-004d/pwm3=89 13-004d/pwm4=89 13-004d/pwm5=89 +MAXPWM=13-002e/pwm1=255 13-002e/pwm2=255 13-002e/pwm3=255 13-002e/pwm4=255 13-002e/pwm5=255 13-004d/pwm1=255 13-004d/pwm2=255 13-004d/pwm3=255 13-004d/pwm4=255 13-004d/pwm5=255 +THYST=13-002e/pwm1=3 13-002e/pwm2=3 13-002e/pwm3=3 13-002e/pwm4=3 13-002e/pwm5=3 13-004d/pwm1=3 13-004d/pwm2=3 13-004d/pwm3=3 13-004d/pwm4=3 13-004d/pwm5=3 \ No newline at end of file diff --git a/device/celestica/x86_64-cel_seastone-r0/fancontrol-F2B b/device/celestica/x86_64-cel_seastone-r0/fancontrol-F2B new file mode 100644 index 000000000000..dc67e2623cc2 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/fancontrol-F2B @@ -0,0 +1,12 @@ +# Configuration file generated by pwmconfig, changes will be lost +INTERVAL=2 +FCTEMPS=13-002e/pwm1=/sys/bus/i2c/devices/5-0048/hwmon/hwmon*/temp1_input 13-002e/pwm2=/sys/bus/i2c/devices/5-0048/hwmon/hwmon*/temp1_input 13-002e/pwm3=/sys/bus/i2c/devices/5-0048/hwmon/hwmon*/temp1_input 13-002e/pwm4=/sys/bus/i2c/devices/5-0048/hwmon/hwmon*/temp1_input 13-002e/pwm5=/sys/bus/i2c/devices/5-0048/hwmon/hwmon*/temp1_input 13-004d/pwm1=/sys/bus/i2c/devices/5-0048/hwmon/hwmon*/temp1_input 13-004d/pwm2=/sys/bus/i2c/devices/5-0048/hwmon/hwmon*/temp1_input 13-004d/pwm3=/sys/bus/i2c/devices/5-0048/hwmon/hwmon*/temp1_input 13-004d/pwm4=/sys/bus/i2c/devices/5-0048/hwmon/hwmon*/temp1_input 13-004d/pwm5=/sys/bus/i2c/devices/5-0048/hwmon/hwmon*/temp1_input +FCFANS=13-004d/pwm5=13-004d/fan5_input 13-004d/pwm4=13-004d/fan4_input 13-004d/pwm3=13-004d/fan3_input 13-004d/pwm2=13-004d/fan2_input 13-004d/pwm1=13-004d/fan1_input 13-002e/pwm5=13-002e/fan5_input 13-002e/pwm4=13-002e/fan4_input 13-002e/pwm3=13-002e/fan3_input 13-002e/pwm2=13-002e/fan2_input 13-002e/pwm1=13-002e/fan1_input +MINTEMP=13-002e/pwm1=26 13-002e/pwm2=26 13-002e/pwm3=26 13-002e/pwm4=26 13-002e/pwm5=26 13-004d/pwm1=26 13-004d/pwm2=26 13-004d/pwm3=26 13-004d/pwm4=26 13-004d/pwm5=26 +MAXTEMP=13-002e/pwm1=45 13-002e/pwm2=45 13-002e/pwm3=45 13-002e/pwm4=45 13-002e/pwm5=45 13-004d/pwm1=45 13-004d/pwm2=45 13-004d/pwm3=45 13-004d/pwm4=45 13-004d/pwm5=45 +MINSTART=13-002e/pwm1=89 13-002e/pwm2=89 13-002e/pwm3=89 13-002e/pwm4=89 13-002e/pwm5=89 13-004d/pwm1=89 13-004d/pwm2=89 13-004d/pwm3=89 13-004d/pwm4=89 13-004d/pwm5=89 +MINSTOP=13-002e/pwm1=89 13-002e/pwm2=89 13-002e/pwm3=89 13-002e/pwm4=89 13-002e/pwm5=89 13-004d/pwm1=89 13-004d/pwm2=89 13-004d/pwm3=89 13-004d/pwm4=89 13-004d/pwm5=89 +MINPWM=13-002e/pwm1=89 13-002e/pwm2=89 13-002e/pwm3=89 13-002e/pwm4=89 13-002e/pwm5=89 13-004d/pwm1=89 13-004d/pwm2=89 13-004d/pwm3=89 13-004d/pwm4=89 13-004d/pwm5=89 +MAXPWM=13-002e/pwm1=255 13-002e/pwm2=255 13-002e/pwm3=255 13-002e/pwm4=255 13-002e/pwm5=255 13-004d/pwm1=255 13-004d/pwm2=255 13-004d/pwm3=255 13-004d/pwm4=255 13-004d/pwm5=255 +THYST=13-002e/pwm1=3 13-002e/pwm2=3 13-002e/pwm3=3 13-002e/pwm4=3 13-002e/pwm5=3 13-004d/pwm1=3 13-004d/pwm2=3 13-004d/pwm3=3 13-004d/pwm4=3 13-004d/pwm5=3 + diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install index 8570fa1eae84..9b456a7c9112 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install @@ -1,5 +1,8 @@ dx010/scripts/dx010_check_qsfp.sh usr/local/bin dx010/cfg/dx010-modules.conf etc/modules-load.d dx010/systemd/platform-modules-dx010.service lib/systemd/system +dx010/scripts/fancontrol.sh etc/init.d +services/fancontrol/fancontrol.service lib/systemd/system +services/fancontrol/fancontrol usr/local/bin dx010/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_seastone-r0 services/platform_api/platform_api_mgnt.sh usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.postinst index 15243c935ca3..8dbf0ece6676 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.postinst +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.postinst @@ -1,6 +1,9 @@ depmod -a systemctl enable platform-modules-dx010.service +systemctl enable fancontrol.service + systemctl start platform-modules-dx010.service +systemctl start fancontrol.service /usr/local/bin/platform_api_mgnt.sh install diff --git a/platform/broadcom/sonic-platform-modules-cel/dx010/scripts/fancontrol.sh b/platform/broadcom/sonic-platform-modules-cel/dx010/scripts/fancontrol.sh new file mode 100644 index 000000000000..75ad6c65b37f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/dx010/scripts/fancontrol.sh @@ -0,0 +1,81 @@ +#! /bin/sh + +### BEGIN INIT INFO +# Provides: fancontrol +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: +# Short-Description: fancontrol +# Description: fan speed regulator +### END INIT INFO + +. /lib/lsb/init-functions + +[ -f /etc/default/rcS ] && . /etc/default/rcS +PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin +DAEMON=/usr/local/bin/fancontrol +DESC="fan speed regulator" +NAME="fancontrol" +PIDFILE=/var/run/fancontrol.pid +MAIN_CONF=/usr/share/sonic/device/x86_64-cel_seastone-r0/fancontrol +DEVPATH=/sys/devices/pci0000:00/0000:00:13.0/i2c-*/i2c-13/13-002e +GPIO_DIR=/sys/class/gpio +BASE_GPIO=$(find $GPIO_DIR | grep gpiochip | grep -o '[[:digit:]]*') +DIRGPIO_START=15 + +test -x $DAEMON || exit 0 + +for i in 1 2 3 4 5 +do + FANFAULT=$(cat ${DEVPATH}/fan${i}_fault) + [ $FANFAULT = 1 ] && continue + FANDIR_GPIO_NUMBER=$((DIRGPIO_START + BASE_GPIO)) + FANDIR_VALUE=$(cat ${GPIO_DIR}/gpio${FANDIR_GPIO_NUMBER}/value) + DIRGPIO_START=$((DIRGPIO_START+1)) + FANDIR=$([ $FANDIR_VALUE = 1 ] && echo "B2F" || echo "F2B") +done +CONF=${MAIN_CONF}-${FANDIR} + +case "$1" in + start) + if [ -f $CONF ] ; then + if $DAEMON --check $CONF 1>/dev/null 2>/dev/null ; then + log_daemon_msg "Starting $DESC" "$NAME\n" + start-stop-daemon --start --quiet --pidfile $PIDFILE --startas $DAEMON $CONF + log_end_msg $? + else + log_failure_msg "Not starting fancontrol, broken configuration file; please re-run pwmconfig." + fi + else + if [ "$VERBOSE" != no ]; then + log_warning_msg "Not starting fancontrol; run pwmconfig first." + fi + fi + ;; + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + start-stop-daemon --stop --quiet --pidfile $PIDFILE --oknodo --startas $DAEMON $CONF + rm -f $PIDFILE + log_end_msg $? + ;; + restart) + $0 stop + sleep 3 + $0 start + ;; + force-reload) + if start-stop-daemon --stop --test --quiet --pidfile $PIDFILE --startas $DAEMON $CONF ; then + $0 restart + fi + ;; + status) + status_of_proc $DAEMON $NAME $CONF && exit 0 || exit $? + ;; + *) + log_success_msg "Usage: /etc/init.d/fancontrol {start|stop|restart|force-reload|status}" + exit 1 + ;; +esac + +exit 0 diff --git a/platform/broadcom/sonic-platform-modules-cel/services/fancontrol/fancontrol b/platform/broadcom/sonic-platform-modules-cel/services/fancontrol/fancontrol index 9155d8a66998..eb15598b0efa 100755 --- a/platform/broadcom/sonic-platform-modules-cel/services/fancontrol/fancontrol +++ b/platform/broadcom/sonic-platform-modules-cel/services/fancontrol/fancontrol @@ -322,11 +322,12 @@ fi cd $DIR # Check for configuration change -if [ "$DIR" != "/" ] && [ -z "$DEVPATH" -o -z "$DEVNAME" ] -then - echo "Configuration is too old, please run pwmconfig again" >&2 - exit 1 -fi +# if [ "$DIR" != "/" ] && [ -z "$DEVPATH" -o -z "$DEVNAME" ] +# then +# echo "Configuration is too old, please run pwmconfig again" >&2 +# exit 1 +# fi + if [ "$DIR" = "/" -a -n "$DEVPATH" ] then echo "Unneeded DEVPATH with absolute device paths" >&2 From 4ba0ff25d2ac89b10b2a94208140f7c52776fb69 Mon Sep 17 00:00:00 2001 From: Stepan Blyshchak <38952541+stepanblyschak@users.noreply.github.com> Date: Mon, 16 Dec 2019 19:07:05 +0200 Subject: [PATCH 252/278] [services] make snmp.timer work again and delay telemetry.service (#3742) Delay CPU intensive services at boot - How I did it Made snmp.timer work and add telemetry.timer. But this is not enough because it breaks the existing snmp dependency on swss. So, in this solution snmp timer is a wanted by swss service, but since OnBootSec timer expires only once it will not trigger snmp service, so I added line "OnUnitActiveSec=0 sec" which will start snmp service based on the last time it was active. On boot only OnBootSec will expire, on swss start/restarts only second timer will expire immediately and trigger snmp service. However, snmp service will not stop after "systemctl stop snmp" because of the second timer which will always expire when snmp service because unavailable. So there is a conflict which will be handled by systemd if we add "Conflicts=" line to both snmp.service and snmp.timer. So during boot: snmp does not start by default swss starts and starts snmp timer OnUnitActiveSec=0 does not expire since there is no snmp active OnBootSec expires and starts snmp service and snmp timer gets stopped During "systemctl restart swss" snmp stops because of Requisite on swss snmp unblocks snmp timer from running swss starts and starts snmp timer OnUnitActiveSec=0 expires imidiately and start snmp which stops snmp timer During "systemctl stop snmp" stop of snmp service unblocks snmp timer but no one starts the timer so it is not started by "OnUnitActiveSec=0" --- files/build_templates/snmp.service.j2 | 3 +-- files/build_templates/snmp.timer | 4 +++- files/build_templates/sonic_debian_extension.j2 | 8 ++++++-- files/build_templates/telemetry.service.j2 | 2 -- files/build_templates/telemetry.timer | 9 +++++++++ slave.mk | 1 + 6 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 files/build_templates/telemetry.timer diff --git a/files/build_templates/snmp.service.j2 b/files/build_templates/snmp.service.j2 index 310048e68beb..4997ab737e37 100644 --- a/files/build_templates/snmp.service.j2 +++ b/files/build_templates/snmp.service.j2 @@ -4,6 +4,7 @@ Requires=updategraph.service Requisite=swss.service After=updategraph.service swss.service syncd.service Before=ntp-config.service +Conflicts=snmp.timer StartLimitIntervalSec=1200 StartLimitBurst=3 @@ -14,5 +15,3 @@ ExecStop=/usr/bin/{{docker_container_name}}.sh stop Restart=always RestartSec=30 -[Install] -WantedBy=multi-user.target swss.service diff --git a/files/build_templates/snmp.timer b/files/build_templates/snmp.timer index 464cf01459ba..6d1838554d0e 100644 --- a/files/build_templates/snmp.timer +++ b/files/build_templates/snmp.timer @@ -1,9 +1,11 @@ [Unit] Description=Delays snmp container until SONiC has started +Conflicts=snmp.service [Timer] +OnUnitActiveSec=0 sec OnBootSec=3min 30 sec Unit=snmp.service [Install] -WantedBy=timers.target +WantedBy=timers.target swss.service diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index b11325e86835..b63b5addac4b 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -359,7 +359,7 @@ EOF ## Bind docker path if [[ $CONFIGURED_ARCH == armhf || $CONFIGURED_ARCH == arm64 ]]; then sudo mkdir -p $FILESYSTEM_ROOT/dockerfs - sudo mount --bind dockerfs $FILESYSTEM_ROOT/dockerfs + sudo mount --bind dockerfs $FILESYSTEM_ROOT/dockerfs fi {% if installer_images.strip() -%} @@ -376,7 +376,7 @@ sudo LANG=C chroot $FILESYSTEM_ROOT docker $SONIC_NATIVE_DOCKERD_FOR_DOCKERFS ta {% endif %} {% endfor %} if [[ $CONFIGURED_ARCH == armhf || $CONFIGURED_ARCH == arm64 ]]; then - sudo umount $FILESYSTEM_ROOT/dockerfs + sudo umount $FILESYSTEM_ROOT/dockerfs sudo rm -fr $FILESYSTEM_ROOT/dockerfs sudo kill -9 `sudo $SONIC_NATIVE_DOCKERD_FOR_DOCKERFS_PID` || true else @@ -404,6 +404,10 @@ sudo LANG=C cp $SCRIPTS_DIR/syncd.sh $FILESYSTEM_ROOT/usr/local/bin/syncd.sh # It implements delayed start of services sudo cp $BUILD_TEMPLATES/snmp.timer $FILESYSTEM_ROOT/etc/systemd/system/ sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable snmp.timer +{% if enable_system_telemetry == 'y' %} +sudo cp $BUILD_TEMPLATES/telemetry.timer $FILESYSTEM_ROOT/etc/systemd/system/ +sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable telemetry.timer +{% endif %} sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get purge -y python-dev sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get clean -y diff --git a/files/build_templates/telemetry.service.j2 b/files/build_templates/telemetry.service.j2 index 98ae2871bf6f..43fa039156d7 100644 --- a/files/build_templates/telemetry.service.j2 +++ b/files/build_templates/telemetry.service.j2 @@ -14,5 +14,3 @@ ExecStop=/usr/bin/{{docker_container_name}}.sh stop Restart=always RestartSec=30 -[Install] -WantedBy=multi-user.target diff --git a/files/build_templates/telemetry.timer b/files/build_templates/telemetry.timer new file mode 100644 index 000000000000..e08f1c09eac6 --- /dev/null +++ b/files/build_templates/telemetry.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Delays telemetry container until SONiC has started + +[Timer] +OnBootSec=3min 30 sec +Unit=telemetry.service + +[Install] +WantedBy=timers.target diff --git a/slave.mk b/slave.mk index e518f1e4d8a5..44b903ddf9c9 100644 --- a/slave.mk +++ b/slave.mk @@ -641,6 +641,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ export sonic_asic_platform="$(patsubst %-$(CONFIGURED_ARCH),%,$(CONFIGURED_PLATFORM))" export enable_organization_extensions="$(ENABLE_ORGANIZATION_EXTENSIONS)" export enable_dhcp_graph_service="$(ENABLE_DHCP_GRAPH_SERVICE)" + export enable_system_telemetry="$(ENABLE_SYSTEM_TELEMETRY)" export enable_ztp="$(ENABLE_ZTP)" export shutdown_bgp_on_start="$(SHUTDOWN_BGP_ON_START)" export enable_pfcwd_on_start="$(ENABLE_PFCWD_ON_START)" From 08ec4fcfe7290d4a05e14a6b7597f4b38f2cef34 Mon Sep 17 00:00:00 2001 From: Dong Zhang <41927498+dzhangalibaba@users.noreply.github.com> Date: Tue, 17 Dec 2019 08:00:14 -0800 Subject: [PATCH 253/278] [swss-common] update submodule for sonic-swss-common (#3916) update multiDB changes in sonic-swss-common, including: [Enhancement] debian/conffiles will give prompt when file existing, need a way to supress prompt (#323) [MultiDB]:swsscommon replace old API with new APIs including tests (#324) Signed-off-by: Dong Zhang d.zhang@alibaba-inc.com --- src/sonic-swss-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-swss-common b/src/sonic-swss-common index 29a2cdfe9ea9..5b55954c5d6d 160000 --- a/src/sonic-swss-common +++ b/src/sonic-swss-common @@ -1 +1 @@ -Subproject commit 29a2cdfe9ea9bb0c4d2d82be9428228a8ab6b9d4 +Subproject commit 5b55954c5d6d4ae343af141357c3a2f6dd600c58 From 7ae371287f5d2c7c046003812c558e5cf169fd85 Mon Sep 17 00:00:00 2001 From: Volodymyr Samotiy Date: Tue, 17 Dec 2019 19:45:28 +0200 Subject: [PATCH 254/278] [Mellanox]: Update SAI submodule (#3883) Signed-off-by: Volodymyr Samotiy --- platform/mellanox/mlnx-sai/SAI-Implementation | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/mellanox/mlnx-sai/SAI-Implementation b/platform/mellanox/mlnx-sai/SAI-Implementation index 925116eb63a5..d878245e364c 160000 --- a/platform/mellanox/mlnx-sai/SAI-Implementation +++ b/platform/mellanox/mlnx-sai/SAI-Implementation @@ -1 +1 @@ -Subproject commit 925116eb63a5a9012dcc22a7a0682ada6e976380 +Subproject commit d878245e364ce8d5edd08bbd7120c44c92362235 From 51b78b5c335099e2c47e7277cbc8748a219eed77 Mon Sep 17 00:00:00 2001 From: Nazarii Hnydyn Date: Tue, 17 Dec 2019 20:58:55 +0200 Subject: [PATCH 255/278] [mellanox]: Enhance pmon synchronization with hw-mgmt platform counters. (#3885) Signed-off-by: Nazarii Hnydyn --- .../x86_64-mlnx_msn2700-r0/platform_wait | 49 +++++++++++++++---- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/device/mellanox/x86_64-mlnx_msn2700-r0/platform_wait b/device/mellanox/x86_64-mlnx_msn2700-r0/platform_wait index 44321184dccc..a233eb41de42 100755 --- a/device/mellanox/x86_64-mlnx_msn2700-r0/platform_wait +++ b/device/mellanox/x86_64-mlnx_msn2700-r0/platform_wait @@ -1,12 +1,37 @@ #!/bin/bash +declare -r SYSLOG_LOGGER="/usr/bin/logger" +declare -r SYSLOG_IDENTIFIER="platform_wait" +declare -r SYSLOG_ERROR="error" +declare -r SYSLOG_NOTICE="notice" +declare -r SYSLOG_INFO="info" + +declare -r HW_MGMT_CONFIG="/var/run/hw-management/config" + +declare -r MODULE_COUNTER="${HW_MGMT_CONFIG}/module_counter" +declare -r SFP_COUNTER="${HW_MGMT_CONFIG}/sfp_counter" + declare -r EXIT_SUCCESS="0" declare -r EXIT_TIMEOUT="1" -declare -r QSFP_PATH="/var/run/hw-management/qsfp" +function log_error() { + eval "${SYSLOG_LOGGER} -t ${SYSLOG_IDENTIFIER} -p ${SYSLOG_ERROR} $@" +} -function WaitForQsfpReady() { - local -r _QSFP_PATH="${1}" +function log_notice() { + eval "${SYSLOG_LOGGER} -t ${SYSLOG_IDENTIFIER} -p ${SYSLOG_NOTICE} $@" +} + +function log_info() { + eval "${SYSLOG_LOGGER} -t ${SYSLOG_IDENTIFIER} -p ${SYSLOG_INFO} $@" +} + +function wait_for_sfp() { + local -r _NUM_MATCH="^[0-9]+$" + local -r _NUM_ZERO="0" + + local _MODULE_CNT="0" + local _SFP_CNT="0" local -i _WDOG_CNT="1" local -ir _WDOG_MAX="300" @@ -14,11 +39,14 @@ function WaitForQsfpReady() { local -r _TIMEOUT="1s" while [[ "${_WDOG_CNT}" -le "${_WDOG_MAX}" ]]; do - for _QSFP in ${_QSFP_PATH}/qsfp*; do - if [[ -e "${_QSFP}" ]]; then + _MODULE_CNT="$(cat ${MODULE_COUNTER} 2>&1)" + _SFP_CNT="$(cat ${SFP_COUNTER} 2>&1)" + + if [[ "${_MODULE_CNT}" =~ ${_NUM_MATCH} && "${_SFP_CNT}" =~ ${_NUM_MATCH} ]]; then + if [[ "${_SFP_CNT}" -gt "${_NUM_ZERO}" && "${_MODULE_CNT}" -eq "${_SFP_CNT}" ]]; then return "${EXIT_SUCCESS}" fi - done + fi let "_WDOG_CNT++" sleep "${_TIMEOUT}" @@ -27,14 +55,15 @@ function WaitForQsfpReady() { return "${EXIT_TIMEOUT}" } -echo "Wait for QSFP I2C interface is ready" +log_info "Wait for SFP interfaces to be ready" -WaitForQsfpReady "${QSFP_PATH}" +wait_for_sfp EXIT_CODE="$?" if [[ "${EXIT_CODE}" != "${EXIT_SUCCESS}" ]]; then - echo "QSFP I2C interface is not ready: timeout" + log_error "SFP interfaces are not ready: timeout" exit "${EXIT_CODE}" fi -echo "QSFP I2C interface is ready: mlxsw_minimal has finished initialization" +log_info "SFP interfaces are ready" + exit "${EXIT_SUCCESS}" From a4b107b1dea1b16bbb000dfd7acaa335cd8e604f Mon Sep 17 00:00:00 2001 From: Ciju Rajan K Date: Wed, 18 Dec 2019 01:23:53 +0530 Subject: [PATCH 256/278] [Juniper][QFX5210] Skip starting 'ledd' (#3920) There is no ledd in qfx5210 platform. This patch skip starting ledd in pmon container. This also will help in fixing the pmon container not getting started if there is no ledd running. Signed-off-by: Ciju Rajan K --- .../juniper/x86_64-juniper_qfx5210-r0/pmon_daemon_control.json | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 device/juniper/x86_64-juniper_qfx5210-r0/pmon_daemon_control.json diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/pmon_daemon_control.json b/device/juniper/x86_64-juniper_qfx5210-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..94592fa8cebc --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} From 063deb9b5f1e0601e7f7d55eef6939943c0f8a2b Mon Sep 17 00:00:00 2001 From: "arheneus@marvell.com" <51254330+antony-rheneus@users.noreply.github.com> Date: Wed, 18 Dec 2019 01:28:17 +0530 Subject: [PATCH 257/278] [Marvell HwSKU] port configration updated with speed (#3919) Signed-off-by: Antony Rheneus --- .../et6448m/port_config.ini | 106 +++++++++--------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/device/marvell/armhf-marvell_et6448m_52x-r0/et6448m/port_config.ini b/device/marvell/armhf-marvell_et6448m_52x-r0/et6448m/port_config.ini index 8073e8bec86e..062c252ce195 100644 --- a/device/marvell/armhf-marvell_et6448m_52x-r0/et6448m/port_config.ini +++ b/device/marvell/armhf-marvell_et6448m_52x-r0/et6448m/port_config.ini @@ -1,53 +1,53 @@ -# name lanes alias -Ethernet0 1 Ethernet0 -Ethernet1 2 Ethernet1 -Ethernet2 3 Ethernet2 -Ethernet3 4 Ethernet3 -Ethernet4 5 Ethernet4 -Ethernet5 6 Ethernet5 -Ethernet6 7 Ethernet6 -Ethernet7 8 Ethernet7 -Ethernet8 9 Ethernet8 -Ethernet9 10 Ethernet9 -Ethernet10 11 Ethernet10 -Ethernet11 12 Ethernet11 -Ethernet12 13 Ethernet12 -Ethernet13 14 Ethernet13 -Ethernet14 15 Ethernet14 -Ethernet15 16 Ethernet15 -Ethernet16 17 Ethernet16 -Ethernet17 18 Ethernet17 -Ethernet18 19 Ethernet18 -Ethernet19 20 Ethernet19 -Ethernet20 21 Ethernet20 -Ethernet21 22 Ethernet21 -Ethernet22 23 Ethernet22 -Ethernet23 24 Ethernet23 -Ethernet24 25 Ethernet24 -Ethernet25 26 Ethernet25 -Ethernet26 27 Ethernet26 -Ethernet27 28 Ethernet27 -Ethernet28 29 Ethernet28 -Ethernet29 30 Ethernet29 -Ethernet30 31 Ethernet30 -Ethernet31 32 Ethernet31 -Ethernet32 33 Ethernet32 -Ethernet33 34 Ethernet33 -Ethernet34 35 Ethernet34 -Ethernet35 36 Ethernet35 -Ethernet36 37 Ethernet36 -Ethernet37 38 Ethernet37 -Ethernet38 39 Ethernet38 -Ethernet39 40 Ethernet39 -Ethernet40 41 Ethernet40 -Ethernet41 42 Ethernet41 -Ethernet42 43 Ethernet42 -Ethernet43 44 Ethernet43 -Ethernet44 45 Ethernet44 -Ethernet45 46 Ethernet45 -Ethernet46 47 Ethernet46 -Ethernet47 48 Ethernet47 -Ethernet48 49 Ethernet48 -Ethernet49 50 Ethernet49 -Ethernet50 51 Ethernet50 -Ethernet51 52 Ethernet51 +# name lanes alias index speed +Ethernet0 1 Ethernet0 1 1000 +Ethernet1 2 Ethernet1 2 1000 +Ethernet2 3 Ethernet2 3 1000 +Ethernet3 4 Ethernet3 4 1000 +Ethernet4 5 Ethernet4 5 1000 +Ethernet5 6 Ethernet5 6 1000 +Ethernet6 7 Ethernet6 7 1000 +Ethernet7 8 Ethernet7 8 1000 +Ethernet8 9 Ethernet8 9 1000 +Ethernet9 10 Ethernet9 10 1000 +Ethernet10 11 Ethernet10 11 1000 +Ethernet11 12 Ethernet11 12 1000 +Ethernet12 13 Ethernet12 13 1000 +Ethernet13 14 Ethernet13 14 1000 +Ethernet14 15 Ethernet14 15 1000 +Ethernet15 16 Ethernet15 16 1000 +Ethernet16 17 Ethernet16 17 1000 +Ethernet17 18 Ethernet17 18 1000 +Ethernet18 19 Ethernet18 19 1000 +Ethernet19 20 Ethernet19 20 1000 +Ethernet20 21 Ethernet20 21 1000 +Ethernet21 22 Ethernet21 22 1000 +Ethernet22 23 Ethernet22 23 1000 +Ethernet23 24 Ethernet23 24 1000 +Ethernet24 25 Ethernet24 25 1000 +Ethernet25 26 Ethernet25 26 1000 +Ethernet26 27 Ethernet26 27 1000 +Ethernet27 28 Ethernet27 28 1000 +Ethernet28 29 Ethernet28 29 1000 +Ethernet29 30 Ethernet29 30 1000 +Ethernet30 31 Ethernet30 31 1000 +Ethernet31 32 Ethernet31 32 1000 +Ethernet32 33 Ethernet32 33 1000 +Ethernet33 34 Ethernet33 34 1000 +Ethernet34 35 Ethernet34 35 1000 +Ethernet35 36 Ethernet35 36 1000 +Ethernet36 37 Ethernet36 37 1000 +Ethernet37 38 Ethernet37 38 1000 +Ethernet38 39 Ethernet38 39 1000 +Ethernet39 40 Ethernet39 40 1000 +Ethernet40 41 Ethernet40 41 1000 +Ethernet41 42 Ethernet41 42 1000 +Ethernet42 43 Ethernet42 43 1000 +Ethernet43 44 Ethernet43 44 1000 +Ethernet44 45 Ethernet44 45 1000 +Ethernet45 46 Ethernet45 46 1000 +Ethernet46 47 Ethernet46 47 1000 +Ethernet47 48 Ethernet47 48 1000 +Ethernet48 49 Ethernet48 49 10000 +Ethernet49 50 Ethernet49 50 10000 +Ethernet50 51 Ethernet50 51 10000 +Ethernet51 52 Ethernet51 52 10000 From 4458efbd7161985c8c14b76fcaf66688d06b2c8d Mon Sep 17 00:00:00 2001 From: srideepDell Date: Tue, 17 Dec 2019 16:26:23 -0700 Subject: [PATCH 258/278] DellEMC: Add support for new platform z9332f -32x400G (#3845) * Switch Vendor: DellEMC * Switch SKU: z9332F * ASIC Vendor: Broadcom * Swich ASIC: tomahawk3 * Port Configuration: 32x400G * SONiC Image: sonic-broadcom.bin * Changes Include ipmitool implementation for platform_sensors script is inclued in pmon startup --- .../DellEMC-Z9332f-O32/buffers.json.j2 | 2 + .../DellEMC-Z9332f-O32/buffers_defaults_t0.j2 | 20 + .../DellEMC-Z9332f-O32/buffers_defaults_t1.j2 | 20 + .../DellEMC-Z9332f-O32/custom_led.bin | Bin 0 -> 920 bytes .../DellEMC-Z9332f-O32/linkscan_led_fw.bin | Bin 0 -> 4752 bytes .../DellEMC-Z9332f-O32/pg_profile_lookup.ini | 23 + .../DellEMC-Z9332f-O32/port_config.ini | 35 + .../DellEMC-Z9332f-O32/qos.json.j2 | 226 ++ .../DellEMC-Z9332f-O32/sai.profile | 1 + .../DellEMC-Z9332f-O32/sai_postinit_cmd.soc | 2530 +++++++++++++++++ .../DellEMC-Z9332f-O32/sai_preinit_cmd.soc | 3 + .../th3-z9332f-32x400G.config.bcm | 519 ++++ .../default_sku | 1 + .../installer.conf | 2 + .../led_proc_init.soc | 7 + .../plugins/eeprom.py | 22 + .../plugins/psuutil.py | 126 + .../plugins/sfputil.py | 307 ++ platform/broadcom/one-image.mk | 1 + platform/broadcom/platform-modules-dell.mk | 8 +- .../debian/control | 5 + .../debian/platform-modules-z9332f.init | 39 + .../debian/platform-modules-z9332f.install | 7 + .../debian/platform-modules-z9332f.postinst | 10 + .../sonic-platform-modules-dell/debian/rules | 2 +- .../z9332f/cfg/z9332f-modules.conf | 17 + .../z9332f/modules/Makefile | 4 + .../z9332f/modules/cls-i2c-ocore.c | 845 ++++++ .../z9332f/modules/cls-i2c-ocore.h | 22 + .../z9332f/modules/cls-switchboard.c | 447 +++ .../z9332f/modules/mc24lc64t.c | 142 + .../z9332f/modules/z9332f-modules.conf | 17 + .../z9332f/scripts/pcisysfs.py | 102 + .../z9332f/scripts/platform_sensors.py | 198 ++ .../z9332f/scripts/sensors | 8 + .../z9332f/scripts/z9332f_platform.sh | 180 ++ .../systemd/platform-modules-z9332f.service | 13 + src/sonic-device-data/tests/permitted_list | 1 + 38 files changed, 5910 insertions(+), 2 deletions(-) create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/buffers.json.j2 create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/buffers_defaults_t0.j2 create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/buffers_defaults_t1.j2 create mode 100755 device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/custom_led.bin create mode 100755 device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/linkscan_led_fw.bin create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/pg_profile_lookup.ini create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/port_config.ini create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/qos.json.j2 create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/sai.profile create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/sai_postinit_cmd.soc create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/sai_preinit_cmd.soc create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/th3-z9332f-32x400G.config.bcm create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/default_sku create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/installer.conf create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/led_proc_init.soc create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/eeprom.py create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/psuutil.py create mode 100644 device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/sfputil.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9332f.init create mode 100644 platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9332f.install create mode 100644 platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9332f.postinst create mode 100644 platform/broadcom/sonic-platform-modules-dell/z9332f/cfg/z9332f-modules.conf create mode 100644 platform/broadcom/sonic-platform-modules-dell/z9332f/modules/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-dell/z9332f/modules/cls-i2c-ocore.c create mode 100644 platform/broadcom/sonic-platform-modules-dell/z9332f/modules/cls-i2c-ocore.h create mode 100644 platform/broadcom/sonic-platform-modules-dell/z9332f/modules/cls-switchboard.c create mode 100644 platform/broadcom/sonic-platform-modules-dell/z9332f/modules/mc24lc64t.c create mode 100644 platform/broadcom/sonic-platform-modules-dell/z9332f/modules/z9332f-modules.conf create mode 100755 platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/pcisysfs.py create mode 100755 platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/platform_sensors.py create mode 100755 platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/sensors create mode 100755 platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/z9332f_platform.sh create mode 100644 platform/broadcom/sonic-platform-modules-dell/z9332f/systemd/platform-modules-z9332f.service diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/buffers.json.j2 b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/buffers.json.j2 new file mode 100644 index 000000000000..0b1cb2c541b6 --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/buffers.json.j2 @@ -0,0 +1,2 @@ +{%- set default_topo = 't1' %} +{%- include 'buffers_config.j2' %} diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/buffers_defaults_t0.j2 b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/buffers_defaults_t0.j2 new file mode 100644 index 000000000000..77747f6403c8 --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/buffers_defaults_t0.j2 @@ -0,0 +1,20 @@ + +{%- set default_cable = '40m' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + }, + "BUFFER_PROFILE": { + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_active) %} + "BUFFER_PG": { + }, +{%- endmacro %} + +{% macro generate_queue_buffers(port_names_active) %} + "BUFFER_QUEUE": { + } +{% endmacro %} + diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/buffers_defaults_t1.j2 b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/buffers_defaults_t1.j2 new file mode 100644 index 000000000000..77747f6403c8 --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/buffers_defaults_t1.j2 @@ -0,0 +1,20 @@ + +{%- set default_cable = '40m' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + }, + "BUFFER_PROFILE": { + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_active) %} + "BUFFER_PG": { + }, +{%- endmacro %} + +{% macro generate_queue_buffers(port_names_active) %} + "BUFFER_QUEUE": { + } +{% endmacro %} + diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/custom_led.bin b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/custom_led.bin new file mode 100755 index 0000000000000000000000000000000000000000..3ee9545e28ae08c5b597570c490af69a5d1f2bb4 GIT binary patch literal 920 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 X`cUsHXR!vGk^Z4y?GFw9z}SBSTZoUr literal 0 HcmV?d00001 diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/pg_profile_lookup.ini b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/pg_profile_lookup.ini new file mode 100644 index 000000000000..a5f3286beef8 --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/pg_profile_lookup.ini @@ -0,0 +1,23 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold xon_offset + 10000 5m 1270 0 190500 -2 2540 + 25000 5m 1270 0 190500 -2 2540 + 40000 5m 1270 0 190500 -2 2540 + 50000 5m 1270 0 190500 -2 2540 + 100000 5m 1270 0 190500 -2 2540 + 200000 5m 1270 0 190500 -2 2540 + 400000 5m 1270 0 190500 -2 2540 + 10000 40m 1270 0 190500 -2 2540 + 25000 40m 1270 0 190500 -2 2540 + 40000 40m 1270 0 190500 -2 2540 + 50000 40m 1270 0 190500 -2 2540 + 100000 40m 1270 0 190500 -2 2540 + 200000 40m 1270 0 190500 -2 2540 + 400000 40m 1270 0 190500 -2 2540 + 10000 300m 1270 0 190500 -2 2540 + 25000 300m 1270 0 190500 -2 2540 + 40000 300m 1270 0 190500 -2 2540 + 50000 300m 1270 0 190500 -2 2540 + 100000 300m 1270 0 190500 -2 2540 + 200000 300m 1270 0 190500 -2 2540 + 400000 300m 1270 0 190500 -2 2540 diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/port_config.ini b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/port_config.ini new file mode 100644 index 000000000000..790fb490cfe6 --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/port_config.ini @@ -0,0 +1,35 @@ +# name lanes alias index speed +Ethernet0 33,34,35,36,37,38,39,40 fourhundredGigE1/1 1 400000 +Ethernet8 41,42,43,44,45,46,47,48 fourhundredGigE1/2 2 400000 +Ethernet16 49,50,51,52,53,54,55,56 fourhundredGigE1/3 3 400000 +Ethernet24 57,58,59,60,61,62,63,64 fourhundredGigE1/4 4 400000 +Ethernet32 65,66,67,68,69,70,71,72 fourhundredGigE1/5 5 400000 +Ethernet40 73,74,75,76,77,78,79,80 fourhundredGigE1/6 6 400000 +Ethernet48 81,82,83,84,85,86,87,88 fourhundredGigE1/7 7 400000 +Ethernet56 89,90,91,92,93,94,95,96 fourhundredGigE1/8 8 400000 +Ethernet64 1,2,3,4,5,6,7,8 fourhundredGigE1/9 9 400000 +Ethernet72 9,10,11,12,13,14,15,16 fourhundredGigE1/10 10 400000 +Ethernet80 17,18,19,20,21,22,23,24 fourhundredGigE1/11 11 400000 +Ethernet88 25,26,27,28,29,30,31,32 fourhundredGigE1/12 12 400000 +Ethernet96 97,98,99,100,101,102,103,104 fourhundredGigE1/13 13 400000 +Ethernet104 105,106,107,108,109,110,111,112 fourhundredGigE1/14 14 400000 +Ethernet112 113,114,115,116,117,118,119,120 fourhundredGigE1/15 15 400000 +Ethernet120 121,122,123,124,125,126,127,128 fourhundredGigE1/16 16 400000 +Ethernet128 129,130,131,132,133,134,135,136 fourhundredGigE1/17 17 400000 +Ethernet136 137,138,139,140,141,142,143,144 fourhundredGigE1/18 18 400000 +Ethernet144 145,146,147,148,149,150,151,152 fourhundredGigE1/19 19 400000 +Ethernet152 153,154,155,156,157,158,159,160 fourhundredGigE1/20 20 400000 +Ethernet160 225,226,227,228,229,230,231,232 fourhundredGigE1/21 21 400000 +Ethernet168 233,234,235,236,237,238,239,240 fourhundredGigE1/22 22 400000 +Ethernet176 241,242,243,244,245,246,247,248 fourhundredGigE1/23 23 400000 +Ethernet184 249,250,251,252,253,254,255,256 fourhundredGigE1/24 24 400000 +Ethernet192 161,162,163,164,165,166,167,168 fourhundredGigE1/25 25 400000 +Ethernet200 169,170,171,172,173,174,175,176 fourhundredGigE1/26 26 400000 +Ethernet208 177,178,179,180,181,182,183,184 fourhundredGigE1/27 27 400000 +Ethernet216 185,186,187,188,189,190,191,192 fourhundredGigE1/28 28 400000 +Ethernet224 193,194,195,196,197,198,199,200 fourhundredGigE1/29 29 400000 +Ethernet232 201,202,203,204,205,206,207,208 fourhundredGigE1/30 30 400000 +Ethernet240 209,210,211,212,213,214,215,216 fourhundredGigE1/31 31 400000 +Ethernet248 217,218,219,220,221,222,223,224 fourhundredGigE1/32 32 400000 +Ethernet256 257 tenGigE1/33 33 10000 +Ethernet257 258 tenGigE1/34 34 10000 diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/qos.json.j2 b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/qos.json.j2 new file mode 100644 index 000000000000..a48e1b56621c --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/qos.json.j2 @@ -0,0 +1,226 @@ +{%- set PORT_ALL = [] %} +{%- for port in PORT %} + {%- if PORT_ALL.append(port) %}{% endif %} +{%- endfor %} +{%- if PORT_ALL | sort_by_port_index %}{% endif %} + +{%- set port_names_list_all = [] %} +{%- for port in PORT_ALL %} + {%- if port_names_list_all.append(port) %}{% endif %} +{%- endfor %} +{%- set port_names_all = port_names_list_all | join(',') -%} + + +{%- set PORT_ACTIVE = [] %} +{%- if DEVICE_NEIGHBOR is not defined %} + {%- set PORT_ACTIVE = PORT_ALL %} +{%- else %} + {%- for port in DEVICE_NEIGHBOR.keys() %} + {%- if PORT_ACTIVE.append(port) %}{%- endif %} + {%- endfor %} +{%- endif %} +{%- if PORT_ACTIVE | sort_by_port_index %}{% endif %} + +{%- set port_names_list_active = [] %} +{%- for port in PORT_ACTIVE %} + {%- if port_names_list_active.append(port) %}{%- endif %} +{%- endfor %} +{%- set port_names_active = port_names_list_active | join(',') -%} + + +{%- set pfc_to_pg_map_supported_asics = ['mellanox', 'barefoot', 'marvell'] -%} + + +{ +{% if generate_tc_to_pg_map is defined %} + {{- generate_tc_to_pg_map() }} +{% else %} + "TC_TO_PRIORITY_GROUP_MAP": { + "DEFAULT": { + "0": "0", + "1": "0", + "2": "0", + "3": "3", + "4": "4", + "5": "0", + "6": "0", + "7": "7" + } + }, +{% endif %} + "MAP_PFC_PRIORITY_TO_QUEUE": { + "DEFAULT": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "TC_TO_QUEUE_MAP": { + "DEFAULT": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "DSCP_TO_TC_MAP": { + "DEFAULT": { + "0" : "0", + "1" : "0", + "2" : "0", + "3" : "0", + "4" : "0", + "5" : "0", + "6" : "0", + "7" : "0", + "8" : "0", + "9" : "0", + "10": "0", + "11": "0", + "12": "0", + "13": "0", + "14": "0", + "15": "0", + "16": "0", + "17": "0", + "18": "0", + "19": "0", + "20": "0", + "21": "0", + "22": "0", + "23": "0", + "24": "0", + "25": "0", + "26": "0", + "27": "0", + "28": "0", + "29": "0", + "30": "0", + "31": "0", + "32": "0", + "33": "0", + "34": "0", + "35": "0", + "36": "0", + "37": "0", + "38": "0", + "39": "0", + "40": "0", + "41": "0", + "42": "0", + "43": "0", + "44": "0", + "45": "0", + "46": "0", + "47": "0", + "48": "0", + "49": "0", + "50": "0", + "51": "0", + "52": "0", + "53": "0", + "54": "0", + "55": "0", + "56": "0", + "57": "0", + "58": "0", + "59": "0", + "60": "0", + "61": "0", + "62": "0", + "63": "0" + } + }, + "SCHEDULER": { + "scheduler.0": { + "type" : "DWRR", + "weight": "1" + }, + "scheduler.1": { + "type" : "DWRR", + "weight": "2" + }, + "scheduler.2": { + "type" : "DWRR", + "weight": "3" + }, + "scheduler.3": { + "type" : "DWRR", + "weight": "4" + }, + "scheduler.4": { + "type" : "DWRR", + "weight": "5" + }, + "scheduler.5": { + "type" : "DWRR", + "weight": "10" + }, + "scheduler.6": { + "type" : "DWRR", + "weight": "25" + }, + "scheduler.7": { + "type" : "STRICT" + } + }, + "PORT_QOS_MAP": { + "{{ port_names_active }}": { + "dscp_to_tc_map" : "[DSCP_TO_TC_MAP|DEFAULT]", + "tc_to_queue_map" : "[TC_TO_QUEUE_MAP|DEFAULT]", + "pfc_enable" : "3,4", + "tc_to_pg_map" : "[TC_TO_PRIORITY_GROUP_MAP|DEFAULT]" + } + }, + "QUEUE": { +{% for port in PORT_ACTIVE %} + "{{ port }}|0": { + "scheduler" : "[SCHEDULER|scheduler.0]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|1": { + "scheduler" : "[SCHEDULER|scheduler.1]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|2": { + "scheduler": "[SCHEDULER|scheduler.2]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|3": { + "scheduler": "[SCHEDULER|scheduler.3]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|4": { + "scheduler": "[SCHEDULER|scheduler.4]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|5": { + "scheduler": "[SCHEDULER|scheduler.5]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|6": { + "scheduler": "[SCHEDULER|scheduler.6]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|7": { + "scheduler": "[SCHEDULER|scheduler.7]" + }{% if not loop.last %},{% endif %} +{% endfor %} + } +} diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/sai.profile b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/sai.profile new file mode 100644 index 000000000000..19cd5cb02839 --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/th3-z9332f-32x400G.config.bcm diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/sai_postinit_cmd.soc b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/sai_postinit_cmd.soc new file mode 100644 index 000000000000..9550e9c822c8 --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/sai_postinit_cmd.soc @@ -0,0 +1,2530 @@ +delay 200 +link off +counter off + +#*** +#*** Port CD0 Preemphasis setting *** +#*** + +local port cd0 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD1 Preemphasis setting *** +#*** + +local port cd1 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD2 Preemphasis setting *** +#*** + +local port cd2 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD3 Preemphasis setting *** +#*** + +local port cd3 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD4 Preemphasis setting *** +#*** + +local port cd4 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD5 Preemphasis setting *** +#*** + +local port cd5 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD6 Preemphasis setting *** +#*** + +local port cd6 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD7 Preemphasis setting *** +#*** + +local port cd7 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD8 Preemphasis setting *** +#*** + +local port cd8 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD9 Preemphasis setting *** +#*** + +local port cd9 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD10 Preemphasis setting *** +#*** + +local port cd10 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x78 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1EC +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD11 Preemphasis setting *** +#*** + +local port cd11 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD12 Preemphasis setting *** +#*** + +local port cd12 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD13 Preemphasis setting *** +#*** + +local port cd13 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD14 Preemphasis setting *** +#*** + +local port cd14 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD15 Preemphasis setting *** +#*** + +local port cd15 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD16 Preemphasis setting *** +#*** + +local port cd16 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD17 Preemphasis setting *** +#*** + +local port cd17 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD18 Preemphasis setting *** +#*** + +local port cd18 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD19 Preemphasis setting *** +#*** + +local port cd19 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD20 Preemphasis setting *** +#*** + +local port cd20 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD21 Preemphasis setting *** +#*** + +local port cd21 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD22 Preemphasis setting *** +#*** + +local port cd22 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD23 Preemphasis setting *** +#*** + +local port cd23 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD24 Preemphasis setting *** +#*** + +local port cd24 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD25 Preemphasis setting *** +#*** + +local port cd25 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD26 Preemphasis setting *** +#*** + +local port cd26 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD27 Preemphasis setting *** +#*** + +local port cd27 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD28 Preemphasis setting *** +#*** + +local port cd28 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x88 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F8 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD29 Preemphasis setting *** +#*** + +local port cd29 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD30 Preemphasis setting *** +#*** + +local port cd30 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x84 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1F4 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +delay 10 + +#*** +#*** Port CD31 Preemphasis setting *** +#*** + +local port cd31 +#*** lane 0 *** +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.0 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.0 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.0 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.0 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.0 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.0 TXFIR_TAP_LOAD=0x1 + +#*** lane 1 *** +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.1 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.1 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.1 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.1 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.1 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.1 TXFIR_TAP_LOAD=0x1 + +#*** lane 2 *** +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.2 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.2 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.2 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.2 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.2 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.2 TXFIR_TAP_LOAD=0x1 + +#*** lane 3 *** +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.3 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.3 TXFIR_TAP2_COEFF=0x90 +phy $port TXFIR_TAP_CTL3r.3 TXFIR_TAP3_COEFF=0 +phy $port TXFIR_TAP_CTL4r.3 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.3 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.3 TXFIR_TAP_LOAD=0x1 + +#*** lane 4 *** +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.4 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.4 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.4 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.4 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.4 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.4 TXFIR_TAP_LOAD=0x1 + +#*** lane 5 *** +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP0_COEFF=4 +phy $port TXFIR_TAP_CTL1r.5 TXFIR_TAP1_COEFF=0x1E4 +phy $port TXFIR_TAP_CTL2r.5 TXFIR_TAP2_COEFF=0x70 +phy $port TXFIR_TAP_CTL3r.5 TXFIR_TAP3_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL4r.5 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.5 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.5 TXFIR_TAP_LOAD=0x1 + +#*** lane 6 *** +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.6 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.6 TXFIR_TAP2_COEFF=0x80 +phy $port TXFIR_TAP_CTL3r.6 TXFIR_TAP3_COEFF=0x1F0 +phy $port TXFIR_TAP_CTL4r.6 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.6 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.6 TXFIR_TAP_LOAD=0x1 + +#*** lane 7 *** +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP0_COEFF=0 +phy $port TXFIR_TAP_CTL1r.7 TXFIR_TAP1_COEFF=0x1E8 +phy $port TXFIR_TAP_CTL2r.7 TXFIR_TAP2_COEFF=0x8C +phy $port TXFIR_TAP_CTL3r.7 TXFIR_TAP3_COEFF=0x1FC +phy $port TXFIR_TAP_CTL4r.7 TXFIR_TAP4_COEFF=0 +phy $port TXFIR_TAP_CTL5r.7 TXFIR_TAP5_COEFF=0 +phy $port TXFIR_TAP_CTL0r.7 TXFIR_TAP_LOAD=0x1 + +link on +counter on diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/sai_preinit_cmd.soc b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/sai_preinit_cmd.soc new file mode 100644 index 000000000000..e48c05b9f664 --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/sai_preinit_cmd.soc @@ -0,0 +1,3 @@ +#Not supported Until SAI 3.6 +#m0 load 0 0x0 /usr/share/sonic/hwsku/linkscan_led_fw.bin +#m0 load 0 0x3800 /usr/share/sonic/hwsku/custom_led.bin diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/th3-z9332f-32x400G.config.bcm b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/th3-z9332f-32x400G.config.bcm new file mode 100644 index 000000000000..3d204640d5aa --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/DellEMC-Z9332f-O32/th3-z9332f-32x400G.config.bcm @@ -0,0 +1,519 @@ +core_clock_frequency=1325 +dpr_clock_frequency=1000 +device_clock_frequency=1325 +port_flex_enable=1 + +#firmware load method, use fast load +load_firmware=0x2 + +ccm_dma_enable=0 +ccmdma_intr_enable=0 +mem_cache_enable=0 +phy_enable=0 +phy_null=1 + +dport_map_enable=1 + +module_64ports.0=0 +tdma_intr_enable.0=1 +ipv6_lpm_128b_enable.0=1 +stat_if_parity_enable.0=1 +oversubscribe_mode=0 +bcm_tunnel_term_compatible_mode.0=1 +table_dma_enable.0=1 +schan_intr_enable.0=0 +parity_enable.0=1 +tdma_timeout_usec=1000000 +lls_num_l2uc.0=10 +miim_intr_enable.0=0 +table_dma_enable=1 +max_vp_lags.0=0 +tdma_intr_enable=1 +tdma_timeout_usec.0=5000000 +parity_correction.0=1 +mmu_lossless.0=0 +bcm_num_cos=8 +default_cpu_tx_queue=7 +pktdma_poll_mode_channel_bitmap=1 +l3_max_ecmp_mode.0=1 +l3_alpm_enable=2 +l3_alpm_ipv6_128b_bkt_rsvd=1 +l2_mem_entries=40960 +l3_mem_entries=40960 + +l2xlrn_thread_interval=50000 +l2xlrn_intr_en=0 + +pbmp_xport_xe=0xffffffFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE + +phy_an_c73=3 + +portmap_1.0=1:400 +portmap_5.0=9:400 +portmap_10.0=17:400 +portmap_14.0=25:400 + +portmap_20.0=33:400 +portmap_24.0=41:400 +portmap_29.0=49:400 +portmap_33.0=57:400 + +portmap_40.0=65:400 +portmap_44.0=73:400 +portmap_49.0=81:400 +portmap_53.0=89:400 + +portmap_60.0=97:400 +portmap_64.0=105:400 +portmap_69.0=113:400 +portmap_73.0=121:400 + +portmap_80.0=129:400 +portmap_84.0=137:400 +portmap_89.0=145:400 +portmap_93.0=153:400 + +portmap_100.0=161:400 +portmap_104.0=169:400 +portmap_109.0=177:400 +portmap_113.0=185:400 + +portmap_120.0=193:400 +portmap_124.0=201:400 +portmap_129.0=209:400 +portmap_133.0=217:400 + +portmap_140.0=225:400 +portmap_144.0=233:400 +portmap_149.0=241:400 +portmap_153.0=249:400 + +portmap_38.0=257:10:1 +portmap_118.0=258:10:1 + +dport_map_port_20=1 +dport_map_port_21=2 +dport_map_port_22=3 +dport_map_port_23=4 +dport_map_port_24=5 +dport_map_port_25=6 +dport_map_port_26=7 +dport_map_port_27=8 +dport_map_port_28=9 +dport_map_port_29=10 +dport_map_port_30=11 +dport_map_port_31=12 +dport_map_port_32=13 +dport_map_port_33=14 +dport_map_port_34=15 +dport_map_port_35=16 +dport_map_port_36=17 +dport_map_port_37=18 +dport_map_port_40=19 +dport_map_port_41=20 +dport_map_port_42=21 +dport_map_port_43=22 +dport_map_port_44=23 +dport_map_port_45=24 +dport_map_port_46=25 +dport_map_port_47=26 +dport_map_port_48=27 +dport_map_port_49=28 +dport_map_port_50=29 +dport_map_port_51=30 +dport_map_port_52=31 +dport_map_port_53=32 +dport_map_port_54=33 +dport_map_port_55=34 +dport_map_port_56=35 +dport_map_port_57=36 +dport_map_port_1=37 +dport_map_port_2=38 +dport_map_port_3=39 +dport_map_port_4=40 +dport_map_port_5=41 +dport_map_port_6=42 +dport_map_port_7=43 +dport_map_port_8=44 +dport_map_port_9=45 +dport_map_port_10=46 +dport_map_port_11=47 +dport_map_port_12=48 +dport_map_port_13=49 +dport_map_port_14=50 +dport_map_port_15=51 +dport_map_port_16=52 +dport_map_port_17=53 +dport_map_port_18=54 +dport_map_port_60=55 +dport_map_port_61=56 +dport_map_port_62=57 +dport_map_port_63=58 +dport_map_port_64=59 +dport_map_port_65=60 +dport_map_port_66=61 +dport_map_port_67=62 +dport_map_port_68=63 +dport_map_port_69=64 +dport_map_port_70=65 +dport_map_port_71=66 +dport_map_port_72=67 +dport_map_port_73=68 +dport_map_port_74=69 +dport_map_port_75=70 +dport_map_port_76=71 +dport_map_port_77=72 +dport_map_port_80=73 +dport_map_port_81=74 +dport_map_port_82=75 +dport_map_port_83=76 +dport_map_port_84=77 +dport_map_port_85=78 +dport_map_port_86=79 +dport_map_port_87=80 +dport_map_port_88=81 +dport_map_port_89=82 +dport_map_port_90=83 +dport_map_port_91=84 +dport_map_port_92=85 +dport_map_port_93=86 +dport_map_port_94=87 +dport_map_port_95=88 +dport_map_port_96=89 +dport_map_port_97=90 +dport_map_port_140=91 +dport_map_port_141=92 +dport_map_port_142=93 +dport_map_port_143=94 +dport_map_port_144=95 +dport_map_port_145=96 +dport_map_port_146=97 +dport_map_port_147=98 +dport_map_port_148=99 +dport_map_port_149=100 +dport_map_port_150=101 +dport_map_port_151=102 +dport_map_port_152=103 +dport_map_port_153=104 +dport_map_port_154=105 +dport_map_port_155=106 +dport_map_port_156=107 +dport_map_port_157=108 +dport_map_port_100=109 +dport_map_port_101=110 +dport_map_port_102=111 +dport_map_port_103=112 +dport_map_port_104=113 +dport_map_port_105=114 +dport_map_port_106=115 +dport_map_port_107=116 +dport_map_port_108=117 +dport_map_port_109=118 +dport_map_port_110=119 +dport_map_port_111=120 +dport_map_port_112=121 +dport_map_port_113=122 +dport_map_port_114=123 +dport_map_port_115=124 +dport_map_port_116=125 +dport_map_port_117=126 +dport_map_port_120=127 +dport_map_port_121=128 +dport_map_port_122=129 +dport_map_port_123=130 +dport_map_port_124=131 +dport_map_port_125=132 +dport_map_port_126=133 +dport_map_port_127=134 +dport_map_port_128=135 +dport_map_port_129=136 +dport_map_port_130=137 +dport_map_port_131=138 +dport_map_port_132=139 +dport_map_port_133=140 +dport_map_port_134=141 +dport_map_port_135=142 +dport_map_port_136=143 +dport_map_port_137=144 +dport_map_port_38=145 +dport_map_port_118=146 + +phy_chain_rx_lane_map_physical{33.0}=0x65732041 +phy_chain_tx_lane_map_physical{33.0}=0x47206531 +phy_chain_rx_lane_map_physical{41.0}=0x07561243 +phy_chain_tx_lane_map_physical{41.0}=0x36207514 +phy_chain_rx_lane_map_physical{49.0}=0x54632071 +phy_chain_tx_lane_map_physical{49.0}=0x06241735 +phy_chain_rx_lane_map_physical{57.0}=0x07561243 +phy_chain_tx_lane_map_physical{57.0}=0x35207614 +phy_chain_rx_lane_map_physical{65.0}=0x45623170 +phy_chain_tx_lane_map_physical{65.0}=0x51260734 +phy_chain_rx_lane_map_physical{73.0}=0x07561243 +phy_chain_tx_lane_map_physical{73.0}=0x37245610 +phy_chain_rx_lane_map_physical{81.0}=0x45632071 +phy_chain_tx_lane_map_physical{81.0}=0x51260734 +phy_chain_rx_lane_map_physical{89.0}=0x07561243 +phy_chain_tx_lane_map_physical{89.0}=0x26437510 +phy_chain_rx_lane_map_physical{1.0}=0x30176524 +phy_chain_tx_lane_map_physical{1.0}=0x20615374 +phy_chain_rx_lane_map_physical{9.0}=0x37562041 +phy_chain_tx_lane_map_physical{9.0}=0x05176432 +phy_chain_rx_lane_map_physical{17.0}=0x43607251 +phy_chain_tx_lane_map_physical{17.0}=0x70261435 +phy_chain_rx_lane_map_physical{25.0}=0x60347125 +phy_chain_tx_lane_map_physical{25.0}=0x46357120 +phy_chain_rx_lane_map_physical{97.0}=0x47601352 +phy_chain_tx_lane_map_physical{97.0}=0x04265137 +phy_chain_rx_lane_map_physical{105.0}=0x73206415 +phy_chain_tx_lane_map_physical{105.0}=0x26374150 +phy_chain_rx_lane_map_physical{113.0}=0x47632051 +phy_chain_tx_lane_map_physical{113.0}=0x03254617 +phy_chain_rx_lane_map_physical{121.0}=0x63027415 +phy_chain_tx_lane_map_physical{121.0}=0x63721045 +phy_chain_rx_lane_map_physical{129.0}=0x30154627 +phy_chain_tx_lane_map_physical{129.0}=0x04735261 +phy_chain_rx_lane_map_physical{137.0}=0x24753061 +phy_chain_tx_lane_map_physical{137.0}=0x37614520 +phy_chain_rx_lane_map_physical{145.0}=0x47601352 +phy_chain_tx_lane_map_physical{145.0}=0x63274510 +phy_chain_rx_lane_map_physical{153.0}=0x07361524 +phy_chain_tx_lane_map_physical{153.0}=0x36527104 +phy_chain_rx_lane_map_physical{225.0}=0x56410273 +phy_chain_tx_lane_map_physical{225.0}=0x10274635 +phy_chain_rx_lane_map_physical{233.0}=0x15740263 +phy_chain_tx_lane_map_physical{233.0}=0x24351607 +phy_chain_rx_lane_map_physical{241.0}=0x74015263 +phy_chain_tx_lane_map_physical{241.0}=0x04152637 +phy_chain_rx_lane_map_physical{249.0}=0x62037514 +phy_chain_tx_lane_map_physical{249.0}=0x72453160 +phy_chain_rx_lane_map_physical{161.0}=0x46510273 +phy_chain_tx_lane_map_physical{161.0}=0x01653724 +phy_chain_rx_lane_map_physical{169.0}=0x25743160 +phy_chain_tx_lane_map_physical{169.0}=0x07216435 +phy_chain_rx_lane_map_physical{177.0}=0x46510273 +phy_chain_tx_lane_map_physical{177.0}=0x01652734 +phy_chain_rx_lane_map_physical{185.0}=0x25743160 +phy_chain_tx_lane_map_physical{185.0}=0x37016425 +phy_chain_rx_lane_map_physical{193.0}=0x46510372 +phy_chain_tx_lane_map_physical{193.0}=0x06153724 +phy_chain_rx_lane_map_physical{201.0}=0x25743160 +phy_chain_tx_lane_map_physical{201.0}=0x36017524 +phy_chain_rx_lane_map_physical{209.0}=0x47601352 +phy_chain_tx_lane_map_physical{209.0}=0x04152736 +phy_chain_rx_lane_map_physical{217.0}=0x26453170 +phy_chain_tx_lane_map_physical{217.0}=0x36027415 + +serdes_core_rx_polarity_flip_physical{33}=0x29 +serdes_core_tx_polarity_flip_physical{33}=0xfe +serdes_core_rx_polarity_flip_physical{41}=0xb1 +serdes_core_tx_polarity_flip_physical{41}=0xe8 +serdes_core_rx_polarity_flip_physical{49}=0xca +serdes_core_tx_polarity_flip_physical{49}=0xb6 +serdes_core_rx_polarity_flip_physical{57}=0x9b +serdes_core_tx_polarity_flip_physical{57}=0xdc +serdes_core_rx_polarity_flip_physical{65}=0x17 +serdes_core_tx_polarity_flip_physical{65}=0x86 +serdes_core_rx_polarity_flip_physical{73}=0x9b +serdes_core_tx_polarity_flip_physical{73}=0x55 +serdes_core_rx_polarity_flip_physical{81}=0xa +serdes_core_tx_polarity_flip_physical{81}=0x6 +serdes_core_rx_polarity_flip_physical{89}=0x9b +serdes_core_tx_polarity_flip_physical{89}=0x48 +serdes_core_rx_polarity_flip_physical{1}=0xec +serdes_core_tx_polarity_flip_physical{1}=0x56 +serdes_core_rx_polarity_flip_physical{9}=0x13 +serdes_core_tx_polarity_flip_physical{9}=0xa6 +serdes_core_rx_polarity_flip_physical{17}=0x5a +serdes_core_tx_polarity_flip_physical{17}=0xc6 +serdes_core_rx_polarity_flip_physical{25}=0xf +serdes_core_tx_polarity_flip_physical{25}=0x4e +serdes_core_rx_polarity_flip_physical{97}=0x17 +serdes_core_tx_polarity_flip_physical{97}=0x2e +serdes_core_rx_polarity_flip_physical{105}=0xce +serdes_core_tx_polarity_flip_physical{105}=0x7c +serdes_core_rx_polarity_flip_physical{113}=0xa +serdes_core_tx_polarity_flip_physical{113}=0x35 + +serdes_core_rx_polarity_flip_physical{121}=0xb9 +serdes_core_tx_polarity_flip_physical{121}=0xef +serdes_core_rx_polarity_flip_physical{129}=0xe8 +serdes_core_tx_polarity_flip_physical{129}=0xac +serdes_core_rx_polarity_flip_physical{137}=0xcb +serdes_core_tx_polarity_flip_physical{137}=0x9c +serdes_core_rx_polarity_flip_physical{145}=0x17 +serdes_core_tx_polarity_flip_physical{145}=0x32 +serdes_core_rx_polarity_flip_physical{153}=0xb9 +serdes_core_tx_polarity_flip_physical{153}=0xaf +serdes_core_rx_polarity_flip_physical{225}=0xaa +serdes_core_tx_polarity_flip_physical{225}=0x7 +serdes_core_rx_polarity_flip_physical{233}=0x31 +serdes_core_tx_polarity_flip_physical{233}=0x47 +serdes_core_rx_polarity_flip_physical{241}=0xe8 +serdes_core_tx_polarity_flip_physical{241}=0x9e +serdes_core_rx_polarity_flip_physical{249}=0xec +serdes_core_tx_polarity_flip_physical{249}=0x1f +serdes_core_rx_polarity_flip_physical{161}=0x6a +serdes_core_tx_polarity_flip_physical{161}=0xd4 +serdes_core_rx_polarity_flip_physical{169}=0x9e +serdes_core_tx_polarity_flip_physical{169}=0x7b +serdes_core_rx_polarity_flip_physical{177}=0x6a +serdes_core_tx_polarity_flip_physical{177}=0xcc +serdes_core_rx_polarity_flip_physical{185}=0x9e +serdes_core_tx_polarity_flip_physical{185}=0x58 +serdes_core_rx_polarity_flip_physical{193}=0x6f +serdes_core_tx_polarity_flip_physical{193}=0x24 +serdes_core_rx_polarity_flip_physical{201}=0x9e +serdes_core_tx_polarity_flip_physical{201}=0xdf +serdes_core_rx_polarity_flip_physical{209}=0x17 +serdes_core_tx_polarity_flip_physical{209}=0xe9 +serdes_core_rx_polarity_flip_physical{217}=0xec +serdes_core_tx_polarity_flip_physical{217}=0x68 + +serdes_lane_config_media_type_49=copper +serdes_lane_config_media_type_50=copper +serdes_lane_config_media_type_51=copper +serdes_lane_config_media_type_52=copper +serdes_lane_config_media_type_54=copper +serdes_lane_config_media_type_55=copper +serdes_lane_config_media_type_56=copper +serdes_lane_config_media_type_57=copper +serdes_lane_config_media_type_53=copper +serdes_lane_config_media_type_60=copper +serdes_lane_config_media_type_61=copper +serdes_lane_config_media_type_62=copper +serdes_lane_config_media_type_63=copper +serdes_lane_config_media_type_65=copper +serdes_lane_config_media_type_66=copper +serdes_lane_config_media_type_67=copper +serdes_lane_config_media_type_68=copper +serdes_lane_config_media_type_64=copper +serdes_lane_config_media_type_80=copper +serdes_lane_config_media_type_81=copper +serdes_lane_config_media_type_82=copper +serdes_lane_config_media_type_83=copper +serdes_lane_config_media_type_85=copper +serdes_lane_config_media_type_86=copper +serdes_lane_config_media_type_87=copper +serdes_lane_config_media_type_88=copper +serdes_lane_config_media_type_84=copper +serdes_lane_config_media_type_100=copper +serdes_lane_config_media_type_101=copper +serdes_lane_config_media_type_102=copper +serdes_lane_config_media_type_103=copper +serdes_lane_config_media_type_105=copper +serdes_lane_config_media_type_106=copper +serdes_lane_config_media_type_107=copper +serdes_lane_config_media_type_108=copper +serdes_lane_config_media_type_104=copper +serdes_lane_config_media_type_120=copper +serdes_lane_config_media_type_121=copper +serdes_lane_config_media_type_122=copper +serdes_lane_config_media_type_123=copper +serdes_lane_config_media_type_125=copper +serdes_lane_config_media_type_126=copper +serdes_lane_config_media_type_127=copper +serdes_lane_config_media_type_128=copper +serdes_lane_config_media_type_124=copper +serdes_lane_config_media_type_140=copper +serdes_lane_config_media_type_141=copper +serdes_lane_config_media_type_142=copper +serdes_lane_config_media_type_143=copper +serdes_lane_config_media_type_145=copper +serdes_lane_config_media_type_146=copper +serdes_lane_config_media_type_147=copper +serdes_lane_config_media_type_148=copper +serdes_lane_config_media_type_144=copper +serdes_lane_config_media_type_40=copper +serdes_lane_config_media_type_41=copper +serdes_lane_config_media_type_42=copper +serdes_lane_config_media_type_43=copper +serdes_lane_config_media_type_45=copper +serdes_lane_config_media_type_46=copper +serdes_lane_config_media_type_47=copper +serdes_lane_config_media_type_48=copper +serdes_lane_config_media_type_44=copper +serdes_lane_config_media_type_69=copper +serdes_lane_config_media_type_70=copper +serdes_lane_config_media_type_71=copper +serdes_lane_config_media_type_72=copper +serdes_lane_config_media_type_74=copper +serdes_lane_config_media_type_75=copper +serdes_lane_config_media_type_76=copper +serdes_lane_config_media_type_77=copper +serdes_lane_config_media_type_73=copper +serdes_lane_config_media_type_1=copper +serdes_lane_config_media_type_2=copper +serdes_lane_config_media_type_3=copper +serdes_lane_config_media_type_4=copper +serdes_lane_config_media_type_6=copper +serdes_lane_config_media_type_7=copper +serdes_lane_config_media_type_8=copper +serdes_lane_config_media_type_9=copper +serdes_lane_config_media_type_5=copper +serdes_lane_config_media_type_29=copper +serdes_lane_config_media_type_30=copper +serdes_lane_config_media_type_31=copper +serdes_lane_config_media_type_32=copper +serdes_lane_config_media_type_34=copper +serdes_lane_config_media_type_35=copper +serdes_lane_config_media_type_36=copper +serdes_lane_config_media_type_37=copper +serdes_lane_config_media_type_33=copper +serdes_lane_config_media_type_89=copper +serdes_lane_config_media_type_90=copper +serdes_lane_config_media_type_91=copper +serdes_lane_config_media_type_92=copper +serdes_lane_config_media_type_94=copper +serdes_lane_config_media_type_95=copper +serdes_lane_config_media_type_96=copper +serdes_lane_config_media_type_97=copper +serdes_lane_config_media_type_93=copper +serdes_lane_config_media_type_109=copper +serdes_lane_config_media_type_110=copper +serdes_lane_config_media_type_111=copper +serdes_lane_config_media_type_112=copper +serdes_lane_config_media_type_114=copper +serdes_lane_config_media_type_115=copper +serdes_lane_config_media_type_116=copper +serdes_lane_config_media_type_117=copper +serdes_lane_config_media_type_113=copper +serdes_lane_config_media_type_129=copper +serdes_lane_config_media_type_130=copper +serdes_lane_config_media_type_131=copper +serdes_lane_config_media_type_132=copper +serdes_lane_config_media_type_134=copper +serdes_lane_config_media_type_135=copper +serdes_lane_config_media_type_136=copper +serdes_lane_config_media_type_137=copper +serdes_lane_config_media_type_133=copper +serdes_lane_config_media_type_149=copper +serdes_lane_config_media_type_150=copper +serdes_lane_config_media_type_151=copper +serdes_lane_config_media_type_152=copper +serdes_lane_config_media_type_154=copper +serdes_lane_config_media_type_155=copper +serdes_lane_config_media_type_156=copper +serdes_lane_config_media_type_157=copper +serdes_lane_config_media_type_153=copper +serdes_lane_config_media_type_10=copper +serdes_lane_config_media_type_11=copper +serdes_lane_config_media_type_12=copper +serdes_lane_config_media_type_13=copper +serdes_lane_config_media_type_15=copper +serdes_lane_config_media_type_16=copper +serdes_lane_config_media_type_17=copper +serdes_lane_config_media_type_18=copper +serdes_lane_config_media_type_14=copper +serdes_lane_config_media_type_20=copper +serdes_lane_config_media_type_21=copper +serdes_lane_config_media_type_22=copper +serdes_lane_config_media_type_23=copper +serdes_lane_config_media_type_25=copper +serdes_lane_config_media_type_26=copper +serdes_lane_config_media_type_27=copper +serdes_lane_config_media_type_28=copper +serdes_lane_config_media_type_24=copper + +#sai_preinit_cmd_file=/usr/share/sonic/hwsku/sai_preinit_cmd.soc +sai_postinit_cmd_file=/usr/share/sonic/hwsku/sai_postinit_cmd.soc + diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/default_sku b/device/dell/x86_64-dellemc_z9332f_d1508-r0/default_sku new file mode 100644 index 000000000000..7716a7af3216 --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/default_sku @@ -0,0 +1 @@ +DellEMC-Z9332f-O32 t1 diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/installer.conf b/device/dell/x86_64-dellemc_z9332f_d1508-r0/installer.conf new file mode 100644 index 000000000000..924e0fb81963 --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/installer.conf @@ -0,0 +1,2 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/led_proc_init.soc b/device/dell/x86_64-dellemc_z9332f_d1508-r0/led_proc_init.soc new file mode 100644 index 000000000000..0c116f35f80b --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/led_proc_init.soc @@ -0,0 +1,7 @@ +# LED microprocessor initialization for Dell z9332f +# +# +#Led0 +#Support only after SAI 3.6 +#led auto on +#led start diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/eeprom.py b/device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/eeprom.py new file mode 100644 index 000000000000..e224cd452496 --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/eeprom.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +############################################################################# +# DellEMC Z9332f +# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + + +class board(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self, name, path, cpld_root, ro): + self.eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0056/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/psuutil.py b/device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/psuutil.py new file mode 100644 index 000000000000..b2c373de358f --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/psuutil.py @@ -0,0 +1,126 @@ +# +# psuutil.py +# Platform-specific PSU status interface for SONiC +# + + +import os.path +import logging +import commands +import sys + + +Z9332F_MAX_PSUS = 2 +IPMI_PSU1_DATA = "docker exec -it pmon ipmitool raw 0x04 0x2d 0x2f | awk '{print substr($0,9,1)}'" +IPMI_PSU1_DATA_DOCKER = "ipmitool raw 0x04 0x2d 0x2f | awk '{print substr($0,9,1)}'" +IPMI_PSU2_DATA = "docker exec -it pmon ipmitool raw 0x04 0x2d 0x39 | awk '{print substr($0,9,1)}'" +IPMI_PSU2_DATA_DOCKER = "ipmitool raw 0x04 0x2d 0x39 | awk '{print substr($0,9,1)}'" +PSU_PRESENCE = "PSU{0}_Status" +# Use this for older firmware +# PSU_PRESENCE="PSU{0}_prsnt" +ipmi_sdr_list = "" + + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + PsuBase.__init__(self) + + def isDockerEnv(self): + num_docker = open('/proc/self/cgroup', 'r').read().count(":/docker") + if num_docker > 0: + return True + else: + return False + + # Fetch a BMC register + def get_pmc_register(self, reg_name): + + status = 1 + global ipmi_sdr_list + ipmi_dev_node = "/dev/pmi0" + ipmi_cmd_1 = IPMI_PSU1_DATA + ipmi_cmd_2 = IPMI_PSU1_DATA + dockerenv = self.isDockerEnv() + if dockerenv == True: + if index == 1: + status, ipmi_sdr_list = commands.getstatusoutput(IPMI_PSU1_DATA_DOCKER) + elif index == 2: + status, ipmi_sdr_list = commands.getstatusoutput(IPMI_PSU2_DATA_DOCKER) + else: + if index == 1: + status, ipmi_sdr_list = commands.getstatusoutput(IPMI_PSU1_DATA) + elif index == 2: + status, ipmi_sdr_list = commands.getstatusoutput(IPMI_PSU2_DATA) + + if status: + logging.error('Failed to execute ipmitool') + sys.exit(0) + + output = ipmi_sdr_list + + return output + + 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 + """ + Z9332F_MAX_PSUS = 2 + return Z9332F_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 + """ + # Until psu_status is implemented this is hardcoded temporarily + + 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 + ret_status = 1 + global ipmi_sdr_list + ipmi_dev_node = "/dev/pmi0" + dockerenv = self.isDockerEnv() + if dockerenv == True: + if index == 1: + status, ipmi_sdr_list = commands.getstatusoutput(IPMI_PSU1_DATA_DOCKER) + elif index == 2: + status, ipmi_sdr_list = commands.getstatusoutput(IPMI_PSU2_DATA_DOCKER) + else: + if index == 1: + status, ipmi_sdr_list = commands.getstatusoutput(IPMI_PSU1_DATA) + elif index == 2: + ret_status, ipmi_sdr_list = commands.getstatusoutput(IPMI_PSU2_DATA) + + #if ret_status: + # print ipmi_sdr_list + # logging.error('Failed to execute ipmitool') + # sys.exit(0) + + psu_status = ipmi_sdr_list + + if psu_status == '1': + status = 1 + + return status + diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/sfputil.py new file mode 100644 index 000000000000..1ea6af1f8d26 --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/sfputil.py @@ -0,0 +1,307 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import struct + import sys + import getopt + import time + import select + from sonic_sfp.sfputilbase import SfpUtilBase + from os import * + from mmap import * + +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +#from xcvrd +SFP_STATUS_REMOVED = '0' +SFP_STATUS_INSERTED = '1' + + + + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 34 + PORTS_IN_BLOCK = 34 + + BASE_RES_PATH = "/sys/bus/pci/devices/0000:09:00.0/resource0" + + _port_to_i2c_mapping = { + 1: 10, + 2: 11, + 3: 12, + 4: 13, + 5: 14, + 6: 15, + 7: 16, + 8: 17, + 9: 18, + 10: 19, + 11: 20, + 12: 21, + 13: 22, + 14: 23, + 15: 24, + 16: 25, + 17: 26, + 18: 27, + 19: 28, + 20: 29, + 21: 30, + 22: 31, + 23: 32, + 24: 33, + 25: 34, + 26: 35, + 27: 36, + 28: 37, + 29: 38, + 30: 39, + 31: 40, + 32: 41, + 33: 1, + 34: 2, + } + + _port_to_eeprom_mapping = {} + + _global_port_pres_dict = {} + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(self.PORT_START, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def pci_mem_read(self, mm, offset): + mm.seek(offset) + read_data_stream = mm.read(4) + reg_val = struct.unpack('I', read_data_stream) + mem_val = str(reg_val)[1:-2] + # print "reg_val read:%x"%reg_val + return mem_val + + def pci_mem_write(self, mm, offset, data): + mm.seek(offset) + # print "data to write:%x"%data + mm.write(struct.pack('I', data)) + + def pci_set_value(self, resource, val, offset): + fd = open(resource, O_RDWR) + mm = mmap(fd, 0) + val = self.pci_mem_write(mm, offset, val) + mm.close() + close(fd) + return val + + def pci_get_value(self, resource, offset): + fd = open(resource, O_RDWR) + mm = mmap(fd, 0) + val = self.pci_mem_read(mm, offset) + mm.close() + close(fd) + return val + + def init_global_port_presence(self): + for port_num in range(self.port_start, (self.port_end + 1)): + presence = self.get_presence(port_num) + if(presence): + self._global_port_pres_dict[port_num] = '1' + else: + self._global_port_pres_dict[port_num] = '0' + + def mod_pres(self): + port_pres_mask =0 + for port_num in range(self.port_start, (self.port_end + 1)): + presence = self.get_presence(port_num) + if(presence): + self._global_port_pres_dict[port_num] = '1' + port_val = (1 << (port_num -1)) + port_pres_mask = (port_pres_mask | port_val) + else: + self._global_port_pres_dict[port_num] = '0' + port_val = ~(1 << (port_num -1)) + port_pres_mask = (port_pres_mask & port_val) + + return port_pres_mask + + + def __init__(self): + eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" + + for x in range(self.port_start, self.port_end + 1): + self.port_to_eeprom_mapping[x] = eeprom_path.format( + self._port_to_i2c_mapping[x]) + self.init_global_port_presence() + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # Port offset starts with 0x4004 + port_offset = 16388 + ((port_num-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == ""): + return False + + # Mask off 4th bit for presence + mask = (1 << 4) + + # Mask off 1st bit for presence 33,34 + if (port_num > 32): + mask = (1 << 0) + + # ModPrsL is active low + if reg_value & mask == 0: + return True + + return False + + def get_low_power_mode(self, port_num): + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == ""): + return False + + # Mask off 4th bit for presence + mask = (1 << 6) + + # LPMode is active high + if reg_value & mask == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == ""): + return False + + # Mask off 4th bit for presence + mask = (1 << 6) + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = reg_value | mask + else: + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + return True + + def reset(self, port_num): + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == ""): + return False + + # Mask off 4th bit for presence + mask = (1 << 6) + + # ResetL is active low + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + # Sleep 1 second to allow it to settle + time.sleep(1) + + reg_value = reg_value | mask + + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + return True + + def get_register(self, reg_file): + retval = 'ERR' + if (not path.isfile(reg_file)): + print reg_file, 'not found !' + return retval + + try: + with fdopen(open(reg_file, O_RDONLY)) as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", reg_file, "file !") + + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + return retval + + def get_transceiver_change_event(self): + port_dict = {} + while True: + for port_num in range(self.port_start, (self.port_end + 1)): + presence = self.get_presence(port_num) + if(presence and self._global_port_pres_dict[port_num] == '0'): + self._global_port_pres_dict[port_num] = '1' + port_dict[port_num] = '1' + elif(not presence and + self._global_port_pres_dict[port_num] == '1'): + self._global_port_pres_dict[port_num] = '0' + port_dict[port_num] = '0' + + if(len(port_dict) > 0): + return True, port_dict + + time.sleep(0.5) + + diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index 8cbf72695920..7436fef0ef1b 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -9,6 +9,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(DELL_Z9264F_PLATFORM_MODULE) \ $(DELL_S5232F_PLATFORM_MODULE) \ $(DELL_S5248F_PLATFORM_MODULE) \ + $(DELL_Z9332F_PLATFORM_MODULE) \ $(DELL_Z9100_PLATFORM_MODULE) \ $(DELL_S6100_PLATFORM_MODULE) \ $(INGRASYS_S8900_54XC_PLATFORM_MODULE) \ diff --git a/platform/broadcom/platform-modules-dell.mk b/platform/broadcom/platform-modules-dell.mk index 583f74f72d8b..298e3c4f7396 100644 --- a/platform/broadcom/platform-modules-dell.mk +++ b/platform/broadcom/platform-modules-dell.mk @@ -1,10 +1,11 @@ -# Dell S6000,Z9100, S6100, Z9264F , S5232 Platform modules +# Dell S6000,Z9100, S6100, Z9264F , S5232F,Z9332F Platform modules DELL_S6000_PLATFORM_MODULE_VERSION = 1.1 DELL_Z9100_PLATFORM_MODULE_VERSION = 1.1 DELL_S6100_PLATFORM_MODULE_VERSION = 1.1 DELL_Z9264F_PLATFORM_MODULE_VERSION = 1.1 DELL_S5232F_PLATFORM_MODULE_VERSION = 1.1 +DELL_Z9332F_PLATFORM_MODULE_VERSION = 1.1 DELL_S5248F_PLATFORM_MODULE_VERSION = 1.1 export DELL_S6000_PLATFORM_MODULE_VERSION @@ -12,6 +13,7 @@ export DELL_Z9100_PLATFORM_MODULE_VERSION export DELL_S6100_PLATFORM_MODULE_VERSION export DELL_Z9264F_PLATFORM_MODULE_VERSION export DELL_S5232F_PLATFORM_MODULE_VERSION +export DELL_Z9332F_PLATFORM_MODULE_VERSION export DELL_S5248F_PLATFORM_MODULE_VERSION DELL_Z9100_PLATFORM_MODULE = platform-modules-z9100_$(DELL_Z9100_PLATFORM_MODULE_VERSION)_amd64.deb @@ -37,6 +39,10 @@ DELL_S5232F_PLATFORM_MODULE = platform-modules-s5232f_$(DELL_S5232F_PLATFORM_MOD $(DELL_S5232F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5232f_c3538-r0 $(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5232F_PLATFORM_MODULE))) +DELL_Z9332F_PLATFORM_MODULE = platform-modules-z9332f_$(DELL_Z9332F_PLATFORM_MODULE_VERSION)_amd64.deb +$(DELL_Z9332F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_z9332f_d1508-r0 +$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_Z9332F_PLATFORM_MODULE))) + DELL_S5248F_PLATFORM_MODULE = platform-modules-s5248f_$(DELL_S5248F_PLATFORM_MODULE_VERSION)_amd64.deb $(DELL_S5248F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5248f_c3538-r0 $(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5248F_PLATFORM_MODULE))) diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/control b/platform/broadcom/sonic-platform-modules-dell/debian/control index f32fa7244acc..3131890e6353 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/control +++ b/platform/broadcom/sonic-platform-modules-dell/debian/control @@ -34,3 +34,8 @@ Package: platform-modules-s5248f Architecture: amd64 Depends: linux-image-4.9.0-9-2-amd64 Description: kernel modules for platform devices such as fan, led, sfp + +Package: platform-modules-z9332f +Architecture: amd64 +Depends: linux-image-4.9.0-9-2-amd64 +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9332f.init b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9332f.init new file mode 100644 index 000000000000..f4fe9eb396fd --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9332f.init @@ -0,0 +1,39 @@ +#!/bin/bash + +### BEGIN INIT INFO +# Provides: setup-board +# Required-Start: +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Setup Z9332f board. +### END INIT INFO + +case "$1" in +start) + echo -n "Setting up board... " + + /usr/local/bin/z9332f_platform.sh init + + echo "done." + ;; + +stop) + /usr/local/bin/z9332f_platform.sh deinit + echo "done." + + ;; + +force-reload|restart) + echo "Not supported" + ;; + +*) + echo "Usage: /etc/init.d/platform-modules-z9332f.init {start|stop}" + exit 1 + ;; +esac + +exit 0 diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9332f.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9332f.install new file mode 100644 index 000000000000..16d2b952186f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9332f.install @@ -0,0 +1,7 @@ +z9332f/scripts/z9332f_platform.sh usr/local/bin +z9332f/scripts/platform_sensors.py usr/local/bin +z9332f/scripts/sensors usr/bin +z9332f/scripts/pcisysfs.py usr/bin +z9332f/cfg/z9332f-modules.conf etc/modules-load.d +z9332f/systemd/platform-modules-z9332f.service etc/systemd/system +common/platform_reboot usr/share/sonic/device/x86_64-dellemc_z9332f_d1508-r0 diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9332f.postinst b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9332f.postinst new file mode 100644 index 000000000000..3a3a72cb304a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9332f.postinst @@ -0,0 +1,10 @@ +# postinst script for Z9332f + +# Enable Dell-Z9332f-platform-service +depmod -a +systemctl enable platform-modules-z9332f.service +systemctl start platform-modules-z9332f.service + + +#DEBHELPER# + diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/rules b/platform/broadcom/sonic-platform-modules-dell/debian/rules index a7f68a21f55a..8af0642b40d3 100755 --- a/platform/broadcom/sonic-platform-modules-dell/debian/rules +++ b/platform/broadcom/sonic-platform-modules-dell/debian/rules @@ -5,7 +5,7 @@ export INSTALL_MOD_DIR:=extra KVERSION ?= $(shell uname -r) KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) -MODULE_DIRS:= s6000 z9100 s6100 z9264f s5232f s5248f +MODULE_DIRS:= s6000 z9100 s6100 z9264f s5232f s5248f z9332f COMMON_DIR := common %: diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/cfg/z9332f-modules.conf b/platform/broadcom/sonic-platform-modules-dell/z9332f/cfg/z9332f-modules.conf new file mode 100644 index 000000000000..b6d4fe4fb00a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/cfg/z9332f-modules.conf @@ -0,0 +1,17 @@ +# /etc/modules: kernel modules to load at boot time. +# +# This file contains the names of kernel modules that should be loaded +# at boot time, one per line. Lines beginning with "#" are ignored. + +i2c-i801 +i2c-isch +i2c-ismt +i2c-dev +i2c-mux +i2c-smbus + +i2c-mux-gpio +i2c-mux-pca954x + +ipmi_devintf +ipmi_si diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/Makefile b/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/Makefile new file mode 100644 index 000000000000..bb71bb0d9185 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/Makefile @@ -0,0 +1,4 @@ +obj-m += cls-switchboard.o +obj-m += cls-i2c-ocore.o +obj-m += mc24lc64t.o + diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/cls-i2c-ocore.c b/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/cls-i2c-ocore.c new file mode 100644 index 000000000000..c80757e6619d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/cls-i2c-ocore.c @@ -0,0 +1,845 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cls-i2c-ocores.c: I2C bus driver for OpenCores I2C controller + * (https://opencores.org/project/i2c/overview) + * + * Peter Korsgaard + * + * Support for the GRLIB port of the controller by + * Andreas Larsson + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include +#include +#include +#include +#include +#include +#include "cls-i2c-ocore.h" + +#define OCORES_FLAG_POLL BIT(0) + +/* + * 'process_lock' exists because ocores_process() and ocores_process_timeout() + * can't run in parallel. + */ +struct ocores_i2c { + void __iomem *base; + int iobase; + u32 reg_shift; + u32 reg_io_width; + unsigned long flags; + wait_queue_head_t wait; + struct i2c_adapter adap; + struct i2c_msg *msg; + int pos; + int nmsgs; + int state; /* see STATE_ */ + int nack_retry; + spinlock_t process_lock; + struct clk *clk; + int ip_clock_khz; + int bus_clock_khz; + void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); + u8 (*getreg)(struct ocores_i2c *i2c, int reg); +}; + +/* registers */ +#define OCI2C_PRELOW 0 +#define OCI2C_PREHIGH 1 +#define OCI2C_CONTROL 2 +#define OCI2C_DATA 3 +#define OCI2C_CMD 4 /* write only */ +#define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */ + +#define OCI2C_CTRL_IEN 0x40 +#define OCI2C_CTRL_EN 0x80 + +#define OCI2C_CMD_START 0x91 +#define OCI2C_CMD_STOP 0x41 +#define OCI2C_CMD_READ 0x21 +#define OCI2C_CMD_WRITE 0x11 +#define OCI2C_CMD_READ_ACK 0x21 +#define OCI2C_CMD_READ_NACK 0x29 +#define OCI2C_CMD_IACK 0x01 + +#define OCI2C_STAT_IF 0x01 +#define OCI2C_STAT_TIP 0x02 +#define OCI2C_STAT_ARBLOST 0x20 +#define OCI2C_STAT_BUSY 0x40 +#define OCI2C_STAT_NACK 0x80 + +#define STATE_DONE 0 +#define STATE_START 1 +#define STATE_WRITE 2 +#define STATE_READ 3 +#define STATE_ERROR 4 + +#define TYPE_OCORES 0 +#define TYPE_GRLIB 1 + +static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite16(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite32(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite16be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite32be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg) +{ + return ioread8(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_16(struct ocores_i2c *i2c, int reg) +{ + return ioread16(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg) +{ + return ioread32(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_16be(struct ocores_i2c *i2c, int reg) +{ + return ioread16be(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg) +{ + return ioread32be(i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_io_8(struct ocores_i2c *i2c, int reg, u8 value) +{ + outb(value, i2c->iobase + reg); +} + +static inline u8 oc_getreg_io_8(struct ocores_i2c *i2c, int reg) +{ + return inb(i2c->iobase + reg); +} + +static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) +{ + i2c->setreg(i2c, reg, value); +} + +static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) +{ + return i2c->getreg(i2c, reg); +} + +static void ocores_process(struct ocores_i2c *i2c, u8 stat) +{ + struct i2c_msg *msg = i2c->msg; + unsigned long flags; + + /* + * If we spin here is because we are in timeout, so we are going + * to be in STATE_ERROR. See ocores_process_timeout() + */ + spin_lock_irqsave(&i2c->process_lock, flags); + + dev_dbg(&i2c->adap.dev, "STATE: %d\n", i2c->state); + + if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) { + /* stop has been sent */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + wake_up(&i2c->wait); + goto out; + } + + /* error? */ + if (stat & OCI2C_STAT_ARBLOST) { + // i2c->state = STATE_ERROR; + i2c->state = STATE_START; + // i2c->nack_retry = 1; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + dev_dbg(&i2c->adap.dev, "ERR: AL\n"); + goto out; + } + + if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { + i2c->state = + (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; + + if (stat & OCI2C_STAT_NACK) { + dev_dbg(&i2c->adap.dev, "ERR: NACK\n"); + // printk(KERN_INFO "ERR: NACK\n"); + i2c->state = STATE_ERROR; + if(!(msg->flags & I2C_M_RD)) + i2c->nack_retry = 1; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + } else { + msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); + } + + /* end of msg? */ + if (i2c->pos == msg->len) { + i2c->nmsgs--; + i2c->msg++; + i2c->pos = 0; + msg = i2c->msg; + + if (i2c->nmsgs) { /* end? */ + /* send start? */ + if (!(msg->flags & I2C_M_NOSTART)) { + u8 addr = i2c_8bit_addr_from_msg(msg); + + i2c->state = STATE_START; + + oc_setreg(i2c, OCI2C_DATA, addr); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + goto out; + } + i2c->state = (msg->flags & I2C_M_RD) + ? STATE_READ : STATE_WRITE; + } else { + i2c->state = STATE_DONE; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + } + + if (i2c->state == STATE_READ) { + oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ? + OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK); + } else { + oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE); + } + +out: + spin_unlock_irqrestore(&i2c->process_lock, flags); +} + +static irqreturn_t ocores_isr(int irq, void *dev_id) +{ + struct ocores_i2c *i2c = dev_id; + u8 stat = oc_getreg(i2c, OCI2C_STATUS); + + dev_dbg(&i2c->adap.dev, "STATUS: 0x%x\n", stat); + // printk(KERN_INFO "STATUS: 0x%x\n", stat); + + if (!(stat & OCI2C_STAT_IF)) + return IRQ_NONE; + + ocores_process(i2c, stat); + + return IRQ_HANDLED; +} + +/** + * Process timeout event + * @i2c: ocores I2C device instance + */ +static void ocores_process_timeout(struct ocores_i2c *i2c) +{ + unsigned long flags; + + spin_lock_irqsave(&i2c->process_lock, flags); + i2c->state = STATE_ERROR; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + spin_unlock_irqrestore(&i2c->process_lock, flags); +} + +/** + * Wait until something change in a given register + * @i2c: ocores I2C device instance + * @reg: register to query + * @mask: bitmask to apply on register value + * @val: expected result + * @timeout: timeout in jiffies + * + * Timeout is necessary to avoid to stay here forever when the chip + * does not answer correctly. + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_wait(struct ocores_i2c *i2c, + int reg, u8 mask, u8 val, + const unsigned long timeout) +{ + unsigned long j; + + j = jiffies + timeout; + while (1) { + u8 status = oc_getreg(i2c, reg); + + if ((status & mask) == val) + break; + + if (time_after(jiffies, j)) + return -ETIMEDOUT; + cpu_relax(); + cond_resched(); + } + return 0; +} + +/** + * Wait until is possible to process some data + * @i2c: ocores I2C device instance + * + * Used when the device is in polling mode (interrupts disabled). + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_poll_wait(struct ocores_i2c *i2c) +{ + u8 mask; + int err; + + if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) { + /* transfer is over */ + mask = OCI2C_STAT_BUSY; + } else { + /* on going transfer */ + mask = OCI2C_STAT_TIP; + /* + * We wait for the data to be transferred (8bit), + * then we start polling on the ACK/NACK bit + */ + udelay((8 * 1000) / i2c->bus_clock_khz); + } + + dev_dbg(&i2c->adap.dev, "Wait for: 0x%x\n", mask); + // printk(KERN_INFO "Wait for: 0x%x\n", mask); + + /* + * once we are here we expect to get the expected result immediately + * so if after 1ms we timeout then something is broken. + */ + err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(30)); + if (err) + dev_warn(i2c->adap.dev.parent, + "%s: STATUS timeout, bit 0x%x did not clear in 1ms\n", + __func__, mask); + return err; +} + +/** + * It handles an IRQ-less transfer + * @i2c: ocores I2C device instance + * + * Even if IRQ are disabled, the I2C OpenCore IP behavior is exactly the same + * (only that IRQ are not produced). This means that we can re-use entirely + * ocores_isr(), we just add our polling code around it. + * + * It can run in atomic context + */ +static void ocores_process_polling(struct ocores_i2c *i2c) +{ + while (1) { + irqreturn_t ret; + int err; + + err = ocores_poll_wait(i2c); + if (err) { + i2c->state = STATE_ERROR; + break; /* timeout */ + } + + ret = ocores_isr(-1, i2c); + if (ret == IRQ_NONE) + break; /* all messages have been transferred */ + } +} + +static int ocores_xfer_core(struct ocores_i2c *i2c, + struct i2c_msg *msgs, int num, + bool polling) +{ + int ret; + u8 ctrl; + + ctrl = oc_getreg(i2c, OCI2C_CONTROL); + if (polling) + oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~OCI2C_CTRL_IEN); + else + oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN); + + i2c->msg = msgs; + i2c->pos = 0; + i2c->nmsgs = num; + i2c->state = STATE_START; + + dev_dbg(&i2c->adap.dev, "STATE: %d\n", i2c->state); + // printk(KERN_INFO "STATE: %d\n", i2c->state); + + oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg)); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + + if (polling) { + ocores_process_polling(i2c); + } else { + ret = wait_event_timeout(i2c->wait, + (i2c->state == STATE_ERROR) || + (i2c->state == STATE_DONE), HZ); + if (ret == 0) { + ocores_process_timeout(i2c); + return -ETIMEDOUT; + } + } + + return (i2c->state == STATE_DONE) ? num : -EIO; +} + +static int ocores_xfer_polling(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, true); +} + +static int ocores_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + int ret; + int retry=0; + int max_retry = 0; + struct ocores_i2c *i2c = i2c_get_adapdata(adap); + + i2c->nack_retry = 0; + + if (i2c->flags & OCORES_FLAG_POLL) + { + //return ocores_xfer_polling(adap, msgs, num); + ret = ocores_xfer_polling(adap, msgs, num); + // Fix i2cdetect issue + if(num == 1) + max_retry = 5; + else + max_retry = 5; + + while((i2c->nack_retry == 1)&&(retry < max_retry)) + { + retry++; + i2c->nack_retry = 0; + ret = ocores_xfer_polling(adap, msgs, num); + // printk("nack retry polling = %d\n",retry); + } + // if(i2c->nack_retry!=0){ + // printk("nack retry = %d, ret=%d\n",retry, ret); + // } + i2c->nack_retry = 0; + return ret; + } + return ocores_xfer_core(i2c, msgs, num, false); +} + +static int ocores_init(struct device *dev, struct ocores_i2c *i2c) +{ + int prescale; + int diff; + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* make sure the device is disabled */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + + prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1; + prescale = clamp(prescale, 0, 0xffff); + + dev_info(dev, "Prescale: %d\n", prescale); + + diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz; + if (abs(diff) > i2c->bus_clock_khz / 10) { + dev_err(dev, + "Unsupported clock settings: core: %d KHz, bus: %d KHz\n", + i2c->ip_clock_khz, i2c->bus_clock_khz); + return -EINVAL; + } + + oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff); + oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8); + + /* Init the device */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_EN); + + return 0; +} + + +static u32 ocores_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm ocores_algorithm = { + .master_xfer = ocores_xfer, + .functionality = ocores_func, +}; + +static const struct i2c_adapter ocores_adapter = { + .owner = THIS_MODULE, + .name = "i2c-goodcores", + .class = I2C_CLASS_DEPRECATED, + .algo = &ocores_algorithm, +}; + +static const struct of_device_id ocores_i2c_match[] = { + { + .compatible = "opencores,i2c-ocores", + .data = (void *)TYPE_OCORES, + }, + { + .compatible = "aeroflexgaisler,i2cmst", + .data = (void *)TYPE_GRLIB, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ocores_i2c_match); + +#ifdef CONFIG_OF +/* + * Read and write functions for the GRLIB port of the controller. Registers are + * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one + * register. The subsequent registers have their offsets decreased accordingly. + */ +static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg) +{ + u32 rd; + int rreg = reg; + + if (reg != OCI2C_PRELOW) + rreg--; + rd = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PREHIGH) + return (u8)(rd >> 8); + else + return (u8)rd; +} + +static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value) +{ + u32 curr, wr; + int rreg = reg; + + if (reg != OCI2C_PRELOW) + rreg--; + if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) { + curr = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PRELOW) + wr = (curr & 0xff00) | value; + else + wr = (((u32)value) << 8) | (curr & 0xff); + } else { + wr = value; + } + iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift)); +} + +static int ocores_i2c_of_probe(struct platform_device *pdev, + struct ocores_i2c *i2c) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + u32 val; + u32 clock_frequency; + bool clock_frequency_present; + + if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { + /* no 'reg-shift', check for deprecated 'regstep' */ + if (!of_property_read_u32(np, "regstep", &val)) { + if (!is_power_of_2(val)) { + dev_err(&pdev->dev, "invalid regstep %d\n", + val); + return -EINVAL; + } + i2c->reg_shift = ilog2(val); + dev_warn(&pdev->dev, + "regstep property deprecated, use reg-shift\n"); + } + } + + clock_frequency_present = !of_property_read_u32(np, "clock-frequency", + &clock_frequency); + i2c->bus_clock_khz = 100; + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + + if (!IS_ERR(i2c->clk)) { + int ret = clk_prepare_enable(i2c->clk); + + if (ret) { + dev_err(&pdev->dev, + "clk_prepare_enable failed: %d\n", ret); + return ret; + } + i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000; + if (clock_frequency_present) + i2c->bus_clock_khz = clock_frequency / 1000; + } + + if (i2c->ip_clock_khz == 0) { + if (of_property_read_u32(np, "opencores,ip-clock-frequency", + &val)) { + if (!clock_frequency_present) { + dev_err(&pdev->dev, + "Missing required parameter 'opencores,ip-clock-frequency'\n"); + clk_disable_unprepare(i2c->clk); + return -ENODEV; + } + i2c->ip_clock_khz = clock_frequency / 1000; + dev_warn(&pdev->dev, + "Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n"); + } else { + i2c->ip_clock_khz = val / 1000; + if (clock_frequency_present) + i2c->bus_clock_khz = clock_frequency / 1000; + } + } + + of_property_read_u32(pdev->dev.of_node, "reg-io-width", + &i2c->reg_io_width); + + match = of_match_node(ocores_i2c_match, pdev->dev.of_node); + if (match && (long)match->data == TYPE_GRLIB) { + dev_dbg(&pdev->dev, "GRLIB variant of i2c-ocores\n"); + // printk(KERN_INFO "GRLIB variant of i2c-ocores\n"); + i2c->setreg = oc_setreg_grlib; + i2c->getreg = oc_getreg_grlib; + } + + return 0; +} +#else +#define ocores_i2c_of_probe(pdev, i2c) -ENODEV +#endif + +static int ocores_i2c_probe(struct platform_device *pdev) +{ + struct ocores_i2c *i2c; + struct ocores_i2c_platform_data *pdata; + struct resource *res; + int irq; + int ret; + int i; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + spin_lock_init(&i2c->process_lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + i2c->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); + } else { + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) + return -EINVAL; + i2c->iobase = res->start; + if (!devm_request_region(&pdev->dev, res->start, + resource_size(res), + pdev->name)) { + dev_err(&pdev->dev, "Can't get I/O resource.\n"); + return -EBUSY; + } + i2c->setreg = oc_setreg_io_8; + i2c->getreg = oc_getreg_io_8; + } + + pdata = dev_get_platdata(&pdev->dev); + if (pdata) { + i2c->reg_shift = pdata->reg_shift; + i2c->reg_io_width = pdata->reg_io_width; + i2c->ip_clock_khz = pdata->clock_khz; + if (pdata->bus_khz) + i2c->bus_clock_khz = pdata->bus_khz; + else + i2c->bus_clock_khz = 100; + } else { + ret = ocores_i2c_of_probe(pdev, i2c); + if (ret) + return ret; + } + + if (i2c->reg_io_width == 0) + i2c->reg_io_width = 1; /* Set to default value */ + + if (!i2c->setreg || !i2c->getreg) { + bool be = pdata ? pdata->big_endian : + of_device_is_big_endian(pdev->dev.of_node); + + switch (i2c->reg_io_width) { + case 1: + i2c->setreg = oc_setreg_8; + i2c->getreg = oc_getreg_8; + break; + + case 2: + i2c->setreg = be ? oc_setreg_16be : oc_setreg_16; + i2c->getreg = be ? oc_getreg_16be : oc_getreg_16; + break; + + case 4: + i2c->setreg = be ? oc_setreg_32be : oc_setreg_32; + i2c->getreg = be ? oc_getreg_32be : oc_getreg_32; + break; + + default: + dev_err(&pdev->dev, "Unsupported I/O width (%d)\n", + i2c->reg_io_width); + ret = -EINVAL; + goto err_clk; + } + } + + init_waitqueue_head(&i2c->wait); + + irq = platform_get_irq(pdev, 0); + if (irq == -ENXIO) { + i2c->flags |= OCORES_FLAG_POLL; + } else { + if (irq < 0) + return irq; + } + + if (!(i2c->flags & OCORES_FLAG_POLL)) { + ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, + pdev->name, i2c); + if (ret) { + dev_err(&pdev->dev, "Cannot claim IRQ\n"); + goto err_clk; + } + } + + ret = ocores_init(&pdev->dev, i2c); + if (ret) + goto err_clk; + + /* hook up driver to tree */ + platform_set_drvdata(pdev, i2c); + i2c->adap = ocores_adapter; + i2c_set_adapdata(&i2c->adap, i2c); + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = pdev->dev.of_node; + + /* add i2c adapter to i2c tree */ + ret = i2c_add_adapter(&i2c->adap); + if (ret) + goto err_clk; + + /* add in known devices to the bus */ + if (pdata) { + for (i = 0; i < pdata->num_devices; i++) + i2c_new_device(&i2c->adap, pdata->devices + i); + } + + return 0; + +err_clk: + clk_disable_unprepare(i2c->clk); + return ret; +} + +static int ocores_i2c_remove(struct platform_device *pdev) +{ + struct ocores_i2c *i2c = platform_get_drvdata(pdev); + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* disable i2c logic */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + + /* remove adapter & data */ + i2c_del_adapter(&i2c->adap); + + if (!IS_ERR(i2c->clk)) + clk_disable_unprepare(i2c->clk); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int ocores_i2c_suspend(struct device *dev) +{ + struct ocores_i2c *i2c = dev_get_drvdata(dev); + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* make sure the device is disabled */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + + if (!IS_ERR(i2c->clk)) + clk_disable_unprepare(i2c->clk); + return 0; +} + +static int ocores_i2c_resume(struct device *dev) +{ + struct ocores_i2c *i2c = dev_get_drvdata(dev); + + if (!IS_ERR(i2c->clk)) { + unsigned long rate; + int ret = clk_prepare_enable(i2c->clk); + + if (ret) { + dev_err(dev, + "clk_prepare_enable failed: %d\n", ret); + return ret; + } + rate = clk_get_rate(i2c->clk) / 1000; + if (rate) + i2c->ip_clock_khz = rate; + } + return ocores_init(dev, i2c); +} + +static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); +#define OCORES_I2C_PM (&ocores_i2c_pm) +#else +#define OCORES_I2C_PM NULL +#endif + +static struct platform_driver ocores_i2c_driver = { + .probe = ocores_i2c_probe, + .remove = ocores_i2c_remove, + .driver = { + .name = "goodcores-i2c", + .of_match_table = ocores_i2c_match, + .pm = OCORES_I2C_PM, + }, +}; + +module_platform_driver(ocores_i2c_driver); + +MODULE_AUTHOR("Peter Korsgaard "); +MODULE_DESCRIPTION("OpenCores I2C bus driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ocores-i2c"); diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/cls-i2c-ocore.h b/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/cls-i2c-ocore.h new file mode 100644 index 000000000000..bc2a53cd6832 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/cls-i2c-ocore.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cls-i2c-ocores.h - definitions for the i2c-ocores interface + * + * Peter Korsgaard + */ + +#ifndef _LINUX_I2C_OCORES_H +#define _LINUX_I2C_OCORES_H + +struct ocores_i2c_platform_data { + u32 reg_shift; /* register offset shift value */ + u32 reg_io_width; /* register io read/write width */ + u32 clock_khz; /* input clock in kHz */ + u32 bus_khz; /* bus clock in kHz */ + bool big_endian; /* registers are big endian */ + u8 num_devices; /* number of devices in the devices list */ + struct i2c_board_info const *devices; /* devices connected to the bus */ +}; + +#endif /* _LINUX_I2C_OCORES_H */ + diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/cls-switchboard.c b/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/cls-switchboard.c new file mode 100644 index 000000000000..240580e577a3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/cls-switchboard.c @@ -0,0 +1,447 @@ +/* + * cls_switchboard.c - PCI device driver for Silverstone Switch board FPGA. + * + * Author: Pradchaya Phucharoen + * + * Copyright (C) 2019 Celestica 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 Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cls-i2c-ocore.h" + +#define MOD_VERSION "2.1.0-1" +#define DRV_NAME "cls-switchboard" + +#define I2C_MUX_CHANNEL(_ch, _adap_id, _deselect) \ + [_ch] = { .adap_id = _adap_id, .deselect_on_exit = _deselect } + +#define FPGA_PCIE_DEVICE_ID 0x7021 +#define MMIO_BAR 0 +#define I2C_BUS_OFS 9 + +/* I2C ocore configurations */ +#define OCORE_REGSHIFT 2 +#define OCORE_IP_CLK_khz 62500 //TODO: check fpga's `wb_clk_i` +#define OCORE_BUS_CLK_khz 100 +#define OCORE_REG_IO_WIDTH 1 + +/* Optical port xcvr configuration */ +#define XCVR_REG_SHIFT 2 +#define XCVR_NUM_PORT 34 +#define XCVR_PORT_REG_SIZE 0x10 + +/* i2c_bus_config - an i2c-core resource and platform data + * @id - I2C bus device ID, for identification. + * @res - resources for an i2c-core device. + * @num_res - size of the resources. + * @pdata - a platform data of an i2c-core device. + */ +struct i2c_bus_config { + int id; + struct resource *res; + ssize_t num_res; + struct ocores_i2c_platform_data pdata; +}; + +/* switchbrd_priv - switchboard private data */ +struct switchbrd_priv { + unsigned long base; + int num_i2c_bus; + struct platform_device **i2cbuses_pdev; + struct platform_device *regio_pdev; + struct platform_device *spiflash_pdev; + //struct platform_device *xcvr_pdev; +}; + + +// NOTE: Silverstone i2c channel mapping is very wierd!!! +/* PCA9548 channel config on MASTER BUS 3 */ +static struct pca954x_platform_mode i2c_mux_70_modes[] = { + I2C_MUX_CHANNEL(5, I2C_BUS_OFS + 23, true), + I2C_MUX_CHANNEL(6, I2C_BUS_OFS + 26, true), + I2C_MUX_CHANNEL(0, I2C_BUS_OFS + 27, true), + I2C_MUX_CHANNEL(7, I2C_BUS_OFS + 28, true), + I2C_MUX_CHANNEL(2, I2C_BUS_OFS + 29, true), + I2C_MUX_CHANNEL(4, I2C_BUS_OFS + 30, true), + I2C_MUX_CHANNEL(3, I2C_BUS_OFS + 31, true), + I2C_MUX_CHANNEL(1, I2C_BUS_OFS + 32, true), +}; + +static struct pca954x_platform_mode i2c_mux_71_modes[] = { + I2C_MUX_CHANNEL(2, I2C_BUS_OFS + 1, true), + I2C_MUX_CHANNEL(3, I2C_BUS_OFS + 2, true), + I2C_MUX_CHANNEL(0, I2C_BUS_OFS + 3, true), + I2C_MUX_CHANNEL(1, I2C_BUS_OFS + 4, true), + I2C_MUX_CHANNEL(6, I2C_BUS_OFS + 5, true), + I2C_MUX_CHANNEL(5, I2C_BUS_OFS + 6, true), + I2C_MUX_CHANNEL(7, I2C_BUS_OFS + 15, true), + I2C_MUX_CHANNEL(4, I2C_BUS_OFS + 8, true), +}; + +static struct pca954x_platform_mode i2c_mux_72_modes[] = { + I2C_MUX_CHANNEL(1, I2C_BUS_OFS + 17, true), + I2C_MUX_CHANNEL(7, I2C_BUS_OFS + 18, true), + I2C_MUX_CHANNEL(4, I2C_BUS_OFS + 19, true), + I2C_MUX_CHANNEL(0, I2C_BUS_OFS + 20, true), + I2C_MUX_CHANNEL(5, I2C_BUS_OFS + 21, true), + I2C_MUX_CHANNEL(2, I2C_BUS_OFS + 22, true), + I2C_MUX_CHANNEL(3, I2C_BUS_OFS + 25, true), + I2C_MUX_CHANNEL(6, I2C_BUS_OFS + 24, true), +}; + +static struct pca954x_platform_mode i2c_mux_73_modes[] = { + I2C_MUX_CHANNEL(4, I2C_BUS_OFS + 9, true), + I2C_MUX_CHANNEL(3, I2C_BUS_OFS + 10, true), + I2C_MUX_CHANNEL(6, I2C_BUS_OFS + 11, true), + I2C_MUX_CHANNEL(2, I2C_BUS_OFS + 12, true), + I2C_MUX_CHANNEL(1, I2C_BUS_OFS + 13, true), + I2C_MUX_CHANNEL(5, I2C_BUS_OFS + 14, true), + I2C_MUX_CHANNEL(7, I2C_BUS_OFS + 7, true), + I2C_MUX_CHANNEL(0, I2C_BUS_OFS + 16, true), +}; + +static struct pca954x_platform_data om_muxes[] = { + { + .modes = i2c_mux_70_modes, + .num_modes = ARRAY_SIZE(i2c_mux_70_modes), + }, + { + .modes = i2c_mux_71_modes, + .num_modes = ARRAY_SIZE(i2c_mux_71_modes), + }, + { + .modes = i2c_mux_72_modes, + .num_modes = ARRAY_SIZE(i2c_mux_72_modes), + }, + { + .modes = i2c_mux_73_modes, + .num_modes = ARRAY_SIZE(i2c_mux_73_modes), + }, +}; + +/* Optical Module bus 3 i2c muxes info */ +static struct i2c_board_info i2c_info_3[] = { + { + I2C_BOARD_INFO("pca9548", 0x70), + .platform_data = &om_muxes[0], + }, + { + I2C_BOARD_INFO("pca9548", 0x71), + .platform_data = &om_muxes[1], + }, + { + I2C_BOARD_INFO("pca9548", 0x72), + .platform_data = &om_muxes[2], + }, + { + I2C_BOARD_INFO("pca9548", 0x73), + .platform_data = &om_muxes[3], + }, +}; + +/* RESOURCE SEPERATES BY FUNCTION */ +/* Resource IOMEM for i2c bus 1 */ +static struct resource cls_i2c_res_1[] = { + { + .start = 0x800, .end = 0x81F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 2 */ +static struct resource cls_i2c_res_2[] = { + { + .start = 0x820, .end = 0x83F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 3 */ +static struct resource cls_i2c_res_3[] = { + { + .start = 0x840, .end = 0x85F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 4 */ +static struct resource cls_i2c_res_4[] = { + { + .start = 0x860, .end = 0x87F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 5 */ +static struct resource cls_i2c_res_5[] = { + { + .start = 0x880, .end = 0x89F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for reg access */ +static struct resource reg_io_res[] = { + { + .start = 0x00, .end = 0xFF, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for spi flash firmware upgrade */ +static struct resource spi_flash_res[] = { + { + .start = 0x1200, .end = 0x121F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for front panel XCVR */ +// static struct resource xcvr_res[] = { +// { +// .start = 0x4000, .end = 0x421F, +// .flags = IORESOURCE_MEM,}, +// }; + +static struct i2c_bus_config i2c_bus_configs[] = { + { + .id = 1, + .res = cls_i2c_res_1, + .num_res = ARRAY_SIZE(cls_i2c_res_1), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = 0, + .devices = NULL, + }, + }, + { + .id = 2, + .res = cls_i2c_res_2, + .num_res = ARRAY_SIZE(cls_i2c_res_2), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = 0, + .devices = NULL, + }, + }, + { + .id = 3, + .res = cls_i2c_res_3, + .num_res = ARRAY_SIZE(cls_i2c_res_3), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = ARRAY_SIZE(i2c_info_3), + .devices = i2c_info_3, + }, + }, + { + .id = 4, + .res = cls_i2c_res_4, + .num_res = ARRAY_SIZE(cls_i2c_res_4), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = 0, + .devices = NULL, + }, + }, + { + .id = 5, + .res = cls_i2c_res_5, + .num_res = ARRAY_SIZE(cls_i2c_res_5), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = 0, + .devices = NULL, + }, + }, +}; + +// TODO: Add a platform configuration struct, and use probe as a factory, +// so xcvr, fwupgrade device can configured as options. + +static int cls_fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + + struct switchbrd_priv *priv; + struct platform_device **i2cbuses_pdev; + struct platform_device *regio_pdev; + struct platform_device *spiflash_pdev; + //struct platform_device *xcvr_pdev; + unsigned long rstart; + int num_i2c_bus, i; + int err; + + err = pci_enable_device(dev); + if (err){ + dev_err(&dev->dev, "Failed to enable PCI device\n"); + goto err_exit; + } + + /* Check for valid MMIO address */ + rstart = pci_resource_start(dev, MMIO_BAR); + if (!rstart) { + dev_err(&dev->dev, "Switchboard base address uninitialized, " + "check FPGA\n"); + err = -ENODEV; + goto err_disable_device; + } + + dev_dbg(&dev->dev, "BAR%d res: 0x%lx-0x%llx\n", MMIO_BAR, + rstart, pci_resource_end(dev, MMIO_BAR)); + + priv = devm_kzalloc(&dev->dev, + sizeof(struct switchbrd_priv), GFP_KERNEL); + if (!priv){ + err = -ENOMEM; + goto err_disable_device; + } + + pci_set_drvdata(dev, priv); + num_i2c_bus = ARRAY_SIZE(i2c_bus_configs); + i2cbuses_pdev = devm_kzalloc( + &dev->dev, + num_i2c_bus * sizeof(struct platform_device*), + GFP_KERNEL); + + reg_io_res[0].start += rstart; + reg_io_res[0].end += rstart; + + spi_flash_res[0].start += rstart; + spi_flash_res[0].end += rstart; + + regio_pdev = platform_device_register_resndata( + &dev->dev, "cls-swbrd-io", + -1, + reg_io_res, ARRAY_SIZE(reg_io_res), + NULL, 0); + + if (IS_ERR(regio_pdev)) { + dev_err(&dev->dev, "Failed to register cls-swbrd-io\n"); + err = PTR_ERR(regio_pdev); + goto err_disable_device; + } + + spiflash_pdev = platform_device_register_resndata( + &dev->dev, "cls-swbrd-fwug", + -1, + spi_flash_res, ARRAY_SIZE(spi_flash_res), + NULL, 0); + + if (IS_ERR(spiflash_pdev)) { + dev_err(&dev->dev, "Failed to register firmware upgrade node\n"); + err = PTR_ERR(spiflash_pdev); + goto err_unregister_regio; + } + + for(i = 0; i < num_i2c_bus; i++){ + + i2c_bus_configs[i].res[0].start += rstart; + i2c_bus_configs[i].res[0].end += rstart; + + dev_dbg(&dev->dev, "i2c-bus.%d: 0x%llx - 0x%llx\n", + i2c_bus_configs[i].id, + i2c_bus_configs[i].res[0].start, + i2c_bus_configs[i].res[0].end); + + i2cbuses_pdev[i] = platform_device_register_resndata( + &dev->dev, "goodcores-i2c", + i2c_bus_configs[i].id, + i2c_bus_configs[i].res, + i2c_bus_configs[i].num_res, + &i2c_bus_configs[i].pdata, + sizeof(i2c_bus_configs[i].pdata)); + + if (IS_ERR(i2cbuses_pdev[i])) { + dev_err(&dev->dev, "Failed to register goodcores-i2c.%d\n", + i2c_bus_configs[i].id); + err = PTR_ERR(i2cbuses_pdev[i]); + goto err_unregister_ocore; + } + } + + priv->base = rstart; + priv->num_i2c_bus = num_i2c_bus; + priv->i2cbuses_pdev = i2cbuses_pdev; + priv->regio_pdev = regio_pdev; + priv->spiflash_pdev = spiflash_pdev; + return 0; + +err_unregister_ocore: + for(i = 0; i < num_i2c_bus; i++){ + if(priv->i2cbuses_pdev[i]){ + platform_device_unregister(priv->i2cbuses_pdev[i]); + } + } +// err_unregister_spiflash: +// platform_device_unregister(spiflash_pdev); +err_unregister_regio: + platform_device_unregister(regio_pdev); +err_disable_device: + pci_disable_device(dev); +err_exit: + return err; +} + +static void cls_fpga_remove(struct pci_dev *dev) +{ + int i; + struct switchbrd_priv *priv = pci_get_drvdata(dev); + + for(i = 0; i < priv->num_i2c_bus; i++){ + if(priv->i2cbuses_pdev[i]) + platform_device_unregister(priv->i2cbuses_pdev[i]); + } + platform_device_unregister(priv->spiflash_pdev); + platform_device_unregister(priv->regio_pdev); + pci_disable_device(dev); + return; +}; + +static const struct pci_device_id pci_clsswbrd[] = { + { PCI_VDEVICE(XILINX, FPGA_PCIE_DEVICE_ID) }, + {0, } +}; + +MODULE_DEVICE_TABLE(pci, pci_clsswbrd); + +static struct pci_driver clsswbrd_pci_driver = { + .name = DRV_NAME, + .id_table = pci_clsswbrd, + .probe = cls_fpga_probe, + .remove = cls_fpga_remove, +}; + +module_pci_driver(clsswbrd_pci_driver); + +MODULE_AUTHOR("Pradchaya P."); +MODULE_DESCRIPTION("Celestica Silverstone switchboard driver"); +MODULE_VERSION(MOD_VERSION); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/mc24lc64t.c b/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/mc24lc64t.c new file mode 100644 index 000000000000..a391056d09a7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/mc24lc64t.c @@ -0,0 +1,142 @@ +/* + * mc24lc64t.c - driver for Microchip 24LC64T + * + * Copyright (C) 2017 Celestica 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 Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct mc24lc64t_data { + struct i2c_client *fake_client; + struct mutex update_lock; +}; + +static ssize_t mc24lc64t_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct i2c_client *client = kobj_to_i2c_client(kobj); + struct mc24lc64t_data *drvdata = i2c_get_clientdata(client); + unsigned long timeout, read_time, i = 0; + int status; + + mutex_lock(&drvdata->update_lock); + + if (i2c_smbus_write_byte_data(client, off>>8, off)) + { + status = -EIO; + goto exit; + } + + msleep(1); + +begin: + + if (i < count) + { + timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/ + do { + read_time = jiffies; + + status = i2c_smbus_read_byte(client); + if (status >= 0) + { + buf[i++] = status; + goto begin; + } + } while (time_before(read_time, timeout)); + + status = -ETIMEDOUT; + goto exit; + } + + status = count; + +exit: + mutex_unlock(&drvdata->update_lock); + + return status; +} + +static struct bin_attribute mc24lc64t_bit_attr = { + .attr = { + .name = "eeprom", + .mode = S_IRUGO, + }, + .size = 65536, + .read = mc24lc64t_read, +}; + +static int mc24lc64t_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = client->adapter; + struct mc24lc64t_data *drvdata; + int err; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA + | I2C_FUNC_SMBUS_READ_BYTE)) + return -EPFNOSUPPORT; + + if (!(drvdata = devm_kzalloc(&client->dev, + sizeof(struct mc24lc64t_data), GFP_KERNEL))) + return -ENOMEM; + + drvdata->fake_client = i2c_new_dummy(client->adapter, client->addr + 1); + if (!drvdata->fake_client) + return -ENOMEM; + + i2c_set_clientdata(client, drvdata); + mutex_init(&drvdata->update_lock); + + err = sysfs_create_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr); + if (err) + i2c_unregister_device(drvdata->fake_client); + + return err; +} + +static int mc24lc64t_remove(struct i2c_client *client) +{ + struct mc24lc64t_data *drvdata = i2c_get_clientdata(client); + + i2c_unregister_device(drvdata->fake_client); + + sysfs_remove_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr); + + return 0; +} + +static const struct i2c_device_id mc24lc64t_id[] = { + { "24lc64t", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mc24lc64t_id); + +static struct i2c_driver mc24lc64t_driver = { + .driver = { + .name = "mc24lc64t", + .owner = THIS_MODULE, + }, + .probe = mc24lc64t_probe, + .remove = mc24lc64t_remove, + .id_table = mc24lc64t_id, +}; + +module_i2c_driver(mc24lc64t_driver); + +MODULE_AUTHOR("Abhisit Sangjan "); +MODULE_DESCRIPTION("Microchip 24LC64T Driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/z9332f-modules.conf b/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/z9332f-modules.conf new file mode 100644 index 000000000000..b6d4fe4fb00a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/modules/z9332f-modules.conf @@ -0,0 +1,17 @@ +# /etc/modules: kernel modules to load at boot time. +# +# This file contains the names of kernel modules that should be loaded +# at boot time, one per line. Lines beginning with "#" are ignored. + +i2c-i801 +i2c-isch +i2c-ismt +i2c-dev +i2c-mux +i2c-smbus + +i2c-mux-gpio +i2c-mux-pca954x + +ipmi_devintf +ipmi_si diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/pcisysfs.py b/platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/pcisysfs.py new file mode 100755 index 000000000000..047618e057c8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/pcisysfs.py @@ -0,0 +1,102 @@ +#!/usr/bin/python +# Copyright (c) 2015 Dell Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. + +import struct +import sys +import getopt +from os import * +from mmap import * + +def usage(): + ''' This is the Usage Method ''' + + print '\t\t pcisysfs.py --get --offset --res ' + print '\t\t pcisysfs.py --set --val --offset --res ' + sys.exit(1) + +def pci_mem_read(mm,offset): + mm.seek(offset) + read_data_stream=mm.read(4) + print "" + reg_val=struct.unpack('I',read_data_stream) + print "reg_val read:%x"%reg_val + return reg_val + +def pci_mem_write(mm,offset,data): + mm.seek(offset) + print "data to write:%x"%data + mm.write(struct.pack('I',data)) + +def pci_set_value(resource,val,offset): + fd=open(resource,O_RDWR) + mm=mmap(fd,0) + pci_mem_write(mm,offset,val) + +def pci_get_value(resource,offset): + fd=open(resource,O_RDWR) + mm=mmap(fd,0) + pci_mem_read(mm,offset) + +def main(argv): + + ''' The main function will read the user input from the + command line argument and process the request ''' + + opts = '' + val = '' + choice = '' + resource = '' + offset = '' + + try: + opts, args = getopt.getopt(argv, "hgsv:" , \ + ["val=","res=","offset=","help", "get", "set"]) + + except getopt.GetoptError: + usage() + + for opt,arg in opts: + + if opt in ('-h','--help'): + choice = 'help' + + elif opt in ('-g', '--get'): + choice = 'get' + + elif opt in ('-s', '--set'): + choice = 'set' + + elif opt == '--res': + resource = arg + + elif opt == '--val': + val = int(arg,16) + + elif opt == '--offset': + offset = int(arg,16) + + if choice == 'set' and val != '' and offset !='' and resource !='': + pci_set_value(resource,val,offset) + + elif choice == 'get' and offset != '' and resource !='': + pci_get_value(resource,offset) + + else: + usage() + +#Calling the main method +if __name__ == "__main__": + main(sys.argv[1:]) + diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/platform_sensors.py new file mode 100755 index 000000000000..2fd2b84900da --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/platform_sensors.py @@ -0,0 +1,198 @@ +#!/usr/bin/python +# On Z9332F, the BaseBoard Management Controller is an +# autonomous subsystem provides monitoring and management +# facility independent of the host CPU. IPMI standard +# protocol is used with ipmitool to fetch sensor details. +# Current script support X00 board only. X01 support will +# be added soon. This provies support for the +# following objects: +# * Onboard temperature sensors +# * FAN trays +# * PSU + + +import os +import sys +import logging +import subprocess +import commands + +Z9332F_MAX_FAN_TRAYS = 7 +Z9332F_MAX_PSUS = 2 +IPMI_SENSOR_DATA = "ipmitool sdr list" +IPMI_SENSOR_DUMP = "/tmp/sdr" + +FAN_PRESENCE = "Fan{0}_Status" +PSU_PRESENCE = "PSU{0}_Status" +# Use this for older firmware +# PSU_PRESENCE="PSU{0}_prsnt" + +IPMI_PSU1_DATA_DOCKER = "ipmitool raw 0x04 0x2d 0x2f | awk '{print substr($0,9,1)}'" +IPMI_PSU2_DATA_DOCKER = "ipmitool raw 0x04 0x2d 0x39 | awk '{print substr($0,9,1)}'" + +ipmi_sdr_list = "" + +# Dump sensor registers + + +def ipmi_sensor_dump(): + + status = 1 + global ipmi_sdr_list + ipmi_cmd = IPMI_SENSOR_DATA + status, ipmi_sdr_list = commands.getstatusoutput(ipmi_cmd) + + if status: + logging.error('Failed to execute:' + ipmi_sdr_list) + sys.exit(0) + +# Fetch a BMC register + + +def get_pmc_register(reg_name): + + output = None + for item in ipmi_sdr_list.split("\n"): + if reg_name in item: + output = item.strip() + + if output is None: + print('\nFailed to fetch: ' + reg_name + ' sensor ') + sys.exit(0) + + output = output.split('|')[1] + + logging.basicConfig(level=logging.DEBUG) + return output + + +# Print the information for temperature sensors + + +def print_temperature_sensors(): + + print("\nOnboard Temperature Sensors:") + + for x in (('TEMP_FAN_U52', 'Fan U52'), + ('TEMP_FAN_U17', 'Fan U17'), + ('TEMP_SW_U52', 'SW U52'), + ('TEMP_SW_U16', 'SW U16'), + ('TEMP_BB_U3', 'Baseboard U3'), + ('TEMP_CPU', 'Near CPU'), + ('TEMP_SW_Internal', 'SW interal'), + ('PSU1_Temp1', 'PSU1 inlet'), + ('PSU1_Temp2', 'PSU1 hotspot'), + ('PSU2_Temp1', 'PSU2 inlet'), + ('PSU2_Temp2', 'PSU2 hotspot'), + ('SW_U04_Temp', 'SW U04'), + ('SW_U14_Temp', 'SW U14'), + ('SW_U4403_Temp', 'SW U4403') + ): + print ' {0:32}{1}'.format(x[1] + ':', get_pmc_register(x[0])) + +ipmi_sensor_dump() + +print_temperature_sensors() + +# Print the information for 1 Fan Tray + + +def print_fan_tray(tray): + + Fan_Status = [' Normal', ' Abnormal'] + Airflow_Direction = ['B2F', 'F2B'] + + print ' Fan Tray ' + str(tray) + ':' + + print ' Fan1 Speed: ',\ + get_pmc_register('Fan{}_Front'.format(tray)) + print ' Fan2 Speed: ',\ + get_pmc_register('Fan{}_Rear'.format(tray)) + print ' Fan State: ',\ + Fan_Status[int(get_pmc_register('Fan{}_Status'.format(tray)), 16)] + + +print('\nFan Trays:') + +for tray in range(1, Z9332F_MAX_FAN_TRAYS + 1): + fan_presence = FAN_PRESENCE.format(tray) + if (get_pmc_register(fan_presence)): + print_fan_tray(tray) + else: + print '\n Fan Tray ' + str(tray + 1) + ': Not present' + + def get_psu_presence(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 + ret_status = 1 + + if index == 1: + status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_PSU1_DATA_DOCKER) + elif index == 2: + ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_PSU2_DATA_DOCKER) + + #if ret_status: + # print ipmi_cmd_ret + # logging.error('Failed to execute ipmitool') + # sys.exit(0) + + psu_status = ipmi_cmd_ret + + if psu_status == '1': + status = 1 + + return status + + +# Print the information for PSU1, PSU2 +def print_psu(psu): + Psu_Type = ['Normal', 'Mismatch'] + Psu_Input_Type = ['AC', 'DC'] + PSU_STATUS_TYPE_BIT = 4 + PSU_STATUS_INPUT_TYPE_BIT = 1 + PSU_FAN_PRESENT_BIT = 2 + PSU_FAN_STATUS_BIT = 1 + PSU_FAN_AIR_FLOW_BIT = 0 + Psu_Fan_Presence = ['Present', 'Absent'] + Psu_Fan_Status = ['Normal', 'Abnormal'] + Psu_Fan_Airflow = ['B2F', 'F2B'] + + # print ' Input: ', Psu_Input_Type[psu_input_type] + # print ' Type: ', Psu_Type[psu_type] + + print ' PSU{}:'.format(psu) + print ' Inlet Temperature: ',\ + get_pmc_register('PSU{}_Temp1'.format(psu)) + print ' Hotspot Temperature: ',\ + get_pmc_register('PSU{}_Temp2'.format(psu)) + print ' FAN RPM: ',\ + get_pmc_register('PSU{}_Fan'.format(psu)) + # print ' FAN Status: ', Psu_Fan_Status[psu1_fan_status] + + # PSU input & output monitors + print ' Input Voltage: ',\ + get_pmc_register('PSU{}_VIn'.format(psu)) + print ' Output Voltage: ',\ + get_pmc_register('PSU{}_VOut'.format(psu)) + print ' Input Power: ',\ + get_pmc_register('PSU{}_PIn'.format(psu)) + print ' Output Power: ',\ + get_pmc_register('PSU{}_POut'.format(psu)) + print ' Input Current: ',\ + get_pmc_register('PSU{}_CIn'.format(psu)) + print ' Output Current: ',\ + get_pmc_register('PSU{}_COut'.format(psu)) + + +print('\nPSUs:') +for psu in range(1, Z9332F_MAX_PSUS + 1): + #psu_presence = PSU_PRESENCE.format(psu) + if (get_psu_presence(psu)): + print_psu(psu) + else: + print '\n PSU ', psu, 'Not present' diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/sensors b/platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/sensors new file mode 100755 index 000000000000..ee53f2b0f325 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/sensors @@ -0,0 +1,8 @@ +#!/bin/bash +docker exec -i pmon sensors "$@" +docker exec -i pmon /usr/bin/platform_sensors.py "$@" + +#To probe sensors not part of lm-sensors +#if [ -r /usr/local/bin/platform_sensors.py ]; then +# python /usr/local/bin/platform_sensors.py +#fi diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/z9332f_platform.sh b/platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/z9332f_platform.sh new file mode 100755 index 000000000000..ab2a787a6627 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/scripts/z9332f_platform.sh @@ -0,0 +1,180 @@ +#!/bin/bash + +init_devnum() { + found=0 + for devnum in 0; do + devname=`cat /sys/bus/i2c/devices/i2c-${devnum}/name` + # I801 adapter f000 + if [[ $devname == 'SMBus I801 adapter at '* ]]; then + found=1 + break + fi + done + + [ $found -eq 0 ] && echo "cannot find I801" && exit 1 +} + +# Attach/Detach syseeprom on CPU board +sys_eeprom() { + case $1 in + "new_device") echo 24lc64t 0x56 > /sys/bus/i2c/devices/i2c-0/$1 + ;; + "delete_device") echo 0x56 > /sys/bus/i2c/devices/i2c-0/$1 + ;; + *) echo "z9332f_platform: sys_eeprom : invalid command !" + ;; + esac +} + +#Attach/Detach the MUX connecting all QSFPs +switch_board_qsfp_mux() { + case $1 in + "new_device") + for ((i=603;i<=607;i++)); + do + echo "Attaching PCA9548 @ 0x74" + echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-$i/$1 + done + + ;; + "delete_device") + for ((i=603;i<=607;i++)); + do + echo "Detaching PCA9548 @ 0x74" + echo 0x74 > /sys/bus/i2c/devices/i2c-$i/$1 + done + + ;; + *) echo "z9332f_platform: switch_board_qsfp_mux: invalid command !" + ;; + esac + sleep 2 +} + +#Attach/Detach 64 instances of EEPROM driver QSFP ports +#eeprom can dump data using below command +switch_board_qsfp() { + case $1 in + "new_device") + for ((i=10;i<=41;i++)); + do + echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + done + ;; + + "delete_device") + for ((i=10;i<=41;i++)); + do + echo 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + done + ;; + + *) echo "z9332f_platform: switch_board_qsfp: invalid command !" + ;; + esac +} + +#Attach/Detach 2 instances of EEPROM driver SFP+ ports +#eeprom can dump data using below command +switch_board_sfp() { + case $1 in + "new_device") + for ((i=1;i<=2;i++)); + do + echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + done + ;; + + "delete_device") + for ((i=1;i<=2;i++)); + do + echo 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + done + ;; + + *) echo "z9332f_platform: switch_board_qsfp: invalid command !" + ;; + esac +} + +#Modsel 64 ports to applicable QSFP type modules +#This enables the adapter to respond for i2c commands +switch_board_modsel() { + resource="/sys/bus/pci/devices/0000:09:00.0/resource0" + for ((i=1;i<=32;i++)); + do + port_addr=$(( 16384 + ((i - 1) * 16))) + hex=$( printf "0x%x" $port_addr ) + python /usr/bin/pcisysfs.py --set --offset $hex --val 0x10 --res $resource > /dev/null 2>&1 + done +} + +#This enables the led control for CPU and default states +switch_board_led_default() { + /usr/sbin/i2cset -y 5 0x0d 0x62 0xd0 +} + +# Readout firmware version of the system and +# store in /var/log/firmware_versions +platform_firmware_versions() { + + FIRMWARE_VERSION_FILE=/var/log/firmware_versions + + rm -rf ${FIRMWARE_VERSION_FILE} + echo "BIOS:`dmidecode -t bios | grep Version | awk -F":" '{print $2}'`" > $FIRMWARE_VERSION_FILE + # Get FPGA version + r=`/usr/bin/pcisysfs.py --get --offset 0x00 --res /sys/bus/pci/devices/0000\:09\:00.0/resource0 | sed '1d; s/.*\(....\)$/\1/; s/\(..\{1\}\)/\1./'` + r_min=$(echo $r | sed 's/.*\(..\)$/0x\1/') + r_maj=$(echo $r | sed 's/^\(..\).*/0x\1/') + echo "FPGA: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE + + ## Get BMC Firmware Revision + #r=`docker exec -it pmon ipmitool mc info | awk '/Firmware Revision/ { print $NF }'` + r=`cat /sys/class/ipmi/ipmi0/device/bmc/firmware_revision` + echo "BMC: $r" >> $FIRMWARE_VERSION_FILE + + #BaseBoard CPLD 0x0d on i2c bus 5 ( physical FPGA I2C-5) + ver=`/usr/sbin/i2cget -y 5 0x0d 0x0` + echo "Baseboard CPLD: $((ver))" >> $FIRMWARE_VERSION_FILE + + #Switch CPLD 1 0x30 on i2c bus 4 ( physical FPGA I2C-4) + ver=`/usr/sbin/i2cget -y 4 0x30 0x0` + echo "Switch CPLD 1: $((ver))" >> $FIRMWARE_VERSION_FILE + + #Switch CPLD 1 0x30 on i2c bus 4 ( physical FPGA I2C-4) + ver=`/usr/sbin/i2cget -y 4 0x31 0x0` + echo "Switch CPLD 2: $((ver))" >> $FIRMWARE_VERSION_FILE +} +init_devnum + +if [ "$1" == "init" ]; then + modprobe i2c-dev + modprobe i2c-mux-pca954x force_deselect_on_exit=1 + modprobe ipmi_devintf + modprobe ipmi_si + modprobe cls-i2c-ocore + modprobe cls-switchboard + modprobe mc24lc64t + #insmod /lib/modules/`uname -r`/extra/mc24lc64t.ko + sys_eeprom "new_device" + switch_board_qsfp "new_device" + switch_board_sfp "new_device" + switch_board_led_default + # python /usr/bin/qsfp_irq_enable.py + platform_firmware_versions + +elif [ "$1" == "deinit" ]; then + sys_eeprom "delete_device" + switch_board_qsfp "delete_device" + switch_board_sfp "delete_device" + modprobe -r i2c-mux-pca954x + modprobe -r i2c-dev + modprobe -r ipmi_devintf + modprobe -r ipmi_si + modprobe -r cls-i2c-ocore + modprobe -r cls-switchboard + modprobe -r mc24lc64t +else + echo "z9332f_platform : Invalid option !" +fi + diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/systemd/platform-modules-z9332f.service b/platform/broadcom/sonic-platform-modules-dell/z9332f/systemd/platform-modules-z9332f.service new file mode 100644 index 000000000000..49064b00d682 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/systemd/platform-modules-z9332f.service @@ -0,0 +1,13 @@ +[Unit] +Description=Dell Z9332f Platform modules +Before=pmon.service +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/z9332f_platform.sh init +ExecStop=/usr/local/bin/z9332f_platform.sh deinit +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/src/sonic-device-data/tests/permitted_list b/src/sonic-device-data/tests/permitted_list index 370a920d2187..5bddb7a0ded7 100644 --- a/src/sonic-device-data/tests/permitted_list +++ b/src/sonic-device-data/tests/permitted_list @@ -2,6 +2,7 @@ arl_clean_timeout_usec asf_mem_profile bcm_linkscan_interval bcm_num_cos +default_cpu_tx_queue bcm_stat_flags bcm_stat_interval bcm_stat_jumbo From 9c4c36e1b5717446e12d119d1a487bf9611c9e89 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Thu, 19 Dec 2019 06:26:34 +0000 Subject: [PATCH 259/278] [broadom]: Upgrade broadcom SAI to 3.7.3.2 [Broadcom] : update saibcm-modules to sdk 6.5.16 [Broadcom SAI] : upgrade Broadcom SAI to 3.7.3.2 --- .../broadcom/docker-syncd-brcm/Dockerfile.j2 | 7 +- platform/broadcom/sai-modules.mk | 2 +- platform/broadcom/sai.mk | 10 +- .../broadcom/saibcm-modules/debian/changelog | 21 + .../debian/opennsl-modules.init | 26 +- .../debian/opennsl-modules.install | 1 + platform/broadcom/saibcm-modules/debian/rules | 6 +- .../broadcom/saibcm-modules/include/ibde.h | 8 - .../broadcom/saibcm-modules/include/kcom.h | 19 +- .../saibcm-modules/include/soc/devids.h | 313 +-- .../broadcom/saibcm-modules/make/Make.config | 7 +- .../saibcm-modules/make/Makefile.linux-gto | 6 - .../make/Makefile.linux-gto-2_6 | 6 - .../saibcm-modules/make/Makefile.linux-iproc | 8 +- .../make/Makefile.linux-kmodule | 2 +- .../make/Makefile.linux-x86-common-2_6 | 2 +- .../Makefile.linux-x86-generic-common-2_6 | 2 +- .../Makefile.linux-x86-smp_generic_64-2_6 | 1 - .../systems/bde/linux/include/linux-bde.h | 13 +- .../systems/bde/linux/include/linux_dma.h | 4 +- .../systems/bde/linux/kernel/Makefile | 24 +- .../bde/linux/kernel/linux-kernel-bde.c | 1287 ++---------- .../systems/bde/linux/kernel/linux_dma.c | 117 +- .../systems/bde/linux/shared/mpool.c | 133 +- .../bde/linux/user/kernel/linux-user-bde.c | 177 +- .../systems/bde/shared/shbde_iproc.c | 16 +- .../linux/kernel/modules/bcm-knet/bcm-knet.c | 1732 ++++++++++++++--- .../linux/kernel/modules/include/bcm-knet.h | 84 +- .../kernel/modules/include/net/psample.h | 24 + .../modules/include/uapi/linux/psample.h | 35 + .../linux/kernel/modules/knet-cb/Makefile | 4 +- .../linux/kernel/modules/knet-cb/knet-cb.c | 104 +- .../linux/kernel/modules/knet-cb/psample-cb.c | 875 +++++++++ .../linux/kernel/modules/knet-cb/psample-cb.h | 58 + .../linux/kernel/modules/psample/Makefile | 64 + .../linux/kernel/modules/psample/psample.c | 302 +++ .../systems/linux/user/common/Makefile | 21 + .../systems/linux/user/iproc/Makefile | 2 +- sonic-slave-stretch/Dockerfile.j2 | 4 +- 39 files changed, 3560 insertions(+), 1967 deletions(-) create mode 100644 platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/net/psample.h create mode 100644 platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/uapi/linux/psample.h create mode 100644 platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/psample-cb.c create mode 100644 platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/psample-cb.h create mode 100644 platform/broadcom/saibcm-modules/systems/linux/kernel/modules/psample/Makefile create mode 100644 platform/broadcom/saibcm-modules/systems/linux/kernel/modules/psample/psample.c diff --git a/platform/broadcom/docker-syncd-brcm/Dockerfile.j2 b/platform/broadcom/docker-syncd-brcm/Dockerfile.j2 index b20e353f842f..1ef1c588777c 100755 --- a/platform/broadcom/docker-syncd-brcm/Dockerfile.j2 +++ b/platform/broadcom/docker-syncd-brcm/Dockerfile.j2 @@ -1,3 +1,4 @@ +{% from "dockers/dockerfile-macros.j2" import install_debian_packages %} FROM docker-config-engine-stretch ARG docker_container_name @@ -14,10 +15,8 @@ debs/{{ deb }}{{' '}} {%- endfor -%} debs/ -RUN dpkg -i \ -{% for deb in docker_syncd_brcm_debs.split(' ') -%} -debs/{{ deb }}{{' '}} -{%- endfor %} +# Install locally-built Debian packages and implicitly install their dependencies +{{ install_debian_packages(docker_syncd_brcm_debs.split(' ')) }} ## TODO: add kmod into Depends RUN apt-get install -yf kmod diff --git a/platform/broadcom/sai-modules.mk b/platform/broadcom/sai-modules.mk index dc77c4b5cb78..1d559d0ad320 100644 --- a/platform/broadcom/sai-modules.mk +++ b/platform/broadcom/sai-modules.mk @@ -1,7 +1,7 @@ # Broadcom SAI modules KVERSION = 4.9.0-9-2-amd64 -BRCM_OPENNSL_KERNEL_VERSION = 3.4.1.11-1 +BRCM_OPENNSL_KERNEL_VERSION = 3.7.3.3-1 BRCM_OPENNSL_KERNEL = opennsl-modules_$(BRCM_OPENNSL_KERNEL_VERSION)_amd64.deb $(BRCM_OPENNSL_KERNEL)_SRC_PATH = $(PLATFORM_PATH)/saibcm-modules diff --git a/platform/broadcom/sai.mk b/platform/broadcom/sai.mk index 833c22f6bb94..63c1e21ec7fc 100644 --- a/platform/broadcom/sai.mk +++ b/platform/broadcom/sai.mk @@ -1,9 +1,9 @@ -BRCM_SAI = libsaibcm_3.5.3.1m-25_amd64.deb -$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm_3.5.3.1m-26_amd64.deb?sv=2015-04-05&sr=b&sig=zo83IKnlT7goymXwynW8%2Fx6rR2eIh0AiIS%2BSrSMUhRE%3D&se=2033-07-21T18%3A50%3A27Z&sp=r" +BRCM_SAI = libsaibcm_3.7.3.3_amd64.deb +$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.7/libsaibcm_3.7.3.3_amd64.deb?sv=2015-04-05&sr=b&sig=Y66VSRUEl4PDf5kHRo%2FS3DBBE9tONSyCzNJvi8IP9n8%3D&se=2033-08-25T01%3A22%3A08Z&sp=r" -BRCM_SAI_DEV = libsaibcm-dev_3.5.3.1m-25_amd64.deb +BRCM_SAI_DEV = libsaibcm-dev_3.7.3.3_amd64.deb $(eval $(call add_derived_package,$(BRCM_SAI),$(BRCM_SAI_DEV))) -$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/libsaibcm-dev_3.5.3.1m-26_amd64.deb?sv=2015-04-05&sr=b&sig=tQmkCIy2mnb9rH7B9oXFUZDwijMGXWnVtta2CNTMbFM%3D&se=2033-07-21T18%3A50%3A47Z&sp=r" +$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.7/libsaibcm-dev_3.7.3.3_amd64.deb?sv=2015-04-05&sr=b&sig=6%2BWzgFL845H9lKE0COsN53P4MO4UWfSo0z%2FmUMFbYVk%3D&se=2033-08-25T01%3A21%3A50Z&sp=r" SONIC_ONLINE_DEBS += $(BRCM_SAI) -$(BRCM_SAI_DEV)_DEPENDS += $(BRCM_SAI) +$(BRCM_SAI_DEV)_DEPENDS += $(BRCM_SAI) \ No newline at end of file diff --git a/platform/broadcom/saibcm-modules/debian/changelog b/platform/broadcom/saibcm-modules/debian/changelog index 5ea7b289ee65..2be513ed0435 100644 --- a/platform/broadcom/saibcm-modules/debian/changelog +++ b/platform/broadcom/saibcm-modules/debian/changelog @@ -1,3 +1,24 @@ +opennsl (3.7.3.3-1) unstable; urgency=medium + + * Port Broadcom SAI 3.7.3.3 + * Cherry-pick change from master branch, 3.7.3.3-1 + + -- Judy Joseph Fri, 2 Dec 2019 15:32:47 +0000 + +opennsl (3.7.3.2-1) unstable; urgency=medium + + * Port Broadcom SAI 3.7.3.2 + * Cherry-pick change from master branch, 3.7.3.2-1 + + -- Judy Joseph Fri, 12 Nov 2019 15:22:47 +0000 + +opennsl (3.7.3.1-1) unstable; urgency=medium + + * Port Broadcom SAI 3.7.3.1 + * Cherry-pick change from master branch, 3.7.3.1-1 + + -- Judy Joseph Fri, 19 Sep 2019 13:11:47 +0000 + opennsl (3.4.1.11-1) unstable; urgency=medium * Port Broadcom SAI 3.4.1.11 diff --git a/platform/broadcom/saibcm-modules/debian/opennsl-modules.init b/platform/broadcom/saibcm-modules/debian/opennsl-modules.init index 1aaa91bb2d82..7def10cbff86 100755 --- a/platform/broadcom/saibcm-modules/debian/opennsl-modules.init +++ b/platform/broadcom/saibcm-modules/debian/opennsl-modules.init @@ -32,14 +32,38 @@ function create_devices() # level logs function load_kernel_modules() { - modprobe linux-kernel-bde dmasize=32M maxpayload=128 debug=4 dma_debug=1 + . /host/machine.conf + + if [ -n "$aboot_platform" ]; then + platform=$aboot_platform + elif [ -n "$onie_platform" ]; then + platform=$onie_platform + else + platform="unknown" + fi + + # Set the default configuration for dmasize and usemsi parameters + dmasize=32M + usemsi=0 + + # Source the platform env file + env_file="/usr/share/sonic/device/$platform/platform_env.conf" + source $env_file + + modprobe linux-kernel-bde dmasize=$dmasize maxpayload=128 debug=4 dma_debug=1 usemsi=$usemsi modprobe linux-user-bde + + # Using insmod with absolute path for psample to make sure bcm psample is loaded. + # There is a different psample.ko module getting created at net/psample/psample.ko + insmod /lib/modules/$(uname -r)/extra/psample.ko + modprobe linux-bcm-knet use_rx_skb=1 rx_buffer_size=9238 debug=0x5020 modprobe linux-knet-cb } function remove_kernel_modules() { + rmmod psample.ko rmmod linux-knet-cb rmmod linux-bcm-knet rmmod linux-user-bde diff --git a/platform/broadcom/saibcm-modules/debian/opennsl-modules.install b/platform/broadcom/saibcm-modules/debian/opennsl-modules.install index 11b100d37f30..e16980dc2c0d 100644 --- a/platform/broadcom/saibcm-modules/debian/opennsl-modules.install +++ b/platform/broadcom/saibcm-modules/debian/opennsl-modules.install @@ -2,4 +2,5 @@ systems/linux/user/x86-smp_generic_64-2_6/linux-bcm-knet.ko lib/modules/4.9.0-9- systems/linux/user/x86-smp_generic_64-2_6/linux-kernel-bde.ko lib/modules/4.9.0-9-2-amd64/extra systems/linux/user/x86-smp_generic_64-2_6/linux-user-bde.ko lib/modules/4.9.0-9-2-amd64/extra systems/linux/user/x86-smp_generic_64-2_6/linux-knet-cb.ko lib/modules/4.9.0-9-2-amd64/extra +systems/linux/user/x86-smp_generic_64-2_6/psample.ko lib/modules/4.9.0-9-2-amd64/extra systemd/opennsl-modules.service lib/systemd/system diff --git a/platform/broadcom/saibcm-modules/debian/rules b/platform/broadcom/saibcm-modules/debian/rules index 33abe645d44a..0092cc1a1027 100755 --- a/platform/broadcom/saibcm-modules/debian/rules +++ b/platform/broadcom/saibcm-modules/debian/rules @@ -60,7 +60,7 @@ kdist_config: prep-deb-files kdist_clean: clean dh_testdir dh_clean - SDK=$(realpath .) LINUX_UAPI_SPLIT=1 DEBIAN_LINUX_HEADER=1 BUILD_KNET_CB=1 KERNDIR=/usr/src/linux-headers-4.9.0-9-2-amd64 KERNEL_SRC=/usr/src/linux-headers-4.9.0-9-2-amd64 $(MAKE) -C systems/linux/user/x86-smp_generic_64-2_6 clean + SDK=$(realpath .) LINUX_UAPI_SPLIT=1 DEBIAN_LINUX_HEADER=1 BUILD_KNET_CB=1 BUILD_PSAMPLE=1 KERNDIR=/usr/src/linux-headers-4.9.0-9-2-amd64 KERNEL_SRC=/usr/src/linux-headers-4.9.0-9-2-amd64 $(MAKE) -C systems/linux/user/x86-smp_generic_64-2_6 clean # rm -f driver/*.o driver/*.ko # ### end KERNEL SETUP @@ -78,7 +78,7 @@ build-arch-stamp: dh_testdir # Add here command to compile/build the package. - SDK=$(realpath .) LINUX_UAPI_SPLIT=1 DEBIAN_LINUX_HEADER=1 BUILD_KNET_CB=1 KERNDIR=/usr/src/linux-headers-4.9.0-9-2-amd64 KERNEL_SRC=/usr/src/linux-headers-4.9.0-9-2-amd64 $(MAKE) -C systems/linux/user/x86-smp_generic_64-2_6 + SDK=$(realpath .) LINUX_UAPI_SPLIT=1 DEBIAN_LINUX_HEADER=1 BUILD_KNET_CB=1 BUILD_PSAMPLE=1 KERNDIR=/usr/src/linux-headers-4.9.0-9-2-amd64 KERNEL_SRC=/usr/src/linux-headers-4.9.0-9-2-amd64 $(MAKE) -C systems/linux/user/x86-smp_generic_64-2_6 touch $@ @@ -103,7 +103,7 @@ clean: rm -f build-arch-stamp build-indep-stamp configure-stamp # Add here commands to clean up after the build process. - SDK=$(realpath .) LINUX_UAPI_SPLIT=1 DEBIAN_LINUX_HEADER=1 BUILD_KNET_CB=1 KERNDIR=/usr/src/linux-headers-4.9.0-9-2-amd64 KERNEL_SRC=/usr/src/linux-headers-4.9.0-9-2-amd64 $(MAKE) -C systems/linux/user/x86-smp_generic_64-2_6 clean + SDK=$(realpath .) LINUX_UAPI_SPLIT=1 DEBIAN_LINUX_HEADER=1 BUILD_KNET_CB=1 BUILD_PSAMPLE=1 KERNDIR=/usr/src/linux-headers-4.9.0-9-2-amd64 KERNEL_SRC=/usr/src/linux-headers-4.9.0-9-2-amd64 $(MAKE) -C systems/linux/user/x86-smp_generic_64-2_6 clean dh_clean diff --git a/platform/broadcom/saibcm-modules/include/ibde.h b/platform/broadcom/saibcm-modules/include/ibde.h index 9c8956f5e3e0..45112eadcb4b 100644 --- a/platform/broadcom/saibcm-modules/include/ibde.h +++ b/platform/broadcom/saibcm-modules/include/ibde.h @@ -148,14 +148,6 @@ typedef struct ibde_s { */ int (*get_cmic_ver)(int d, uint32 *ver); - /* - * Probe available devices. - * Return value : - * 0: success to probe available devices - * -1: error happens during probe - */ - int (*probe)(void); - /* * I2C operations on the Device, assuming it is connected by I2C to the CPU. */ diff --git a/platform/broadcom/saibcm-modules/include/kcom.h b/platform/broadcom/saibcm-modules/include/kcom.h index 76f3e47a8de5..1e3cad0753bc 100644 --- a/platform/broadcom/saibcm-modules/include/kcom.h +++ b/platform/broadcom/saibcm-modules/include/kcom.h @@ -121,6 +121,13 @@ typedef struct kcom_msg_hdr_s { #define KCOM_NETIF_NAME_MAX 16 +/* + * Max size of Sand System Headers + * For DNX, Module Header(20B) + PTCH(2B) + ITMH(5B) + * For DPP, PTCH(2B) + ITMH(4B) + */ +#define KCOM_NETIF_SYSTEM_HEADERS_SIZE_MAX 27 + typedef struct kcom_netif_s { uint16 id; uint8 type; @@ -133,6 +140,8 @@ typedef struct kcom_netif_s { uint8 macaddr[6]; uint8 ptch[2]; uint8 itmh[4]; + uint8 system_headers[KCOM_NETIF_SYSTEM_HEADERS_SIZE_MAX]; + uint8 system_headers_size; char name[KCOM_NETIF_NAME_MAX]; } kcom_netif_t; @@ -216,6 +225,13 @@ typedef struct kcom_filter_s { uint8 b[KCOM_FILTER_BYTES_MAX]; uint32 w[KCOM_FILTER_WORDS_MAX]; } mask; + /** Information to parse Dune system headers */ + uint32 ftmh_lb_key_ext_size; + uint32 ftmh_stacking_ext_size; + uint32 pph_base_size; + uint32 pph_lif_ext_size[8]; + uint8 udh_enable; + uint32 udh_length_type[4]; } kcom_filter_t; /* @@ -470,8 +486,7 @@ typedef struct kcom_msg_filter_destroy_s { * Get list of currently defined packet filters. */ #ifndef KCOM_FILTER_MAX -/* SAI_FIXUP - Increased the filters to 1024 from 128 */ -#define KCOM_FILTER_MAX 1024 +#define KCOM_FILTER_MAX 128 #endif typedef struct kcom_msg_filter_list_s { diff --git a/platform/broadcom/saibcm-modules/include/soc/devids.h b/platform/broadcom/saibcm-modules/include/soc/devids.h index cb072a78cbd7..7546ef392298 100644 --- a/platform/broadcom/saibcm-modules/include/soc/devids.h +++ b/platform/broadcom/saibcm-modules/include/soc/devids.h @@ -14,7 +14,7 @@ * version 2 (GPLv2) along with this source code. */ /* - * Copyright: (c) 2018 Broadcom. + * Copyright: (c) 2019 Broadcom. * All Rights Reserved. */ @@ -835,31 +835,6 @@ #define BCM56746_A0_REV_ID 1 #define BCM56746_A1_REV_ID 2 -#define BCM88230_DEVICE_ID 0x0230 -#define BCM88230_A0_REV_ID 1 -#define BCM88230_B0_REV_ID 0x11 -#define BCM88230_C0_REV_ID 0x21 -#define BCM88231_DEVICE_ID 0x0231 -#define BCM88231_A0_REV_ID 1 -#define BCM88231_B0_REV_ID 0x11 -#define BCM88231_C0_REV_ID 0x21 -#define BCM88235_DEVICE_ID 0x0235 -#define BCM88235_A0_REV_ID 1 -#define BCM88235_B0_REV_ID 0x11 -#define BCM88235_C0_REV_ID 0x21 -#define BCM88236_DEVICE_ID 0x0236 -#define BCM88236_A0_REV_ID 1 -#define BCM88236_B0_REV_ID 0x11 -#define BCM88236_C0_REV_ID 0x21 -#define BCM88239_DEVICE_ID 0x0239 -#define BCM88239_A0_REV_ID 1 -#define BCM88239_B0_REV_ID 0x11 -#define BCM88239_C0_REV_ID 0x21 -#define BCM56613_DEVICE_ID 0xb613 -#define BCM56613_A0_REV_ID 1 -#define BCM56613_B0_REV_ID 0x11 -#define BCM56613_C0_REV_ID 0x21 - #define BCM88732_DEVICE_ID 0x0732 #define BCM88732_A0_REV_ID 1 #define BCM88732_A1_REV_ID 2 @@ -1243,10 +1218,13 @@ #define BCM56981_A0_REV_ID 1 #define BCM56982_DEVICE_ID 0xb982 #define BCM56982_A0_REV_ID 1 +#define BCM56982_B0_REV_ID 0x11 #define BCM56983_DEVICE_ID 0xb983 #define BCM56983_A0_REV_ID 1 +#define BCM56983_B0_REV_ID 0x11 #define BCM56984_DEVICE_ID 0xb984 #define BCM56984_A0_REV_ID 1 +#define BCM56984_B0_REV_ID 0x11 #define BCM56968_DEVICE_ID 0xb968 #define BCM56968_A0_REV_ID 1 @@ -1428,33 +1406,43 @@ #define BCM56370_DEVICE_ID 0xb370 #define BCM56370_A0_REV_ID 1 +#define BCM56370_A1_REV_ID 0x02 #define BCM56371_DEVICE_ID 0xb371 #define BCM56371_A0_REV_ID 1 +#define BCM56371_A1_REV_ID 0x02 #define BCM56372_DEVICE_ID 0xb372 #define BCM56372_A0_REV_ID 1 +#define BCM56372_A1_REV_ID 0x02 #define BCM56374_DEVICE_ID 0xb374 #define BCM56374_A0_REV_ID 1 +#define BCM56374_A1_REV_ID 0x02 #define BCM56375_DEVICE_ID 0xb375 #define BCM56375_A0_REV_ID 1 +#define BCM56375_A1_REV_ID 0x02 #define BCM56376_DEVICE_ID 0xb376 #define BCM56376_A0_REV_ID 1 +#define BCM56376_A1_REV_ID 0x02 #define BCM56377_DEVICE_ID 0xb377 #define BCM56377_A0_REV_ID 1 +#define BCM56377_A1_REV_ID 0x02 #define BCM56577_DEVICE_ID 0xb577 #define BCM56577_A0_REV_ID 1 +#define BCM56577_A1_REV_ID 0x02 #define BCM56578_DEVICE_ID 0xb578 #define BCM56578_A0_REV_ID 1 +#define BCM56578_A1_REV_ID 0x02 #define BCM56579_DEVICE_ID 0xb579 #define BCM56579_A0_REV_ID 1 +#define BCM56579_A1_REV_ID 0x02 #define BCM56770_DEVICE_ID 0xb770 #define BCM56770_A0_REV_ID 1 @@ -1488,247 +1476,6 @@ #define BROADCOM_PHYID_HIGH 0x0040 -#define BCM5338_PHYID_LOW 0x62b0 -#define BCM5338_A0_REV_ID 0 -#define BCM5338_A1_REV_ID 1 -#define BCM5338_B0_REV_ID 3 - -#define BCM5324_PHYID_LOW 0xbc20 -#define BCM5324_PHYID_HIGH 0x143 -#define BCM5324_A1_PHYID_HIGH 0x153 -#define BCM5324_DEVICE_ID 0xbc20 -#define BCM5324_A0_REV_ID 0 -#define BCM5324_A1_REV_ID 1 -#define BCM5324_A2_REV_ID 2 - -#define BCM5380_PHYID_LOW 0x6250 -#define BCM5380_A0_REV_ID 0 - -#define BCM5388_PHYID_LOW 0x6288 -#define BCM5388_A0_REV_ID 0 - -#define BCM5396_PHYID_LOW 0xbd70 -#define BCM5396_PHYID_HIGH 0x143 -#define BCM5396_DEVICE_ID 0x96 -#define BCM5396_A0_REV_ID 0 - -#define BCM5389_PHYID_LOW 0xbd70 -#define BCM5389_PHYID_HIGH 0x143 -#define BCM5389_DEVICE_ID 0x89 -#define BCM5389_A0_REV_ID 0 -#define BCM5389_A1_DEVICE_ID 0x86 -#define BCM5389_A1_REV_ID 1 - -#define BCM5398_PHYID_LOW 0xbcd0 -#define BCM5398_PHYID_HIGH 0x0143 -#define BCM5398_DEVICE_ID 0x98 -#define BCM5398_A0_REV_ID 0 - -#define BCM5325_PHYID_LOW 0xbc30 -#define BCM5325_PHYID_HIGH 0x143 -#define BCM5325_DEVICE_ID 0xbc30 -#define BCM5325_A0_REV_ID 0 -#define BCM5325_A1_REV_ID 1 - -#define BCM5348_PHYID_LOW 0xbe40 -#define BCM5348_PHYID_HIGH 0x0143 -#define BCM5348_DEVICE_ID 0x48 -#define BCM5348_A0_REV_ID 0 -#define BCM5348_A1_REV_ID 1 - -#define BCM5397_PHYID_LOW 0xbcd0 -#define BCM5397_PHYID_HIGH 0x0143 -#define BCM5397_DEVICE_ID 0x97 -#define BCM5397_A0_REV_ID 0 - -#define BCM5347_PHYID_LOW 0xbe40 -#define BCM5347_PHYID_HIGH 0x0143 -#define BCM5347_DEVICE_ID 0x47 -#define BCM5347_A0_REV_ID 0 - -#define BCM5395_PHYID_LOW 0xbcf0 -#define BCM5395_PHYID_HIGH 0x0143 -#define BCM5395_DEVICE_ID 0xbcf0 -#define BCM5395_A0_REV_ID 0 - -#define BCM53242_PHYID_LOW 0xbf10 -#define BCM53242_PHYID_HIGH 0x0143 -#define BCM53242_DEVICE_ID 0xbf10 -#define BCM53242_A0_REV_ID 0 -#define BCM53242_B0_REV_ID 4 -#define BCM53242_B1_REV_ID 5 - -#define BCM53262_PHYID_LOW 0xbf20 -#define BCM53262_PHYID_HIGH 0x0143 -#define BCM53262_DEVICE_ID 0xbf20 -#define BCM53262_A0_REV_ID 0 -#define BCM53262_B0_REV_ID 4 -#define BCM53262_B1_REV_ID 5 - -#define BCM53115_PHYID_LOW 0xbf80 -#define BCM53115_PHYID_HIGH 0x0143 -#define BCM53115_DEVICE_ID 0xbf80 -#define BCM53115_A0_REV_ID 0 -#define BCM53115_A1_REV_ID 1 -#define BCM53115_B0_REV_ID 2 -#define BCM53115_B1_REV_ID 3 -#define BCM53115_C0_REV_ID 8 - -#define BCM53118_PHYID_LOW 0xbfe0 -#define BCM53118_PHYID_HIGH 0x0143 -#define BCM53118_DEVICE_ID 0xbfe0 -#define BCM53118_A0_REV_ID 0 - -#define BCM53118_B0_REV_ID 4 -#define BCM53118_B1_REV_ID 5 - -#define BCM53280_PHYID_LOW 0x5e90 -#define BCM53280_PHYID_HIGH 0x0362 -#define BCM53280_DEVICE_ID (0x4 | BCM53280_PHYID_LOW) -#define BCM53280_A0_REV_ID 0 -#define BCM53280_B0_REV_ID 0x4 -#define BCM53280_B1_REV_ID 0x5 -#define BCM53280_B2_REV_ID 0x6 -#define BCM53286_DEVICE_ID (0x4 | BCM53280_PHYID_LOW) -#define BCM53288_DEVICE_ID (0xc | BCM53280_PHYID_LOW) -#define BCM53284_DEVICE_ID (0x7 | BCM53280_PHYID_LOW) -#define BCM53283_DEVICE_ID (0x6 | BCM53280_PHYID_LOW) -#define BCM53282_DEVICE_ID (0x5 | BCM53280_PHYID_LOW) -#define BCM53101_PHYID_LOW 0x5ed0 -#define BCM53101_PHYID_HIGH 0x0362 -#define BCM53101_DEVICE_ID 0x5ed0 -#define BCM53101_A0_REV_ID 0 -#define BCM53101_B0_REV_ID 4 - -#define BCM53125_PHYID_LOW 0x5f20 -#define BCM53125_PHYID_HIGH 0x0362 -#define BCM53125_DEVICE_ID 0x5f20 -#define BCM53125_A0_REV_ID 0 -#define BCM53125_B0_REV_ID 0x4 -#define BCM53125_MODEL_ID 0x53125 - -#define BCM53134_PHYID_LOW 0x5350 -#define BCM53134_PHYID_HIGH 0xAE02 -#define BCM53134_DEVICE_ID 0x5350 -#define BCM53134_A0_REV_ID 0x0 -#define BCM53134_B0_REV_ID 0x1 -#define BCM53134_B1_REV_ID 0x2 -#define BCM53134_A0_MODEL_ID 0x5035 -#define BCM53134_B0_MODEL_ID 0x5075 - -#define BCM53128_PHYID_LOW 0x5e10 -#define BCM53128_PHYID_HIGH 0x0362 -#define BCM53128_DEVICE_ID 0x5e10 -#define BCM53128_A0_REV_ID 0 -#define BCM53128_B0_REV_ID 0x4 -#define BCM53128_MODEL_ID 0x53128 - -#define BCM53600_PHYID_LOW 0x5f40 -#define BCM53600_PHYID_HIGH 0x0362 -#define BCM53600_DEVICE_ID (0x3 | BCM53600_PHYID_LOW) -#define BCM53600_A0_REV_ID 0 -#define BCM53602_DEVICE_ID (0x1 | BCM53600_PHYID_LOW) -#define BCM53603_DEVICE_ID (0x2 | BCM53600_PHYID_LOW) -#define BCM53604_DEVICE_ID (0x3 | BCM53600_PHYID_LOW) -#define BCM53606_DEVICE_ID (0x7 | BCM53600_PHYID_LOW) - -#define BCM89500_PHYID_LOW 0x5d30 -#define BCM89500_PHYID_HIGH 0x0362 -#define BCM89500_DEVICE_ID 0x9500 -#define BCM89501_DEVICE_ID 0x9501 -#define BCM89200_DEVICE_ID 0x9200 -#define BCM89500_A0_REV_ID 0 -#define BCM89500_B0_REV_ID 0x4 -#define BCM89500_MODEL_ID 0x89500 - -#define BCM53010_PHYID_LOW 0x8760 -#define BCM53010_PHYID_HIGH 0x600d -#define BCM53010_DEVICE_ID 0x3010 -#define BCM53011_DEVICE_ID 0x3011 -#define BCM53012_DEVICE_ID 0x3012 -#define BCM53010_A0_REV_ID 0 -#define BCM53010_A2_REV_ID 0x2 -#define BCM53010_MODEL_ID 0x53010 - -#define BCM53018_PHYID_LOW 0x87c0 -#define BCM53018_PHYID_HIGH 0x600d -#define BCM53017_DEVICE_ID 0x3016 -#define BCM53018_DEVICE_ID 0x3018 -#define BCM53019_DEVICE_ID 0x3019 -#define BCM53018_A0_REV_ID 0 -#define BCM53018_MODEL_ID 0x53016 - -#define BCM53020_PHYID_LOW 0x87f0 -#define BCM53020_PHYID_HIGH 0x600d -#define BCM53020_DEVICE_ID 0x8022 -#define BCM53022_DEVICE_ID 0x8022 -#define BCM53023_DEVICE_ID 0x8023 -#define BCM53025_DEVICE_ID 0x8025 -#define BCM58625_DEVICE_ID 0x8625 -#define BCM58622_DEVICE_ID 0x8622 -#define BCM58623_DEVICE_ID 0x8623 -#define BCM58525_DEVICE_ID 0x8525 -#define BCM58522_DEVICE_ID 0x8522 -#define BCM53020_A0_REV_ID 0 -#define BCM53020_MODEL_ID 0x3025 - -#define BCM4713_DEVICE_ID 0x4713 -#define BCM4713_A0_REV_ID 0 -#define BCM4713_A9_REV_ID 9 - -#define BCM53000_GMAC_DEVICE_ID 0x4715 -#define BCM53000_A0_REV_ID 0 - -#define BCM53010_GMAC_DEVICE_ID 0x4715 - -#define BCM53000PCIE_DEVICE_ID 0x5300 - -#define SANDBURST_VENDOR_ID 0x17ba -#define BME3200_DEVICE_ID 0x0280 -#define BME3200_A0_REV_ID 0x0000 -#define BME3200_B0_REV_ID 0x0001 -#define BM9600_DEVICE_ID 0x0480 -#define BM9600_A0_REV_ID 0x0000 -#define BM9600_B0_REV_ID 0x0010 -#define QE2000_DEVICE_ID 0x0300 -#define QE2000_A1_REV_ID 0x0001 -#define QE2000_A2_REV_ID 0x0002 -#define QE2000_A3_REV_ID 0x0003 -#define QE2000_A4_REV_ID 0x0004 -#define BCM88020_DEVICE_ID 0x0380 -#define BCM88020_A0_REV_ID 0x0000 -#define BCM88020_A1_REV_ID 0x0001 -#define BCM88020_A2_REV_ID 0x0002 -#define BCM88025_DEVICE_ID 0x0580 -#define BCM88025_A0_REV_ID 0x0000 -#define BCM88030_DEVICE_ID 0x0038 -#define BCM88030_A0_REV_ID 0x0001 -#define BCM88030_A1_REV_ID 0x0002 -#define BCM88030_B0_REV_ID 0x0011 -#define BCM88030_B1_REV_ID 0x0012 -#define BCM88034_DEVICE_ID 0x0034 -#define BCM88034_A0_REV_ID (BCM88030_A0_REV_ID) -#define BCM88034_A1_REV_ID (BCM88030_A1_REV_ID) -#define BCM88034_B0_REV_ID (BCM88030_B0_REV_ID) -#define BCM88034_B1_REV_ID (BCM88030_B1_REV_ID) -#define BCM88039_DEVICE_ID 0x0039 -#define BCM88039_A0_REV_ID (BCM88030_A0_REV_ID) -#define BCM88039_A1_REV_ID (BCM88030_A1_REV_ID) -#define BCM88039_B0_REV_ID (BCM88030_B0_REV_ID) -#define BCM88039_B1_REV_ID (BCM88030_B1_REV_ID) -#define BCM88130_DEVICE_ID 0x0480 -#define BCM88130_A0_REV_ID 0x0000 -#define BCM88130_A1_REV_ID 0x0001 -#define BCM88130_B0_REV_ID 0x0010 -#define PLX_VENDOR_ID 0x10b5 -#define PLX9656_DEVICE_ID 0x9656 -#define PLX9656_REV_ID 0x0000 -#define PLX9056_DEVICE_ID 0x9056 -#define PLX9056_REV_ID 0x0000 - -#define TK371X_DEVICE_ID 0x8600 -#define TK371X_A0_REV_ID 0x0 - #define GEDI_DEVICE_ID 0xa100 #define GEDI_REV_ID 0x0001 #define ARAD_DEVICE_ID 0x8650 @@ -1778,6 +1525,7 @@ #define DNXC_A0_REV_ID 0x0001 #define DNXC_A1_REV_ID 0x0002 #define DNXC_B0_REV_ID 0x0011 +#define DNXC_B1_REV_ID 0x0012 #define BCM88790_DEVICE_ID 0x8790 #define BCM88790_A0_REV_ID DNXC_A0_REV_ID #define BCM88790_B0_REV_ID DNXC_B0_REV_ID @@ -1933,9 +1681,34 @@ #define BCM88381_A0_REV_ID JERICHO_PLUS_A0_REV_ID #define JERICHO_2_DEVICE_ID 0x8690 -#define JERICHO_2_A0_REV_ID 0x0001 +#define JERICHO_2_A0_REV_ID DNXC_A0_REV_ID +#define JERICHO_2_B0_REV_ID DNXC_B0_REV_ID +#define JERICHO_2_B1_REV_ID DNXC_B1_REV_ID #define BCM88690_DEVICE_ID JERICHO_2_DEVICE_ID #define BCM88690_A0_REV_ID JERICHO_2_A0_REV_ID +#define BCM88690_B0_REV_ID JERICHO_2_B0_REV_ID +#define BCM88690_B1_REV_ID JERICHO_2_B1_REV_ID +#define BCM88691_DEVICE_ID 0x8691 +#define BCM88692_DEVICE_ID 0x8692 +#define BCM88693_DEVICE_ID 0x8693 +#define BCM88694_DEVICE_ID 0x8694 +#define BCM88695_DEVICE_ID 0x8695 +#define BCM88696_DEVICE_ID 0x8696 +#define BCM88697_DEVICE_ID 0x8697 +#define BCM88698_DEVICE_ID 0x8698 +#define BCM88699_DEVICE_ID 0x8699 +#define BCM8869A_DEVICE_ID 0x869A +#define BCM8869B_DEVICE_ID 0x869B +#define BCM8869C_DEVICE_ID 0x869C +#define BCM8869D_DEVICE_ID 0x869D +#define BCM8869E_DEVICE_ID 0x869E +#define BCM8869F_DEVICE_ID 0x869F +#define BCM_JR2_DEVID_MASK 0xFFF0 + +#define J2C_DEVICE_ID 0x8800 +#define J2C_A0_REV_ID DNXC_A0_REV_ID +#define BCM88800_DEVICE_ID J2C_DEVICE_ID +#define BCM88800_A0_REV_ID J2C_A0_REV_ID #define QAX_DEVICE_ID 0x8470 #define QAX_A0_REV_ID 0x0001 @@ -1964,6 +1737,7 @@ #define BCM88270_A1_REV_ID QUX_A1_REV_ID #define BCM88272_DEVICE_ID 0x8272 #define BCM88273_DEVICE_ID 0x8273 +#define BCM88274_DEVICE_ID 0x8274 #define BCM88278_DEVICE_ID 0x8278 #define BCM88279_DEVICE_ID 0x8279 @@ -2045,5 +1819,8 @@ #define ACP_PCI_VENDOR_ID 0x10ee #define ACP_PCI_DEVICE_ID 0x7011 #define ACP_PCI_REV_ID 0x0001 + +#define PLX9056_DEVICE_ID 0x9056 + #endif diff --git a/platform/broadcom/saibcm-modules/make/Make.config b/platform/broadcom/saibcm-modules/make/Make.config index b8fa17bda119..409a6a49b3f3 100644 --- a/platform/broadcom/saibcm-modules/make/Make.config +++ b/platform/broadcom/saibcm-modules/make/Make.config @@ -54,12 +54,7 @@ endif -include ${SDK}/make/Make.local ifdef ALL_CHIPS - ROBO_CHIPS = 1 ESW_CHIPS = 1 -else - ifndef ROBO_CHIPS - ESW_CHIPS = 1 - endif endif # ALL_CHIPS # @@ -166,7 +161,7 @@ CFLAGS += ${INCFLAGS} CXXFLAGS += ${INCFLAGS} CPPFLAGS += ${INCFLAGS} -CFLAGS += -DSAI_FIXUP -DBCM_PORT_DEFAULT_DISABLE -DBCM_VLAN_NO_DEFAULT_ETHER -DBCM_VLAN_NO_DEFAULT_CPU -DBCM_WARM_BOOT_SUPPORT -DSAL_CONFIG_FILE_DISABLE -DSAL_THREAD_NAME_PRINT_DISABLE -UKCOM_FILTER_MAX -DKCOM_FILTER_MAX=256 -DALPM_ENABLE -DOPENNSL_PHY_ROUTINES -DTH2_CPU_POOL_SETUP -DINCLUDE_L3 -DSAI_ONLY -DPRINT_TO_SYSLOG -D_SHR_PBMP_WIDTH=256 -DINCLUDE_DIAG_SHELL -DSTATIC=static -DLOG_TEST -DLOG_SAI -D_GNU_SOURCE +CFLAGS += -DSAI_FIXUP -UKCOM_FILTER_MAX -DKCOM_FILTER_MAX=1024 # # Debug #ifdef control diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-gto b/platform/broadcom/saibcm-modules/make/Makefile.linux-gto index 947c20e74f93..786b4cc26bc3 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-gto +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-gto @@ -74,12 +74,6 @@ modname_flags = $(if $(filter 1,$(words $(modname))),\ KFLAG_INCLD = $(TOOLCHAIN_BIN_DIR)/../lib/gcc/$(TARGET_ARCHITECTURE)/4.6.4/include ifdef BROADCOM_SVK -ifdef BCM_BME3200_B0 -PLX_PCI2LBUS=1 -endif -ifdef BCM_BM9600_B0 -PLX_PCI2LBUS=1 -endif ifeq ($PLX_PCI2LBUS, 1) CFLAGS += -DBCM_PLX9656_LOCAL_BUS -DBDE_LINUX_NON_INTERRUPTIBLE endif diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-gto-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-gto-2_6 index 4caa4902421f..56085c7a3cdd 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-gto-2_6 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-gto-2_6 @@ -224,12 +224,6 @@ endif endif ifdef BROADCOM_SVK -ifdef BCM_BME3200_B0 -PLX_PCI2LBUS=1 -endif -ifdef BCM_BM9600_B0 -PLX_PCI2LBUS=1 -endif ifeq ($PLX_PCI2LBUS, 1) CFLAGS += -DBCM_PLX9656_LOCAL_BUS -DBDE_LINUX_NON_INTERRUPTIBLE endif diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc index 7c0f9411f5e2..092e474e2563 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc @@ -27,11 +27,11 @@ endif # TARGET_ARCHITECTURE Compiler for target architecture # KERNDIR Kernel directory for iPROC-CMICd devices ifeq (BE,$(ENDIAN_MODE)) -TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/iproc-be/XLDK +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk50-be/XLDK32 TARGET_ARCHITECTURE:=armeb-broadcom-linux-uclibcgnueabi KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux else -TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/iproc/XLDK +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk50/XLDK32 TARGET_ARCHITECTURE:= arm-broadcom-linux-uclibcgnueabi KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux endif @@ -60,6 +60,8 @@ CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0 ENDIAN = LE_HOST=1 endif +CFLAGS += -fno-aggressive-loop-optimizations + CFGFLAGS += -D$(ENDIAN) -DIPROC_CMICD CFGFLAGS += -DBCM_PLATFORM_STRING=\"IPROC_CMICD\" @@ -80,7 +82,7 @@ basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))" modname_flags = $(if $(filter 1,$(words $(modname))),\ -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") -KFLAG_INCLD ?= $(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/lib/gcc/$(TARGET_ARCHITECTURE)/4.9.3/include +KFLAG_INCLD ?= $(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/lib/gcc/$(TARGET_ARCHITECTURE)/4.9.4/include ifeq (,$(KFLAGS)) KFLAGS := -D__LINUX_ARM_ARCH__=7 -D__KERNEL__ -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/arm/include -I$(KERNDIR)/arch/arm/include/generated -I$(KERNDIR)/arch/arm/mach-iproc/include -Wall -Wstrict-prototypes -Wno-trigraphs -Os -fno-strict-aliasing -fno-common -marm -mabi=aapcs-linux -fno-pic -pipe -msoft-float -ffreestanding -march=armv7-a -mfpu=vfp -mfloat-abi=softfp -fomit-frame-pointer -g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -mlong-calls diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-kmodule b/platform/broadcom/saibcm-modules/make/Makefile.linux-kmodule index 3ad11d169c64..540c497ea258 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-kmodule +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-kmodule @@ -71,7 +71,7 @@ $(KMODULE): rm -f *.o *.ko .*.cmd rm -fr .tmp_versions ln -s $(LIBDIR)/$(MODULE) $(PRE_COMPILED_OBJ)_shipped - echo "suppress warning" > .$(PRE_COMPILED_OBJ).cmd + if [ ! -f $(KERNBLDDIR)/NO_SUPRESS ]; then echo "# suppress warning" > .$(PRE_COMPILED_OBJ).cmd; fi $(MAKE) -C $(KERNBLDDIR) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) modules if [ ! -f Module.symvers ]; then echo "old kernel (pre-2.6.17)" > Module.symvers; fi cp -f $(KMODULE) $(LIBDIR) diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-common-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-common-2_6 index 07af2afcc93b..25e953136bc0 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-common-2_6 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-common-2_6 @@ -22,7 +22,7 @@ ENDIAN = LE_HOST=1 CFGFLAGS += -D$(ENDIAN) CFGFLAGS += -DBCM_PLATFORM_STRING=\"X86\" ifeq (,$(findstring -DSAL_BDE_DMA_MEM_DEFAULT,$(CFGFLAGS))) -CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=32 +CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=16 endif # Extra variables. diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-generic-common-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-generic-common-2_6 index ab342c12d210..bf0ea85d578e 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-generic-common-2_6 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-generic-common-2_6 @@ -48,4 +48,4 @@ AUTOCONF = $(KERNDIR)/include/linux/autoconf.h endif # gcc system include path -SYSINC = $(shell gcc -print-search-dirs | grep install | cut -c 10-)include +SYSINC = $(shell $(CC) -print-search-dirs | grep install | cut -c 10-)include diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 index bb0bbea536a3..bc0230ec8226 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 @@ -43,4 +43,3 @@ KFLAGS += -I$(KERNDIR_COMMON)/include -I$(KERNDIR_COMMON)/include/uapi -I$(KERND endif include ${SDK}/make/Makefile.linux-x86-common-2_6 - diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux-bde.h b/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux-bde.h index 927201bc1fd8..bdf7a56dcabb 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux-bde.h +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux-bde.h @@ -222,7 +222,7 @@ extern int lkbde_dev_instid_set(int d, uint32 instid); extern int lkbde_irq_mask_set(int d, uint32 addr, uint32 mask, uint32 fmask); extern int lkbde_irq_mask_get(int d, uint32 *mask, uint32 *fmask); -#if (defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT)) +#ifdef BCM_SAND_SUPPORT extern int lkbde_cpu_write(int d, uint32 addr, uint32 *buf); extern int lkbde_cpu_read(int d, uint32 addr, uint32 *buf); extern int lkbde_cpu_pci_register(int d); @@ -241,15 +241,12 @@ extern int lkbde_cpu_pci_register(int d); */ #define LKBDE_IPROC_REG 0x4000 -#if defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) +#ifdef BCM_SAND_SUPPORT #include #if defined(__DUNE_LINUX_BCM_CPU_PCIE__) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) #ifndef _SIMPLE_MEMORY_ALLOCATION_ #define _SIMPLE_MEMORY_ALLOCATION_ 1 #endif -#ifndef USE_LINUX_BDE_MMAP -#define USE_LINUX_BDE_MMAP 1 -#endif #endif #endif @@ -271,13 +268,9 @@ extern int lkbde_cpu_pci_register(int d); #define _SIMPLE_MEMORY_ALLOCATION_ 9 /* compile in the allocation method, but do not use it by default */ #endif -/* By default we use our private mmap only if /dev/mem mmap has restrictions */ +/* By default we use our private mmap for DMA pool */ #ifndef USE_LINUX_BDE_MMAP -#ifdef CONFIG_STRICT_DEVMEM #define USE_LINUX_BDE_MMAP 1 -#else -#define USE_LINUX_BDE_MMAP 0 -#endif #endif #endif /* __KERNEL__ */ diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux_dma.h b/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux_dma.h index bfbbceb2d8e7..3bf7488abce9 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux_dma.h +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux_dma.h @@ -58,7 +58,7 @@ #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) #endif -extern void _dma_init(int robo_switch, int dev_index); +extern void _dma_init(int dev_index); extern int _dma_cleanup(void); extern void _dma_pprint(void); extern uint32_t *_salloc(int d, int size, const char *name); @@ -68,7 +68,7 @@ extern int _sflush(int d, void *ptr, int length); extern sal_paddr_t _l2p(int d, void *vaddr); extern void *_p2l(int d, sal_paddr_t paddr); extern int _dma_pool_allocated(void); -extern int _dma_range_valid(unsigned long phys_addr, unsigned long size); +extern int _dma_mmap(struct file *filp, struct vm_area_struct *vma); #endif /* __KERNEL__ */ diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/Makefile b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/Makefile index 3d504a5665fa..aedd487b1f11 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/Makefile +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/Makefile @@ -33,33 +33,11 @@ LIBS = $(LIBDIR)/libkern.a BDE = linux-kernel-bde.o -ifdef ROBO_CHIPS -CFLAGS += -I$(ET_ROBO) -I${SDK}/include/shared/et -ET_ROBO = ${SDK}/systems/drv/et -endif - # need to add vpath sources -VPATH = ../shared $(ET_ROBO) +VPATH = ../shared # Add the srcs to be found by vpath LSRCS += mpool.c -ifdef ROBO_CHIPS -platformsplt = $(subst -, , ${platform}) # change hyphens to spaces -platformbase = $(word 1,${platformsplt}) - -ifeq ($(platformbase), keystone) - LSRCS += etc_robo_spi.c aiutils.c -else - ifeq ($(platformbase), keystone_le) - LSRCS += etc_robo_spi.c aiutils.c - else - ifeq ($(platformbase), iproc) - LSRCS += robo_srab.c robo_spi.c aiutils.c - endif - endif -endif # platformbase - -endif # ROBO_CHIPS # Add shared BDE sources VPATH += ../../shared diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux-kernel-bde.c b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux-kernel-bde.c index 1a04b2b52e9b..464a72bd3e41 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux-kernel-bde.c +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux-kernel-bde.c @@ -35,30 +35,22 @@ #include "linux_shbde.h" -#ifdef BCM_ROBO_SUPPORT -/* robo/et related header files */ -#include - -#include - -#if defined(KEYSTONE) -#include -#include -#include -#include -#elif defined(IPROC_CMICD) -#include -#include -#ifdef BCM_STARFIGHTER3_SUPPORT -#include -#endif -#include -#include -#else /* BCM4704 */ -#include -#include -#endif -#endif /* BCM_ROBO_SUPPORT */ + +#ifdef __GNUC__ +#if __GNUC__ == 8 +/* + * Prevent gcc 8.1.10 using a compiler inline memcpy even if using -fno-builtin or + * -fno-builtin-memcpy . + * __inline_memcpy and __memcpy are kernel functions that may be used instead, + * for either an inline or non-inline implementations of the function + */ +#define MEMCPY __inline_memcpy +#else +#define MEMCPY memcpy +#endif /* __GNUC__ == 8 */ +#else /* ifdef __GNUC__ */ +#define MEMCPY memcpy +#endif /* ifdef __GNUC__ */ #define PCI_USE_INT_NONE (-1) #define PCI_USE_INT_INTX (0) @@ -108,26 +100,6 @@ int msixcnt = 1; #define PCI_DEVICE_ID_PLX_9056 0x9056 #endif -/* local defined device IDs, refer to bcmdevs.h */ -#ifndef BCM53000_GMAC_ID -#define BCM53000_GMAC_ID 0x4715 /* 53003 gmac id */ -#endif -#ifndef BCM53010_GMAC_ID -#define BCM53010_GMAC_ID 0x4715 /* 5301x gmac id */ -#endif -#ifndef BCM47XX_ENET_ID -#define BCM47XX_ENET_ID 0x4713 /* 4710 enet */ -#endif -#ifndef BCM53010_CHIP_ID -#define BCM53010_CHIP_ID 0xcf12 /* 53010 chipcommon chipid */ -#endif -#ifndef BCM53018_CHIP_ID -#define BCM53018_CHIP_ID 0xcf1a /* 53018 chipcommon chipid */ -#endif -#ifndef BCM53020_CHIP_ID -#define BCM53020_CHIP_ID 0xcf1e /* 53020 chipcommon chipid */ -#endif - /* For 2.4.x kernel support */ #ifndef IRQF_SHARED #define IRQF_SHARED SA_SHIRQ @@ -186,14 +158,6 @@ MODULE_PARM_DESC(spifreq, "Force SPI Frequency for Keystone CPU (0 for default frequency)"); #endif -#if defined(BCM_EA_SUPPORT) -#if defined(BCM_TK371X_SUPPORT) -static int eadevices; -LKM_MOD_PARAM(eadevices, "i", int, 0); -MODULE_PARM_DESC(eadevices, -"Number of TK371X devices"); -#endif /* */ -#endif /* BCM_EA_SUPPORT */ /* Compatibility */ #ifdef LKM_2_4 @@ -203,7 +167,7 @@ MODULE_PARM_DESC(eadevices, #define IRQ_HANDLED #define SYNC_IRQ(_i) synchronize_irq() #else /* LKM_2_6 */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) #define _ISR_RET irqreturn_t #else #define _ISR_RET int @@ -212,6 +176,7 @@ MODULE_PARM_DESC(eadevices, #define _ISR_PARAMS(_i,_d,_r) int _i, void *_d #else #define _ISR_PARAMS(_i,_d,_r) int _i, void *_d, struct pt_regs *_r +typedef irqreturn_t (*irq_handler_t)(int _i, void *_d, struct pt_regs *_r); #endif #define SYNC_IRQ(_i) synchronize_irq(_i) char * ___strtok; @@ -364,7 +329,6 @@ static int _ndevices = 0; static int _switch_ndevices = 0; static int _ether_ndevices = 0; static int _cpu_ndevices = 0; -static int robo_switch = 0; #define VALID_DEVICE(_n) ((_n >= 0) && (_n < _ndevices)) @@ -375,48 +339,10 @@ static uint32 iproc_cmicx_irqs[IHOST_CMICX_MAX_INTRS]; #endif /* CPU MMIO area used with CPU cards provided on demo boards */ -#if (defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT)) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__)) +#if defined(BCM_SAND_SUPPORT) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__)) static void *cpu_address = NULL; #endif -#ifdef BCM_ROBO_SUPPORT - -/* for SPI access via bcm4710 core */ -static void *robo = NULL; -static void *sbh = NULL; - -#ifdef ALTA_ROBO_SPI - -extern void *alta_eth_spi_ctrl; - -extern int -robo_spi_read(void *cookie, uint16_t reg, uint8_t *buf, int len); - -extern int -robo_spi_write(void *cookie, uint16_t reg, uint8_t *buf, int len); - -#define ROBO_RREG(_robo, _dev, _page, _reg, _buf, _len) \ - robo_spi_read(_dev ? NULL : alta_eth_spi_ctrl, \ - (_page << 8) | (_reg), _buf, _len) -#define ROBO_WREG(_robo, _dev, _page, _reg, _buf, _len) \ - robo_spi_write(_dev ? NULL : alta_eth_spi_ctrl, \ - (_page << 8) | (_reg), _buf, _len) - -#else /* !ALTA_ROBO_SPI */ - -#if defined(KEYSTONE) || defined(IPROC_CMICD) -#define ROBO_RREG(_robo, _dev, _page, _reg, _buf, _len) \ - robo_rreg(_robo, _dev, _page, _reg, _buf, _len) -#define ROBO_WREG(_robo, _dev, _page, _reg, _buf, _len) \ - robo_wreg(_robo, _dev, _page, _reg, _buf, _len) -#else -#define ROBO_RREG(_robo, _dev, _page, _reg, _buf, _len) -#define ROBO_WREG(_robo, _dev, _page, _reg, _buf, _len) -#endif - -#endif /* ALTA_ROBO_SPI */ - -#endif /* BCM_ROBO_SUPPORT */ /* Broadcom BCM4704 */ #define BCM4704_VENDOR_ID 0x14E4 @@ -500,6 +426,17 @@ robo_spi_write(void *cookie, uint16_t reg, uint8_t *buf, int len); #define BCM58712_PCI_VENDOR_ID 0x14E4 #define BCM58712_PCI_DEVICE_ID 0x168E +/* Default gicd address if not available in DTB */ +#define IHOST_GICD_REG_ADDR 0x10781100 +#define IHOST_GICD_REG_REMAP_LEN 0x100 + +#define IHOST_GICD_REG_ADDR_VALID(d, addr) \ + (_devices[d].bde_dev.base_address1 && \ + (addr & 0xFFFFFF00) == _devices[d].phys_address1) + +#define IHOST_GICD_REG_ADDR_REMAP(d, addr) \ + (void *)(_devices[d].bde_dev.base_address1 + (addr - _devices[d].phys_address1)) + static uint32_t _read(int d, uint32_t addr); #ifdef BCM_ICS @@ -551,6 +488,19 @@ _parse_eb_args(char *str, char * format, ...) static void _bde_add_device(void) { + int add_switch_device = 0; + if (_devices[_ndevices].dev_type & BDE_SWITCH_DEV_TYPE) { + _switch_ndevices++; + add_switch_device = 1; + } else if (_devices[_ndevices].dev_type & BDE_ETHER_DEV_TYPE) { + _ether_ndevices++; + } else if (_devices[_ndevices].dev_type & BDE_CPU_DEV_TYPE) { + _cpu_ndevices++; + } else { + return; + } + _ndevices++; + /* * In order to be backward compatible with the user mode BDE * (specifically the interrupt IOCTLs) and the CM, switch devices @@ -558,7 +508,7 @@ _bde_add_device(void) * order), we let the non-switch device(s) drop down to the end of * the device array. */ - if (_switch_ndevices > 0) { + if (add_switch_device) { bde_ctrl_t tmp_dev; int i, s = 0; @@ -573,13 +523,12 @@ _bde_add_device(void) } _devices[i] = tmp_dev; } - } - /* Initialize device locks and dma */ - if (_ndevices > 0) { - spin_lock_init(&_devices[_ndevices-1].lock); - _dma_init(robo_switch, _ndevices-1); + _dma_init(_switch_ndevices-1); } + + /* Initialize device locks */ + spin_lock_init(&_devices[_ndevices-1].lock); } static int @@ -590,8 +539,7 @@ _eb_device_create(resource_size_t paddr, int irq, int rd_hw, int wr_hw) dev_id = _ndevices; - ctrl = _devices + _ndevices++; - _switch_ndevices++; + ctrl = _devices + _ndevices; ctrl->dev_type |= BDE_EB_DEV_TYPE | BDE_SWITCH_DEV_TYPE; ctrl->pci_device = NULL; /* No PCI bus */ @@ -617,15 +565,15 @@ _eb_device_create(resource_size_t paddr, int irq, int rd_hw, int wr_hw) ctrl->isr = NULL; ctrl->isr_data = NULL; - _bde_add_device(); - gprintk("Created EB device at BA=%x IRQ=%d RD16=%d WR16=%d device=0x%x\n", (unsigned int)paddr, irq, rd_hw, wr_hw, ctrl->bde_dev.device); + _bde_add_device(); + return 0; } -#if defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT) +#ifdef BCM_SAND_SUPPORT #include @@ -637,9 +585,6 @@ sand_device_create(void) ctrl = _devices; /* FIX_ME: on petra, take first device */ #ifndef __DUNE_LINUX_BCM_CPU_PCIE__ - _switch_ndevices++; - _ndevices++; - ctrl->dev_type |= BDE_PCI_DEV_TYPE | BDE_SWITCH_DEV_TYPE; ctrl->pci_device = NULL; /* No PCI bus */ @@ -677,7 +622,7 @@ sand_device_create(void) return 0; } -#endif +#endif /* BCM_SAND_SUPPORT */ #ifdef IPROC_CMICD static void @@ -739,8 +684,7 @@ iproc_cmicd_probe(struct platform_device *pldev) } size = memres->end - memres->start + 1; - ctrl = _devices + _ndevices++; - _switch_ndevices++; + ctrl = _devices + _ndevices; ctrl->dev_type = BDE_AXI_DEV_TYPE | BDE_SWITCH_DEV_TYPE | BDE_256K_REG_SPACE; ctrl->pci_device = NULL; /* No PCI bus */ @@ -764,6 +708,24 @@ iproc_cmicd_probe(struct platform_device *pldev) ctrl->bde_dev.device = readl(icfg_chip_id) & 0xffff; ctrl->bde_dev.rev = readl(icfg_chip_id+1) & 0xff; iounmap(icfg_chip_id); + /* Map GICD block in the AXI memory space into CPU address space */ + memres = iproc_platform_get_resource(pldev, IORESOURCE_MEM, 1); + if (memres) { + ctrl->bde_dev.base_address1 = (sal_vaddr_t)IOREMAP(memres->start, memres->end - memres->start + 1); + ctrl->phys_address1 = memres->start; + } else { + /* Use default address if not available in DTB */ + ctrl->bde_dev.base_address1 = (sal_vaddr_t)IOREMAP(IHOST_GICD_REG_ADDR, IHOST_GICD_REG_REMAP_LEN); + ctrl->phys_address1 = IHOST_GICD_REG_ADDR; + } + if (ctrl->bde_dev.base_address1) { + if (debug >= 1) { + gprintk("base_address1:0x%lx phys_address1:0x%lx\n", + (unsigned long)ctrl->bde_dev.base_address1, (unsigned long)ctrl->phys_address1); + } + } else { + gprintk("Error mapping ihost GICD registers\n"); + } } else #endif { @@ -777,6 +739,7 @@ iproc_cmicd_probe(struct platform_device *pldev) ctrl->bde_dev.device = dev_rev_id & 0xffff; ctrl->bde_dev.rev = (dev_rev_id >> 16) & 0xff; #endif + ctrl->bde_dev.base_address1 = 0; } #ifdef CONFIG_OF @@ -901,10 +864,6 @@ iproc_has_cmicd(void) /* Only allowed accessing CMICD module if the SOC has it */ switch (cca_cid) { - case BCM53010_CHIP_ID: - case BCM53018_CHIP_ID: - case BCM53020_CHIP_ID: - return 0; default: break; } @@ -1052,8 +1011,7 @@ _ics_bde_create(void) resource_size_t paddr; if (_ndevices == 0) { - ctrl = _devices + _ndevices++; - _switch_ndevices++; + ctrl = _devices + _ndevices; ctrl->dev_type |= BDE_ICS_DEV_TYPE | BDE_SWITCH_DEV_TYPE; ctrl->pci_device = NULL; /* No PCI bus */ @@ -1072,8 +1030,8 @@ _ics_bde_create(void) ctrl->isr = NULL; ctrl->isr_data = NULL; - _bde_add_device(); printk("Created ICS device ..%x\n", ctrl->bde_dev.base_address); + _bde_add_device(); } return 0; @@ -1248,7 +1206,6 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM56150_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56151_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56152_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM56613_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56930_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56931_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -1301,14 +1258,6 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM56044_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56045_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56046_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88230_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88030_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88034_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88039_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88231_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88235_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88236_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88239_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM55440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56441_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -1450,15 +1399,6 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM56174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM53570_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM53575_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, -#ifdef BCM_ROBO_SUPPORT - { BROADCOM_VENDOR_ID, BCM47XX_ENET_ID, PCI_ANY_ID, PCI_ANY_ID }, -#ifdef KEYSTONE - { BROADCOM_VENDOR_ID, BCM53000_GMAC_ID, PCI_ANY_ID, PCI_ANY_ID }, -#endif -#endif - { SANDBURST_VENDOR_ID, QE2000_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { SANDBURST_VENDOR_ID, BCM88020_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { SANDBURST_VENDOR_ID, BCM88025_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9656, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056, PCI_ANY_ID, PCI_ANY_ID }, { BCM53000_VENDOR_ID, BCM53000PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -1506,6 +1446,7 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM88270_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88272_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88273_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88274_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88278_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88279_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -1524,7 +1465,6 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM88685_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88380_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88381_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88690_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88202_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88360_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88361_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -1537,6 +1477,25 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM88661_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88664_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, #endif +#ifdef BCM_DNX_SUPPORT + { BROADCOM_VENDOR_ID, BCM88690_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88690_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88691_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88692_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88693_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88694_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88695_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88696_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88697_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88698_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88699_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88800_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, +#endif /* BCM_DNX_SUPPORT */ #ifdef BCM_DFE_SUPPORT { BROADCOM_VENDOR_ID, BCM88750_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88753_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -2083,24 +2042,20 @@ _msi_connect(bde_ctrl_t *ctrl) #else ret = pci_enable_msix(ctrl->pci_device, ctrl->entries, ctrl->msix_cnt); -#endif if (ret > 0) { /* Not enough vectors available , Retry MSI-X */ gprintk("Retrying with MSI-X interrupts = %d\n", ret); ctrl->msix_cnt = ret; msixcnt = ret; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) - ret = pci_enable_msix_range(ctrl->pci_device, - ctrl->entries, ctrl->msix_cnt, ctrl->msix_cnt); -#else ret = pci_enable_msix(ctrl->pci_device, ctrl->entries, ctrl->msix_cnt); -#endif if (ret != 0) goto er_intx_free; - } else if (ret < 0) { - /* Error */ - goto er_intx_free; + } +#endif + if (ret < 0) { + /* Error */ + goto er_intx_free; } else { gprintk("Enabled MSI-X interrupts = %d\n", ctrl->msix_cnt); return 0; @@ -2228,13 +2183,12 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) int cmic_bar; int baroff = 0; int iproc = 0; - uint32 gmac_base = 0; int plx_dev = 0; int eth_dev = 0; int cpu_dev = 0; int update_devid = 0; int paxb_core = 0; - int rescan = 0, rescan_idx = -1; + int add_dev = 0, rescan = 0, rescan_idx = -1; shbde_hal_t shared_bde, *shbde = &shared_bde; if (debug >= 4) {gprintk("probing: vendor_id=0x%x, device_id=0x%x\n", dev->vendor, dev->device);} @@ -2280,17 +2234,6 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) case PCI_DEVICE_ID_PLX_9656: plx_dev = 1; break; -#if defined (BCM_ROBO_SUPPORT) && defined(KEYSTONE) - case BCM53000_GMAC_ID: - eth_dev = 1; - gmac_base = SB_ENUM_BASE; - break; -#endif -#if defined (BCM_ROBO_SUPPORT) - case BCM47XX_ENET_ID: - eth_dev = 1; - break; -#endif case BCM53000PCIE_DEVICE_ID: cpu_dev = 1; break; @@ -2332,10 +2275,10 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) if (_ether_ndevices >= LINUX_BDE_MAX_ETHER_DEVICES) { return 0;; } - ctrl = _devices + _ndevices++; - _ether_ndevices++; + ctrl = _devices + _ndevices; ctrl->dev_type |= BDE_ETHER_DEV_TYPE; ctrl->iLine = dev->irq; + add_dev = 1; if (debug >= 1) gprintk("Found PCI device %04x:%04x as Ethernet device\n", dev->vendor, dev->device); @@ -2343,9 +2286,9 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) if (_cpu_ndevices >= LINUX_BDE_MAX_CPU_DEVICES) { return 0;; } - ctrl = _devices + _ndevices++; - _cpu_ndevices++; + ctrl = _devices + _ndevices; ctrl->dev_type |= BDE_CPU_DEV_TYPE; + add_dev = 1; if (debug >= 1) gprintk("Found PCI device %04x:%04x as CPU device\n", dev->vendor, dev->device); @@ -2365,16 +2308,16 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) ctrl = _devices + rescan_idx; ctrl->dev_state = BDE_DEV_STATE_CHANGED; } else { - ctrl = _devices + _ndevices++; - _switch_ndevices++; + ctrl = _devices + _ndevices; ctrl->dev_type |= BDE_SWITCH_DEV_TYPE; ctrl->domain_no = pci_domain_nr(dev->bus); ctrl->bus_no = dev->bus->number; ctrl->dev_state = BDE_DEV_STATE_NORMAL; + add_dev = 1; } /* Save shared BDE HAL in device structure */ - memcpy(&ctrl->shbde, shbde, sizeof(ctrl->shbde)); + MEMCPY(&ctrl->shbde, shbde, sizeof(ctrl->shbde)); if (update_devid) { /* Re-read the device ID */ @@ -2675,42 +2618,8 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) } /* Save shared BDE HAL in device structure */ - memcpy(&ctrl->shbde, shbde, sizeof(ctrl->shbde)); - - - /* - * Since the GMAC driver of Robo chips needs access to the - * ChipCommon and Wrapper registers, we set the base address - * as the enumeration base address and its size as 3MB to - * cover all Wrapper register regions. - */ - if (gmac_base) { - uint32_t offset; - - ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(gmac_base, 0x300000); - - /* Record the base address of GMAC core */ - offset = ctrl->phys_address - gmac_base; - ctrl->alt_base_addr = ctrl->bde_dev.base_address + offset; - ctrl->phys_address = gmac_base; - } - - /* - * Workaround bug in FE2K A1 part; shows as A0 part in PCI config space, - * read the FE's regs directly to get the true revision - */ - if (ctrl->bde_dev.device == BCM88020_DEVICE_ID && ctrl->bde_dev.rev == 0) { -#define FE2000_REVISION_OFFSET (0x0) - uint32_t fe_rev; + MEMCPY(&ctrl->shbde, shbde, sizeof(ctrl->shbde)); - fe_rev = *((uint32_t*)(ctrl->bde_dev.base_address + FE2000_REVISION_OFFSET)); - if ((fe_rev >> 16) == BCM88020_DEVICE_ID) { - fe_rev &= 0xff; - } else { - fe_rev = (fe_rev >> 24) & 0xff; - } - ctrl->bde_dev.rev = fe_rev; - } ctrl->isr = NULL; ctrl->isr_data = NULL; @@ -2732,28 +2641,21 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) if (debug >= 1) gprintk("PCI resource len 8MB\n"); } -#if defined (BCM_ROBO_SUPPORT) && !defined(ALTA_ROBO_SPI) - /* MDC/MDIO path for pseudo PHY access to ROBO register on BCM5836/4704 */ - if (dev->device == BCM47XX_ENET_ID) { - ((uint32 *)ctrl->bde_dev.base_address)[0x410 / 4] = 0; - } -#endif #ifdef LINUX_BDE_DMA_DEVICE_SUPPORT ctrl->dma_dev = &dev->dev; #endif - if (!rescan) { - _bde_add_device(); - } - if (debug >= 2) { gprintk("_pci_probe: configured dev:0x%x rev:0x%x with base_addresses: 0x%lx 0x%lx\n", (unsigned)ctrl->bde_dev.device, (unsigned)ctrl->bde_dev.rev, (unsigned long)ctrl->bde_dev.base_address, (unsigned long)ctrl->bde_dev.base_address1); } - /* Let's boogie */ + if (add_dev) { + _bde_add_device(); + } + /* Let's boogie */ return 0; } @@ -2833,8 +2735,7 @@ static struct pci_driver _device_driver = { static void _spi_device_setup(void) { bde_ctrl_t *ctrl; - ctrl = _devices + _ndevices++; - _switch_ndevices++; + ctrl = _devices + _ndevices; ctrl->dev_type |= BDE_SWITCH_DEV_TYPE; ctrl->iLine = 0xa3; ctrl->be_pio = 0; @@ -2846,483 +2747,12 @@ _spi_device_setup(void) { gprintk("SPI Slave Mode: force ctrl->bde_dev.rev=0x%x\n",ctrl->bde_dev.rev); gprintk("SPI Slave Mode: force ctrl->dev_type=0x%x\n",ctrl->dev_type); } + _bde_add_device(); } #endif /* BCM_ICS */ -#ifdef BCM_ROBO_SUPPORT - -#ifdef KEYSTONE -#define DEFAULT_FREQ (SPI_FREQ_DEFAULT) -#define FREQ_20MHZ (SPI_FREQ_20MHZ) -#else /* IPROC_CMICD */ -#define DEFAULT_FREQ (0) -#define FREQ_20MHZ (0) -#endif - - -/* -* The model_info /rev_info for Robo devices is defined like this: -* -* 31 28 27 24 23 20 19 16 15 8 7 0 -* +----+---------+------+-----+---------+--------+ -* | op | reserved| mask |len | page |offset | -* +----+---------+------+-----+---------+--------+ -* -* op: 1:OR phyidl, 2: use PCIE device ID -* mlen: mask len (in bytes) 1:means 0xf,2 means 0xff -* len: Size of model/rev ID register (in bytes) -* page: Page containing model ID and revision registers -* offset: Model/rev ID register offset -*/ -static struct bde_spi_device_id _spi_id_table[] = { - { BCM53242_PHYID_HIGH, BCM53242_PHYID_LOW , 0, 0, DEFAULT_FREQ}, - { BCM53262_PHYID_HIGH, BCM53262_PHYID_LOW , 0, 0, DEFAULT_FREQ}, - { BCM53115_PHYID_HIGH, BCM53115_PHYID_LOW , 0, 0, DEFAULT_FREQ}, - { BCM53118_PHYID_HIGH, BCM53118_PHYID_LOW , 0, 0, DEFAULT_FREQ}, - { BCM53280_PHYID_HIGH, BCM53280_PHYID_LOW , 0x101800e8, 0, FREQ_20MHZ}, - { BCM53101_PHYID_HIGH, BCM53101_PHYID_LOW , 0, 0x110240, FREQ_20MHZ}, - { BCM53125_PHYID_HIGH, BCM53125_PHYID_LOW , 0, 0x110240, FREQ_20MHZ}, - { BCM53128_PHYID_HIGH, BCM53128_PHYID_LOW , 0, 0x110240, FREQ_20MHZ}, - { BCM53600_PHYID_HIGH, BCM53600_PHYID_LOW , 0x101800e8, 0, FREQ_20MHZ}, - { BCM89500_PHYID_HIGH, BCM89500_PHYID_LOW ,0x240230, 0x110240, FREQ_20MHZ}, - { BCM53010_PHYID_HIGH, BCM53010_PHYID_LOW ,0x240230, 0x110240, 0}, - { BCM53018_PHYID_HIGH, BCM53018_PHYID_LOW ,0x240230, 0x110240, 0}, - { BCM5389_PHYID_HIGH, BCM5389_PHYID_LOW, 0x110230, 0x110240, DEFAULT_FREQ}, - { BCM53020_PHYID_HIGH, BCM53020_PHYID_LOW ,0x20240230, 0x110240, 0}, - { BCM5396_PHYID_HIGH , BCM5396_PHYID_LOW, 0x110230, 0x110240, DEFAULT_FREQ}, - { BCM53134_PHYID_HIGH, BCM53134_PHYID_LOW , 0, 0x110240, DEFAULT_FREQ}, - { 0, 0, 0, 0, 0 }, -}; -#endif - -#ifdef BCM_ROBO_SUPPORT - -static int -_spi_device_valid_check(unsigned short phyidh,unsigned short phyidl, uint8 check_flag) -{ - struct bde_spi_device_id *_ids; - int idx, match_idx; - - match_idx = -1; - idx = 0; - - if (check_flag == 0){ - /* check_flag == 0 check phyidh only*/ - for (_ids = _spi_id_table; - _ids->phyid_high && _ids->phyid_low; _ids++){ - if (_ids->phyid_high == phyidh) { - return 0; - } - } - /* No valid SPI devices found */ - return 1; - } else { - while(_spi_id_table[idx].phyid_high){ - if (phyidh == _spi_id_table[idx].phyid_high && - phyidl == _spi_id_table[idx].phyid_low) { - /* Found a match */ - match_idx = idx; - break; - } - idx++; - } - return match_idx; - } -} - -#if defined(IPROC_CMICD) || defined(KEYSTONE) -#define ROBO_ATTACH_AVAIL -#endif - -#ifdef ROBO_ATTACH_AVAIL - -#define SOC_ATTACH(_sc)\ - ai_soc_kattach(_sc) - -#if defined(IPROC_CMICD) -#ifdef BCM_STARFIGHTER3_SUPPORT -#define ROBO_ATTACH_SPI(_sih, _ss)\ - robo_attach_spi(_sih) -#define ROBO_DETACH_SPI(robo)\ - robo_detach_spi(robo) -#define ROBO_SPI_RREG(_robo, _dev, _page, _reg, _buf, _len) \ - robo_spi_rreg(_robo, _dev, _page, _reg, _buf, _len) -#define ROBO_SPI_WREG(_robo, _dev, _page, _reg, _buf, _len) \ - robo_spi_wreg(_robo, _dev, _page, _reg, _buf, _len) -#endif -#define ROBO_ATTACH(_sih, _ss)\ - robo_attach(_sih) -#define MAX_BUSTYPE 1 -#define ROBO_SWITCH_BUS(_robo, _bustype) -#define ROBO_SELECT_DEVICE(_robo, _phyidh, _phyidl) -#else /* KEYSTONE */ -#define ROBO_ATTACH(_sih, _ss)\ - robo_attach(_sih, _ss) -/* bustype 2: ROBO_MDCMDIO_BUS, 1: ROBO_SPI_BUS */ -#define MAX_BUSTYPE 2 -#define ROBO_SWITCH_BUS(_robo, _bustype)\ - robo_switch_bus(_robo, _bustype) - -#define ROBO_SELECT_DEVICE(_robo, _phyidh, _phyidl) \ - robo_select_device(_robo, _phyidh, _phyidl) -#endif - -#else - -#define SOC_ATTACH(_sc) (NULL) -#define ROBO_ATTACH(_sih, _ss) (NULL) -#define MAX_BUSTYPE (0) -#define ROBO_SWITCH_BUS(_robo, _bustype) -#define ROBO_SELECT_DEVICE(_robo, _phyidh, _phyidl) -#endif - - -#if defined(IPROC_CMICD) && defined(BCM_STARFIGHTER3_SUPPORT) -static int -probe_robo_switch_iproc_spi(void) -{ - int dev; - int max_devices, max_bustype; - uint8 buf[8]; - unsigned short phyidh = 0, phyidl = 0; - - - /* Get Robo device handle */ - if (robo == NULL) { - robo = (void *)ROBO_ATTACH_SPI(sbh, 0); - } - if (robo == NULL) { - return -ENODEV; - } - - max_bustype = MAX_BUSTYPE + 1; - - while(_spi_device_valid_check(phyidh, 0, 0)) { - max_bustype --; - if(!max_bustype) - return -ENODEV; - buf[0] = buf[1] = 0; - ROBO_SPI_RREG(robo, 0, 0x10, 0x04, buf, (uint)2); - phyidh = buf[0] | (buf[1] << 8); - /* re-try */ - if ((phyidh == 0x0) || (phyidh == 0xffff)) { - ROBO_SPI_RREG(robo, 0, 0x10, 0x04, buf, (uint)2); - phyidh = buf[0] | (buf[1] << 8); - } - } - - /* For psedo_phy access, only support one robo switch*/ - /* For Northstar, only one switch on SRAB interface */ - max_devices = (max_bustype == MAX_BUSTYPE) ? 1 : LINUX_BDE_MAX_SWITCH_DEVICES; - - for (dev = 0; dev < max_devices; dev++) { - bde_ctrl_t *ctrl; - int match_idx, i; - unsigned short phyidl_nr; /* phyidl with revision stripped */ - uint16 model_id; - uint8 rev_id; - uint32 addr, len; - uint32 mlen; - - if (_switch_ndevices >= LINUX_BDE_MAX_SWITCH_DEVICES) { - break; - } - buf[0] = buf[1] = 0; - ROBO_SPI_RREG(robo, dev, 0x10, 0x04, buf, (uint)2); - phyidh = buf[0] | (buf[1] << 8); - - buf[0] = buf[1] = 0; - ROBO_SPI_RREG(robo, dev, 0x10, 0x06, buf, (uint)2); - phyidl = buf[0] | (buf[1] << 8); - - /* Strip revision */ - phyidl_nr = phyidl & 0xfff0; - - match_idx = _spi_device_valid_check(phyidh, phyidl_nr, 1); - if (match_idx == -1) { - if (debug >= 1) gprintk("found %d robo device(s).\n", robo_switch); - break; - } - - model_id = phyidl_nr; - - if(_spi_id_table[match_idx].rev_info){ - addr = _spi_id_table[match_idx].rev_info & 0xffff; - len = (_spi_id_table[match_idx].rev_info >> 16) & 0xf; - ROBO_SPI_RREG(robo, dev, (addr >> 8), (addr & 0xff), buf, (uint)len); - mlen = (_spi_id_table[match_idx].rev_info >> 20) & 0xf; - rev_id = 0; - for (i = 0; i < mlen; i++) - rev_id |= buf[i] << (i << 3); - } else { - rev_id = phyidl & 0xf; - } - - gprintk("found robo device with %d:%04x:%04x:%04x:%02x\n", - dev, phyidh, phyidl, model_id, rev_id); - - ROBO_SELECT_DEVICE(robo, phyidh, phyidl); - - /* Match supported chips */ - ctrl = _devices + _ndevices++; - _switch_ndevices++; - - if (NULL == (ctrl->spi_device = (struct spi_dev *) - KMALLOC(sizeof(struct spi_dev), GFP_KERNEL))) { - gprintk("no memory available"); - return -ENOMEM; - } - ctrl->dev_type = (BDE_SPI_DEV_TYPE | BDE_SWITCH_DEV_TYPE); - ctrl->spi_device->cid = dev; - ctrl->spi_device->part = model_id; - ctrl->spi_device->rev = rev_id; - ctrl->spi_device->robo = robo; - ctrl->spi_device->phyid_high = phyidh; - ctrl->spi_device->phyid_low = phyidl; - ctrl->bde_dev.device = model_id; - ctrl->bde_dev.rev = rev_id; - ctrl->bde_dev.base_address = (sal_vaddr_t)NULL; - ctrl->isr = NULL; - ctrl->isr_data = NULL; - robo_switch++; - _bde_add_device(); - - } - - return robo_switch; - -} - -int spi_device_found = 0; - -#endif /* IPROC_CMICD || SF3 */ - - -static int -probe_robo_switch(void) -{ - int dev; - int max_devices, max_bustype; - uint8 buf[8]; - unsigned short phyidh = 0, phyidl = 0; -#if defined(KEYSTONE) - uint32 spi_freq = 0; -#endif -#if defined(IPROC_CMICD) - sal_vaddr_t addr_base; - uint32 data_reg; -#endif /* IPROC_CMICD */ - - - spin_lock_init(&bus_lock); - - if (_switch_ndevices) { - /* - * Currently skip probe robo if esw chips were found - * FIX this while combined plateform support. - */ - return robo_switch; - } - - /* Get Robo device handle */ - if (robo == NULL) { - sbh = (void *)SOC_ATTACH(NULL); - if (sbh == NULL) { - return -ENODEV; - } - } - -#if defined(IPROC_CMICD) && defined(BCM_STARFIGHTER3_SUPPORT) - robo_switch = probe_robo_switch_iproc_spi(); - - if (robo_switch > 0) { - /* Robo switch found by SPI probe */ - spi_device_found = 1; - gprintk("SPI device found, Skipping SRAB probe\n"); - return robo_switch; - } else { - gprintk("SPI device NOT found, Probe SRAB probe\n"); - ROBO_DETACH_SPI(robo); - } -#endif - - if (robo == NULL) { - robo = (void *)ROBO_ATTACH(sbh, 0); - } - if (robo == NULL) { - return -ENODEV; - } - - max_bustype = MAX_BUSTYPE + 1; - - while(_spi_device_valid_check(phyidh, 0, 0)) { - max_bustype --; - if(!max_bustype) - return -ENODEV; - ROBO_SWITCH_BUS(robo, max_bustype); - buf[0] = buf[1] = 0; - ROBO_RREG(robo, 0, 0x10, 0x04, buf, (uint)2); - phyidh = buf[0] | (buf[1] << 8); - /* re-try */ - if ((phyidh == 0x0) || (phyidh == 0xffff)) { - ROBO_RREG(robo, 0, 0x10, 0x04, buf, (uint)2); - phyidh = buf[0] | (buf[1] << 8); - } - } - - /* For psedo_phy access, only support one robo switch*/ - /* For Northstar, only one switch on SRAB interface */ - max_devices = (max_bustype == MAX_BUSTYPE) ? 1 : LINUX_BDE_MAX_SWITCH_DEVICES; - - for (dev = 0; dev < max_devices; dev++) { - bde_ctrl_t *ctrl; - int match_idx, i; - unsigned short phyidl_nr; /* phyidl with revision stripped */ - uint16 model_id; - uint8 rev_id; -#if defined(KEYSTONE) || defined(IPROC_CMICD) - uint32 addr, len; -#endif - uint32 mlen, op; - - if (_switch_ndevices >= LINUX_BDE_MAX_SWITCH_DEVICES) { - break; - } - buf[0] = buf[1] = 0; - ROBO_RREG(robo, dev, 0x10, 0x04, buf, (uint)2); - phyidh = buf[0] | (buf[1] << 8); - - buf[0] = buf[1] = 0; - ROBO_RREG(robo, dev, 0x10, 0x06, buf, (uint)2); - phyidl = buf[0] | (buf[1] << 8); - - /* Strip revision */ - phyidl_nr = phyidl & 0xfff0; - - match_idx = _spi_device_valid_check(phyidh, phyidl_nr, 1); - if (match_idx == -1) { - if (debug >= 1) gprintk("found %d robo device(s).\n", robo_switch); - break; - } - - if(_spi_id_table[match_idx].model_info){ -#if defined(KEYSTONE) || defined(IPROC_CMICD) - addr = _spi_id_table[match_idx].model_info & 0xffff; - len = (_spi_id_table[match_idx].model_info >> 16) & 0xf; -#endif - ROBO_RREG(robo, dev, (addr >> 8), (addr & 0xff), buf, (uint)len); - mlen = (_spi_id_table[match_idx].model_info >> 20) & 0xf; - model_id = 0; - for (i = 0; i < mlen; i++) - model_id |= buf[i] << (i << 3); - op = (_spi_id_table[match_idx].model_info >> 28) & 0xf; - if(op == 1) { - model_id |= phyidl_nr; -#if defined(IPROC_CMICD) - } else if (op == 2) { - /* The package id of NS+ is determined by : - * Write 0 to 0x18012120 (PAXB_0_CONFIG_IND_ADDR) - * Read 0x18012124 (PAX_B_CONFIG_IND_DATA), - * bits 31:16 will be the device id from OTP space - */ -#define PAXB_ENUM_BASE (0x18012000) -#define PAXB_CONFIG_IND_ADDR_OFFSET (0x120) -#define PAXB_CONFIG_IND_DATA_OFFSET (0x124) - - addr_base = (sal_vaddr_t)IOREMAP(PAXB_ENUM_BASE, 0x1000); - if (!addr_base) { - gprintk("ioremap of PAXB registers failed\n"); - } else { - writel(0x0, (uint32 *)(addr_base + - PAXB_CONFIG_IND_ADDR_OFFSET)); - data_reg = readl((uint32 *)(addr_base + - PAXB_CONFIG_IND_DATA_OFFSET)); - model_id = (data_reg >> 16); - iounmap((void *)addr_base); - - /* - * Some model ID can't be determined by PCIE device ID - * It needs to refer some OTP values. - */ - robo_model_id_adjust_from_otp(robo, &model_id); - } - -#undef PAXB_ENUM_BASE -#undef PAXB_CONFIG_IND_ADDR_OFFSET -#undef PAXB_CONFIG_IND_DATA_OFFSET -#endif /* IPROC_CMICD */ - } - } else { - model_id = phyidl_nr; - } - if(_spi_id_table[match_idx].rev_info){ -#if defined(KEYSTONE) || defined(IPROC_CMICD) - addr = _spi_id_table[match_idx].rev_info & 0xffff; - len = (_spi_id_table[match_idx].rev_info >> 16) & 0xf; -#endif - ROBO_RREG(robo, dev, (addr >> 8), (addr & 0xff), buf, (uint)len); - mlen = (_spi_id_table[match_idx].rev_info >> 20) & 0xf; - rev_id = 0; - for (i = 0; i < mlen; i++) - rev_id |= buf[i] << (i << 3); - } else { - rev_id = phyidl & 0xf; - } - gprintk("found robo device with %d:%04x:%04x:%04x:%02x\n", - dev, phyidh, phyidl, model_id, rev_id); - - ROBO_SELECT_DEVICE(robo, phyidh, phyidl); - - /* Match supported chips */ - ctrl = _devices + _ndevices++; - _switch_ndevices++; - - if (NULL == (ctrl->spi_device = (struct spi_dev *) - KMALLOC(sizeof(struct spi_dev), GFP_KERNEL))) { - gprintk("no memory available"); - return -ENOMEM; - } - ctrl->dev_type = (BDE_SPI_DEV_TYPE | BDE_SWITCH_DEV_TYPE); - ctrl->spi_device->cid = dev; - ctrl->spi_device->part = model_id; - ctrl->spi_device->rev = rev_id; - ctrl->spi_device->robo = robo; - ctrl->spi_device->phyid_high = phyidh; - ctrl->spi_device->phyid_low = phyidl; - ctrl->bde_dev.device = model_id; - ctrl->bde_dev.rev = rev_id; - ctrl->bde_dev.base_address = (sal_vaddr_t)NULL; - ctrl->isr = NULL; - ctrl->isr_data = NULL; - robo_switch++; -#if defined(KEYSTONE) - spi_freq = _spi_id_table[match_idx].spifreq; -#endif - _bde_add_device(); - } - -#if defined(KEYSTONE) - /* Override the SPI frequency from user configuration */ - if (spifreq != 0) { - spi_freq = spifreq; - } - if (spi_freq != 0) { - /* - * The underlying chip can support the SPI frequency - * higher than default (2MHz). - */ - if (spi_freq != SPI_FREQ_DEFAULT) { - chipc_spi_set_freq(robo, 0, spi_freq); - } - } -#endif - return robo_switch; - -} - -#endif #if defined(BCM_METROCORE_LOCAL_BUS) static bde_ctrl_t* @@ -3330,8 +2760,7 @@ map_local_bus(uint64_t addr, uint32_t size) { bde_ctrl_t *ctrl; - ctrl = _devices + _ndevices++; - _switch_ndevices++; + ctrl = _devices + _ndevices; /* * For now: use EB type as `local bus' @@ -3347,7 +2776,6 @@ map_local_bus(uint64_t addr, uint32_t size) ctrl->phys_address = addr; _bde_add_device(); - return(ctrl); } @@ -3355,106 +2783,6 @@ map_local_bus(uint64_t addr, uint32_t size) #endif - -#ifdef BCM_METROCORE_LOCAL_BUS - /* - * SBX platform has both PCI- and local bus-attached devices - * The local bus devices have fixed address ranges (and don't - * support or require DMA), but are otherwise the same as PCI devices - */ -#define FPGA_IRQ 37 -#define FPGA_PHYS 0x100E0000 -#define BME_PHYS 0x100C0000 -#define SE_PHYS 0x100D0000 -#define FPGA_SIZE 0x00004000 -#define BME_SIZE 0x00004000 -#define MAC0_PHYS 0x100B0000 -#define MAC1_PHYS 0x100B8000 -#define MAC_SIZE 0x800 - - -/* - * Please refer to "Supervisor Fabric Module (SFM) Specification" - * page 23 for the following registers. - */ -#define FPGA_LC_POWER_DISABLE_OFFSET 0x4 -#define FPGA_LC_POWER_DISABLE_ENABLE_ALL_MASK 0x1e - -#define FPGA_LC_POWER_RESET_OFFSET 0x5 -#define FPGA_LC_POWER_RESET_ENABLE_ALL_MASK 0x1e - -#define FPGA_SW_SFM_MASTER_MODE_OFFSET 0x14 -#define FPGA_SW_SFM_MASTER_MODE_ENABLE_MASK 0x10 - - -static int -probe_metrocore_local_bus(void) { - bde_ctrl_t *ctrl; - uint32_t dev_rev_id; - VOL uint8_t *fpga; - - /* - * Write the FPGA on the fabric card, to let metrocore - * line cards out of reset. We actually don't bother to determine whether - * the card is a line card or a fabric card because when we do - * this on the line cards, it has no effect. - */ - fpga = (uint8_t *) IOREMAP(FPGA_PHYS, FPGA_SIZE); - fpga[FPGA_SW_SFM_MASTER_MODE_OFFSET] - |= FPGA_SW_SFM_MASTER_MODE_ENABLE_MASK; - fpga[FPGA_LC_POWER_DISABLE_OFFSET] - |= FPGA_LC_POWER_DISABLE_ENABLE_ALL_MASK; - fpga[FPGA_LC_POWER_RESET_OFFSET] - |= FPGA_LC_POWER_RESET_ENABLE_ALL_MASK; - - ctrl = map_local_bus(BME_PHYS, BME_SIZE); - - dev_rev_id = - *((uint32_t *) - (((uint8_t *) ctrl->bde_dev.base_address) + BME_REVISION_OFFSET)); - ctrl->bde_dev.device = dev_rev_id >> 16; - ctrl->bde_dev.rev = (dev_rev_id & 0xFF); - - if ((ctrl->bde_dev.device != BME3200_DEVICE_ID) && - (ctrl->bde_dev.device != BCM88130_DEVICE_ID)) { - gprintk("probe_metrocore_local_bus: wrong BME type: " - "0x%x (vs 0x%x or 0x%x)\n", - ctrl->bde_dev.device, BME3200_DEVICE_ID, BCM88130_DEVICE_ID); - return -1; - } - - ctrl->iLine = FPGA_IRQ; - ctrl->isr = NULL; - ctrl->isr_data = NULL; - - /* - * - * We start from SE & include the FPGA, which is 128k - */ - ctrl = map_local_bus(SE_PHYS, 128 * 1024); - - dev_rev_id = - *((uint32_t *) - (((uint8_t *) ctrl->bde_dev.base_address) + BME_REVISION_OFFSET)); - ctrl->bde_dev.device = dev_rev_id >> 16; - ctrl->bde_dev.rev = (dev_rev_id & 0xFF); - - if ((ctrl->bde_dev.device != BME3200_DEVICE_ID) && - (ctrl->bde_dev.device != BCM88130_DEVICE_ID)) { - gprintk("probe_metrocore_local_bus: wrong SE (BME) type: " - "0x%x (vs 0x%x)\n", - ctrl->bde_dev.device, BME3200_DEVICE_ID); - return -1; - } - - ctrl->iLine = FPGA_IRQ; - ctrl->isr = NULL; - ctrl->isr_data = NULL; - - return 0; -} -#endif - #ifdef BCM_PLX9656_LOCAL_BUS #if 1 @@ -3476,8 +2804,7 @@ map_local_bus2(bde_ctrl_t *plx_ctrl, uint32_t dev_base, uint32_t size) uint8_t *addr; bde_ctrl_t *ctrl; - ctrl = _devices + _ndevices++; - _switch_ndevices++; + ctrl = _devices + _ndevices; /* * For now: use EB type as `local bus' @@ -3499,15 +2826,11 @@ map_local_bus2(bde_ctrl_t *plx_ctrl, uint32_t dev_base, uint32_t size) ctrl->bde_dev.device = dev_rev_id >> 16; ctrl->bde_dev.rev = (dev_rev_id & 0xFF); + _bde_add_device(); switch (ctrl->bde_dev.device) { - case BCM88130_DEVICE_ID: - case BME3200_DEVICE_ID: - break; default: - gprintk("wrong BME type: 0x%x (vs 0x%x or 0x%x)\n", - ctrl->bde_dev.device, BME3200_DEVICE_ID, BCM88130_DEVICE_ID); return 0; } return(ctrl); @@ -3557,143 +2880,8 @@ probe_plx_local_bus(void) #endif /* BCM_PLX9656_LOCAL_BUS */ -#if defined(BCM_EA_SUPPORT) -#if defined(BCM_TK371X_SUPPORT) -static void -probe_tk371x_dev(void) -{ - bde_ctrl_t *ctrl; - int ea_uid=0; - /* eadevices is from the argument of insmod */ - for (ea_uid = 0; ea_uid < eadevices; ea_uid++) { - ctrl = _devices + _ndevices++; - _switch_ndevices++; - ctrl->dev_type = (BDE_MII_DEV_TYPE | BDE_SWITCH_DEV_TYPE); - ctrl->bde_dev.device = TK371X_DEVICE_ID; - ctrl->bde_dev.rev = 0x0; - ctrl->bde_dev.base_address = (sal_vaddr_t)NULL; - ctrl->iLine = 0; - } -} -#endif /* BCM_TK371X_SUPPORT*/ -#endif /* BCM_EA_SUPPORT */ - - -#if defined(BCM_ROBO_SUPPORT) -#if defined(IPROC_CMICD) -struct chip_device_info { - uint32 cc_base; /* Chip-common register base */ - uint32 cc_size; /* Chip-common register limit */ - uint32 cid_reg_off; /* Chip id register offset */ -}; - -static struct chip_device_info _chip_table = { -#if defined(IPROC_CMICD) - 0x18000000, 0x00000300, 0x00000000 -#else - 0,0,0 -#endif -}; - -struct gmac_device_info { - uint32 cid; /* chip id */ - uint32 rid; /* revision id */ - uint32 pid; /* package id */ - - uint32 gmac_dev_id; /* gmac core device id */ - uint32 gmac_base_addr; /* gmac core base address */ - int gmac_irq; /* gmac irq number */ -}; - -static struct gmac_device_info _gmac_table[] = { -#if defined(IPROC_CMICD) - {BCM53010_CHIP_ID, 0, 0, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53012 */ - {BCM53010_CHIP_ID, 0, 2, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53011 */ - {BCM53010_CHIP_ID, 0, 1, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53010 */ - {BCM53018_CHIP_ID, 0, 0, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53018 */ - {BCM53018_CHIP_ID, 0, 2, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53017 */ - {BCM53018_CHIP_ID, 0, 1, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53019 */ - {BCM53020_CHIP_ID, 0, 0, BCM53010_GMAC_ID, 0x18024000, 181}, /* BCM53022 */ - {BCM53020_CHIP_ID, 4, 0, BCM53010_GMAC_ID, 0x18023000, 180}, /* BCM53022 */ -#endif - {0,0,0,0,0,0} -}; - -static sal_vaddr_t _cca_base = 0; - -static int -_gmac_dev_create(void) -{ - bde_ctrl_t *ctrl; - uint32 gmac_base = 0; - uint32 offset = 0; - uint32 cca_cid; - uint32 cid, rid, pid; - int i = 0, found; - if (_chip_table.cc_base == 0) { - gprintk("Create GMAC device failed. Unable to identify CPU.\n"); - return -1; - } - - /* 1. Determine which CPU/GMAC configuration is now */ - _cca_base = (sal_vaddr_t)IOREMAP(_chip_table.cc_base, _chip_table.cc_size); - cca_cid = readl((uint32 *)(_cca_base + _chip_table.cid_reg_off)); - - cid = cca_cid & CID_ID_MASK; - rid = (cca_cid & CID_REV_MASK) >> CID_REV_SHIFT; - pid = (cca_cid & CID_PKG_MASK) >> CID_PKG_SHIFT; - - found = 0; - for (i = 0; ; i++) { - if (_gmac_table[i].cid == 0) { - /* End of table */ - break; - } - if ((_gmac_table[i].cid == cid) && - (_gmac_table[i].rid == rid) && - (_gmac_table[i].pid == pid)) { - /* found */ - found = 1; - break; - } - } - if (!found) { - gprintk("Create GMAC device failed. Unable to identify GMAC device.\n"); - } - - /* 2. Create GMAC device */ - /* fill-in necessary information depends on the CPU/GMAC configuration */ - if ((cid == BCM53010_CHIP_ID) || (cid == BCM53018_CHIP_ID) || - (cid == BCM53020_CHIP_ID)) { - ctrl = _devices + _ndevices++; - _ether_ndevices++; - - ctrl->dev_type |= BDE_ETHER_DEV_TYPE; - ctrl->dev_type |= BDE_PCI_DEV_TYPE; - - ctrl->iLine = _gmac_table[i].gmac_irq; - - ctrl->be_pio = 0; - - ctrl->bde_dev.rev = _gmac_table[i].rid; - ctrl->bde_dev.device = _gmac_table[i].gmac_dev_id; - - gmac_base = 0x18000000; - offset = _gmac_table[i].gmac_base_addr - gmac_base; - ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(gmac_base, 0x300000); - ctrl->alt_base_addr = ctrl->bde_dev.base_address + offset; - ctrl->phys_address = gmac_base; - - ctrl->isr = NULL; - ctrl->isr_data = NULL; - } - - return 0; -} -#endif -#endif /* * Generic module functions @@ -3738,13 +2926,6 @@ _init(void) /* Register our goodies */ _device_driver.name = LINUX_KERNEL_BDE_NAME; -#if defined(BCM_ROBO_SUPPORT) -#if defined(IPROC_CMICD) - if (_gmac_dev_create()) { - return -ENODEV; - } -#endif -#endif /* defined (BCM_ROBO_SUPPORT) */ /* Configure MSI interrupt support */ use_msi = usemsi; @@ -3797,17 +2978,11 @@ _init(void) #endif #endif /* BCM_ICS */ -#ifdef BCM_ROBO_SUPPORT - probe_robo_switch(); -#endif -#if defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT) +#ifdef BCM_SAND_SUPPORT sand_device_create(); #endif -#if defined(BCM_TK371X_SUPPORT) - probe_tk371x_dev(); -#endif /* * Probe for EB Bus devices. */ @@ -3863,24 +3038,6 @@ _cleanup(void) } #endif -#if defined(BCM_ROBO_SUPPORT) -#if defined(IPROC_CMICD) - if (_cca_base) { - iounmap((void *)_cca_base); - } -#endif - - if (robo) { -#if defined(KEYSTONE) || defined(IPROC_CMICD) - robo_detach(robo); -#endif /* KEYSTONE || IPROC_CMICD */ - } - if (sbh) { -#if defined(KEYSTONE) || defined(IPROC_CMICD) - ai_soc_detach(sbh); -#endif /* KEYSTONE || IPROC_CMICD */ - } -#endif for (i = 0; i < _ndevices; i++) { bde_ctrl_t *ctrl = _devices + i; @@ -3891,7 +3048,7 @@ _cleanup(void) } } } -#if (defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT)) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__)) +#if defined(BCM_SAND_SUPPORT) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__)) if (cpu_address) { /* unmap CPU card MMIO */ iounmap(cpu_address); cpu_address = NULL; @@ -3950,7 +3107,10 @@ _pprint(void) continue; } if (ctrl->dev_type & BDE_PCI_DEV_TYPE) { - pprintf("PCI device 0x%x:0x%x:%d:0x%.8lx:0x%.8lx:%d%s\n", + pprintf("PCI device %02x:%02x.%x 0x%x:0x%x:%d:0x%.8lx:0x%.8lx:%d%s\n", + (unsigned int)ctrl->pci_device->bus->number, + PCI_SLOT(ctrl->pci_device->devfn), + PCI_FUNC(ctrl->pci_device->devfn), ctrl->pci_device->vendor, ctrl->pci_device->device, ctrl->bde_dev.rev, @@ -3991,40 +3151,6 @@ _pprint(void) return 0; } -#if USE_LINUX_BDE_MMAP -/* - * Some kernels (mainly x86) prevent mapping of kernel RAM memory to - * user space via the /dev/mem device. The function below provides a - * backdoor to mapping the DMA pool to user space via the - * /dev/linux-kernel-bde device. - */ -static int _mmap(struct file *filp, struct vm_area_struct *vma) -{ - unsigned long phys_addr = vma->vm_pgoff << PAGE_SHIFT; - unsigned long size = vma->vm_end - vma->vm_start; - - if(!_dma_range_valid(phys_addr, size)) { - return -EINVAL; - } - -#ifdef REMAP_DMA_NONCACHED - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); -#endif - - if (remap_pfn_range(vma, - vma->vm_start, - vma->vm_pgoff, - size, - vma->vm_page_prot)) { - gprintk("Failed to mmap phys range 0x%lx-0x%lx to 0x%lx-0x%lx\n", - phys_addr, phys_addr + size, vma->vm_start,vma->vm_end); - return -EAGAIN; - } - - return 0; -} -#endif /* USE_LINUX_BDE_MMAP */ - /* Workaround for broken Busybox/PPC insmod */ static char _modname[] = LINUX_KERNEL_BDE_NAME; @@ -4034,9 +3160,7 @@ static gmodule_t _gmodule = { init: _init, cleanup: _cleanup, pprint: _pprint, -#if USE_LINUX_BDE_MMAP - mmap: _mmap, -#endif + mmap: _dma_mmap, }; gmodule_t * @@ -4336,7 +3460,7 @@ _interrupt_connect(int d, gprintk("%s(%d):device# = %d, irq = %d\n", __func__, __LINE__, d, ctrl->entries[i].vector); } - ret = request_irq(ctrl->entries[i].vector, _isr, 0, + ret = request_irq(ctrl->entries[i].vector, (irq_handler_t)_isr, 0, LINUX_KERNEL_BDE_NAME, ctrl); if (ret < 0) break; @@ -4358,7 +3482,7 @@ _interrupt_connect(int d, if (unlikely(debug >= 1)) gprintk("%s(%d):device# = %d, request_irq(%d)\n", __func__, __LINE__, d, iproc_cmicx_irqs[i]); - ret = request_irq(iproc_cmicx_irqs[i], _isr, + ret = request_irq(iproc_cmicx_irqs[i], (irq_handler_t)_isr, irq_flags, LINUX_KERNEL_BDE_NAME, ctrl); if (ret < 0) { gprintk("request_irq(%d) failed(%d)\n", iproc_cmicx_irqs[i], ret); @@ -4536,6 +3660,9 @@ _iproc_read(int d, uint32_t addr) } if (_devices[d].dev_type & BDE_AXI_DEV_TYPE) { + if (IHOST_GICD_REG_ADDR_VALID(d, addr)) { + return readl(IHOST_GICD_REG_ADDR_REMAP(d, addr)); + } return _iproc_ihost_read(d, addr); } @@ -4556,6 +3683,10 @@ _iproc_write(int d, uint32_t addr, uint32_t data) } if (_devices[d].dev_type & BDE_AXI_DEV_TYPE) { + if (IHOST_GICD_REG_ADDR_VALID(d, addr)) { + writel(data, IHOST_GICD_REG_ADDR_REMAP(d, addr)); + return 0; + } return _iproc_ihost_write(d, addr, data); } @@ -4626,126 +3757,7 @@ _get_cmic_ver(int d , uint32_t *ver) return -1; } -#ifdef BCM_ROBO_SUPPORT -#define SOC_ROBO_PAGE_BP 8 /* for Robo Chip only */ - -#if defined(IPROC_CMICD) -extern int ccb_mii_read(int dev_type, int phy_addr, int reg_off, uint16 *data); -extern int ccb_mii_write(int dev_type, int phy_addr, int reg_off, uint16 data); - -/* device type */ -#define MII_DEV_LOCAL 0 -#define MII_DEV_EXT 1 -#endif - -static int -_spi_read(int d, uint32 addr, uint8 *buf, int len) -{ -#if defined(KEYSTONE) || defined(IPROC_CMICD) - bde_ctrl_t *ctrl; - uint8 page, offset; -#endif -#if defined(IPROC_CMICD) - int rv = 0; - uint16 value = 0; -#endif - - if (!VALID_DEVICE(d)) { - return -1; - } - - if (!(_devices[d].dev_type & BDE_SPI_DEV_TYPE)) { - gprintk("_spi_read: Not SPI device %d, type %x\n", - d, _devices[d].dev_type); - return -1; - } - -#if defined(KEYSTONE) || defined(IPROC_CMICD) - ctrl = _devices + d; -#endif - -#if defined(IPROC_CMICD) - if (addr & SOC_EXTERNAL_PHY_BUS_CPUMDIO) { - rv = ccb_mii_read(MII_DEV_EXT, (addr >> 8) & 0xff, addr & 0xff, &value); - memcpy(buf, &value, 2); - return rv; - } -#endif - -#if defined(KEYSTONE) || defined(IPROC_CMICD) - page = (addr >> SOC_ROBO_PAGE_BP) & 0xFF; - offset = addr & 0xFF; -#endif - -#if defined(IPROC_CMICD) && defined(BCM_STARFIGHTER3_SUPPORT) - if (spi_device_found) { - ROBO_SPI_RREG(ctrl->spi_device->robo, ctrl->spi_device->cid, - page, offset, buf, (uint)len); - } else -#endif - { - ROBO_RREG(ctrl->spi_device->robo, ctrl->spi_device->cid, - page, offset, buf, (uint)len); - } - - return 0; -} - -static int -_spi_write(int d, uint32 addr, uint8 *buf, int len) -{ -#if defined(KEYSTONE) || defined(IPROC_CMICD) - bde_ctrl_t *ctrl; - uint8 page, offset; -#endif -#if defined(IPROC_CMICD) - int rv = 0; - uint16 value = 0; -#endif - if (!VALID_DEVICE(d)) { - return -1; - } - - if (!(_devices[d].dev_type & BDE_SPI_DEV_TYPE)) { - gprintk("_spi_write: Not SPI device %d, type %x\n", - d, _devices[d].dev_type); - return -1; - } - -#if defined(KEYSTONE) || defined(IPROC_CMICD) - ctrl = _devices + d; -#endif - -#if defined(IPROC_CMICD) - if (addr & SOC_EXTERNAL_PHY_BUS_CPUMDIO) { - memcpy(&value, buf, 2); - rv = ccb_mii_write(MII_DEV_EXT, (addr >> 8) & 0xff, addr & 0xff, value); - return rv; - } -#endif - -#if defined(KEYSTONE) || defined(IPROC_CMICD) - page = (addr >> SOC_ROBO_PAGE_BP) & 0xFF; - offset = addr & 0xFF; -#endif - -#if defined(IPROC_CMICD) && defined(BCM_STARFIGHTER3_SUPPORT) - if (spi_device_found) { - ROBO_SPI_WREG(ctrl->spi_device->robo, ctrl->spi_device->cid, - page, offset, buf, (uint)len); - } else -#endif - { - ROBO_WREG(ctrl->spi_device->robo, ctrl->spi_device->cid, - page, offset, buf, (uint)len); - } - - return 0; -} - -#endif - -#if defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT) +#ifdef BCM_SAND_SUPPORT int lkbde_cpu_write(int d, uint32 addr, uint32 *buf) { @@ -4853,7 +3865,7 @@ lkbde_cpu_pci_register(int d) case BCM88380_DEVICE_ID: case BCM88381_DEVICE_ID: case BCM88680_DEVICE_ID: - case BCM88690_DEVICE_ID: + case BCM88800_DEVICE_ID: case BCM88470_DEVICE_ID: case BCM88470P_DEVICE_ID: case BCM88471_DEVICE_ID: @@ -4865,6 +3877,7 @@ lkbde_cpu_pci_register(int d) case BCM88270_DEVICE_ID: case BCM88272_DEVICE_ID: case BCM88273_DEVICE_ID: + case BCM88274_DEVICE_ID: case BCM88278_DEVICE_ID: case BCM8206_DEVICE_ID: case BCM88350_DEVICE_ID: @@ -4902,6 +3915,22 @@ lkbde_cpu_pci_register(int d) break; } +#ifdef BCM_DNX_SUPPORT + /*All Jericho 2 devices from 0x8690 to 0x869F*/ + if (SOC_IS_JERICHO_2_TYPE(ctrl->bde_dev.device)) { + /* Fix bar 0 address */ /* FIXME: write full phy address */ + pci_write_config_byte(ctrl->pci_device, 0x12, 0x10); + pci_write_config_byte(ctrl->pci_device, 0x13, 0x60); + + /* + * For DMA transactions - set Max_Payload_Size and + * Max_Read_Request_Size to 128 bytes. + */ + pci_write_config_byte(ctrl->pci_device, 0xb5, 0x0c); + pci_write_config_byte(ctrl->pci_device, 0xb4, 0x0); + } +#endif + /* Redo ioremap */ if (ctrl->bde_dev.base_address) { iounmap((void *)ctrl->bde_dev.base_address); @@ -4955,7 +3984,7 @@ lkbde_mem_read(int d, uint32 addr, uint32 *buf) return 0; } LKM_EXPORT_SYM(lkbde_mem_read); -#endif /* defined(BCM_PETRA_SUPPORT) */ +#endif /* BCM_SAND_SUPPORT */ static ibde_t _ibde = { name: _name, @@ -4975,13 +4004,9 @@ static ibde_t _ibde = { interrupt_disconnect: _interrupt_disconnect, l2p: _l2p, p2l: _p2l, -#if defined(BCM_ROBO_SUPPORT) - spi_read: _spi_read, - spi_write: _spi_write, -#else + NULL, NULL, -#endif /* defined(BCM_ROBO_SUPPORT) */ iproc_read: _iproc_read, iproc_write: _iproc_write, get_cmic_ver: _get_cmic_ver, @@ -5328,7 +4353,7 @@ LKM_EXPORT_SYM(lkbde_dev_state_set); LKM_EXPORT_SYM(lkbde_dev_state_get); LKM_EXPORT_SYM(lkbde_dev_instid_set); LKM_EXPORT_SYM(lkbde_dev_instid_get); -#if (defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT)) +#ifdef BCM_SAND_SUPPORT LKM_EXPORT_SYM(lkbde_cpu_write); LKM_EXPORT_SYM(lkbde_cpu_read); LKM_EXPORT_SYM(lkbde_cpu_pci_register); diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_dma.c b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_dma.c index 32b769784c2e..eb3dc0495195 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_dma.c +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_dma.c @@ -85,10 +85,25 @@ #if _SIMPLE_MEMORY_ALLOCATION_ == 1 #define ALLOC_METHOD_DEFAULT ALLOC_TYPE_API +#if defined(__arm__) +#define USE_DMA_MMAP_COHERENT +#define _PGPROT_NONCACHED(x) x = pgprot_noncached((x)) +#elif defined(__aarch64__ ) +#define USE_DMA_MMAP_COHERENT +#define _PGPROT_NONCACHED(x) x = pgprot_writecombine((x)) +#endif #else #define ALLOC_METHOD_DEFAULT ALLOC_TYPE_CHUNK #endif +#ifndef _PGPROT_NONCACHED +#ifdef REMAP_DMA_NONCACHED +#define _PGPROT_NONCACHED(x) x = pgprot_noncached((x)) +#else +#define _PGPROT_NONCACHED(x) +#endif +#endif + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) #include #define virt_to_bus virt_to_phys @@ -101,6 +116,12 @@ #define VIRT_TO_PAGE(p) virt_to_page((p)) #endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) +#define DMA_MAPPING_ERROR(d, p) dma_mapping_error((d),(p)) +#else +#define DMA_MAPPING_ERROR(d, p) dma_mapping_error((p)) +#endif + #ifndef KMALLOC_MAX_SIZE #define KMALLOC_MAX_SIZE (1UL << (MAX_ORDER - 1 + PAGE_SHIFT)) #endif @@ -170,7 +191,6 @@ MODULE_PARM_DESC(himemaddr, #else #define DMA_MEM_DEFAULT (8 * ONE_MB) #endif -#define DMA_MEM_DEFAULT_ROBO (4 * ONE_MB) /* We try to assemble a contiguous segment from chunks of this size */ #define DMA_BLOCK_SIZE (512 * ONE_KB) @@ -203,6 +223,7 @@ static unsigned long _himemaddr = 0; static int _use_dma_mapping = 0; static LIST_HEAD(_dma_seg); +#define DMA_DEV_INDEX 0 /* Device index to allocate memory pool */ #define DMA_DEV(n) lkbde_get_dma_dev(n) #define BDE_NUM_DEVICES(t) lkbde_get_num_devices(t) @@ -545,7 +566,7 @@ _pgcleanup(void) case ALLOC_TYPE_API: if (_dma_vbase) { if (dma_debug >= 1) gprintk("freeing v=%p p=0x%lx size=0x%lx\n", _dma_vbase,(unsigned long) _dma_pbase, (unsigned long)_dma_mem_size); - dma_free_coherent(DMA_DEV(0), _dma_mem_size, _dma_vbase, _dma_pbase); + dma_free_coherent(DMA_DEV(DMA_DEV_INDEX), _dma_mem_size, _dma_vbase, _dma_pbase); } break; #endif /* _SIMPLE_MEMORY_ALLOCATION_ */ @@ -554,7 +575,7 @@ _pgcleanup(void) struct list_head *pos, *tmp; int i, ndevices; if (_use_dma_mapping) { - ndevices = BDE_NUM_DEVICES(BDE_ALL_DEVICES); + ndevices = BDE_NUM_DEVICES(BDE_SWITCH_DEVICES); for (i = 0; i < ndevices && DMA_DEV(i); i ++) { dma_unmap_single(DMA_DEV(i), (dma_addr_t)_dma_pbase, _dma_mem_size, DMA_BIDIRECTIONAL); } @@ -591,7 +612,6 @@ static void _alloc_mpool(size_t size) { unsigned long pbase = 0; - #if defined(__arm__) && !defined(CONFIG_HIGHMEM) if (_use_himem) { gprintk("DMA in high memory requires CONFIG_HIGHMEM on ARM CPUs.\n"); @@ -614,6 +634,9 @@ _alloc_mpool(size_t size) _dma_vbase = IOREMAP(_dma_pbase, size); } else { /* Get DMA memory from kernel */ + if (dma_debug >= 1) { + gprintk("Allocating DMA memory using method dmaalloc=%d\n", dmaalloc); + } switch (dmaalloc) { #if _SIMPLE_MEMORY_ALLOCATION_ case ALLOC_TYPE_API: { @@ -624,8 +647,9 @@ _alloc_mpool(size_t size) /* get a memory allocation from the kernel */ { dma_addr_t dma_handle; - if (!(_dma_vbase = dma_alloc_coherent(DMA_DEV(0), alloc_size, &dma_handle, GFP_KERNEL)) || !dma_handle) { - gprintk("failed to allocate the memory pool of size 0x%lx\n", (unsigned long)alloc_size); + if (!(_dma_vbase = dma_alloc_coherent(DMA_DEV(DMA_DEV_INDEX), + alloc_size, &dma_handle, GFP_KERNEL)) || !dma_handle) { + gprintk("Failed to allocate coherent memory pool of size 0x%lx\n", (unsigned long)alloc_size); return; } _cpu_pbase = pbase = dma_handle; @@ -643,14 +667,14 @@ _alloc_mpool(size_t size) case ALLOC_TYPE_CHUNK: _dma_vbase = _pgalloc(size); if (!_dma_vbase) { - gprintk("failed to allocate the memory pool of size 0x%lx\n", (unsigned long)size); + gprintk("Failed to allocate memory pool of size 0x%lx\n", (unsigned long)size); return; } _cpu_pbase = virt_to_bus(_dma_vbase); /* Use dma_map_single to obtain DMA bus address or IOVA if iommu is present. */ - if (DMA_DEV(0)) { - pbase = dma_map_single(DMA_DEV(0), _dma_vbase, size, DMA_BIDIRECTIONAL); - if (dma_mapping_error(DMA_DEV(0), pbase)) { + if (DMA_DEV(DMA_DEV_INDEX)) { + pbase = dma_map_single(DMA_DEV(DMA_DEV_INDEX), _dma_vbase, size, DMA_BIDIRECTIONAL); + if (DMA_MAPPING_ERROR(DMA_DEV(DMA_DEV_INDEX), pbase)) { gprintk("Failed to map memory at %p\n", _dma_vbase); _pgcleanup(); _dma_vbase = NULL; @@ -659,7 +683,6 @@ _alloc_mpool(size_t size) } _use_dma_mapping = 1; } else { - /* Device has not been probed. */ pbase = _cpu_pbase; } break; @@ -719,15 +742,21 @@ _dma_cleanup(void) return 0; } -void _dma_init(int robo_switch, int dev_index) +void _dma_init(int dev_index) { unsigned long pbase; - if (dev_index > 0) { - if ((_use_dma_mapping == 1) && DMA_DEV(dev_index) && _dma_vbase) { + if (dev_index > DMA_DEV_INDEX) { + if (_use_dma_mapping && DMA_DEV(dev_index) && _dma_vbase) { pbase = dma_map_single(DMA_DEV(dev_index), _dma_vbase, _dma_mem_size, DMA_BIDIRECTIONAL); - if (dma_mapping_error(DMA_DEV(dev_index), pbase)) { + if (DMA_MAPPING_ERROR(DMA_DEV(dev_index), pbase)) { gprintk("Failed to map memory for device %d at %p\n", dev_index, _dma_vbase); + return; + } + if (pbase != (unsigned long)_dma_pbase) { + /* Bus address/IOVA must be identical for all devices. */ + gprintk("Device %d has different pbase: %lx (should be %lx)\n", + dev_index, pbase, (unsigned long)_dma_pbase); } } return; @@ -745,10 +774,6 @@ void _dma_init(int robo_switch, int dev_index) gprintk("dmasize must be a power of 2 (1M, 2M, 4M, 8M etc.)\n"); _dma_mem_size = 0; } - } else { - if(robo_switch){ - _dma_mem_size = DMA_MEM_DEFAULT_ROBO; - } } if (himem) { @@ -775,42 +800,54 @@ void _dma_init(int robo_switch, int dev_index) _alloc_mpool(_dma_mem_size); if (_dma_vbase == NULL) { gprintk("no DMA memory available\n"); - } - else { + } else { mpool_init(); _dma_pool = mpool_create(_dma_vbase, _dma_mem_size); } } } -#if USE_LINUX_BDE_MMAP /* - * Function: _dma_range_valid + * Some kernels are configured to prevent mapping of kernel RAM memory + * into user space via the /dev/mem device. * - * Purpose: - * Check if DMA address range is valid. - * Parameters: - * phys_addr - start physical address - * size - range size - * Returns: - * 0 : not valid - * 1 : valid + * The function below provides a backdoor to mapping the DMA pool to + * user space via the BDE device file. */ -int -_dma_range_valid(unsigned long phys_addr, unsigned long size) +int _dma_mmap(struct file *filp, struct vm_area_struct *vma) { - unsigned long pool_start = _cpu_pbase; - unsigned long pool_end = pool_start + _dma_mem_size; + unsigned long phys_addr = vma->vm_pgoff << PAGE_SHIFT; + unsigned long size = vma->vm_end - vma->vm_start; - if (phys_addr < pool_start || (phys_addr + size) > pool_end) { + if (phys_addr < (unsigned long )_cpu_pbase || + (phys_addr + size) > ((unsigned long )_cpu_pbase + _dma_mem_size)) { gprintk("range 0x%lx-0x%lx outside DMA pool 0x%lx-0x%lx\n", - phys_addr, phys_addr + size, pool_start, pool_end); - return 0; + phys_addr, phys_addr + size, (unsigned long )_cpu_pbase, + (unsigned long )_cpu_pbase + _dma_mem_size); + return -EINVAL; + } + +#ifdef USE_DMA_MMAP_COHERENT + if (dmaalloc == ALLOC_TYPE_API) { + vma->vm_pgoff = 0; + return dma_mmap_coherent(DMA_DEV(DMA_DEV_INDEX), vma, (void *)_dma_vbase, phys_addr, size); } - return 1; -} #endif + _PGPROT_NONCACHED(vma->vm_page_prot); + + if (remap_pfn_range(vma, + vma->vm_start, + vma->vm_pgoff, + size, + vma->vm_page_prot)) { + gprintk("Failed to mmap phys range 0x%lx-0x%lx to 0x%lx-0x%lx\n", + phys_addr, phys_addr + size, vma->vm_start,vma->vm_end); + return -EAGAIN; + } + return 0; +} + /* * Function: _dma_pool_allocated * diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/shared/mpool.c b/platform/broadcom/saibcm-modules/systems/bde/linux/shared/mpool.c index 7a377cd00787..13206596ee26 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/shared/mpool.c +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/shared/mpool.c @@ -70,12 +70,31 @@ static sal_sem_t _mpool_lock; #endif #endif +#define MPOOL_BUF_SIZE 1024 +#define MPOOL_BUF_ALLOC_COUNT_MAX 16 + typedef struct mpool_mem_s { unsigned char *address; int size; + struct mpool_mem_s *prev; struct mpool_mem_s *next; } mpool_mem_t; +static int _buf_alloc_count; +static mpool_mem_t *mpool_buf[MPOOL_BUF_ALLOC_COUNT_MAX]; +static mpool_mem_t *free_list; + +#define ALLOC_INIT_MPOOL_BUF(ptr) \ + ptr = MALLOC((sizeof(mpool_mem_t) * MPOOL_BUF_SIZE)); \ + if (ptr) { \ + int i; \ + for (i = 0; i < MPOOL_BUF_SIZE - 1; i++) { \ + ptr[i].next = &ptr[i+1]; \ + } \ + ptr[MPOOL_BUF_SIZE - 1].next = NULL; \ + free_list = &ptr[0]; \ + } + /* * Function: mpool_init * @@ -116,6 +135,10 @@ mpool_alloc(mpool_handle_t pool, int size) MPOOL_LOCK(); + if (size < BCM_CACHE_LINE_BYTES) { + size = BCM_CACHE_LINE_BYTES; + } + mod = size & (BCM_CACHE_LINE_BYTES - 1); if (mod != 0 ) { size += (BCM_CACHE_LINE_BYTES - mod); @@ -131,21 +154,37 @@ mpool_alloc(mpool_handle_t pool, int size) MPOOL_UNLOCK(); return NULL; } - newptr = MALLOC(sizeof(mpool_mem_t)); - if (!newptr) { - MPOOL_UNLOCK(); - return NULL; + + if (!free_list) { + if (_buf_alloc_count == MPOOL_BUF_ALLOC_COUNT_MAX) { + MPOOL_UNLOCK(); + return NULL; + } + + ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]); + + if (mpool_buf[_buf_alloc_count] == NULL) { + MPOOL_UNLOCK(); + return NULL; + } + + _buf_alloc_count++; } + + newptr = free_list; + free_list = free_list->next; newptr->address = ptr->address + ptr->size; newptr->size = size; newptr->next = ptr->next; + newptr->prev = ptr; + ptr->next->prev = newptr; ptr->next = newptr; #ifdef TRACK_DMA_USAGE _dma_mem_used += size; #endif - MPOOL_UNLOCK(); + MPOOL_UNLOCK(); return newptr->address; } @@ -165,25 +204,29 @@ void mpool_free(mpool_handle_t pool, void *addr) { unsigned char *address = (unsigned char *)addr; - mpool_mem_t *ptr = pool, *prev = NULL; + mpool_mem_t *head = pool, *ptr = NULL; MPOOL_LOCK(); - - while (ptr && ptr->next) { - if (ptr->next->address == address) { + + if (!(head && head->prev)) { + MPOOL_UNLOCK(); + return; + } + + ptr = head->prev->prev; + + while (ptr && (ptr != head)) { + if (ptr->address == address) { #ifdef TRACK_DMA_USAGE - _dma_mem_used -= ptr->next->size; + _dma_mem_used -= ptr->size; #endif + ptr->prev->next = ptr->next; + ptr->next->prev = ptr->prev; + ptr->next = free_list; + free_list = ptr; break; } - ptr = ptr->next; - } - - if (ptr && ptr->next) { - prev = ptr; - ptr = ptr->next; - prev->next = ptr->next; - FREE(ptr); + ptr = ptr->prev; } MPOOL_UNLOCK(); @@ -208,34 +251,45 @@ mpool_create(void *base_ptr, int size) { mpool_mem_t *head, *tail; int mod = (int)(((unsigned long)base_ptr) & (BCM_CACHE_LINE_BYTES - 1)); + int i; MPOOL_LOCK(); + for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) { + mpool_buf[i] = NULL; + } + + _buf_alloc_count = 0; + + ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]); + + if (mpool_buf[_buf_alloc_count] == NULL) { + MPOOL_UNLOCK(); + return NULL; + } + + _buf_alloc_count++; + if (mod) { base_ptr = (char*)base_ptr + (BCM_CACHE_LINE_BYTES - mod); size -= (BCM_CACHE_LINE_BYTES - mod); } size &= ~(BCM_CACHE_LINE_BYTES - 1); - - head = (mpool_mem_t *)MALLOC(sizeof(mpool_mem_t)); - if (head == NULL) { - return NULL; - } - tail = (mpool_mem_t *)MALLOC(sizeof(mpool_mem_t)); - if (tail == NULL) { - FREE(head); - return NULL; - } - + head = free_list; + free_list = free_list->next; + tail = free_list; + free_list = free_list->next; + head->size = tail->size = 0; head->address = base_ptr; tail->address = head->address + size; + head->prev = tail; head->next = tail; + tail->prev = head; tail->next = NULL; MPOOL_UNLOCK(); - return head; } @@ -252,13 +306,20 @@ mpool_create(void *base_ptr, int size) int mpool_destroy(mpool_handle_t pool) { - mpool_mem_t *ptr, *next; - + int i; + MPOOL_LOCK(); - for (ptr = pool; ptr; ptr = next) { - next = ptr->next; - FREE(ptr); + if ((mpool_mem_t *)pool != mpool_buf[0]) { + MPOOL_UNLOCK(); + return 0; + } + + for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) { + if (mpool_buf[i]) { + FREE(mpool_buf[i]); + mpool_buf[i] = NULL; + } } MPOOL_UNLOCK(); @@ -285,7 +346,7 @@ mpool_usage(mpool_handle_t pool) MPOOL_LOCK(); for (ptr = pool; ptr; ptr = ptr->next) { - usage += ptr->size; + usage += ptr->size; } MPOOL_UNLOCK(); diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.c b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.c index 6c7c9bb95056..370f89e022c4 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.c +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.c @@ -33,9 +33,6 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) #include #endif -#ifdef KEYSTONE -#include -#endif MODULE_AUTHOR("Broadcom Corporation"); @@ -676,124 +673,10 @@ _bcm88750_interrupt(bde_ctrl_t *ctrl) #endif } -static void -_qe2k_interrupt(bde_ctrl_t *ctrl) -{ - bde_inst_resource_t *res; - - res = &_bde_inst_resource[ctrl->inst]; - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x20/sizeof(uint32)); - - atomic_set(&res->intr, 1); -#ifdef BDE_LINUX_NON_INTERRUPTIBLE - wake_up(&res->intr_wq); -#else - wake_up_interruptible(&res->intr_wq); -#endif -} - -static void -_fe2k_interrupt(bde_ctrl_t *ctrl) -{ - bde_inst_resource_t *res; - - res = &_bde_inst_resource[ctrl->inst]; - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x18/sizeof(uint32)); /* PC_INTERRUPT_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x24/sizeof(uint32)); /* PC_ERROR0_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x2c/sizeof(uint32)); /* PC_ERROR1_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x34/sizeof(uint32)); /* PC_UNIT_MASK */ - - atomic_set(&res->intr, 1); -#ifdef BDE_LINUX_NON_INTERRUPTIBLE - wake_up(&res->intr_wq); -#else - wake_up_interruptible(&res->intr_wq); -#endif -} - -static void -_fe2kxt_interrupt(bde_ctrl_t *ctrl) -{ - bde_inst_resource_t *res; - - res = &_bde_inst_resource[ctrl->inst]; - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x2c/sizeof(uint32)); /* PC_INTERRUPT_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x38/sizeof(uint32)); /* PC_ERROR0_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x40/sizeof(uint32)); /* PC_ERROR1_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x50/sizeof(uint32)); /* PC_UNIT_MASK */ - - atomic_set(&res->intr, 1); -#ifdef BDE_LINUX_NON_INTERRUPTIBLE - wake_up(&res->intr_wq); -#else - wake_up_interruptible(&res->intr_wq); -#endif -} - -static void -_bme3200_interrupt(bde_ctrl_t *ctrl) -{ - bde_inst_resource_t *res; - - res = &_bde_inst_resource[ctrl->inst]; - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x54/sizeof(uint32)); /* PI_PT_ERROR0 */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x5c/sizeof(uint32)); /* PI_PT_ERROR1 */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x64/sizeof(uint32)); /* PI_PT_ERROR2 */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x6c/sizeof(uint32)); /* PI_PT_ERROR3 */ - - atomic_set(&res->intr, 1); -#ifdef BDE_LINUX_NON_INTERRUPTIBLE - wake_up(&res->intr_wq); -#else - wake_up_interruptible(&res->intr_wq); -#endif -} - - -static void -_bm9600_interrupt(bde_ctrl_t *ctrl) -{ - bde_inst_resource_t *res; - - res = &_bde_inst_resource[ctrl->inst]; - - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x5c/sizeof(uint32)); /* PI_INTERRUPT_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0xc/sizeof(uint32)); /* PI_UNIT_INTERRUPT0_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x14/sizeof(uint32)); /* PI_UNIT_INTERRUPT1_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x1c/sizeof(uint32)); /* PI_UNIT_INTERRUPT2_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x24/sizeof(uint32)); /* PI_UNIT_INTERRUPT3_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x2c/sizeof(uint32)); /* PI_UNIT_INTERRUPT4_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x34/sizeof(uint32)); /* PI_UNIT_INTERRUPT5_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x3c/sizeof(uint32)); /* PI_UNIT_INTERRUPT6_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x44/sizeof(uint32)); /* PI_UNIT_INTERRUPT7_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x4c/sizeof(uint32)); /* PI_UNIT_INTERRUPT8_MASK */ - SSOC_WRITEL(0xffffffff, ctrl->ba + 0x54/sizeof(uint32)); /* PI_UNIT_INTERRUPT9_MASK */ - - atomic_set(&res->intr, 1); -#ifdef BDE_LINUX_NON_INTERRUPTIBLE - wake_up(&res->intr_wq); -#else - wake_up_interruptible(&res->intr_wq); -#endif -} - - - /* The actual interrupt handler of ethernet devices */ static void _ether_interrupt(bde_ctrl_t *ctrl) { -#ifdef KEYSTONE - /* - * Since the two GMAC cores are sharing the same IRQ. - * Add the checking to handle the interrupt events. - */ - if ((ctrl->devid == BCM53000_GMAC_ID)) { - if ((readl(ctrl->ba + 0x020/4) & readl(ctrl->ba + 0x024/4)) == 0) { - return; - } - } -#endif SSOC_WRITEL(0, ctrl->ba + 0x024/4); atomic_set(&_ether_interrupt_has_taken_place, 1); @@ -813,11 +696,6 @@ static struct _intr_mode_s { { (isr_f)_cmicm_interrupt, "CMICm" }, { (isr_f)_cmicd_interrupt, "CMICd" }, { (isr_f)_cmicd_cmc0_interrupt, "CMICd CMC0" }, - { (isr_f)_qe2k_interrupt, "QE2K" }, - { (isr_f)_fe2k_interrupt, "FE2K" }, - { (isr_f)_fe2kxt_interrupt, "FE2KXT" }, - { (isr_f)_bme3200_interrupt, "BME3200" }, - { (isr_f)_bm9600_interrupt, "BM9600" }, { (isr_f)_bcm88750_interrupt, "BCM88750" }, { (isr_f)_cmicx_interrupt, "CMICx" }, { NULL, NULL } @@ -845,7 +723,7 @@ _devices_init(int d) uint32 ver; uint16 device_id_mask = 0xFFF0; uint16 device_id; - int state = 0; + uint32 state = 0; (void)lkbde_dev_state_get(d, &state); if (state == BDE_DEV_STATE_REMOVED) { @@ -864,21 +742,6 @@ _devices_init(int d) } if (ctrl->dev_type & BDE_SWITCH_DEV_TYPE) { switch (user_bde->get_dev(d)->device) { - case QE2000_DEVICE_ID: - ctrl->isr = (isr_f)_qe2k_interrupt; - break; - case BCM88020_DEVICE_ID: - ctrl->isr = (isr_f)_fe2k_interrupt; - break; - case BCM88025_DEVICE_ID: - ctrl->isr = (isr_f)_fe2kxt_interrupt; - break; - case BME3200_DEVICE_ID: - ctrl->isr = (isr_f)_bme3200_interrupt; - break; - case BM9600_DEVICE_ID: - ctrl->isr = (isr_f)_bm9600_interrupt; - break; case BCM88750_DEVICE_ID: case BCM88753_DEVICE_ID: case BCM88754_DEVICE_ID: @@ -920,7 +783,7 @@ _devices_init(int d) case BCM88380_DEVICE_ID: case BCM88381_DEVICE_ID: case BCM88680_DEVICE_ID: - case BCM88690_DEVICE_ID: + case BCM88800_DEVICE_ID: case BCM88770_DEVICE_ID: case BCM88773_DEVICE_ID: case BCM88774_DEVICE_ID: @@ -938,6 +801,7 @@ _devices_init(int d) case BCM88270_DEVICE_ID: case BCM88272_DEVICE_ID: case BCM88273_DEVICE_ID: + case BCM88274_DEVICE_ID: case BCM88278_DEVICE_ID: case BCM88279_DEVICE_ID: case BCM8206_DEVICE_ID: @@ -1002,7 +866,15 @@ _devices_init(int d) } break; } - /* All Ramon devices from 0x8790 to 0x879F */ + +#ifdef BCM_DNX_SUPPORT + /*All Jericho 2 devices from 0x8690 to 0x869F*/ + if (SOC_IS_JERICHO_2_TYPE(user_bde->get_dev(d)->device)) { + ctrl->isr = (isr_f)_cmicx_interrupt; + } +#endif + + /*All Ramon devices from 0x8790 to 0x879F*/ if ((user_bde->get_dev(d)->device & BCM88790_DEVICE_ID) == BCM88790_DEVICE_ID) { ctrl->isr = (isr_f)_cmicx_interrupt; } @@ -1456,30 +1328,9 @@ _ioctl(unsigned int cmd, unsigned long arg) } break; case LUBDE_USLEEP: - sal_usleep(io.d0); - break; case LUBDE_UDELAY: - sal_udelay(io.d0); - break; case LUBDE_SEM_OP: - switch (io.d0) { - case LUBDE_SEM_OP_CREATE: - io.p0 = (bde_kernel_addr_t)sal_sem_create("", io.d1, io.d2); - break; - case LUBDE_SEM_OP_DESTROY: - sal_sem_destroy((sal_sem_t)io.p0); - break; - case LUBDE_SEM_OP_TAKE: - io.rc = sal_sem_take((sal_sem_t)io.p0, io.d2); - break; - case LUBDE_SEM_OP_GIVE: - io.rc = sal_sem_give((sal_sem_t)io.p0); - break; - default: - io.rc = LUBDE_FAIL; - break; - } - break; + return -EINVAL; case LUBDE_WRITE_IRQ_MASK: io.rc = lkbde_irq_mask_set(io.dev, io.d0, io.d1, 0); break; @@ -1499,7 +1350,7 @@ _ioctl(unsigned int cmd, unsigned long arg) case LUBDE_WRITE_REG_16BIT_BUS: io.rc = user_bde->write(io.dev, io.d0, io.d1); break; -#if (defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT)) +#ifdef BCM_SAND_SUPPORT case LUBDE_CPU_WRITE_REG: { if (lkbde_cpu_write(io.dev, io.d0, (uint32*)io.dx.buf) == -1) { diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_iproc.c b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_iproc.c index e1bdcc4db0da..05253141b2ff 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_iproc.c +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_iproc.c @@ -30,6 +30,8 @@ #define BAR0_PAXB_CONFIG_IND_ADDR 0x2120 #define BAR0_PAXB_CONFIG_IND_DATA 0x2124 +#define PAXB_0_CMICD_TO_PCIE_INTR_EN 0x2380 + #define BAR0_PAXB_IMAP0_0 (0x2c00) #define BAR0_PAXB_IMAP0_1 (0x2c04) #define BAR0_PAXB_IMAP0_2 (0x2c08) @@ -287,7 +289,8 @@ shbde_iproc_paxb_init(shbde_hal_t *shbde, void *iproc_regs, iproc32_write(shbde, reg, data | 0x1); } } - /* Configure MSIX interrupt page, only need for iproc ver == 0x10 */ + + /* Configure MSIX interrupt page, only need for iproc ver == 0x10 */ if ((icfg->use_msi == 2) && (icfg->iproc_ver == 0x10)) { unsigned int mask = (0x1 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT) - 1; reg = ROFFS(iproc_regs, PAXB_0_FUNC0_IMAP1_3); @@ -296,6 +299,17 @@ shbde_iproc_paxb_init(shbde_hal_t *shbde, void *iproc_regs, data |= 0x410 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT; iproc32_write(shbde, reg, data); } + + /* Disable INTx interrupt if MSI/MSIX is selected */ + reg = ROFFS(iproc_regs, PAXB_0_CMICD_TO_PCIE_INTR_EN); + data = iproc32_read(shbde, reg); + if (icfg->use_msi) { + data &= ~0x1; + } else { + data |= 0x1; + } + iproc32_write(shbde, reg, data); + return pci_num; } diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c index 3559ace7a898..0c91c3ecd5f7 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c @@ -67,6 +67,7 @@ #include #include +#include #include #include #include @@ -405,6 +406,59 @@ static inline struct sk_buff *skb_padto(struct sk_buff *skb, unsigned int len) pci_dma_mapping_error(d, a) #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) +enum { + SKBTX_HW_TSTAMP = 1 << 0, + SKBTX_SW_TSTAMP = 1 << 1, + SKBTX_IN_PROGRESS = 1 << 2, +}; +struct skb_shared_hwtstamps { + ktime_t hwtstamp; + ktime_t syststamp; +}; +struct bkn_skb_shared_info { + uint8_t tx_flags; + struct skb_shared_hwtstamps hwtstamps; +}; +#define bkn_skb_shinfo(_skb) ((struct bkn_skb_shared_info *)(unsigned char *)_skb->end) +#define bkn_skb_tx_flags(_skb) bkn_skb_shinfo(_skb)->tx_flags +static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb) +{ + return &bkn_skb_shinfo(skb)->hwtstamps; +} +void skb_tstamp_tx(struct sk_buff *orig_skb, struct skb_shared_hwtstamps *hwtstamps) +{ +} +static inline void bkn_skb_tx_timestamp(struct sk_buff *skb) +{ +} +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) +static inline ktime_t ns_to_ktime(u64 ns) +{ + static const ktime_t ktime; + return ktime; +} +#endif +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +#include +enum { + SKBTX_HW_TSTAMP = 1 << 0, + SKBTX_SW_TSTAMP = 1 << 1, + SKBTX_IN_PROGRESS = 1 << 2, +}; +#define bkn_skb_tx_flags(_skb) skb_shinfo(_skb)->tx_flags.flags +static inline void bkn_skb_tx_timestamp(struct sk_buff *skb) +{ +} +#else +#include +#define bkn_skb_tx_flags(_skb) skb_shinfo(_skb)->tx_flags +static inline void bkn_skb_tx_timestamp(struct sk_buff *skb) +{ + return skb_tx_timestamp(skb); +} +#endif + #ifdef LINUX_BDE_DMA_DEVICE_SUPPORT #define DMA_DEV device #define DMA_FROMDEV DMA_FROM_DEVICE @@ -471,6 +525,9 @@ typedef struct bkn_dcb_chain_s { #define NUM_CMICX_RX_CHAN 7 #define NUM_CMICM_RX_CHAN 3 +#define FCS_SZ 4 +#define TAG_SZ 4 + /* Device control info */ typedef struct bkn_switch_info_s { struct list_head list; @@ -497,6 +554,12 @@ typedef struct bkn_switch_info_s { int dcb_type; /* DCB type */ int dcb_wsize; /* DCB size (in 32-bit words) */ int pkt_hdr_size; /* Packet header size */ + uint32_t ftmh_lb_key_ext_size; /* FTMH LB-Key Extension existence/size */ + uint32_t ftmh_stacking_ext_size; /* FTMH Stacking extension existence/size */ + uint32_t pph_base_size; /* Size of PPH base */ + uint32_t pph_lif_ext_size[8]; /* Size of PPH Lif extension header */ + uint8_t udh_enable; /* Indicates UDH existence */ + uint32_t udh_length_type[4]; /* Size of UDH header per type */ int rx_chans; /* Number of Rx channels */ uint32_t dma_hi; /* DMA higher address */ uint32_t cmic_type; /* CMIC type (CMICe or CMICm) */ @@ -516,6 +579,10 @@ typedef struct bkn_switch_info_s { uint32_t inst_id; /* Instance id of this device */ int evt_idx; /* Event queue index for this device*/ int basedev_suspended; /* Base device suspended */ + int tx_hwts; /* HW timestamp for Tx */ + int rx_hwts; /* HW timestamp for Rx */ + struct sk_buff_head tx_ptp_queue; /* Tx PTP skb queue */ + struct work_struct tx_ptp_work; /* Tx PTP work */ struct { bkn_desc_info_t desc[MAX_TX_DCBS+1]; int free; /* Number of free Tx DCBs */ @@ -574,71 +641,163 @@ typedef struct bkn_switch_info_s { } rx[NUM_RX_CHAN]; } bkn_switch_info_t; -#define BKN_DNX_HDR_MAX_SIZE 40 +/* PTCH_2 */ +#define BKN_DNX_PTCH_2_SIZE 2 +/* ITMH */ +#define BKN_DNX_ITMH_SIZE 5 +/* Modlue Header */ +#define BKN_DNX_MODULE_HEADER_SIZE 20 +/* FTMH */ +#define BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_MSB 17 +#define BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_NOF_BITS 16 +#define BKN_DNX_FTMH_PP_DSP_MSB 33 +#define BKN_DNX_FTMH_PP_DSP_NOF_BITS 8 +#define BKN_DNX_FTMH_ACTION_TYPE_MSB 43 +#define BKN_DNX_FTMH_ACTION_TYPE_NOF_BITS 2 +#define BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_MSB 73 +#define BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_NOF_BITS 1 +#define BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_MSB 74 +#define BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_NOF_BITS 1 +#define BKN_DNX_FTMH_TM_DST_EXT_PRESENT_MSB 75 +#define BKN_DNX_FTMH_TM_DST_EXT_PRESENT_NOF_BITS 1 +#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_MSB 76 +#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_NOF_BITS 1 +#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_MSB 77 +#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_NOF_BITS 1 +#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_MSB 78 +#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_NOF_BITS 1 +/* Fix Length for FTMH and Extension headers */ +#define BKN_DNX_FTMH_BASE_SIZE 10 +#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE 2 +#define BKN_DNX_FTMH_TM_DST_EXT_SIZE 3 +#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE 3 +#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE 6 +/* TSH */ +#define BKN_DNX_TSH_SIZE 4 +/* PPH */ +#define BKN_DNX_PPH_BASE_TYPE_9 9 +#define BKN_DNX_PPH_BASE_TYPE_10 10 +#define BKN_DNX_PPH_BASE_TYPE_12 12 +#define BKN_DNX_PPH_9_FORWARD_DOMAIN_MSB 5 +#define BKN_DNX_PPH_9_FORWARD_DOMAIN_NOF_BITS 16 +#define BKN_DNX_PPH_9_LEARN_EXT_PRESENT_MSB 53 +#define BKN_DNX_PPH_9_LEARN_EXT_PRESENT_NOF_BITS 1 +#define BKN_DNX_PPH_9_FHEI_SIZE_MSB 54 +#define BKN_DNX_PPH_9_FHEI_SIZE_NOF_BITS 2 +#define BKN_DNX_PPH_9_LIF_EXT_TYPE_MSB 56 +#define BKN_DNX_PPH_9_LIF_EXT_TYPE_NOF_BITS 3 +#define BKN_DNX_PPH_10_FORWARD_DOMAIN_MSB 9 +#define BKN_DNX_PPH_10_FORWARD_DOMAIN_NOF_BITS 16 +#define BKN_DNX_PPH_10_LEARN_EXT_PRESENT_MSB 61 +#define BKN_DNX_PPH_10_LEARN_EXT_PRESENT_NOF_BITS 1 +#define BKN_DNX_PPH_10_FHEI_SIZE_MSB 62 +#define BKN_DNX_PPH_10_FHEI_SIZE_NOF_BITS 2 +#define BKN_DNX_PPH_10_LIF_EXT_TYPE_MSB 64 +#define BKN_DNX_PPH_10_LIF_EXT_TYPE_NOF_BITS 3 +#define BKN_DNX_PPH_12_FORWARD_DOMAIN_MSB 21 +#define BKN_DNX_PPH_12_FORWARD_DOMAIN_NOF_BITS 18 +#define BKN_DNX_PPH_12_LEARN_EXT_PRESENT_MSB 77 +#define BKN_DNX_PPH_12_LEARN_EXT_PRESENT_NOF_BITS 1 +#define BKN_DNX_PPH_12_FHEI_SIZE_MSB 78 +#define BKN_DNX_PPH_12_FHEI_SIZE_NOF_BITS 2 +#define BKN_DNX_PPH_12_LIF_EXT_TYPE_MSB 80 +#define BKN_DNX_PPH_12_LIF_EXT_TYPE_NOF_BITS 3 +/* PPH.FHEI_TYPE */ +#define BKN_DNX_PPH_FHEI_TYPE_SZ0 1 +#define BKN_DNX_PPH_FHEI_TYPE_SZ1 2 +#define BKN_DNX_PPH_FHEI_TYPE_SZ2 3 +/* FHEI */ +#define BKN_DNX_PPH_FHEI_SZ0_SIZE 3 +#define BKN_DNX_PPH_FHEI_SZ1_SIZE 5 +#define BKN_DNX_PPH_FHEI_SZ2_SIZE 8 +#define BKN_DNX_PPH_FHEI_TRAP_5B_QUALIFIER_MSB 0 +#define BKN_DNX_PPH_FHEI_TRAP_5B_QUALIFIER_NOF_BITS 27 +#define BKN_DNX_PPH_FHEI_TRAP_5B_CODE_MSB 27 +#define BKN_DNX_PPH_FHEI_TRAP_5B_CODE_NOF_BITS 9 +#define BKN_DNX_PPH_FHEI_TRAP_5B_TYPE_MSB 36 +#define BKN_DNX_PPH_FHEI_TRAP_5B_TYPE_NOF_BITS 4 +/* PPH Extension */ +#define BKN_DNX_PPH_LEARN_EXT_SIZE 19 +/* UDH */ +#define BKN_DNX_UDH_DATA_TYPE_0_MSB 0 +#define BKN_DNX_UDH_DATA_TYPE_0_NOF_BITS 2 +#define BKN_DNX_UDH_DATA_TYPE_1_MSB 2 +#define BKN_DNX_UDH_DATA_TYPE_1_NOF_BITS 2 +#define BKN_DNX_UDH_DATA_TYPE_2_MSB 4 +#define BKN_DNX_UDH_DATA_TYPE_2_NOF_BITS 2 +#define BKN_DNX_UDH_DATA_TYPE_3_MSB 6 +#define BKN_DNX_UDH_DATA_TYPE_3_NOF_BITS 2 +#define BKN_DNX_UDH_BASE_SIZE 1 + +#define BKN_DPP_HDR_MAX_SIZE 40 +/* PTCH_2 */ +#define BKN_DPP_PTCH_2_SIZE 2 +/* ITMH */ +#define BKN_DPP_ITMH_SIZE 4 /* FTMH */ -#define BKN_DNX_FTMH_LB_EXT_EN 0x1 -#define BKN_DNX_FTMH_STACKING_EXT_EN 0x2 -#define BKN_DNX_FTMH_SIZE_BYTE 9 -#define BKN_DNX_FTMH_LB_EXT_SIZE_BYTE 1 -#define BKN_DNX_FTMH_STACKING_SIZE_BYTE 2 -#define BKN_DNX_FTMH_DEST_EXT_SIZE_BYTE 2 -#define BKN_DNX_FTMH_LB_EXT_SIZE_BYTE 1 -#define BKN_DNX_FTMH_PKT_SIZE_MSB 0 -#define BKN_DNX_FTMH_PKT_SIZE_NOF_BITS 14 -#define BKN_DNX_FTMH_TC_MSB 14 -#define BKN_DNX_FTMH_TC_NOF_BITS 3 -#define BKN_DNX_FTMH_SRC_SYS_PORT_MSB 17 -#define BKN_DNX_FTMH_SRC_SYS_PORT_NOF_BITS 16 -#define BKN_DNX_FTMH_EXT_DSP_EXIST_MSB 68 -#define BKN_DNX_FTMH_EXT_DSP_EXIST_NOF_BITS 1 -#define BKN_DNX_FTMH_EXT_MSB 45 -#define BKN_DNX_FTMH_EXT_NOF_BITS 2 -#define BKN_DNX_FTMH_FIRST_EXT_MSB 72 -#define BKN_DNX_FTMH_ACTION_TYPE_MSB 43 -#define BKN_DNX_FTMH_ACTION_TYPE_NOF_BITS 2 -#define BKN_DNX_FTMH_PPH_TYPE_MSB 45 -#define BKN_DNX_FTMH_PPH_TYPE_NOF_BITS 2 +#define BKN_DPP_FTMH_LB_EXT_EN 0x1 +#define BKN_DPP_FTMH_STACKING_EXT_EN 0x2 +#define BKN_DPP_FTMH_SIZE_BYTE 9 +#define BKN_DPP_FTMH_LB_EXT_SIZE_BYTE 1 +#define BKN_DPP_FTMH_STACKING_SIZE_BYTE 2 +#define BKN_DPP_FTMH_DEST_EXT_SIZE_BYTE 2 +#define BKN_DPP_FTMH_LB_EXT_SIZE_BYTE 1 +#define BKN_DPP_FTMH_PKT_SIZE_MSB 0 +#define BKN_DPP_FTMH_PKT_SIZE_NOF_BITS 14 +#define BKN_DPP_FTMH_TC_MSB 14 +#define BKN_DPP_FTMH_TC_NOF_BITS 3 +#define BKN_DPP_FTMH_SRC_SYS_PORT_MSB 17 +#define BKN_DPP_FTMH_SRC_SYS_PORT_NOF_BITS 16 +#define BKN_DPP_FTMH_EXT_DSP_EXIST_MSB 68 +#define BKN_DPP_FTMH_EXT_DSP_EXIST_NOF_BITS 1 +#define BKN_DPP_FTMH_EXT_MSB 45 +#define BKN_DPP_FTMH_EXT_NOF_BITS 2 +#define BKN_DPP_FTMH_FIRST_EXT_MSB 72 +#define BKN_DPP_FTMH_ACTION_TYPE_MSB 43 +#define BKN_DPP_FTMH_ACTION_TYPE_NOF_BITS 2 +#define BKN_DPP_FTMH_PPH_TYPE_MSB 45 +#define BKN_DPP_FTMH_PPH_TYPE_NOF_BITS 2 + /* PPH */ -#define BKN_DNX_PPH_SIZE_BYTE 7 -#define BKN_DNX_PPH_EEI_EXTENSION_PRESENT_MSB 0 -#define BKN_DNX_PPH_EEI_EXTENSION_PRESENT_NOF_BITS 1 -#define BKN_DNX_PPH_LEARN_EXENSION_PRESENT_MSB 1 -#define BKN_DNX_PPH_LEARN_EXENSION_PRESENT_NOF_BITS 1 -#define BKN_DNX_PPH_FHEI_SIZE_MSB 2 -#define BKN_DNX_PPH_FHEI_SIZE_NOF_BITS 2 -#define BKN_DNX_PPH_FORWARD_CODE_MSB 4 -#define BKN_DNX_PPH_FORWARD_CODE_NOF_BITS 4 -#define BKN_DNX_PPH_VSI_MSB 22 -#define BKN_DNX_PPH_VSI_NOF_BITS 16 +#define BKN_DPP_PPH_SIZE_BYTE 7 +#define BKN_DPP_PPH_EEI_EXTENSION_PRESENT_MSB 0 +#define BKN_DPP_PPH_EEI_EXTENSION_PRESENT_NOF_BITS 1 +#define BKN_DPP_PPH_LEARN_EXENSION_PRESENT_MSB 1 +#define BKN_DPP_PPH_LEARN_EXENSION_PRESENT_NOF_BITS 1 +#define BKN_DPP_PPH_FHEI_SIZE_MSB 2 +#define BKN_DPP_PPH_FHEI_SIZE_NOF_BITS 2 +#define BKN_DPP_PPH_FORWARD_CODE_MSB 4 +#define BKN_DPP_PPH_FORWARD_CODE_NOF_BITS 4 +#define BKN_DPP_PPH_VSI_MSB 22 +#define BKN_DPP_PPH_VSI_NOF_BITS 16 /* FHEI TRAP/SNOOP 3B */ -#define BKN_DNX_PPH_FHEI_3B_SIZE_BYTE 3 -#define BKN_DNX_PPH_FHEI_5B_SIZE_BYTE 5 -#define BKN_DNX_PPH_FHEI_8B_SIZE_BYTE 8 -#define BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB 0 -#define BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS 16 -#define BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB 16 -#define BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_NOF_BITS 8 +#define BKN_DPP_PPH_FHEI_3B_SIZE_BYTE 3 +#define BKN_DPP_PPH_FHEI_5B_SIZE_BYTE 5 +#define BKN_DPP_PPH_FHEI_8B_SIZE_BYTE 8 +#define BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB 0 +#define BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS 16 +#define BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB 16 +#define BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_NOF_BITS 8 /* PPH extension */ -#define BKN_DNX_PPH_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE 3 -#define BKN_DNX_PPH_LEARN_EXTENSION_SIZE_BYTE 5 - +#define BKN_DPP_PPH_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE 3 +#define BKN_DPP_PPH_LEARN_EXTENSION_SIZE_BYTE 5 /* ftmh action type. */ -typedef enum bkn_dnx_ftmh_action_type_e { - BKN_DNX_FTMH_ACTION_TYPE_FORWARD = 0, /* TM action is forward */ - BKN_DNX_FTMH_ACTION_TYPE_SNOOP = 1, /* TM action is snoop */ - BKN_DNX_FTMH_ACTION_TYPE_INBOUND_MIRROR = 2, /* TM action is inbound mirror. */ - BKN_DNX_FTMH_ACTION_TYPE_OUTBOUND_MIRROR = 3 /* TM action is outbound mirror. */ -}bkn_dnx_ftmh_action_type_t; +typedef enum bkn_dpp_ftmh_action_type_e { + BKN_DPP_FTMH_ACTION_TYPE_FORWARD = 0, /* TM action is forward */ + BKN_DPP_FTMH_ACTION_TYPE_SNOOP = 1, /* TM action is snoop */ + BKN_DPP_FTMH_ACTION_TYPE_INBOUND_MIRROR = 2, /* TM action is inbound mirror. */ + BKN_DPP_FTMH_ACTION_TYPE_OUTBOUND_MIRROR = 3 /* TM action is outbound mirror. */ +}bkn_dpp_ftmh_action_type_t; /* ftmh dest extension. */ -typedef struct bkn_dnx_ftmh_dest_extension_s { +typedef struct bkn_dpp_ftmh_dest_extension_s { uint8 valid; /* Set if the extension is present */ uint32_t dst_sys_port; /* Destination System Port */ -} bkn_dnx_ftmh_dest_extension_t; +} bkn_dpp_ftmh_dest_extension_t; /* dnx packet */ -typedef struct bkn_pkt_dnx_s { +typedef struct bkn_dune_system_header_info_s { uint32_t ntwrk_header_ptr; struct { uint32_t packet_size; /* Packet size in bytes */ @@ -652,8 +811,13 @@ typedef struct bkn_pkt_dnx_s { uint32_t trap_qualifier; /* RAW Data */ uint32_t trap_id; /* RAW Data */ } internal; -} bkn_dnx_packet_info; - + uint32_t system_header_size; + uint32_t ftmh_spa; /* FTMH: Source-System-Port-Aggregate*/ + uint32_t pph_forward_domain; /* PPH: Forward-Domain*/ + uint32_t fhei_qualifier; /* FHEI: Qualifier */ + uint32_t fhei_code; /* FHEI: Code */ + uint32_t fhei_type; /* FHEI: Type */ +} bkn_dune_system_header_info_t; #define PREV_IDX(_cur, _max) (((_cur) == 0) ? (_max) - 1 : (_cur) - 1) @@ -715,6 +879,8 @@ typedef struct bkn_priv_s { uint32_t vlan; uint32_t flags; uint32_t cb_user_data; + uint8_t system_headers[27]; + uint32_t system_headers_size; } bkn_priv_t; typedef struct bkn_filter_s { @@ -755,6 +921,14 @@ LIST_HEAD(_sinfo_list); static knet_skb_cb_f knet_rx_cb = NULL; static knet_skb_cb_f knet_tx_cb = NULL; static knet_filter_cb_f knet_filter_cb = NULL; +static knet_hw_tstamp_enable_cb_f knet_hw_tstamp_enable_cb = NULL; +static knet_hw_tstamp_enable_cb_f knet_hw_tstamp_disable_cb = NULL; +static knet_hw_tstamp_tx_time_get_cb_f knet_hw_tstamp_tx_time_get_cb = NULL; +static knet_hw_tstamp_tx_meta_get_cb_f knet_hw_tstamp_tx_meta_get_cb = NULL; +static knet_hw_tstamp_ptp_clock_index_cb_f knet_hw_tstamp_ptp_clock_index_cb = NULL; +static knet_hw_tstamp_rx_time_upscale_cb_f knet_hw_tstamp_rx_time_upscale_cb = NULL; +static knet_netif_cb_f knet_netif_create_cb = NULL; +static knet_netif_cb_f knet_netif_destroy_cb = NULL; /* * Thread management @@ -955,6 +1129,8 @@ static bkn_thread_ctrl_t bkn_evt_ctrl; #define CMICX_IRQ_STATr (CMICX_CMC_BASE + 0x0000106c) #define CMICX_IRQ_STAT_CLRr (CMICX_CMC_BASE + 0x00001074) #define CMICX_IRQ_ENABr 0x18013100 +#define IHOST_GIC_GIC400_GICD_ISENABLERN_5r 0x10781114 +#define IHOST_GIC_GIC400_GICD_ICENABLERN_5r 0x10781194 /* CMICx interrupts reserved for kernel handler */ #define CMICX_TXRX_IRQ_MASK 0xffffffff @@ -992,6 +1168,7 @@ static bkn_thread_ctrl_t bkn_evt_ctrl; #define CMICX_DS_CMC_DESC_DONE(ch) (0x00000001 << ((ch) * 4)) #define CMICX_DS_CMC_CHAIN_DONE(ch) (0x00000002 << ((ch) * 4)) #define CMICX_DS_CMC_CTRLD_INT(ch) (0x00000008 << ((ch) * 4)) +#define CMICX_DS_CMC_DMA_CHAIN_DONE (0x00000001) #define CMICX_DS_CMC_DMA_ACTIVE (0x00000002) #define DMA_TO_BUS_HI(dma) ((dma) | sinfo->dma_hi) @@ -1498,12 +1675,25 @@ xgsx_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls) static inline void xgsx_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask) { + uint32_t irq_mask_reg = CMICX_IRQ_ENABr; + uint32_t irq_mask, irq_fmask, disable_mask; + if (sinfo->napi_poll_mode) { mask = 0; } + if (sinfo->cpu_no == 1) { + lkbde_irq_mask_get(sinfo->dev_no, &irq_mask, &irq_fmask); + disable_mask = ~mask & (irq_mask & irq_fmask); + if (disable_mask) { + lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV | LKBDE_IPROC_REG, + IHOST_GIC_GIC400_GICD_ICENABLERN_5r, disable_mask, CMICX_TXRX_IRQ_MASK); + } + irq_mask_reg = IHOST_GIC_GIC400_GICD_ISENABLERN_5r; + } + lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV | LKBDE_IPROC_REG, - CMICX_IRQ_ENABr, mask, CMICX_TXRX_IRQ_MASK); + irq_mask_reg, mask, CMICX_TXRX_IRQ_MASK); } static inline void @@ -2094,6 +2284,7 @@ bkn_rx_refill(bkn_switch_info_t *sinfo, int chan) bkn_desc_info_t *desc; uint32_t *dcb; uint32_t resv_size = sinfo->cmic_type == 'x' ? RCPU_HDR_SIZE : RCPU_RX_ENCAP_SIZE; + uint32_t meta_size = sinfo->cmic_type == 'x' ? RCPU_RX_META_SIZE : 0; int prev; if (sinfo->rx[chan].use_rx_skb == 0) { @@ -2121,7 +2312,7 @@ bkn_rx_refill(bkn_switch_info_t *sinfo, int chan) chan, sinfo->rx[chan].cur)); } skb = desc->skb; - desc->dma_size = rx_buffer_size; + desc->dma_size = rx_buffer_size + meta_size; #ifdef KNET_NO_AXI_DMA_INVAL /* * FIXME: Need to retain this code until iProc customers have been @@ -2166,7 +2357,7 @@ bkn_rx_refill(bkn_switch_info_t *sinfo, int chan) } if (sinfo->cmic_type == 'x') { dcb[1] = DMA_TO_BUS_HI(desc->skb_dma >> 32); - dcb[2] |= rx_buffer_size; + dcb[2] |= rx_buffer_size + meta_size; } else { dcb[1] |= rx_buffer_size; } @@ -2327,6 +2518,37 @@ bkn_dma_abort(bkn_switch_info_t *sinfo) return 0; } +static int +device_is_dpp(bkn_switch_info_t *sinfo) +{ + int is_dpp = 0; + + is_dpp = (sinfo->dcb_type == 28) ? 1 : 0; + return is_dpp; +} + +static int +device_is_dnx(bkn_switch_info_t *sinfo) +{ + int is_dnx = 0; + + /* No EP_TO_CPU header for DNX(JR2) */ + is_dnx = ((sinfo->cmic_type == 'x') && (sinfo->pkt_hdr_size ==0)) ? 1 : 0; + return is_dnx; +} + +/* is DPP or is DNX*/ +static int +device_is_sand(bkn_switch_info_t *sinfo) +{ + int is_sand = 0; + + if (device_is_dpp(sinfo) || device_is_dnx(sinfo)) { + is_sand = 1; + } + return is_sand; +} + static bkn_filter_t * bkn_match_rx_pkt(bkn_switch_info_t *sinfo, uint8_t *pkt, int pktlen, void *meta, int chan, bkn_filter_t *cbf) @@ -2349,12 +2571,38 @@ bkn_match_rx_pkt(bkn_switch_info_t *sinfo, uint8_t *pkt, int pktlen, wsize = BYTES2WORDS(size); DBG_VERB(("Filter: size = %d (%d), data = 0x%08x, mask = 0x%08x\n", size, wsize, kf->data.w[0], kf->mask.w[0])); + + if (device_is_dnx(sinfo)) { + DBG_DUNE(("Filter: size = %d (wsize %d)\n", size, wsize)); + for (idx = 0; idx < wsize; idx++) + { + DBG_DUNE(("OOB[%d]: 0x%08x [0x%08x]\n", idx, kf->data.w[idx], kf->mask.w[idx])); + } + DBG_DUNE(("Meta Data [+ Selected Raw packet data]\n")); + for (idx = 0; idx < wsize; idx++) + { + DBG_DUNE(("Scratch[%d]: 0x%08x\n", idx, scratch.data.w[idx])); + } + } + match = 1; if (match) { - if (kf->priority < (num_rx_prio * sinfo->rx_chans)) { - if (kf->priority < (num_rx_prio * chan) || - kf->priority >= (num_rx_prio * (chan + 1))) { - match = 0; + if (device_is_sand(sinfo)) + { + /** priority 0 means no priority check */ + if (kf->priority && (kf->priority < (num_rx_prio * sinfo->rx_chans))) { + if (kf->priority < (num_rx_prio * chan) || + kf->priority >= (num_rx_prio * (chan + 1))) { + match = 0; + } + } + } + else { + if (kf->priority < (num_rx_prio * sinfo->rx_chans)) { + if (kf->priority < (num_rx_prio * chan) || + kf->priority >= (num_rx_prio * (chan + 1))) { + match = 0; + } } } } @@ -2422,6 +2670,43 @@ bkn_netif_lookup(bkn_switch_info_t *sinfo, int id) return NULL; } +static int +bkn_hw_tstamp_rx_set(bkn_switch_info_t *sinfo, struct sk_buff *skb, uint32 *meta) +{ + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); + uint32_t *md = meta; + uint64_t ts = 0; + + switch (sinfo->dcb_type) { + case 26: + case 32: + case 33: + ts = md[14]; + ts = ts << 32 | md[12]; + break; + case 36: + ts = md[10]; + break; + case 38: + ts = md[4] & 0xffff; + ts = ts << 32 | md[5]; + break; + default: + return -1; + } + + if (knet_hw_tstamp_rx_time_upscale_cb) { + if (knet_hw_tstamp_rx_time_upscale_cb(sinfo->dev_no, &ts) < 0) { + return -1; + } + } + + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + shhwtstamps->hwtstamp = ns_to_ktime(be64_to_cpu(ts)); + + return 0; +} + static int bkn_add_rcpu_encap(bkn_switch_info_t *sinfo, struct sk_buff *skb, void *meta) { @@ -2491,15 +2776,6 @@ bkn_eth_type_update(struct sk_buff *skb, int ethertype) #define BKN_DNX_BYTE_SWAP(x) ((((x) << 24)) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) >> 24))) #endif -static int -device_is_dune(bkn_switch_info_t *sinfo) -{ - int is_dune = 0; - - is_dune = (sinfo->dcb_type == 28) ? 1 : 0; - return is_dune; -} - static int packet_is_untagged(uint16_t tpid) { @@ -2513,7 +2789,7 @@ packet_is_untagged(uint16_t tpid) } static void -bkn_dnx_bitstream_set_field(uint32_t *input_buffer, uint32_t start_bit, uint32_t nof_bits, uint32_t field) +bkn_bitstream_set_field(uint32_t *input_buffer, uint32_t start_bit, uint32_t nof_bits, uint32_t field) { uint32_t place; uint32_t field_bit_i; @@ -2540,7 +2816,7 @@ bkn_dnx_bitstream_set_field(uint32_t *input_buffer, uint32_t start_bit, uint32_t } static void -bkn_dnx_bitstream_get_field(uint8_t *input_buffer, uint32_t start_bit, uint32_t nof_bits, uint32_t *output_value) +bkn_bitstream_get_field(uint8_t *input_buffer, uint32_t start_bit, uint32_t nof_bits, uint32_t *output_value) { uint32_t idx; uint32_t buf_sizes=0; @@ -2590,7 +2866,7 @@ bkn_dnx_bitstream_get_field(uint8_t *input_buffer, uint32_t start_bit, uint32_t } static void -bkn_dnx_packet_parse_ftmh(bkn_switch_info_t *sinfo, uint8_t hdr_buff[], bkn_dnx_packet_info *packet_info) +bkn_dpp_packet_parse_ftmh(bkn_switch_info_t *sinfo, uint8_t hdr_buff[], bkn_dune_system_header_info_t *packet_info) { uint32_t header_ptr = 0; uint32_t dsp_ext_exist=0; @@ -2599,76 +2875,76 @@ bkn_dnx_packet_parse_ftmh(bkn_switch_info_t *sinfo, uint8_t hdr_buff[], bkn_dnx_ header_ptr = packet_info->ntwrk_header_ptr; /* Packet-size */ - bkn_dnx_bitstream_get_field( + bkn_bitstream_get_field( &hdr_buff[header_ptr], - BKN_DNX_FTMH_PKT_SIZE_MSB, - BKN_DNX_FTMH_PKT_SIZE_NOF_BITS, + BKN_DPP_FTMH_PKT_SIZE_MSB, + BKN_DPP_FTMH_PKT_SIZE_NOF_BITS, &fld_val); packet_info->ftmh.packet_size = fld_val; /* Traffic-class */ - bkn_dnx_bitstream_get_field( + bkn_bitstream_get_field( &hdr_buff[header_ptr], - BKN_DNX_FTMH_TC_MSB, - BKN_DNX_FTMH_TC_NOF_BITS, + BKN_DPP_FTMH_TC_MSB, + BKN_DPP_FTMH_TC_NOF_BITS, &fld_val); packet_info->ftmh.prio = fld_val; /* Source-system-port-aggregate */ - bkn_dnx_bitstream_get_field( + bkn_bitstream_get_field( &hdr_buff[header_ptr], - BKN_DNX_FTMH_SRC_SYS_PORT_MSB, - BKN_DNX_FTMH_SRC_SYS_PORT_NOF_BITS, + BKN_DPP_FTMH_SRC_SYS_PORT_MSB, + BKN_DPP_FTMH_SRC_SYS_PORT_NOF_BITS, &fld_val); packet_info->ftmh.src_sys_port = fld_val; /* TM-action-type */ - bkn_dnx_bitstream_get_field( + bkn_bitstream_get_field( &hdr_buff[header_ptr], - BKN_DNX_FTMH_ACTION_TYPE_MSB, - BKN_DNX_FTMH_ACTION_TYPE_NOF_BITS, + BKN_DPP_FTMH_ACTION_TYPE_MSB, + BKN_DPP_FTMH_ACTION_TYPE_NOF_BITS, &fld_val); packet_info->ftmh.action_type = fld_val; /* PPH-type */ - bkn_dnx_bitstream_get_field( + bkn_bitstream_get_field( &hdr_buff[header_ptr], - BKN_DNX_FTMH_PPH_TYPE_MSB, - BKN_DNX_FTMH_PPH_TYPE_NOF_BITS, + BKN_DPP_FTMH_PPH_TYPE_MSB, + BKN_DPP_FTMH_PPH_TYPE_NOF_BITS, &fld_val); packet_info->ftmh.pph_type = fld_val; - packet_info->ntwrk_header_ptr += BKN_DNX_FTMH_SIZE_BYTE; + packet_info->ntwrk_header_ptr += BKN_DPP_FTMH_SIZE_BYTE; DBG_DUNE(("FTMH(%d) Packet-size %d Action-type %d PPH-type %d Source-system-port 0x%x Traffic-class %d\n", packet_info->ntwrk_header_ptr, packet_info->ftmh.packet_size, packet_info->ftmh.action_type, packet_info->ftmh.pph_type, packet_info->ftmh.src_sys_port, packet_info->ftmh.prio)); /* LB-Key ext */ - if ((sinfo->pkt_hdr_size & BKN_DNX_FTMH_LB_EXT_EN) == BKN_DNX_FTMH_LB_EXT_EN) + if ((sinfo->pkt_hdr_size & BKN_DPP_FTMH_LB_EXT_EN) == BKN_DPP_FTMH_LB_EXT_EN) { - packet_info->ntwrk_header_ptr += BKN_DNX_FTMH_LB_EXT_SIZE_BYTE; + packet_info->ntwrk_header_ptr += BKN_DPP_FTMH_LB_EXT_SIZE_BYTE; DBG_DUNE(("FTMH(%d) FTMH LB-Key Extension is present\n", packet_info->ntwrk_header_ptr)); } /* DSP ext*/ fld_val = 0; - bkn_dnx_bitstream_get_field( + bkn_bitstream_get_field( &hdr_buff[header_ptr], - BKN_DNX_FTMH_EXT_DSP_EXIST_MSB, - BKN_DNX_FTMH_EXT_DSP_EXIST_NOF_BITS, + BKN_DPP_FTMH_EXT_DSP_EXIST_MSB, + BKN_DPP_FTMH_EXT_DSP_EXIST_NOF_BITS, &dsp_ext_exist); if (dsp_ext_exist) { - packet_info->ntwrk_header_ptr += BKN_DNX_FTMH_DEST_EXT_SIZE_BYTE; + packet_info->ntwrk_header_ptr += BKN_DPP_FTMH_DEST_EXT_SIZE_BYTE; DBG_DUNE(("FTMH(%d) DSP-extension-present 1\n", packet_info->ntwrk_header_ptr)); } /* stacking ext */ - if ((sinfo->pkt_hdr_size & BKN_DNX_FTMH_STACKING_EXT_EN) == BKN_DNX_FTMH_STACKING_EXT_EN) + if ((sinfo->pkt_hdr_size & BKN_DPP_FTMH_STACKING_EXT_EN) == BKN_DPP_FTMH_STACKING_EXT_EN) { - packet_info->ntwrk_header_ptr += BKN_DNX_FTMH_STACKING_SIZE_BYTE; + packet_info->ntwrk_header_ptr += BKN_DPP_FTMH_STACKING_SIZE_BYTE; DBG_DUNE(("FTMH(%d) FTMH Stacking Extension is present\n", packet_info->ntwrk_header_ptr)); } return; } static void -bkn_dnx_packet_parse_internal(bkn_switch_info_t *sinfo, uint8_t hdr_buff[], bkn_dnx_packet_info *packet_info) +bkn_dpp_packet_parse_internal(bkn_switch_info_t *sinfo, uint8_t hdr_buff[], bkn_dune_system_header_info_t *packet_info) { uint32_t header_ptr = 0; uint32_t fld_val; @@ -2680,38 +2956,38 @@ bkn_dnx_packet_parse_internal(bkn_switch_info_t *sinfo, uint8_t hdr_buff[], bkn_ header_ptr = packet_info->ntwrk_header_ptr; - bkn_dnx_bitstream_get_field( + bkn_bitstream_get_field( &hdr_buff[header_ptr], - BKN_DNX_PPH_EEI_EXTENSION_PRESENT_MSB, - BKN_DNX_PPH_EEI_EXTENSION_PRESENT_NOF_BITS, + BKN_DPP_PPH_EEI_EXTENSION_PRESENT_MSB, + BKN_DPP_PPH_EEI_EXTENSION_PRESENT_NOF_BITS, &eei_extension_present); - bkn_dnx_bitstream_get_field( + bkn_bitstream_get_field( &hdr_buff[header_ptr], - BKN_DNX_PPH_LEARN_EXENSION_PRESENT_MSB, - BKN_DNX_PPH_LEARN_EXENSION_PRESENT_NOF_BITS, + BKN_DPP_PPH_LEARN_EXENSION_PRESENT_MSB, + BKN_DPP_PPH_LEARN_EXENSION_PRESENT_NOF_BITS, &learn_extension_present); - bkn_dnx_bitstream_get_field( + bkn_bitstream_get_field( &hdr_buff[header_ptr], - BKN_DNX_PPH_FHEI_SIZE_MSB, - BKN_DNX_PPH_FHEI_SIZE_NOF_BITS, + BKN_DPP_PPH_FHEI_SIZE_MSB, + BKN_DPP_PPH_FHEI_SIZE_NOF_BITS, &fhei_size); - bkn_dnx_bitstream_get_field( + bkn_bitstream_get_field( &hdr_buff[header_ptr], - BKN_DNX_PPH_FORWARD_CODE_MSB, - BKN_DNX_PPH_FORWARD_CODE_NOF_BITS, + BKN_DPP_PPH_FORWARD_CODE_MSB, + BKN_DPP_PPH_FORWARD_CODE_NOF_BITS, &forward_code); /* 7: CPU-Trap */ is_trapped = (uint8_t)(forward_code == 7); - bkn_dnx_bitstream_get_field( + bkn_bitstream_get_field( &hdr_buff[header_ptr], - BKN_DNX_PPH_VSI_MSB, - BKN_DNX_PPH_VSI_NOF_BITS, + BKN_DPP_PPH_VSI_MSB, + BKN_DPP_PPH_VSI_NOF_BITS, &fld_val); packet_info->internal.vsi = fld_val; /* size of PPH base is 7 */ - packet_info->ntwrk_header_ptr += BKN_DNX_PPH_SIZE_BYTE; + packet_info->ntwrk_header_ptr += BKN_DPP_PPH_SIZE_BYTE; header_ptr = packet_info->ntwrk_header_ptr; DBG_DUNE(("PPH(%d) Forward-Code %d EEI-Extension %d Learn-Extension %d VSI %d FHEI-size %d\n", packet_info->ntwrk_header_ptr, @@ -2721,38 +2997,38 @@ bkn_dnx_packet_parse_internal(bkn_switch_info_t *sinfo, uint8_t hdr_buff[], bkn_ if (is_trapped && (fhei_size == 1)) { /* CPU trap code qualifier */ - bkn_dnx_bitstream_get_field( + bkn_bitstream_get_field( &hdr_buff[header_ptr], - BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB, - BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS, + BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB, + BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS, &fld_val); packet_info->internal.trap_qualifier = fld_val; /* CPU trap code */ - bkn_dnx_bitstream_get_field( + bkn_bitstream_get_field( &hdr_buff[header_ptr], - BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB, - BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_NOF_BITS, + BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB, + BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_NOF_BITS, &fld_val); packet_info->internal.trap_id = fld_val; } switch(fhei_size) { case 1: - packet_info->ntwrk_header_ptr += BKN_DNX_PPH_FHEI_3B_SIZE_BYTE; + packet_info->ntwrk_header_ptr += BKN_DPP_PPH_FHEI_3B_SIZE_BYTE; break; case 2: - packet_info->ntwrk_header_ptr += BKN_DNX_PPH_FHEI_5B_SIZE_BYTE; + packet_info->ntwrk_header_ptr += BKN_DPP_PPH_FHEI_5B_SIZE_BYTE; break; case 3: - packet_info->ntwrk_header_ptr += BKN_DNX_PPH_FHEI_8B_SIZE_BYTE; + packet_info->ntwrk_header_ptr += BKN_DPP_PPH_FHEI_8B_SIZE_BYTE; break; default: break; } if (eei_extension_present) { - packet_info->ntwrk_header_ptr += BKN_DNX_PPH_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE; + packet_info->ntwrk_header_ptr += BKN_DPP_PPH_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE; } if (learn_extension_present) { - packet_info->ntwrk_header_ptr += BKN_DNX_PPH_LEARN_EXTENSION_SIZE_BYTE; + packet_info->ntwrk_header_ptr += BKN_DPP_PPH_LEARN_EXTENSION_SIZE_BYTE; } DBG_DUNE(("FHEI(%d) trap_qualifier 0x%x trap_id 0x%x\n", packet_info->ntwrk_header_ptr, packet_info->internal.trap_qualifier, packet_info->internal.trap_id)); @@ -2760,23 +3036,23 @@ bkn_dnx_packet_parse_internal(bkn_switch_info_t *sinfo, uint8_t hdr_buff[], bkn_ } static int -bkn_dnx_packet_header_parse(bkn_switch_info_t *sinfo, uint8 *buff, uint32_t buff_len, bkn_dnx_packet_info *packet_info) +bkn_dpp_packet_header_parse(bkn_switch_info_t *sinfo, uint8 *buff, uint32_t buff_len, bkn_dune_system_header_info_t *packet_info) { - uint8_t hdr_buff[BKN_DNX_HDR_MAX_SIZE]; + uint8_t hdr_buff[BKN_DPP_HDR_MAX_SIZE]; uint32_t hdr_size; uint8_t has_internal = 0; if ((buff == NULL) || (packet_info == NULL)) { return -1; } - hdr_size = buff_len < BKN_DNX_HDR_MAX_SIZE ? buff_len: BKN_DNX_HDR_MAX_SIZE; + hdr_size = buff_len < BKN_DPP_HDR_MAX_SIZE ? buff_len: BKN_DPP_HDR_MAX_SIZE; memcpy(hdr_buff, buff, hdr_size); /* FTMH */ - bkn_dnx_packet_parse_ftmh(sinfo, hdr_buff, packet_info); + bkn_dpp_packet_parse_ftmh(sinfo, hdr_buff, packet_info); if (packet_info->ftmh.packet_size != (buff_len + 2)) { DBG_DUNE(("FTMH packet size verfication failed, %d-%d\n", packet_info->ftmh.packet_size, buff_len)); - memset(packet_info, 0, sizeof(bkn_dnx_packet_info)); + memset(packet_info, 0, sizeof(bkn_dune_system_header_info_t)); return -1; } switch (packet_info->ftmh.pph_type) { @@ -2798,7 +3074,7 @@ bkn_dnx_packet_header_parse(bkn_switch_info_t *sinfo, uint8 *buff, uint32_t buff } if (has_internal) { - bkn_dnx_packet_parse_internal(sinfo, &hdr_buff[0], packet_info); + bkn_dpp_packet_parse_internal(sinfo, &hdr_buff[0], packet_info); } /* FIXME: */ @@ -2807,6 +3083,398 @@ bkn_dnx_packet_header_parse(bkn_switch_info_t *sinfo, uint8 *buff, uint32_t buff return 0; } +static int +bkn_dnx_packet_header_parse(bkn_switch_info_t *sinfo, uint8 *buf, uint32_t buf_len, bkn_dune_system_header_info_t *packet_info) +{ + uint32_t fld_val; + uint32_t hdr_size = 0; + uint32_t pkt_offset_ingress_untrapped =0; + uint8_t tm_dst_ext_present = 0; + uint8_t app_specific_ext_size = 0; + uint8_t flow_id_ext_size = 0; + uint8_t bier_bfr_ext_size = 0; + uint8_t is_pph_en = 0; + uint8_t is_tsh_en = 0; + + if ((buf == NULL) || (packet_info == NULL)) { + return -1; + } + + /* FTMH: Source-System-Port-Aggregate */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_MSB, + BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_NOF_BITS, + &fld_val); + packet_info->ftmh_spa = fld_val; + /* FTMH: PPH-Type TSH */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_MSB, + BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_NOF_BITS, + &fld_val); + is_tsh_en = fld_val; + /* FTMH: PPH-Type PPH base */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_MSB, + BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_NOF_BITS, + &fld_val); + is_pph_en = fld_val; + /* FTMH: TM-Destination-Extension-Present */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_TM_DST_EXT_PRESENT_MSB, + BKN_DNX_FTMH_TM_DST_EXT_PRESENT_NOF_BITS, + &fld_val); + tm_dst_ext_present = fld_val; + /* FTMH: Application-Specific-Extension-Size */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_MSB, + BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_NOF_BITS, + &fld_val); + app_specific_ext_size = fld_val; + /* FTMH: Flow-ID-Extension-Size */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_MSB, + BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_NOF_BITS, + &fld_val); + flow_id_ext_size = fld_val; + /* FTMH: BIER-BFR-Extension-Size */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_MSB, + BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_NOF_BITS, + &fld_val); + bier_bfr_ext_size = fld_val; + + hdr_size = BKN_DNX_FTMH_BASE_SIZE; + pkt_offset_ingress_untrapped = BKN_DNX_FTMH_BASE_SIZE; + + DBG_DUNE(("FTMH(%d) source-system-port 0x%x is_tsh_en %d is_pph_en %d\n", + hdr_size, packet_info->ftmh_spa, is_tsh_en, is_pph_en)); + + /* FTMH LB-Key Extension */ + if (sinfo->ftmh_lb_key_ext_size > 0) + { + hdr_size += sinfo->ftmh_lb_key_ext_size; + DBG_DUNE(("FTMH LB-Key Extension(%d) is present\n", sinfo->ftmh_lb_key_ext_size)); + } + /* FTMH Stacking Extension */ + if (sinfo->ftmh_stacking_ext_size > 0) + { + hdr_size += sinfo->ftmh_stacking_ext_size; + DBG_DUNE(("FTMH Stacking Extension(%d) is present\n", sinfo->ftmh_stacking_ext_size)); + } + /* FTMH BIER BFR Extension */ + if (bier_bfr_ext_size > 0) + { + hdr_size += BKN_DNX_FTMH_BIER_BFR_EXT_SIZE; + DBG_DUNE(("FTMH BIER BFR Extension(2) is present\n")); + } + /* FTMH TM Destination Extension */ + if (tm_dst_ext_present > 0) + { + hdr_size += BKN_DNX_FTMH_TM_DST_EXT_SIZE; + DBG_DUNE(("FTMH TM Destination Extension(3) is present\n")); + } + /* FTMH Application Specific Extension */ + if (app_specific_ext_size > 0) + { + hdr_size += BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE; + DBG_DUNE(("FTMH Application Specific Extension(6) is present\n")); + } + /* FTMH Flow-ID Extension */ + if (flow_id_ext_size > 0) + { + hdr_size += BKN_DNX_FTMH_FLOW_ID_EXT_SIZE; + DBG_DUNE(("FTMH Flow-ID Extension(3) is present\n")); + } + + /* Given the packet is trapped to CPU */ + + /* Time-Stamp Header */ + if (is_tsh_en == TRUE) + { + hdr_size += BKN_DNX_TSH_SIZE; + DBG_DUNE(("Time-Stamp Header(4) is present\n")); + } + + /* Packet Processing Header */ + if (is_pph_en) + { + uint8_t learn_ext_present; + uint8_t fhei_size; + uint8_t lif_ext_type; + + switch (sinfo->pph_base_size) + { + case BKN_DNX_PPH_BASE_TYPE_9: + /* FTMH: Forward-Domain */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_9_FORWARD_DOMAIN_MSB, + BKN_DNX_PPH_9_FORWARD_DOMAIN_NOF_BITS, + &fld_val); + packet_info->pph_forward_domain = fld_val; + /* FTMH: Learn-Extension-Present */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_9_LEARN_EXT_PRESENT_MSB, + BKN_DNX_PPH_9_LEARN_EXT_PRESENT_NOF_BITS, + &fld_val); + learn_ext_present = fld_val; + /* FTMH: FHEI-Size */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_9_FHEI_SIZE_MSB, + BKN_DNX_PPH_9_FHEI_SIZE_NOF_BITS, + &fld_val); + fhei_size = fld_val; + /* FTMH: LIF-Extension-Type */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_9_LIF_EXT_TYPE_MSB, + BKN_DNX_PPH_9_LIF_EXT_TYPE_NOF_BITS, + &fld_val); + lif_ext_type = fld_val; + + hdr_size += BKN_DNX_PPH_BASE_TYPE_9; + DBG_DUNE(("PPH(10) FWD_DOMAIN %d, LEARN_EXT %d, FHEI_SIZE %d, LIF_EXT %d \n", + packet_info->pph_forward_domain, learn_ext_present, fhei_size, lif_ext_type)); + break; + case BKN_DNX_PPH_BASE_TYPE_10: + /* FTMH: Forward-Domain */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_10_FORWARD_DOMAIN_MSB, + BKN_DNX_PPH_10_FORWARD_DOMAIN_NOF_BITS, + &fld_val); + packet_info->pph_forward_domain = fld_val; + /* FTMH: Learn-Extension-Present */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_10_LEARN_EXT_PRESENT_MSB, + BKN_DNX_PPH_10_LEARN_EXT_PRESENT_NOF_BITS, + &fld_val); + learn_ext_present = fld_val; + /* FTMH: FHEI-Size */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_10_FHEI_SIZE_MSB, + BKN_DNX_PPH_10_FHEI_SIZE_NOF_BITS, + &fld_val); + fhei_size = fld_val; + /* FTMH: LIF-Extension-Type */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_10_LIF_EXT_TYPE_MSB, + BKN_DNX_PPH_10_LIF_EXT_TYPE_NOF_BITS, + &fld_val); + lif_ext_type = fld_val; + + hdr_size += BKN_DNX_PPH_BASE_TYPE_10; + DBG_DUNE(("PPH(10) FWD_DOMAIN %d, LEARN_EXT %d, FHEI_SIZE %d, LIF_EXT %d \n", + packet_info->pph_forward_domain, learn_ext_present, fhei_size, lif_ext_type)); + break; + case BKN_DNX_PPH_BASE_TYPE_12: + /* FTMH: Forward-Domain */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_12_FORWARD_DOMAIN_MSB, + BKN_DNX_PPH_12_FORWARD_DOMAIN_NOF_BITS, + &fld_val); + packet_info->pph_forward_domain = fld_val; + /* FTMH: Learn-Extension-Present */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_12_LEARN_EXT_PRESENT_MSB, + BKN_DNX_PPH_12_LEARN_EXT_PRESENT_NOF_BITS, + &fld_val); + learn_ext_present = fld_val; + /* FTMH: FHEI-Size */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_12_FHEI_SIZE_MSB, + BKN_DNX_PPH_12_FHEI_SIZE_NOF_BITS, + &fld_val); + fhei_size = fld_val; + /* FTMH: LIF-Extension-Type */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_12_LIF_EXT_TYPE_MSB, + BKN_DNX_PPH_12_LIF_EXT_TYPE_NOF_BITS, + &fld_val); + lif_ext_type = fld_val; + + hdr_size += BKN_DNX_PPH_BASE_TYPE_12; + DBG_DUNE(("PPH(12) FWD_DOMAIN %d, LEARN_EXT %d, FHEI_SIZE %d, LIF_EXT %d \n", + packet_info->pph_forward_domain, learn_ext_present, fhei_size, lif_ext_type)); + break; + default: + fhei_size = 0; + lif_ext_type = 0; + learn_ext_present = 0; + break; + } + if (fhei_size) + { + switch (fhei_size) + { + case BKN_DNX_PPH_FHEI_TYPE_SZ0: + hdr_size += BKN_DNX_PPH_FHEI_SZ0_SIZE; + DBG_DUNE(("FHEI(3) is present\n")); + break; + case BKN_DNX_PPH_FHEI_TYPE_SZ1: + /* FHEI: Code */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_FHEI_TRAP_5B_TYPE_MSB, + BKN_DNX_PPH_FHEI_TRAP_5B_TYPE_NOF_BITS, + &fld_val); + packet_info->fhei_type = fld_val; + /* FHEI-Size == 5B, FHEI-Type == Trap/Sniff */ + if (packet_info->fhei_type == 0x5) + { + /* FHEI: Qualifier */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_FHEI_TRAP_5B_QUALIFIER_MSB, + BKN_DNX_PPH_FHEI_TRAP_5B_QUALIFIER_NOF_BITS, + &fld_val); + packet_info->fhei_qualifier = fld_val; + /* FHEI: Code */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_FHEI_TRAP_5B_CODE_MSB, + BKN_DNX_PPH_FHEI_TRAP_5B_CODE_NOF_BITS, + &fld_val); + packet_info->fhei_code = fld_val; + } + hdr_size += BKN_DNX_PPH_FHEI_SZ1_SIZE; + DBG_DUNE(("FHEI(5) is present code 0x%x qualifier 0x%x\n", packet_info->fhei_code, packet_info->fhei_qualifier)); + break; + case BKN_DNX_PPH_FHEI_TYPE_SZ2: + hdr_size += BKN_DNX_PPH_FHEI_SZ1_SIZE; + DBG_DUNE(("FHEI(8) is present\n")); + break; + } + } + + /* PPH LIF Extension */ + if (lif_ext_type) + { + hdr_size += sinfo->pph_lif_ext_size[lif_ext_type]; + DBG_DUNE(("PPH LIF Extension(%d) is present\n", sinfo->pph_lif_ext_size[lif_ext_type])); + } + + /* PPH Learn Extension */ + if (learn_ext_present) + { + hdr_size += BKN_DNX_PPH_LEARN_EXT_SIZE; + DBG_DUNE(("PPH Learn Extension(19) is present\n")); + } + } + + /* UDH Header */ + if (sinfo->udh_enable) + { + uint8 data_type_0; + uint8 data_type_1; + uint8 data_type_2; + uint8 data_type_3; + + DBG_DUNE(("UDH base(1) is present\n")); + + /* UDH: UDH-Data-Type[0] */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_UDH_DATA_TYPE_0_MSB, + BKN_DNX_UDH_DATA_TYPE_0_NOF_BITS, + &fld_val); + data_type_0 = fld_val; + hdr_size += sinfo->udh_length_type[data_type_0]; + /* UDH: UDH-Data-Type[1] */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_UDH_DATA_TYPE_1_MSB, + BKN_DNX_UDH_DATA_TYPE_1_NOF_BITS, + &fld_val); + data_type_1 = fld_val; + hdr_size += sinfo->udh_length_type[data_type_1]; + /* UDH: UDH-Data-Type[2] */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_UDH_DATA_TYPE_2_MSB, + BKN_DNX_UDH_DATA_TYPE_2_NOF_BITS, + &fld_val); + data_type_2 = fld_val; + hdr_size += sinfo->udh_length_type[data_type_2]; + /* UDH: UDH-Data-Type[3] */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_UDH_DATA_TYPE_3_MSB, + BKN_DNX_UDH_DATA_TYPE_3_NOF_BITS, + &fld_val); + data_type_3 = fld_val; + hdr_size += sinfo->udh_length_type[data_type_3]; + hdr_size += BKN_DNX_UDH_BASE_SIZE; + } + + /* + * Check if fhei_type if of type trap + * There is a RISK that raw packet data is parsed and fhei_type is 0x5 by chance + */ + if (packet_info->fhei_type == 0x5) + { + /* Done for ingress trapped packets */ + packet_info->system_header_size = hdr_size; + DBG_DUNE(("Total Size of Headers is %d\n", packet_info->system_header_size)); + return 0; + } + else + { + /* New generated header will be FTMH(80b), TSH(32b), PPH(96b), FHEI(40b) */ + + /* Revert packet_info except info from FTHM base header */ + packet_info->fhei_qualifier = 0; + packet_info->fhei_code = 0; + packet_info->fhei_type = 0; + hdr_size = pkt_offset_ingress_untrapped; + + /* Time-Stamp Header */ + hdr_size += BKN_DNX_TSH_SIZE; + DBG_DUNE(("Time-Stamp Header(4) is present\n")); + + /** Packet Processing Header */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_12_FORWARD_DOMAIN_MSB, + BKN_DNX_PPH_12_FORWARD_DOMAIN_NOF_BITS, + &fld_val); + packet_info->pph_forward_domain = fld_val; + hdr_size += BKN_DNX_PPH_BASE_TYPE_12; + DBG_DUNE(("PPH(12) is present\n")); + + /* + * FHEI(Trap,40) + * 5B-FHEI format for sys_hdr_generation_profile:J2-OAM + * 8b' 0 + * 19b'oam_id + * 9b' cpu_trap_code: INGRESS_TRAP_ID is always 0 here + * 4b' type(0x5): J2-Configuration FHEI Type for CPU trap + */ + hdr_size += BKN_DNX_PPH_FHEI_SZ1_SIZE; + DBG_DUNE(("FHEI(5) is present\n")); + } + packet_info->system_header_size = hdr_size; + DBG_DUNE(("Total Size of Headers is %d\n", packet_info->system_header_size)); + return 0; +} + + static int bkn_do_api_rx(bkn_switch_info_t *sinfo, int chan, int budget) { @@ -2824,7 +3492,8 @@ bkn_do_api_rx(bkn_switch_info_t *sinfo, int chan, int budget) int pktlen; int idx; int dcbs_done = 0; - bkn_dnx_packet_info packet_info = {0}; + bkn_dune_system_header_info_t packet_info = {0}; + uint32_t dnx_meta_data[3] = {0}; dcb_chain = sinfo->rx[chan].api_dcb_chain; if (dcb_chain == NULL) { @@ -2868,9 +3537,16 @@ bkn_do_api_rx(bkn_switch_info_t *sinfo, int chan, int budget) } pkt = (uint8_t *)kernel_bde->p2l(sinfo->dev_no, (sal_paddr_t)pkt_dma); if (sinfo->cmic_type == 'x') { - meta = (uint32_t *)pkt; - err_woff = sinfo->pkt_hdr_size / sizeof(uint32_t) - 1; - meta[err_woff] = dcb[sinfo->dcb_wsize-1]; + if (device_is_dnx(sinfo)){ + meta = &dnx_meta_data[0]; + /* get error bit from last DCB words */ + err_woff = 2; + meta[err_woff] = dcb[sinfo->dcb_wsize-1]; + } else { + meta = (uint32_t *)pkt; + err_woff = sinfo->pkt_hdr_size / sizeof(uint32_t) - 1; + meta[err_woff] = dcb[sinfo->dcb_wsize-1]; + } } else { meta = dcb; err_woff = sinfo->dcb_wsize - 1; @@ -2878,22 +3554,22 @@ bkn_do_api_rx(bkn_switch_info_t *sinfo, int chan, int budget) pktlen = dcb[sinfo->dcb_wsize-1] & SOC_DCB_KNET_COUNT_MASK; bkn_dump_pkt(pkt, pktlen, XGS_DMA_RX_CHAN); - if (device_is_dune(sinfo)) { + if (device_is_dpp(sinfo)) { uint16_t tpid = 0; uint16_t vid = 0; int res = -1; - memset(&packet_info, 0, sizeof(bkn_dnx_packet_info)); - res = bkn_dnx_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info); + memset(&packet_info, 0, sizeof(bkn_dune_system_header_info_t)); + res = bkn_dpp_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info); if (res == 0) { if (packet_info.ftmh.action_type == 0x2) { - bkn_dnx_bitstream_set_field((uint32_t *)dcb, 192, 32, 0x8); + bkn_bitstream_set_field((uint32_t *)dcb, 192, 32, 0x8); } else if (packet_info.ftmh.action_type == 0x1) { - bkn_dnx_bitstream_set_field((uint32_t *)dcb, 231, 25, 0x20); + bkn_bitstream_set_field((uint32_t *)dcb, 231, 25, 0x20); } - bkn_dnx_bitstream_set_field((uint32_t *)dcb, 112, 16, packet_info.ftmh.src_sys_port); - bkn_dnx_bitstream_set_field((uint32_t *)dcb, 296, 12, packet_info.internal.vsi); - bkn_dnx_bitstream_set_field((uint32_t *)dcb, 64, 32, (packet_info.internal.trap_id << 16 | packet_info.internal.trap_qualifier)); + bkn_bitstream_set_field((uint32_t *)dcb, 112, 16, packet_info.ftmh.src_sys_port); + bkn_bitstream_set_field((uint32_t *)dcb, 296, 12, packet_info.internal.vsi); + bkn_bitstream_set_field((uint32_t *)dcb, 64, 32, (packet_info.internal.trap_id << 16 | packet_info.internal.trap_qualifier)); pkt += packet_info.ntwrk_header_ptr; pktlen -= packet_info.ntwrk_header_ptr; bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN); @@ -2919,10 +3595,25 @@ bkn_do_api_rx(bkn_switch_info_t *sinfo, int chan, int budget) } } } + else if (device_is_dnx(sinfo)) { + int res = -1; + res = bkn_dnx_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info); + if (res == 0) { + bkn_bitstream_set_field(meta, 0, 16, packet_info.fhei_code); + bkn_bitstream_set_field(meta, 16, 16, packet_info.fhei_qualifier); + bkn_bitstream_set_field(meta, 32, 16, packet_info.ftmh_spa); + bkn_bitstream_set_field(meta, 48, 16, (packet_info.pph_forward_domain & 0xffff)); - if (device_is_dune(sinfo)) { - filter = bkn_match_rx_pkt(sinfo, pkt, pktlen + packet_info.ntwrk_header_ptr, - dcb, chan, &cbf); + pkt += packet_info.system_header_size; + pktlen -= packet_info.system_header_size; + bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN); + } + } + + if (device_is_dpp(sinfo)) { + filter = bkn_match_rx_pkt(sinfo, pkt, pktlen, dcb, chan, &cbf); + } else if (device_is_dnx(sinfo)) { + filter = bkn_match_rx_pkt(sinfo, pkt, pktlen, meta, chan, &cbf); } else { filter = bkn_match_rx_pkt(sinfo, pkt + sinfo->pkt_hdr_size, pktlen - sinfo->pkt_hdr_size, meta, chan, &cbf); @@ -3001,7 +3692,7 @@ bkn_do_api_rx(bkn_switch_info_t *sinfo, int chan, int budget) } skb_copy_to_linear_data(skb, pkt, pktlen); - if (device_is_dune(sinfo)) { + if (device_is_sand(sinfo)) { /* CRC has been stripped */ skb_put(skb, pktlen); } else { @@ -3023,6 +3714,11 @@ bkn_do_api_rx(bkn_switch_info_t *sinfo, int chan, int budget) } } + /* Do Rx timestamping */ + if (sinfo->rx_hwts) { + bkn_hw_tstamp_rx_set(sinfo, skb, meta); + } + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { bkn_add_rcpu_encap(sinfo, skb, meta); DBG_PDMP(("After add RCPU ENCAP\n")); @@ -3095,7 +3791,8 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) int pktlen; int idx; int dcbs_done = 0; - bkn_dnx_packet_info packet_info = {0}; + bkn_dune_system_header_info_t packet_info = {0}; + uint32_t dnx_meta_data[3] = {0}; if (!sinfo->rx[chan].running) { /* Rx not ready */ @@ -3122,9 +3819,16 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) sinfo->rx[chan].pkts++; skb = desc->skb; if (sinfo->cmic_type == 'x') { - meta = (uint32_t *)skb->data; - err_woff = sinfo->pkt_hdr_size / sizeof(uint32_t) - 1; - meta[err_woff] = dcb[sinfo->dcb_wsize-1]; + if (device_is_dnx(sinfo)){ + meta = &dnx_meta_data[0]; + /* get error bit from last DCB words */ + err_woff = 2; + meta[err_woff] = dcb[sinfo->dcb_wsize-1]; + } else { + meta = (uint32_t *)skb->data; + err_woff = sinfo->pkt_hdr_size / sizeof(uint32_t) - 1; + meta[err_woff] = dcb[sinfo->dcb_wsize-1]; + } } else { meta = dcb; err_woff = sinfo->dcb_wsize - 1; @@ -3138,23 +3842,23 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) desc->skb_dma = 0; bkn_dump_pkt(skb->data, pktlen, XGS_DMA_RX_CHAN); - if (device_is_dune(sinfo)) { + if (device_is_dpp(sinfo)) { uint16_t tpid = 0; uint16_t vid = 0; uint8_t *pkt = skb->data; int res = 0; - memset(&packet_info, 0, sizeof(bkn_dnx_packet_info)); - res = bkn_dnx_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info); + memset(&packet_info, 0, sizeof(bkn_dune_system_header_info_t)); + res = bkn_dpp_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info); if (res == 0) { if (packet_info.ftmh.action_type == 0x2) { - bkn_dnx_bitstream_set_field((uint32_t *)dcb, 192, 32, 0x8); + bkn_bitstream_set_field((uint32_t *)dcb, 192, 32, 0x8); } else if (packet_info.ftmh.action_type == 0x1) { - bkn_dnx_bitstream_set_field((uint32_t *)dcb, 231, 25, 0x20); + bkn_bitstream_set_field((uint32_t *)dcb, 231, 25, 0x20); } - bkn_dnx_bitstream_set_field((uint32_t *)dcb, 112, 16, packet_info.ftmh.src_sys_port); - bkn_dnx_bitstream_set_field((uint32_t *)dcb, 296, 12, packet_info.internal.vsi); - bkn_dnx_bitstream_set_field((uint32_t *)dcb, 64, 32, (packet_info.internal.trap_id << 16 | packet_info.internal.trap_qualifier)); + bkn_bitstream_set_field((uint32_t *)dcb, 112, 16, packet_info.ftmh.src_sys_port); + bkn_bitstream_set_field((uint32_t *)dcb, 296, 12, packet_info.internal.vsi); + bkn_bitstream_set_field((uint32_t *)dcb, 64, 32, (packet_info.internal.trap_id << 16 | packet_info.internal.trap_qualifier)); pkt = skb->data + packet_info.ntwrk_header_ptr; /* check if vlan tag exists */ tpid = (uint16_t)((pkt[12] << 8) | pkt[13]); @@ -3178,10 +3882,29 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) } } } + else if (device_is_dnx(sinfo)) { + uint8_t *pkt = skb->data; + int res = -1; + + res = bkn_dnx_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info); + if (res == 0) { + bkn_bitstream_set_field(meta, 0, 16, packet_info.fhei_code); + bkn_bitstream_set_field(meta, 16, 16, packet_info.fhei_qualifier); + bkn_bitstream_set_field(meta, 32, 16, packet_info.ftmh_spa); + bkn_bitstream_set_field(meta, 48, 16, (packet_info.pph_forward_domain & 0xffff)); - if (device_is_dune(sinfo)) { - filter = bkn_match_rx_pkt(sinfo, skb->data + packet_info.ntwrk_header_ptr, + pkt += packet_info.system_header_size; + pktlen -= packet_info.ntwrk_header_ptr; + bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN); + } + } + + if (device_is_dpp(sinfo)) { + filter = bkn_match_rx_pkt(sinfo, skb->data + packet_info.ntwrk_header_ptr, pktlen, dcb, chan, &cbf); + } else if (device_is_dnx(sinfo)) { + filter = bkn_match_rx_pkt(sinfo, skb->data + packet_info.system_header_size, + pktlen, meta, chan, &cbf); } else { filter = bkn_match_rx_pkt(sinfo, skb->data + sinfo->pkt_hdr_size, pktlen - sinfo->pkt_hdr_size, meta, chan, &cbf); @@ -3216,12 +3939,12 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) sinfo->rx[chan].pkts_f_netif++; if (((filter->kf.mirror_type == KCOM_DEST_T_API) && - (!device_is_dune(sinfo))) || dbg_pkt_enable) { + (!device_is_sand(sinfo))) || dbg_pkt_enable) { sinfo->rx[chan].pkts_m_api++; bkn_api_rx_copy_from_skb(sinfo, chan, desc); } - if (device_is_dune(sinfo)) { + if (device_is_dpp(sinfo)) { if (filter->kf.mirror_type == KCOM_DEST_T_API) { sinfo->rx[chan].pkts_m_api++; bkn_api_rx_copy_from_skb(sinfo, chan, desc); @@ -3232,11 +3955,22 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) bkn_dump_pkt(skb->data, 32, XGS_DMA_RX_CHAN); /* CRC has been stripped on Dune*/ skb_put(skb, pktlen); + } else if (device_is_dnx(sinfo)) { + if (filter->kf.mirror_type == KCOM_DEST_T_API) { + sinfo->rx[chan].pkts_m_api++; + bkn_api_rx_copy_from_skb(sinfo, chan, desc); + } + /* Strip Dune headers */ + skb->data += packet_info.system_header_size; + pktlen -= packet_info.system_header_size; + bkn_dump_pkt(skb->data, 32, XGS_DMA_RX_CHAN); + /* CRC has been stripped on Dune*/ + skb_put(skb, pktlen); } else { skb_put(skb, pktlen - 4); /* Strip CRC */ } - if (sinfo->cmic_type == 'x') { + if (sinfo->cmic_type == 'x' && !device_is_dnx(sinfo)) { skb_pull(skb, sinfo->pkt_hdr_size); } @@ -3252,7 +3986,7 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) ((u32*)skb->data)[2] = ((u32*)skb->data)[1]; ((u32*)skb->data)[1] = ((u32*)skb->data)[0]; skb_pull(skb, 4); - if (sinfo->cmic_type == 'x') { + if (sinfo->cmic_type == 'x' && !device_is_dnx(sinfo)) { for (idx = sinfo->pkt_hdr_size / sizeof(uint32_t); idx; idx--) { meta[idx] = meta[idx - 1]; } @@ -3292,6 +4026,11 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) } } + /* Do Rx timestamping */ + if (sinfo->rx_hwts) { + bkn_hw_tstamp_rx_set(sinfo, skb, meta); + } + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { bkn_add_rcpu_encap(sinfo, skb, meta); DBG_PDMP(("After add RCPU ENCAP\n")); @@ -3489,6 +4228,45 @@ bkn_resume_tx(bkn_switch_info_t *sinfo) } } +static int +bkn_hw_tstamp_tx_set(bkn_switch_info_t *sinfo, struct sk_buff *skb) +{ + struct skb_shared_hwtstamps shhwtstamps; + uint64_t ts = 0; + uint32_t hdrlen = sinfo->cmic_type == 'x' ? PKT_TX_HDR_SIZE : 0; + int port; + + if (!knet_hw_tstamp_tx_time_get_cb) { + return -1; + } + + port = KNET_SKB_CB(skb)->port; + if (knet_hw_tstamp_tx_time_get_cb(sinfo->dev_no, port, skb->data + hdrlen, &ts) < 0) { + return -1; + } + + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + shhwtstamps.hwtstamp = ns_to_ktime(be64_to_cpu(ts)); + skb_tstamp_tx(skb, &shhwtstamps); + + return 0; +} + +static void +bkn_hw_tstamp_tx_work(struct work_struct *work) +{ + bkn_switch_info_t *sinfo = container_of(work, bkn_switch_info_t, tx_ptp_work); + struct sk_buff *skb; + + while (skb_queue_len(&sinfo->tx_ptp_queue)) { + skb = skb_dequeue(&sinfo->tx_ptp_queue); + if (bkn_hw_tstamp_tx_set(sinfo, skb) < 0) { + gprintk("Timestamp has not been taken for the current skb.\n"); + } + dev_kfree_skb_any(skb); + } +} + static int bkn_do_tx(bkn_switch_info_t *sinfo) { @@ -3515,7 +4293,12 @@ bkn_do_tx(bkn_switch_info_t *sinfo) DMA_UNMAP_SINGLE(sinfo->dma_dev, desc->skb_dma, desc->dma_size, DMA_TODEV); - dev_kfree_skb_any(desc->skb); + if (bkn_skb_tx_flags(desc->skb) & SKBTX_IN_PROGRESS) { + skb_queue_tail(&sinfo->tx_ptp_queue, desc->skb); + schedule_work(&sinfo->tx_ptp_work); + } else { + dev_kfree_skb_any(desc->skb); + } desc->skb = NULL; desc->skb_dma = 0; } @@ -3926,10 +4709,16 @@ xgsx_do_dma(bkn_switch_info_t *sinfo, int budget) { int rx_dcbs_done = 0, tx_dcbs_done = 0; int chan_done, budget_chans = 0; - uint32_t irq_stat; + uint32_t irq_stat, tx_dma_stat, rx_dma_stat[NUM_CMICX_RX_CHAN]; int chan; DEV_READ32(sinfo, CMICX_IRQ_STATr, &irq_stat); + DEV_READ32(sinfo, CMICX_DMA_STATr + 0x80 * XGS_DMA_TX_CHAN, &tx_dma_stat); + for (chan = 0; chan < sinfo->rx_chans; chan++) { + DEV_READ32(sinfo, + CMICX_DMA_STATr + 0x80 * (XGS_DMA_RX_CHAN + chan), + &rx_dma_stat[chan]); + } for (chan = 0; chan < sinfo->rx_chans; chan++) { if ((irq_stat & CMICX_DS_CMC_CTRLD_INT(XGS_DMA_RX_CHAN + chan)) || @@ -3964,14 +4753,14 @@ xgsx_do_dma(bkn_switch_info_t *sinfo, int budget) continue; } - if (irq_stat & CMICX_DS_CMC_CHAIN_DONE(XGS_DMA_RX_CHAN + chan)) { + if (rx_dma_stat[chan] & CMICX_DS_CMC_DMA_CHAIN_DONE) { xgsx_dma_chain_clear(sinfo, XGS_DMA_RX_CHAN + chan); bkn_rx_chain_done(sinfo, chan); } } if ((irq_stat & CMICX_DS_CMC_CTRLD_INT(XGS_DMA_TX_CHAN)) || - (irq_stat & CMICX_DS_CMC_CHAIN_DONE(XGS_DMA_TX_CHAN))) { + (tx_dma_stat & CMICX_DS_CMC_DMA_CHAIN_DONE)) { if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { xgsx_dma_desc_clear(sinfo, XGS_DMA_TX_CHAN); } else { @@ -4229,6 +5018,70 @@ bkn_set_mac_address(struct net_device *dev, void *addr) } #endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) +static int +bkn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + bkn_priv_t *priv = netdev_priv(dev); + bkn_switch_info_t *sinfo = priv->sinfo; + struct hwtstamp_config config; + + if (cmd == SIOCSHWTSTAMP) { + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) { + return -EFAULT; + } + + if (!knet_hw_tstamp_enable_cb || !knet_hw_tstamp_disable_cb || + priv->type != KCOM_NETIF_T_PORT) { + return -ERANGE; + } + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + knet_hw_tstamp_disable_cb(sinfo->dev_no, priv->port); + sinfo->tx_hwts = 0; + break; + case HWTSTAMP_TX_ON: + knet_hw_tstamp_enable_cb(sinfo->dev_no, priv->port); + sinfo->tx_hwts = 1; + break; + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + if (sinfo->rx_hwts) { + knet_hw_tstamp_disable_cb(sinfo->dev_no, priv->port); + sinfo->rx_hwts = 0; + } + break; + default: + if (!sinfo->rx_hwts) { + knet_hw_tstamp_enable_cb(sinfo->dev_no, priv->port); + sinfo->rx_hwts = 1; + } + config.rx_filter = HWTSTAMP_FILTER_ALL; + break; + } + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + if (cmd == SIOCGHWTSTAMP) { + config.flags = 0; + config.tx_type = sinfo->tx_hwts ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; + config.rx_filter = sinfo->rx_hwts ? HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE; + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; + } +#endif + + return -EINVAL; +} +#endif + static int bkn_change_mtu(struct net_device *dev, int new_mtu) { @@ -4354,6 +5207,44 @@ bkn_set_multicast_list(struct net_device *dev) { } +static int +bkn_hw_tstamp_tx_config(bkn_switch_info_t *sinfo, struct sk_buff *skb, uint32_t *meta) +{ + uint32_t *md = NULL; + + if (!knet_hw_tstamp_tx_meta_get_cb) { + return -1; + } + + KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF; + knet_hw_tstamp_tx_meta_get_cb(sinfo->dev_no, skb, &md); + if (!md) { + return -1; + } + + switch (sinfo->dcb_type) { + case 26: + case 32: + case 33: + meta[2] |= md[0]; + meta[3] |= md[1]; + meta[4] |= md[2]; + meta[5] |= md[3]; + break; + case 36: + case 38: + meta[0] |= md[0]; + meta[1] |= md[1]; + meta[2] |= md[2]; + meta[3] |= md[3]; + break; + default: + return -1; + } + + return 0; +} + static int bkn_tx(struct sk_buff *skb, struct net_device *dev) { @@ -4391,8 +5282,8 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) uint32_t *dcb, *meta; pktdata = skb->data; - pktlen = skb->len + 4; - hdrlen = sinfo->cmic_type == 'x' ? PKT_TX_HDR_SIZE : 0; + pktlen = skb->len; + hdrlen = (sinfo->cmic_type == 'x' ) ? ((device_is_dnx(sinfo)) ? priv->system_headers_size: PKT_TX_HDR_SIZE) : 0; rcpulen = 0; sop = 0; @@ -4447,7 +5338,7 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) if (skb_header_cloned(skb)) { /* Current SKB cannot be modified */ DBG_SKB(("Realloc Tx SKB\n")); - new_skb = dev_alloc_skb(pktlen + 4); + new_skb = dev_alloc_skb(pktlen + TAG_SZ + FCS_SZ); if (new_skb == NULL) { DBG_WARN(("Tx drop: No SKB memory\n")); priv->stats.tx_dropped++; @@ -4458,7 +5349,7 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) } memcpy(new_skb->data, pktdata, 12); memcpy(&new_skb->data[16], &pktdata[12], pktlen - 12); - skb_put(new_skb, pktlen + 4); + skb_put(new_skb, pktlen + TAG_SZ); dev_kfree_skb_any(skb); skb = new_skb; pktdata = skb->data; @@ -4466,26 +5357,25 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) } else { /* Add tag to RCPU header space */ DBG_SKB(("Expand into unused RCPU header\n")); - rcpulen -= 4; + rcpulen -= TAG_SZ; pktdata = &skb->data[rcpulen]; for (idx = 0; idx < 12; idx++) { - pktdata[idx] = pktdata[idx + 4]; + pktdata[idx] = pktdata[idx + TAG_SZ]; } } pktdata[12] = 0x81; pktdata[13] = 0x00; pktdata[14] = (priv->vlan >> 8) & 0xf; pktdata[15] = priv->vlan & 0xff; - pktlen += 4; + pktlen += TAG_SZ; } } } else { if (sinfo->cmic_type == 'x' && priv->port >= 0) { - if (skb_header_cloned(skb) || skb_headroom(skb) < hdrlen + 4 || - (sinfo->dcb_type == 36 && (unsigned long)skb->data % 4)) { + if (skb_header_cloned(skb) || skb_headroom(skb) < hdrlen + 4) { /* Current SKB cannot be modified */ DBG_SKB(("Realloc Tx SKB\n")); - new_skb = dev_alloc_skb(pktlen + hdrlen + 4); + new_skb = dev_alloc_skb(pktlen + hdrlen + 4 + FCS_SZ); if (new_skb == NULL) { DBG_WARN(("Tx drop: No SKB memory\n")); priv->stats.tx_dropped++; @@ -4494,7 +5384,10 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&sinfo->lock, flags); return 0; } - skb_reserve(new_skb, 4); + if (!device_is_dnx(sinfo)) + { + skb_reserve(new_skb, 4); + } memcpy(new_skb->data + hdrlen, skb->data, pktlen); skb_put(new_skb, pktlen + hdrlen); dev_kfree_skb_any(skb); @@ -4511,13 +5404,14 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) } if (priv->port < 0 || (priv->flags & KCOM_NETIF_F_ADD_TAG)) { + DBG_DUNE(("ADD VLAN TAG\n")); /* Need to add VLAN tag if packet is untagged */ tpid = (skb->data[hdrlen + 12] << 8) | skb->data[hdrlen + 13]; if (tpid != 0x8100) { if (skb_header_cloned(skb) || skb_headroom(skb) < 4) { /* Current SKB cannot be modified */ DBG_SKB(("Realloc Tx SKB\n")); - new_skb = dev_alloc_skb(pktlen + 4); + new_skb = dev_alloc_skb(pktlen + TAG_SZ + FCS_SZ); if (new_skb == NULL) { DBG_WARN(("Tx drop: No SKB memory\n")); priv->stats.tx_dropped++; @@ -4529,15 +5423,15 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) memcpy(new_skb->data, skb->data, hdrlen + 12); memcpy(&new_skb->data[hdrlen + 16], &skb->data[hdrlen + 12], pktlen - hdrlen - 12); - skb_put(new_skb, pktlen + 4); + skb_put(new_skb, pktlen + TAG_SZ); dev_kfree_skb_any(skb); skb = new_skb; } else { /* Add tag to existing buffer */ DBG_SKB(("Expand Tx SKB\n")); - skb_push(skb, 4); + skb_push(skb, TAG_SZ); for (idx = 0; idx < hdrlen + 12; idx++) { - skb->data[idx] = skb->data[idx + 4]; + skb->data[idx] = skb->data[idx + TAG_SZ]; } } pktdata = skb->data; @@ -4545,7 +5439,7 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) pktdata[hdrlen + 13] = 0x00; pktdata[hdrlen + 14] = (priv->vlan >> 8) & 0xf; pktdata[hdrlen + 15] = priv->vlan & 0xff; - pktlen += 4; + pktlen += TAG_SZ; } } } @@ -4556,8 +5450,8 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) if (tpid == 0x8100) { taglen = 4; } - if (pktlen < (64 + taglen + hdrlen)) { - pktlen = (64 + taglen + hdrlen); + if (pktlen < (60 + taglen + hdrlen)) { + pktlen = (60 + taglen + hdrlen); if (SKB_PADTO(skb, pktlen) != 0) { DBG_WARN(("Tx drop: skb_padto failed\n")); priv->stats.tx_dropped++; @@ -4568,12 +5462,11 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) } /* skb_padto may update the skb->data pointer */ pktdata = &skb->data[rcpulen]; - DBG_SKB(("Packet padded to %d bytes\n", pktlen)); } - if (pktlen > SOC_DCB_KNET_COUNT_MASK) { + if ((pktlen + FCS_SZ) > SOC_DCB_KNET_COUNT_MASK) { DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n", - pktlen, SOC_DCB_KNET_COUNT_MASK)); + (pktlen + FCS_SZ), SOC_DCB_KNET_COUNT_MASK)); sinfo->tx.pkts_d_over_limit++; priv->stats.tx_dropped++; dev_kfree_skb_any(skb); @@ -4582,7 +5475,7 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) } dcb = desc->dcb_mem; - meta = sinfo->cmic_type == 'x' ? (uint32_t *)pktdata : dcb; + meta = (sinfo->cmic_type == 'x') ? (uint32_t *)pktdata : dcb; memset(dcb, 0, sinfo->dcb_wsize * sizeof(uint32_t)); if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { /* If module header SOP is non-zero, use RCPU meta data */ @@ -4634,7 +5527,7 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) if (skb_header_cloned(skb) || skb_headroom(skb) < 4) { /* Current SKB cannot be modified */ DBG_SKB(("Realloc Tx SKB for DNX ITMH header\n")); - new_skb = dev_alloc_skb(pktlen + 4 + 2); + new_skb = dev_alloc_skb(pktlen + 4 + 2 + FCS_SZ); if (new_skb == NULL) { DBG_WARN(("Tx drop: No SKB memory for DNX ITMH header\n")); priv->stats.tx_dropped++; @@ -4663,7 +5556,7 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) if (skb_header_cloned(skb) || skb_headroom(skb) < 4) { /* Current SKB cannot be modified */ DBG_SKB(("Realloc Tx SKB for DNX header\n")); - new_skb = dev_alloc_skb(pktlen + 2); + new_skb = dev_alloc_skb(pktlen + 2 + FCS_SZ); if (new_skb == NULL) { DBG_WARN(("Tx drop: No SKB memory for DNX header\n")); priv->stats.tx_dropped++; @@ -4737,6 +5630,16 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) dcb[4] |= (priv->qnum & 0x3f) << 8; } break; + case 39: + if (device_is_dnx(sinfo)) { + /* + * if KCOM_NETIF_T_PORT, add MH+PTCH+ITMH header + * if KCOM_NETIF_T_VLAN, add MH+PTCH+header + */ + pktdata = skb->data; + memcpy(&pktdata[0], priv->system_headers, priv->system_headers_size); + } + break; default: dcb[2] = 0xff000000; dcb[3] = 0x00000100; @@ -4761,10 +5664,10 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) /* Restore (possibly) altered packet variables * bit0 -bit15 of dcb[1] is used to save requested byte count */ - if ((skb->len + 4) <= SOC_DCB_KNET_COUNT_MASK) { - pktlen = skb->len + 4; - if (pktlen < (64 + taglen + hdrlen)) { - pktlen = (64 + taglen + hdrlen); + if ((skb->len + FCS_SZ) <= SOC_DCB_KNET_COUNT_MASK) { + pktlen = skb->len; + if (pktlen < (60 + taglen + hdrlen)) { + pktlen = (60 + taglen + hdrlen); if (SKB_PADTO(skb, pktlen) != 0) { DBG_WARN(("Tx drop: skb_padto failed\n")); priv->stats.tx_dropped++; @@ -4776,9 +5679,12 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) DBG_SKB(("Packet padded to %d bytes after tx callback\n", pktlen)); } pktdata = skb->data; + if (sinfo->cmic_type == 'x') { + meta = (uint32_t *)pktdata; + } } else { DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n", - pktlen, SOC_DCB_KNET_COUNT_MASK)); + (pktlen + FCS_SZ), SOC_DCB_KNET_COUNT_MASK)); sinfo->tx.pkts_d_over_limit++; priv->stats.tx_dropped++; sinfo->tx.pkts_d_callback++; @@ -4788,8 +5694,20 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) } } + /* Do Tx timestamping */ + if (priv->port >= 0) { + if (bkn_skb_tx_flags(skb) & SKBTX_HW_TSTAMP && sinfo->tx_hwts) { + KNET_SKB_CB(skb)->port = priv->port; + bkn_hw_tstamp_tx_config(sinfo, skb, meta); + bkn_skb_tx_flags(skb) |= SKBTX_IN_PROGRESS; + } + bkn_skb_tx_timestamp(skb); + } + /* Prepare for DMA */ desc->skb = skb; + /* Add FCS bytes */ + pktlen = pktlen + FCS_SZ; desc->dma_size = pktlen; desc->skb_dma = DMA_MAP_SINGLE(sinfo->dma_dev, pktdata, desc->dma_size, @@ -4859,9 +5777,8 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) } static void -bkn_timer(unsigned long context) +bkn_timer_func(bkn_switch_info_t *sinfo) { - bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context; unsigned long flags; int chan; int restart_timer; @@ -4892,6 +5809,22 @@ bkn_timer(unsigned long context) spin_unlock_irqrestore(&sinfo->lock, flags); } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)) +static void +bkn_timer(unsigned long context) +{ + bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context; + return bkn_timer_func(sinfo); +} +#else +static void +bkn_timer(struct timer_list *t) +{ + bkn_switch_info_t *sinfo = from_timer(sinfo, t, timer); + return bkn_timer_func(sinfo); +} +#endif + static void bkn_rx_add_tokens(bkn_switch_info_t *sinfo, int chan) { @@ -4925,9 +5858,8 @@ bkn_rx_add_tokens(bkn_switch_info_t *sinfo, int chan) } static void -bkn_rxtick(unsigned long context) +bkn_rxtick_func(bkn_switch_info_t *sinfo) { - bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context; unsigned long flags; unsigned long cur_jif, ticks; uint32_t pkt_diff; @@ -4962,6 +5894,22 @@ bkn_rxtick(unsigned long context) add_timer(&sinfo->rxtick); } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)) +static void +bkn_rxtick(unsigned long context) +{ + bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context; + return bkn_rxtick_func(sinfo); +} +#else +static void +bkn_rxtick(struct timer_list *t) +{ + bkn_switch_info_t *sinfo = from_timer(sinfo, t, rxtick); + return bkn_rxtick_func(sinfo); +} +#endif + static void bkn_rx_rate_config(bkn_switch_info_t *sinfo) { @@ -5041,11 +5989,17 @@ bkn_create_sinfo(int dev_no) sinfo->evt_idx = -1; spin_lock_init(&sinfo->lock); + skb_queue_head_init(&sinfo->tx_ptp_queue); + INIT_WORK(&sinfo->tx_ptp_work, bkn_hw_tstamp_tx_work); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)) init_timer(&sinfo->timer); - sinfo->timer.expires = jiffies + 1; sinfo->timer.data = (unsigned long)sinfo; sinfo->timer.function = bkn_timer; +#else + timer_setup(&sinfo->timer, bkn_timer, 0); +#endif + sinfo->timer.expires = jiffies + 1; INIT_LIST_HEAD(&sinfo->tx.api_dcb_list); @@ -5063,10 +6017,14 @@ bkn_create_sinfo(int dev_no) sinfo->rx[0].use_rx_skb = 0; } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)) init_timer(&sinfo->rxtick); - sinfo->rxtick.expires = jiffies + 1; sinfo->rxtick.data = (unsigned long)sinfo; sinfo->rxtick.function = bkn_rxtick; +#else + timer_setup(&sinfo->rxtick, bkn_rxtick, 0); +#endif + sinfo->rxtick.expires = jiffies + 1; for (chan = 0; chan < NUM_RX_CHAN; chan++) { sinfo->rx[chan].rate_max = rx_rate[chan]; @@ -5081,7 +6039,6 @@ bkn_create_sinfo(int dev_no) return sinfo; } - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) static const struct net_device_ops bkn_netdev_ops = { .ndo_open = bkn_open, @@ -5091,7 +6048,7 @@ static const struct net_device_ops bkn_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_rx_mode = bkn_set_multicast_list, .ndo_set_mac_address = bkn_set_mac_address, - .ndo_do_ioctl = NULL, + .ndo_do_ioctl = bkn_ioctl, .ndo_tx_timeout = NULL, .ndo_change_mtu = bkn_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -5100,6 +6057,61 @@ static const struct net_device_ops bkn_netdev_ops = { }; #endif +static void +bkn_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) +{ + strlcpy(drvinfo->driver, "bcm-knet", sizeof(drvinfo->driver)); + snprintf(drvinfo->version, sizeof(drvinfo->version), "%d", KCOM_VERSION); + strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); + strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info)); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)) +static int +bkn_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) +{ + bkn_priv_t *priv = netdev_priv(dev); + bkn_switch_info_t *sinfo = priv->sinfo; + + switch (sinfo->dcb_type) { + case 26: + case 32: + case 33: + case 36: + case 38: + info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + info->tx_types = 1 << HWTSTAMP_TX_OFF | 1 << HWTSTAMP_TX_ON; + info->rx_filters = 1 << HWTSTAMP_FILTER_NONE | 1 << HWTSTAMP_FILTER_ALL; + if (knet_hw_tstamp_ptp_clock_index_cb) { + info->phc_index = knet_hw_tstamp_ptp_clock_index_cb(sinfo->dev_no); + } else { + info->phc_index = -1; + } + break; + default: + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE; + info->phc_index = -1; + break; + } + + return 0; +} +#endif + +static const struct ethtool_ops bkn_ethtool_ops = { + .get_drvinfo = bkn_get_drvinfo, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)) + .get_ts_info = bkn_get_ts_info, +#endif +}; + static struct net_device * bkn_init_ndev(u8 *mac, char *name) { @@ -5148,6 +6160,7 @@ bkn_init_ndev(u8 *mac, char *name) dev->poll_controller = bkn_poll_controller; #endif #endif + dev->ethtool_ops = &bkn_ethtool_ops; if (name && *name) { strncpy(dev->name, name, IFNAMSIZ-1); } @@ -6417,10 +7430,12 @@ bkn_knet_hw_reset(kcom_msg_hw_reset_t *kmsg, int len) /* Clean all if no channels specified */ bkn_dma_abort(sinfo); bkn_clean_dcbs(sinfo); + skb_queue_purge(&sinfo->tx_ptp_queue); } else { if (kmsg->channels & (1 << XGS_DMA_TX_CHAN)) { bkn_dma_abort_tx(sinfo); bkn_clean_tx_dcbs(sinfo); + skb_queue_purge(&sinfo->tx_ptp_queue); } for (chan = 0; chan < sinfo->rx_chans; chan++) { if (kmsg->channels & (1 << (XGS_DMA_RX_CHAN + chan))) { @@ -6464,6 +7479,10 @@ bkn_knet_hw_init(kcom_msg_hw_init_t *kmsg, int len) sinfo->rx_chans = NUM_RX_CHAN; } + DBG_DUNE(("CMIC:%c DCB:%d WSIZE:%d DMA HI: 0x%08x HDR size: %d\n", + sinfo->cmic_type, sinfo->dcb_type, sinfo->dcb_wsize, + sinfo->dma_hi, sinfo->pkt_hdr_size)); + /* Config Continuous DMA mode */ sinfo->cdma_channels = kmsg->cdma_channels & ~(~0 << (sinfo->rx_chans + 1)); @@ -6602,17 +7621,26 @@ bkn_knet_netif_create(kcom_msg_netif_create_t *kmsg, int len) priv->vlan = kmsg->netif.vlan; if (priv->type == KCOM_NETIF_T_PORT) { priv->port = kmsg->netif.port; - memcpy(priv->itmh, kmsg->netif.itmh, 4); + if (device_is_dpp(sinfo)) { + memcpy(priv->itmh, kmsg->netif.itmh, 4); + } else if (device_is_dnx(sinfo)) { + memcpy(priv->system_headers, kmsg->netif.system_headers, kmsg->netif.system_headers_size); + priv->system_headers_size = kmsg->netif.system_headers_size; + } priv->qnum = kmsg->netif.qnum; } else { - if ((device_is_dune(sinfo)) && (priv->type == KCOM_NETIF_T_VLAN)) { - /* set port as SSP to PTCH */ - priv->port = kmsg->netif.port; - priv->qnum = kmsg->netif.qnum; - } - else { - priv->port = -1; - } + if (device_is_sand(sinfo)) { + if (device_is_dpp(sinfo)) { + priv->port = kmsg->netif.port; + priv->qnum = kmsg->netif.qnum; + }else if (device_is_dnx(sinfo)) { + memcpy(priv->system_headers, kmsg->netif.system_headers, kmsg->netif.system_headers_size); + priv->system_headers_size = kmsg->netif.system_headers_size; + } + } + else { + priv->port = -1; + } } priv->flags = kmsg->netif.flags; priv->cb_user_data = kmsg->netif.cb_user_data; @@ -6673,14 +7701,28 @@ bkn_knet_netif_create(kcom_msg_netif_create_t *kmsg, int len) } } - spin_unlock_irqrestore(&sinfo->lock, flags); - DBG_VERB(("Assigned ID %d to Ethernet device %s\n", priv->id, dev->name)); kmsg->netif.id = priv->id; memcpy(kmsg->netif.macaddr, dev->dev_addr, 6); memcpy(kmsg->netif.name, dev->name, KCOM_NETIF_NAME_MAX - 1); + + if (knet_netif_create_cb != NULL) { + int retv = knet_netif_create_cb(kmsg->hdr.unit, &(kmsg->netif), dev); + if (retv) { + gprintk("Warning: knet_netif_create_cb() returned %d for netif '%s'\n", retv, dev->name); + } + } + + spin_unlock_irqrestore(&sinfo->lock, flags); + + if (device_is_dnx(sinfo)) { + int idx = 0; + for (idx = 0; idx < priv->system_headers_size; idx++) { + DBG_DUNE(("System Header[%d]: 0x%02x\n", idx, priv->system_headers[idx])); + } + } return sizeof(*kmsg); } @@ -6720,6 +7762,12 @@ bkn_knet_netif_destroy(kcom_msg_netif_destroy_t *kmsg, int len) return sizeof(kcom_msg_hdr_t); } + if (knet_netif_destroy_cb != NULL) { + kcom_netif_t netif; + memset(&netif, 0, sizeof(kcom_netif_t)); + netif.id = priv->id; + knet_netif_destroy_cb(kmsg->hdr.unit, &netif, priv->dev); + } list_del(&priv->list); if (priv->id < sinfo->ndev_max) { @@ -6875,6 +7923,17 @@ bkn_knet_filter_create(kcom_msg_filter_create_t *kmsg, int len) } memset(filter, 0, sizeof(*filter)); memcpy(&filter->kf, &kmsg->filter, sizeof(filter->kf)); + + if (device_is_dnx(sinfo)) { + /* Information to parser Dune system headers */ + sinfo->ftmh_lb_key_ext_size = kmsg->filter.ftmh_lb_key_ext_size; + sinfo->ftmh_stacking_ext_size = kmsg->filter.ftmh_stacking_ext_size; + sinfo->pph_base_size = kmsg->filter.pph_base_size; + memcpy(sinfo->pph_lif_ext_size, kmsg->filter.pph_lif_ext_size, sizeof(sinfo->pph_lif_ext_size)); + sinfo->udh_enable = kmsg->filter.udh_enable; + memcpy(sinfo->udh_length_type, kmsg->filter.udh_length_type, sizeof(sinfo->udh_length_type)); + } + filter->kf.id = id; /* Add according to priority */ @@ -6898,6 +7957,20 @@ bkn_knet_filter_create(kcom_msg_filter_create_t *kmsg, int len) DBG_VERB(("Created filter ID %d (%s).\n", filter->kf.id, filter->kf.desc)); + if (device_is_dnx(sinfo)) { + int idx, wsize; + wsize = BYTES2WORDS(filter->kf.oob_data_size + filter->kf.pkt_data_size); + DBG_DUNE(("Filter: oob_data_size = %d pkt_data_size=%d wsize %d\n", filter->kf.oob_data_size, filter->kf.pkt_data_size, wsize)); + for (idx = 0; idx < wsize; idx++) + { + DBG_DUNE(("OOB[%d]: 0x%08x [0x%08x]\n", idx, filter->kf.data.w[idx], filter->kf.mask.w[idx])); + } + DBG_DUNE(("DNX system headers parameters:LB_KEY_EXT %d, STK_EXT %d, PPH_BASE %d, LIF_EXT %d %d %d, UDH_ENA %d, %d %d %d %d\n", + sinfo->ftmh_lb_key_ext_size, sinfo->ftmh_stacking_ext_size, sinfo->pph_base_size, + sinfo->pph_lif_ext_size[1],sinfo->pph_lif_ext_size[2], sinfo->pph_lif_ext_size[3], + sinfo->udh_enable, sinfo->udh_length_type[0], sinfo->udh_length_type[1], sinfo->udh_length_type[2], sinfo->udh_length_type[3])); + } + return len; } @@ -7252,10 +8325,14 @@ bkn_get_next_dma_event(kcom_msg_dma_info_t *kmsg) if (sinfo && (sinfo->inst_id != 0) && ((sinfo->inst_id & (1 << dev_evt)) == 0)) { - DBG_INST((" %s skip dev(%d)\n",__FUNCTION__,dev_evt)); + DBG_INST((" %s skip dev(%d)\n",__FUNCTION__,dev_no)); continue; } + if (sinfo->evt_idx == -1) { + /* Event queue is not ready yet */ + continue; + } if (sinfo && sinfo->dma_events) { DBG_EVT(("Next DMA events (0x%08x)\n", sinfo->dma_events)); kmsg->hdr.unit = sinfo->dev_no; @@ -7269,9 +8346,11 @@ bkn_get_next_dma_event(kcom_msg_dma_info_t *kmsg) break; } - if (dev_no == last_dev_no) { + if ((dev_no == last_dev_no) || + (_bkn_multi_inst && (dev_no == dev_evt))) { evt = &_bkn_evt[sinfo->evt_idx]; - DBG_INST(("wait queue index %d\n",sinfo->evt_idx)); + DBG_INST(("dev_no %d dev_evt %d wait queue index %d\n", + dev_no, dev_evt, sinfo->evt_idx)); wait_event_interruptible(evt->evt_wq, evt->evt_wq_get != evt->evt_wq_put); DBG_VERB(("Event thread wakeup\n")); @@ -7367,6 +8446,7 @@ _cleanup(void) spin_lock_irqsave(&sinfo->lock, flags); bkn_clean_dcbs(sinfo); + skb_queue_purge(&sinfo->tx_ptp_queue); spin_unlock_irqrestore(&sinfo->lock, flags); } @@ -7671,6 +8751,68 @@ gmodule_get(void) return &_gmodule; } +/* + * Get DCB type and other HW info + */ +int +bkn_hw_info_get(int unit, knet_hw_info_t *hw_info) +{ + bkn_switch_info_t *sinfo; + sinfo = bkn_sinfo_from_unit(unit); + if (sinfo == NULL) { + gprintk("Warning: unknown unit: %d\n", unit); + return (-1); + } + + hw_info->cmic_type = sinfo->cmic_type; + hw_info->dcb_type = sinfo->dcb_type; + hw_info->dcb_size = WORDS2BYTES(sinfo->dcb_wsize); + hw_info->pkt_hdr_size = sinfo->pkt_hdr_size; + hw_info->cdma_channels = sinfo->cdma_channels; + + return (0); +} + +int +bkn_netif_create_cb_register(knet_netif_cb_f netif_cb) +{ + if (knet_netif_create_cb != NULL) { + return -1; + } + knet_netif_create_cb = netif_cb; + return 0; +} + +int +bkn_netif_create_cb_unregister(knet_netif_cb_f netif_cb) +{ + if (netif_cb != NULL && knet_netif_create_cb != netif_cb) { + return -1; + } + knet_netif_create_cb = NULL; + return 0; +} + +int +bkn_netif_destroy_cb_register(knet_netif_cb_f netif_cb) +{ + if (knet_netif_destroy_cb != NULL) { + return -1; + } + knet_netif_destroy_cb = netif_cb; + return 0; +} + +int +bkn_netif_destroy_cb_unregister(knet_netif_cb_f netif_cb) +{ + if (netif_cb != NULL && knet_netif_destroy_cb != netif_cb) { + return -1; + } + knet_netif_destroy_cb = NULL; + return 0; +} + /* * Call-back interfaces for other Linux kernel drivers. * @@ -7679,6 +8821,11 @@ gmodule_get(void) * * The Tx call-back allows an external module to modify SKB contents * before it is injected inot the switch. + * + * The HW timestamp callbacks invoke an external module to enable, disable + * HW timestamp on a specific port which is indicated while the netif is + * created through KNET API. KNET can also get device-specific SOBMH and + * timestamp for a Tx PTP packet through these callbacks. */ int @@ -7741,9 +8888,152 @@ bkn_filter_cb_unregister(knet_filter_cb_f filter_cb) return 0; } +int +bkn_hw_tstamp_enable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb) +{ + if (knet_hw_tstamp_enable_cb != NULL) { + return -1; + } + knet_hw_tstamp_enable_cb = hw_tstamp_enable_cb; + return 0; +} + +int +bkn_hw_tstamp_enable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb) +{ + if (hw_tstamp_enable_cb == NULL || + knet_hw_tstamp_enable_cb != hw_tstamp_enable_cb) { + return -1; + } + knet_hw_tstamp_enable_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_disable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb) +{ + if (knet_hw_tstamp_disable_cb != NULL) { + return -1; + } + knet_hw_tstamp_disable_cb = hw_tstamp_disable_cb; + return 0; +} + +int +bkn_hw_tstamp_disable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb) +{ + if (hw_tstamp_disable_cb == NULL || + knet_hw_tstamp_disable_cb != hw_tstamp_disable_cb) { + return -1; + } + knet_hw_tstamp_disable_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_tx_time_get_cb_register(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb) +{ + if (knet_hw_tstamp_tx_time_get_cb != NULL) { + return -1; + } + knet_hw_tstamp_tx_time_get_cb = hw_tstamp_tx_time_get_cb; + return 0; +} + +int +bkn_hw_tstamp_tx_time_get_cb_unregister(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb) +{ + if (hw_tstamp_tx_time_get_cb == NULL || + knet_hw_tstamp_tx_time_get_cb != hw_tstamp_tx_time_get_cb) { + return -1; + } + knet_hw_tstamp_tx_time_get_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_tx_meta_get_cb_register(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb) +{ + if (knet_hw_tstamp_tx_meta_get_cb != NULL) { + return -1; + } + knet_hw_tstamp_tx_meta_get_cb = hw_tstamp_tx_meta_get_cb; + return 0; +} + +int +bkn_hw_tstamp_tx_meta_get_cb_unregister(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb) +{ + if (hw_tstamp_tx_meta_get_cb == NULL || + knet_hw_tstamp_tx_meta_get_cb != hw_tstamp_tx_meta_get_cb) { + return -1; + } + knet_hw_tstamp_tx_meta_get_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_ptp_clock_index_cb_register(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb) +{ + if (knet_hw_tstamp_ptp_clock_index_cb != NULL) { + return -1; + } + knet_hw_tstamp_ptp_clock_index_cb = hw_tstamp_ptp_clock_index_cb; + return 0; +} + +int +bkn_hw_tstamp_ptp_clock_index_cb_unregister(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb) +{ + if (hw_tstamp_ptp_clock_index_cb == NULL || + knet_hw_tstamp_ptp_clock_index_cb != hw_tstamp_ptp_clock_index_cb) { + return -1; + } + knet_hw_tstamp_ptp_clock_index_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_rx_time_upscale_cb_register(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb) +{ + if (knet_hw_tstamp_rx_time_upscale_cb != NULL) { + return -1; + } + knet_hw_tstamp_rx_time_upscale_cb = hw_tstamp_rx_time_upscale_cb; + return 0; +} + +int +bkn_hw_tstamp_rx_time_upscale_cb_unregister(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb) +{ + if (hw_tstamp_rx_time_upscale_cb == NULL || + knet_hw_tstamp_rx_time_upscale_cb != hw_tstamp_rx_time_upscale_cb) { + return -1; + } + knet_hw_tstamp_rx_time_upscale_cb = NULL; + return 0; +} + LKM_EXPORT_SYM(bkn_rx_skb_cb_register); LKM_EXPORT_SYM(bkn_rx_skb_cb_unregister); LKM_EXPORT_SYM(bkn_tx_skb_cb_register); LKM_EXPORT_SYM(bkn_tx_skb_cb_unregister); LKM_EXPORT_SYM(bkn_filter_cb_register); LKM_EXPORT_SYM(bkn_filter_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_enable_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_enable_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_disable_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_disable_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_tx_time_get_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_tx_time_get_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_tx_meta_get_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_tx_meta_get_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_ptp_clock_index_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_ptp_clock_index_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_rx_time_upscale_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_rx_time_upscale_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_info_get); +LKM_EXPORT_SYM(bkn_netif_create_cb_register); +LKM_EXPORT_SYM(bkn_netif_create_cb_unregister); +LKM_EXPORT_SYM(bkn_netif_destroy_cb_register); +LKM_EXPORT_SYM(bkn_netif_destroy_cb_unregister); diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/bcm-knet.h b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/bcm-knet.h index 760690b3fb9d..477c037a0c43 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/bcm-knet.h +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/bcm-knet.h @@ -39,14 +39,17 @@ typedef struct { * Call-back interfaces for other Linux kernel drivers. */ #include +#include +#include typedef struct { uint32 netif_user_data; uint32 filter_user_data; uint16 dcb_type; + int port; } knet_skb_cb_t; -#define KNET_SKB_CB(__skb) ((knet_skb_cb_t *)&((__skb)->cb[0])) +#define KNET_SKB_CB(_skb) ((knet_skb_cb_t *)_skb->cb) typedef struct sk_buff * (*knet_skb_cb_f)(struct sk_buff *skb, int dev_no, void *meta); @@ -55,6 +58,21 @@ typedef int (*knet_filter_cb_f)(uint8_t *pkt, int size, int dev_no, void *meta, int chan, kcom_filter_t *filter); +typedef int +(*knet_hw_tstamp_enable_cb_f)(int dev_no, int port); + +typedef int +(*knet_hw_tstamp_tx_time_get_cb_f)(int dev_no, int port, uint8_t *pkt, uint64_t *ts); + +typedef int +(*knet_hw_tstamp_tx_meta_get_cb_f)(int dev_no, struct sk_buff *skb, uint32_t **md); + +typedef int +(*knet_hw_tstamp_ptp_clock_index_cb_f)(int dev_no); + +typedef int +(*knet_hw_tstamp_rx_time_upscale_cb_f)(int dev_no, uint64_t *ts); + extern int bkn_rx_skb_cb_register(knet_skb_cb_f rx_cb); @@ -73,6 +91,68 @@ bkn_filter_cb_register(knet_filter_cb_f filter_cb); extern int bkn_filter_cb_unregister(knet_filter_cb_f filter_cb); -#endif +extern int +bkn_hw_tstamp_enable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb); + +extern int +bkn_hw_tstamp_enable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb); + +extern int +bkn_hw_tstamp_disable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb); + +extern int +bkn_hw_tstamp_disable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb); + +extern int +bkn_hw_tstamp_tx_time_get_cb_register(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb); + +extern int +bkn_hw_tstamp_tx_time_get_cb_unregister(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb); + +extern int +bkn_hw_tstamp_tx_meta_get_cb_register(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb); + +extern int +bkn_hw_tstamp_tx_meta_get_cb_unregister(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb); + +extern int +bkn_hw_tstamp_ptp_clock_index_cb_register(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb); + +extern int +bkn_hw_tstamp_ptp_clock_index_cb_unregister(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb); + +extern int +bkn_hw_tstamp_rx_time_upscale_cb_register(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb); + +extern int +bkn_hw_tstamp_rx_time_upscale_cb_unregister(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb); + +typedef struct { + uint8 cmic_type; + uint8 dcb_type; + uint8 dcb_size; + uint8 pkt_hdr_size; + uint32 cdma_channels; +} knet_hw_info_t; + +extern int +bkn_hw_info_get(int unit, knet_hw_info_t *hw_info); + +typedef int +(*knet_netif_cb_f)(int unit, kcom_netif_t *netif, struct net_device *dev); + +extern int +bkn_netif_create_cb_register(knet_netif_cb_f netif_cb); + +extern int +bkn_netif_create_cb_unregister(knet_netif_cb_f netif_cb); + +extern int +bkn_netif_destroy_cb_register(knet_netif_cb_f netif_cb); + +extern int +bkn_netif_destroy_cb_unregister(knet_netif_cb_f netif_cb); + +#endif /* __KERNEL__ */ #endif /* __LINUX_BCM_KNET_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/net/psample.h b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/net/psample.h new file mode 100644 index 000000000000..57c000785e9c --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/net/psample.h @@ -0,0 +1,24 @@ +#ifndef __NET_PSAMPLE_H +#define __NET_PSAMPLE_H + +#include +#include +#include +#include + +struct psample_group { + struct list_head list; + struct net *net; + u32 group_num; + u32 refcount; + u32 seq; +}; + +extern struct psample_group *psample_group_get(struct net *net, u32 group_num); +extern void psample_group_put(struct psample_group *group); + +extern void psample_sample_packet(struct psample_group *group, struct sk_buff *skb, + u32 trunc_size, int in_ifindex, int out_ifindex, + u32 sample_rate); + +#endif /* __NET_PSAMPLE_H */ diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/uapi/linux/psample.h b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/uapi/linux/psample.h new file mode 100644 index 000000000000..ed48996ec0e8 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/uapi/linux/psample.h @@ -0,0 +1,35 @@ +#ifndef __UAPI_PSAMPLE_H +#define __UAPI_PSAMPLE_H + +enum { + /* sampled packet metadata */ + PSAMPLE_ATTR_IIFINDEX, + PSAMPLE_ATTR_OIFINDEX, + PSAMPLE_ATTR_ORIGSIZE, + PSAMPLE_ATTR_SAMPLE_GROUP, + PSAMPLE_ATTR_GROUP_SEQ, + PSAMPLE_ATTR_SAMPLE_RATE, + PSAMPLE_ATTR_DATA, + + /* commands attributes */ + PSAMPLE_ATTR_GROUP_REFCOUNT, + + __PSAMPLE_ATTR_MAX +}; + +enum psample_command { + PSAMPLE_CMD_SAMPLE, + PSAMPLE_CMD_GET_GROUP, + PSAMPLE_CMD_NEW_GROUP, + PSAMPLE_CMD_DEL_GROUP, +}; + +/* Can be overridden at runtime by module option */ +#define PSAMPLE_ATTR_MAX (__PSAMPLE_ATTR_MAX - 1) + +#define PSAMPLE_NL_MCGRP_CONFIG_NAME "config" +#define PSAMPLE_NL_MCGRP_SAMPLE_NAME "packets" +#define PSAMPLE_GENL_NAME "psample" +#define PSAMPLE_GENL_VERSION 1 + +#endif diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/Makefile b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/Makefile index d7ca56cd5701..2a167bb9e811 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/Makefile @@ -36,7 +36,9 @@ KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko build: $(MODULE) $(KMODULE) endif -KBUILD_EXTRA_SYMBOLS := ${BLDDIR}/../bcm-knet/kernel_module/Module.symvers +ifeq ($(BUILD_PSAMPLE),1) +KBUILD_EXTRA_SYMBOLS += ${BLDDIR}/../psample/kernel_module/Module.symvers +endif # BCM Network Device diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c index da221f9f453a..89d1087212c7 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c @@ -1,5 +1,5 @@ /* - * Copyright 2017 Broadcom + * Copyright 2017-2019 Broadcom * * 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 @@ -45,17 +45,20 @@ #include #include +/* Enable sflow sampling using psample */ +#ifdef PSAMPLE_SUPPORT +#include "psample-cb.h" +#endif + MODULE_AUTHOR("Broadcom Corporation"); MODULE_DESCRIPTION("Broadcom Linux KNET Call-Back Driver"); MODULE_LICENSE("GPL"); - -static int debug; +int debug; LKM_MOD_PARAM(debug, "i", int, 0); MODULE_PARM_DESC(debug, "Debug level (default 0)"); - /* Module Information */ #define MODULE_MAJOR 121 #define MODULE_NAME "linux-knet-cb" @@ -63,8 +66,10 @@ MODULE_PARM_DESC(debug, /* set KNET_CB_DEBUG for debug info */ #define KNET_CB_DEBUG -#define FILTER_TAG_STRIP 0 -#define FILTER_TAG_KEEP 1 +/* These below need to match incoming enum values */ +#define FILTER_TAG_STRIP 0 +#define FILTER_TAG_KEEP 1 +#define FILTER_TAG_ORIGINAL 2 /* Maintain tag strip statistics */ struct strip_stats_s { @@ -105,7 +110,7 @@ strip_vlan_tag(struct sk_buff *skb) * * DCB type 14: word 12, bits 10.11 * DCB type 19, 20, 21, 22, 30: word 12, bits 10..11 - * DCB type 23, 29: word 13, bits 0..1 + * DCB type 23, 29: word 13, bits 0..1 * DCB type 31, 34, 37: word 13, bits 0..1 * DCB type 26, 32, 33, 35: word 13, bits 0..1 * @@ -150,7 +155,7 @@ get_tag_status(int dcb_type, void *meta) { /* untested */ /* TH3 only parses outer tag. */ - const int tag_map[4] = { 0, 2, -1, -1 }; + const int tag_map[4] = { 0, 2, -1, -1 }; tag_status = tag_map[(dcb[9] >> 13) & 0x3]; } break; @@ -162,7 +167,7 @@ get_tag_status(int dcb_type, void *meta) if (debug & 0x1) { gprintk("%s; DCB Type: %d; tag status: %d\n", __func__, dcb_type, tag_status); } -#endif +#endif return tag_status; } @@ -183,12 +188,12 @@ strip_tag_rx_cb(struct sk_buff *skb, int dev_no, void *meta) if (debug & 0x1) { gprintk("%s Enter; netif Flags: %08X filter_flags %08X \n", __func__, netif_flags, filter_flags); - } + } #endif /* KNET implements this already */ if (filter_flags == FILTER_TAG_KEEP) - { +{ strip_stats.skipped++; return skb; } @@ -217,8 +222,17 @@ strip_tag_rx_cb(struct sk_buff *skb, int dev_no, void *meta) return skb; } + if (filter_flags == FILTER_TAG_ORIGINAL) + { + /* If untagged or single inner, strip the extra tag that knet + keep tag will add. */ + if (tag_status < 2) + { + strip_tag = 1; + } + } strip_stats.checked++; - + if (strip_tag) { #ifdef KNET_CB_DEBUG if (debug & 0x1) { @@ -235,7 +249,6 @@ strip_tag_rx_cb(struct sk_buff *skb, int dev_no, void *meta) } } #endif - return skb; } @@ -250,16 +263,50 @@ strip_tag_tx_cb(struct sk_buff *skb, int dev_no, void *meta) /* Filter callback not used */ static int strip_tag_filter_cb(uint8_t * pkt, int size, int dev_no, void *meta, - int chan, kcom_filter_t *kf) + int chan, kcom_filter_t *kf) { /* Pass through for now */ return 0; } +static int +knet_filter_cb(uint8_t * pkt, int size, int dev_no, void *meta, + int chan, kcom_filter_t *kf) +{ + /* check for filter callback handler */ +#ifdef PSAMPLE_SUPPORT + if (strncmp(kf->desc, PSAMPLE_CB_NAME, KCOM_FILTER_DESC_MAX) == 0) { + return psample_filter_cb (pkt, size, dev_no, meta, chan, kf); + } +#endif + return strip_tag_filter_cb (pkt, size, dev_no, meta, chan, kf); +} + +static int +knet_netif_create_cb(int unit, kcom_netif_t *netif, struct net_device *dev) +{ + int retv = 0; +#ifdef PSAMPLE_SUPPORT + retv = psample_netif_create_cb(unit, netif, dev); +#endif + return retv; +} + +static int +knet_netif_destroy_cb(int unit, kcom_netif_t *netif, struct net_device *dev) +{ + int retv = 0; +#ifdef PSAMPLE_SUPPORT + retv = psample_netif_destroy_cb(unit, netif, dev); +#endif + return retv; +} + /* * Get statistics. * % cat /proc/linux-knet-cb */ + static int _pprint(void) { @@ -275,19 +322,40 @@ static int _cleanup(void) { bkn_rx_skb_cb_unregister(strip_tag_rx_cb); - bkn_tx_skb_cb_unregister(strip_tag_tx_cb); - bkn_filter_cb_unregister(strip_tag_filter_cb); + /* strip_tag_tx_cb is currently a no-op, so no need to unregister */ + if (0) + { + bkn_tx_skb_cb_unregister(strip_tag_tx_cb); + } + bkn_filter_cb_unregister(knet_filter_cb); + bkn_netif_create_cb_unregister(knet_netif_create_cb); + bkn_netif_destroy_cb_unregister(knet_netif_destroy_cb); + +#ifdef PSAMPLE_SUPPORT + psample_cleanup(); +#endif return 0; } static int _init(void) { + bkn_rx_skb_cb_register(strip_tag_rx_cb); - bkn_tx_skb_cb_register(strip_tag_tx_cb); - bkn_filter_cb_register(strip_tag_filter_cb); + /* strip_tag_tx_cb is currently a no-op, so no need to register */ + if (0) + { + bkn_tx_skb_cb_register(strip_tag_tx_cb); + } +#ifdef PSAMPLE_SUPPORT + psample_init(); +#endif + + bkn_filter_cb_register(knet_filter_cb); + bkn_netif_create_cb_register(knet_netif_create_cb); + bkn_netif_destroy_cb_register(knet_netif_destroy_cb); return 0; } diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/psample-cb.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/psample-cb.c new file mode 100644 index 000000000000..ef6fc102ce78 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/psample-cb.c @@ -0,0 +1,875 @@ +/* + * Copyright 2017-2019 Broadcom + * + * 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. + */ +/* + * $Id: psample_cb.c $ + * $Copyright: (c) 2019 Broadcom Corp. + * All Rights Reserved.$ + */ + +/* + * Driver for call-back functions for Linux KNET driver. + * + * This code is used to integrate packet sampling KNET callback to + * the psample infra for sending sampled pkts to userspace sflow + * applications such as Host Sflow (https://github.com/sflow/host-sflow) + * using genetlink interfaces. + * + * The module can be built from the standard Linux user mode target + * directories using the following command (assuming bash), e.g. + * + * cd $SDK/systems/linux/user/ + * make BUILD_KNET_CB=1 + * + */ + +#include /* Must be included first */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "psample-cb.h" + +#define PSAMPLE_CB_DBG +#ifdef PSAMPLE_CB_DBG +extern int debug; +#define PSAMPLE_CB_DBG_PRINT(...) \ + if (debug & 0x1) { \ + gprintk(__VA_ARGS__); \ + } +#else +#define PSAMPLE_CB_DBG_PRINT(...) +#endif + +/* HIGIG2 header fields */ +#define SOC_HIGIG_SOP (0xfb) +#define SOC_HIGIG_START(x) ((x[0] >> 24) & 0xff) +#define SOC_HIGIG_DSTPORT(x) ((x[1] >> 11) & 0x1f) +#define SOC_HIGIG_SRCPORT(x) ((x[1] >> 16) & 0x1f) +#define SOC_HIGIG2_SOP (0xfb) //0xfc - TODO: how can we differentiate between Higig and higig2? +#define SOC_HIGIG2_START(x) ((x[0] >> 24) & 0xff) +#define SOC_HIGIG2_DSTPORT(x) ((x[0] >> 0) & 0xff) +#define SOC_HIGIG2_SRCPORT(x) ((x[1] >> 16) & 0xff) +#define SOC_DCB32_HG_OFFSET (6) + +#define FCS_SZ 4 +#define PSAMPLE_NLA_PADDING 4 + +#define PSAMPLE_RATE_DFLT 1 +#define PSAMPLE_SIZE_DFLT 128 +static int psample_size = PSAMPLE_SIZE_DFLT; +LKM_MOD_PARAM(psample_size, "i", int, 0); +MODULE_PARM_DESC(psample_size, +"psample pkt size (default 128 bytes)"); + +/* driver proc entry root */ +static struct proc_dir_entry *psample_proc_root = NULL; + +/* psample general info */ +typedef struct { + struct list_head netif_list; + knet_hw_info_t hw; + struct net *netns; + spinlock_t lock; +} psample_info_t; +static psample_info_t g_psample_info = {{0}}; + +/* Maintain sampled pkt statistics */ +typedef struct psample_stats_s { + unsigned long pkts_f_psample_cb; + unsigned long pkts_f_psample_mod; + unsigned long pkts_f_handled; + unsigned long pkts_f_pass_through; + unsigned long pkts_d_no_group; + unsigned long pkts_d_sampling_disabled; + unsigned long pkts_d_no_skb; + unsigned long pkts_d_not_ready; + unsigned long pkts_d_metadata; + unsigned long pkts_d_meta_srcport; + unsigned long pkts_d_meta_dstport; + unsigned long pkts_d_invalid_size; +} psample_stats_t; +static psample_stats_t g_psample_stats = {0}; + +typedef struct psample_meta_s { + int trunc_size; + int src_ifindex; + int dst_ifindex; + int sample_rate; +} psample_meta_t; + + +static psample_netif_t* +psample_netif_lookup_by_port(int unit, int port) +{ + struct list_head *list; + psample_netif_t *psample_netif = NULL; + unsigned long flags; + + /* look for port from list of available net_devices */ + spin_lock_irqsave(&g_psample_info.lock, flags); + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + if (psample_netif->port == port) { + spin_unlock_irqrestore(&g_psample_info.lock, flags); + return psample_netif; + } + } + spin_unlock_irqrestore(&g_psample_info.lock, flags); + return (NULL); +} + +static int +psample_info_get (int unit, psample_info_t *psample_info) +{ + int rv = 0; + if (!psample_info) { + gprintk("%s: psample_info is NULL\n", __func__); + return (-1); + } + + /* get hw info */ + rv = bkn_hw_info_get(unit, &psample_info->hw); + if (rv < 0) { + gprintk("%s: failed to get hw info\n", __func__); + return (-1); + } + + PSAMPLE_CB_DBG_PRINT("%s: DCB type %d\n", + __func__, psample_info->hw.dcb_type); + return (0); +} + +static int +psample_meta_srcport_get(uint8_t *pkt, void *pkt_meta) +{ + int srcport = 0; + uint32_t *metadata = (uint32_t*)pkt_meta; + + switch(g_psample_info.hw.dcb_type) { + case 36: /* TD3 */ + case 38: /* TH3 */ + break; + case 32: /* TH1/TH2 */ + case 26: /* TD2 */ + case 23: /* HX4 */ + metadata += SOC_DCB32_HG_OFFSET; + break; + default: + break; + } + + if (SOC_HIGIG2_START(metadata) == SOC_HIGIG2_SOP) + { + srcport = SOC_HIGIG2_SRCPORT(metadata); + } + else if (SOC_HIGIG_START(metadata) == SOC_HIGIG_SOP) + { + srcport = SOC_HIGIG_SRCPORT(metadata); + } + else + { + PSAMPLE_CB_DBG_PRINT("%s: Could not detect metadata sop type: 0x%02x (w[0]: 0x%04x)\n", __func__, + SOC_HIGIG_START(metadata), metadata[0]); + return -1; + } + return srcport; +} + +static int +psample_meta_dstport_get(uint8_t *pkt, void *pkt_meta) +{ + int dstport = 0; + uint32_t *metadata = (uint32_t*)pkt_meta; + + switch(g_psample_info.hw.dcb_type) { + case 36: /* TD3 */ + case 38: /* TH3 */ + break; + case 32: /* TH1/TH2 */ + case 26: /* TD2 */ + case 23: /* HX4 */ + metadata += SOC_DCB32_HG_OFFSET; + break; + default: + break; + } + + if (SOC_HIGIG2_START(metadata) == SOC_HIGIG2_SOP) + { + dstport = SOC_HIGIG2_DSTPORT(metadata); + } + else if (SOC_HIGIG_START(metadata) == SOC_HIGIG_SOP) + { + dstport = SOC_HIGIG_DSTPORT(metadata); + } + else + { + PSAMPLE_CB_DBG_PRINT("%s: Could not detect metadata sop type: 0x%02x (w[0]: 0x%04x)\n", __func__, + SOC_HIGIG_START(metadata), metadata[0]); + return (-1); + } + return dstport; +} + +static int +psample_meta_sample_reason(uint8_t *pkt, void *pkt_meta) +{ + uint32_t *metadata = (uint32_t*)pkt_meta; + uint32_t reason = 0; + uint32_t reason_hi = 0; + uint32_t sample_rx_reason_mask = 0; + + /* Sample Pkt reason code (bcmRxReasonSampleSource) */ + switch(g_psample_info.hw.dcb_type) { + case 36: /* TD3 */ + case 38: /* TH3 */ + reason_hi = *(metadata + 4); + reason = *(metadata + 5); + sample_rx_reason_mask = (1 << 3); + break; + case 32: /* TH1/TH2 */ + case 26: /* TD2 */ + case 23: /* HX4 */ + default: + reason_hi = *(metadata + 2); + reason = *(metadata + 3); + sample_rx_reason_mask = (1 << 5); + break; + } + + PSAMPLE_CB_DBG_PRINT("%s: DCB%d sample_rx_reason_mask: 0x%08x, reason: 0x%08x, reason_hi: 0x%08x\n", + __func__, g_psample_info.hw.dcb_type, sample_rx_reason_mask, reason, reason_hi); + + /* Check if only sample reason code is set. + * If only sample reason code, then consume pkt. + * If other reason codes exist, then pkt should be + * passed through to Linux network stack. + */ + if ((reason & ~sample_rx_reason_mask) || reason_hi) { + return 0; /* multiple reasons set, pass through */ + } + + /* only sample rx reason set, consume pkt */ + return (1); +} + +static int +psample_meta_get(int unit, uint8_t *pkt, void *pkt_meta, psample_meta_t *sflow_meta) +{ + int srcport, dstport; + int src_ifindex = 0; + int dst_ifindex = 0; + int sample_rate = PSAMPLE_RATE_DFLT; + int sample_size = PSAMPLE_SIZE_DFLT; + psample_netif_t *psample_netif = NULL; + +#ifdef PSAMPLE_CB_DBG + if (debug & 0x1) { + int i=0; + uint8_t *meta = (uint8_t*)pkt_meta; + PSAMPLE_CB_DBG_PRINT("%s: psample pkt metadata\n", __func__); + for (i=0; i<64; i+=16) { + PSAMPLE_CB_DBG_PRINT("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + meta[i+0], meta[i+1], meta[i+2], meta[i+3], meta[i+4], meta[i+5], meta[i+6], meta[i+7], + meta[i+8], meta[i+9], meta[i+10], meta[i+11], meta[i+12], meta[i+13], meta[i+14], meta[i+15]); + } + } +#endif + + /* parse pkt metadata for src and dst ports */ + srcport = psample_meta_srcport_get(pkt, pkt_meta); + dstport = psample_meta_dstport_get(pkt, pkt_meta); + if ((srcport == -1) || (dstport == -1)) { + gprintk("%s: invalid srcport %d or dstport %d\n", __func__, srcport, dstport); + return (-1); + } + + /* find src port netif (no need to lookup CPU port) */ + if (srcport != 0) { + if ((psample_netif = psample_netif_lookup_by_port(unit, srcport))) { + src_ifindex = psample_netif->dev->ifindex; + sample_rate = psample_netif->sample_rate; + sample_size = psample_netif->sample_size; + } else { + g_psample_stats.pkts_d_meta_srcport++; + PSAMPLE_CB_DBG_PRINT("%s: could not find srcport(%d)\n", __func__, srcport); + } + } + + /* find dst port netif (no need to lookup CPU port) */ + if (dstport != 0) { + if ((psample_netif = psample_netif_lookup_by_port(unit, dstport))) { + dst_ifindex = psample_netif->dev->ifindex; + } else { + g_psample_stats.pkts_d_meta_dstport++; + PSAMPLE_CB_DBG_PRINT("%s: could not find dstport(%d)\n", __func__, dstport); + } + } + + PSAMPLE_CB_DBG_PRINT("%s: srcport %d, dstport %d, src_ifindex %d, dst_ifindex %d, trunc_size %d, sample_rate %d\n", + __func__, srcport, dstport, src_ifindex, dst_ifindex, sample_size, sample_rate); + + sflow_meta->src_ifindex = src_ifindex; + sflow_meta->dst_ifindex = dst_ifindex; + sflow_meta->trunc_size = sample_size; + sflow_meta->sample_rate = sample_rate; + + return (0); +} + +int +psample_filter_cb(uint8_t * pkt, int size, int dev_no, void *pkt_meta, + int chan, kcom_filter_t *kf) +{ + struct psample_group *group; + psample_meta_t meta; + struct sk_buff skb; + int rv = 0; + static int info_get = 0; + + if (!info_get) { + rv = psample_info_get (dev_no, &g_psample_info); + if (rv < 0) { + gprintk("%s: failed to get psample info\n", __func__); + goto PSAMPLE_FILTER_CB_PKT_HANDLED; + } + info_get = 1; + } + + PSAMPLE_CB_DBG_PRINT("%s: pkt size %d, kf->dest_id %d, kf->cb_user_data %d\n", + __func__, size, kf->dest_id, kf->cb_user_data); + g_psample_stats.pkts_f_psample_cb++; + + /* get psample group info. psample genetlink group ID passed in kf->dest_id */ + group = psample_group_get(g_psample_info.netns, kf->dest_id); + if (!group) { + gprintk("%s: Could not find psample genetlink group %d\n", __func__, kf->cb_user_data); + g_psample_stats.pkts_d_no_group++; + goto PSAMPLE_FILTER_CB_PKT_HANDLED; + } + + /* get psample metadata */ + rv = psample_meta_get(dev_no, pkt, pkt_meta, &meta); + if (rv < 0) { + gprintk("%s: Could not parse pkt metadata\n", __func__); + g_psample_stats.pkts_d_metadata++; + goto PSAMPLE_FILTER_CB_PKT_HANDLED; + } + + /* Adjust original pkt size to remove 4B FCS */ + if (size < FCS_SZ) { + g_psample_stats.pkts_d_invalid_size++; + goto PSAMPLE_FILTER_CB_PKT_HANDLED; + } else { + size -= FCS_SZ; + } + + /* Account for padding in libnl used by psample */ + if (meta.trunc_size >= size) { + meta.trunc_size = size - PSAMPLE_NLA_PADDING; + } + + PSAMPLE_CB_DBG_PRINT("%s: group 0x%x, trunc_size %d, src_ifdx %d, dst_ifdx %d, sample_rate %d\n", + __func__, group->group_num, meta.trunc_size, meta.src_ifindex, meta.dst_ifindex, meta.sample_rate); + + /* drop if configured sample rate is 0 */ + if (meta.sample_rate > 0) { + /* setup skb to point to pkt */ + memset(&skb, 0, sizeof(struct sk_buff)); + skb.len = size; + skb.data = pkt; + + psample_sample_packet(group, + &skb, + meta.trunc_size, + meta.src_ifindex, + meta.dst_ifindex, + meta.sample_rate); + + g_psample_stats.pkts_f_psample_mod++; + } else { + g_psample_stats.pkts_d_sampling_disabled++; + } + +PSAMPLE_FILTER_CB_PKT_HANDLED: + /* if sample reason only, consume pkt. else pass through */ + rv = psample_meta_sample_reason(pkt, pkt_meta); + if (rv) { + g_psample_stats.pkts_f_handled++; + } else { + g_psample_stats.pkts_f_pass_through++; + } + return rv; +} + +int +psample_netif_create_cb(int unit, kcom_netif_t *netif, struct net_device *dev) +{ + int found; + struct list_head *list; + psample_netif_t *psample_netif, *lpsample_netif; + unsigned long flags; + + if ((psample_netif = kmalloc(sizeof(psample_netif_t), GFP_KERNEL)) == NULL) { + gprintk("%s: failed to alloc psample mem for netif '%s'\n", + __func__, dev->name); + return (-1); + } + + spin_lock_irqsave(&g_psample_info.lock, flags); + + psample_netif->dev = dev; + psample_netif->id = netif->id; + psample_netif->port = netif->port; + psample_netif->vlan = netif->vlan; + psample_netif->qnum = netif->qnum; + psample_netif->sample_rate = PSAMPLE_RATE_DFLT; + psample_netif->sample_size = PSAMPLE_SIZE_DFLT; + + /* insert netif sorted by ID similar to bkn_knet_netif_create() */ + found = 0; + list_for_each(list, &g_psample_info.netif_list) { + lpsample_netif = (psample_netif_t*)list; + if (netif->id < lpsample_netif->id) { + found = 1; + break; + } + } + + if (found) { + /* Replace previously removed interface */ + list_add_tail(&psample_netif->list, &lpsample_netif->list); + } else { + /* No holes - add to end of list */ + list_add_tail(&psample_netif->list, &g_psample_info.netif_list); + } + + spin_unlock_irqrestore(&g_psample_info.lock, flags); + + PSAMPLE_CB_DBG_PRINT("%s: added psample netif '%s'\n", __func__, dev->name); + return (0); +} + +int +psample_netif_destroy_cb(int unit, kcom_netif_t *netif, struct net_device *dev) +{ + int found; + struct list_head *list; + psample_netif_t *psample_netif; + unsigned long flags; + + if (!netif || !dev) { + gprintk("%s: netif or net_device is NULL\n", __func__); + return (-1); + } + + spin_lock_irqsave(&g_psample_info.lock, flags); + + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + if (netif->id == psample_netif->id) { + found = 1; + list_del(&psample_netif->list); + PSAMPLE_CB_DBG_PRINT("%s: removing psample netif '%s'\n", __func__, dev->name); + kfree(psample_netif); + break; + } + } + + spin_unlock_irqrestore(&g_psample_info.lock, flags); + + if (!found) { + gprintk("%s: netif ID %d not found!\n", __func__, netif->id); + return (-1); + } + return (0); +} + +/* + * psample rate Proc Read Entry + */ +static int +psample_proc_rate_show(struct seq_file *m, void *v) +{ + struct list_head *list; + psample_netif_t *psample_netif; + unsigned long flags; + + spin_lock_irqsave(&g_psample_info.lock, flags); + + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + seq_printf(m, " %-14s %d\n", psample_netif->dev->name, psample_netif->sample_rate); + } + + spin_unlock_irqrestore(&g_psample_info.lock, flags); + + return 0; +} + +static int +psample_proc_rate_open(struct inode * inode, struct file * file) +{ + return single_open(file, psample_proc_rate_show, NULL); +} + +/* + * psample rate Proc Write Entry + * + * Syntax: + * = + * + * Where is a virtual network interface name. + * + * Examples: + * eth4=1000 + */ +static ssize_t +psample_proc_rate_write(struct file *file, const char *buf, + size_t count, loff_t *loff) +{ + int found; + struct list_head *list; + psample_netif_t *psample_netif; + char sample_str[40], *ptr, *newline; + unsigned long flags; + + + if (count > sizeof(sample_str)) { + count = sizeof(sample_str) - 1; + sample_str[count] = '\0'; + } + if (copy_from_user(sample_str, buf, count)) { + return -EFAULT; + } + sample_str[count] = 0; + newline = strchr(sample_str, '\n'); + if (newline) { + /* Chop off the trailing newline */ + *newline = '\0'; + } + + if ((ptr = strchr(sample_str, '=')) == NULL && + (ptr = strchr(sample_str, ':')) == NULL) { + gprintk("Error: Pkt sample rate syntax not recognized: '%s'\n", sample_str); + return count; + } + *ptr++ = 0; + + spin_lock_irqsave(&g_psample_info.lock, flags); + + found = 0; + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + if (strcmp(psample_netif->dev->name, sample_str) == 0) { + psample_netif->sample_rate = simple_strtol(ptr, NULL, 10); + // TODO MLI@BRCM - check valid sample rate + found = 1; + break; + } + } + + spin_unlock_irqrestore(&g_psample_info.lock, flags); + + if (!found) { + gprintk("Warning: Failed setting psample rate on unknown network interface: '%s'\n", sample_str); + } + return count; +} + +struct file_operations psample_proc_rate_file_ops = { + owner: THIS_MODULE, + open: psample_proc_rate_open, + read: seq_read, + llseek: seq_lseek, + write: psample_proc_rate_write, + release: single_release, +}; + +/* + * psample size Proc Read Entry + */ +static int +psample_proc_size_show(struct seq_file *m, void *v) +{ + struct list_head *list; + psample_netif_t *psample_netif; + unsigned long flags; + + spin_lock_irqsave(&g_psample_info.lock, flags); + + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + seq_printf(m, " %-14s %d\n", psample_netif->dev->name, psample_netif->sample_size); + } + + spin_unlock_irqrestore(&g_psample_info.lock, flags); + return 0; +} + +static int +psample_proc_size_open(struct inode * inode, struct file * file) +{ + return single_open(file, psample_proc_size_show, NULL); +} + +/* + * psample size Proc Write Entry + * + * Syntax: + * = + * + * Where is a virtual network interface name. + * + * Examples: + * eth4=128 + */ +static ssize_t +psample_proc_size_write(struct file *file, const char *buf, + size_t count, loff_t *loff) +{ + int found; + struct list_head *list; + psample_netif_t *psample_netif; + char sample_str[40], *ptr, *newline; + unsigned long flags; + + if (count > sizeof(sample_str)) { + count = sizeof(sample_str) - 1; + sample_str[count] = '\0'; + } + if (copy_from_user(sample_str, buf, count)) { + return -EFAULT; + } + sample_str[count] = 0; + newline = strchr(sample_str, '\n'); + if (newline) { + /* Chop off the trailing newline */ + *newline = '\0'; + } + + if ((ptr = strchr(sample_str, '=')) == NULL && + (ptr = strchr(sample_str, ':')) == NULL) { + gprintk("Error: Pkt sample size syntax not recognized: '%s'\n", sample_str); + return count; + } + *ptr++ = 0; + + spin_lock_irqsave(&g_psample_info.lock, flags); + + found = 0; + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + if (strcmp(psample_netif->dev->name, sample_str) == 0) { + psample_netif->sample_size = simple_strtol(ptr, NULL, 10); + // TODO MLI@BRCM - check valid sample size + found = 1; + break; + } + } + + spin_unlock_irqrestore(&g_psample_info.lock, flags); + + if (!found) { + gprintk("Warning: Failed setting psample size on unknown network interface: '%s'\n", sample_str); + } + return count; +} + +struct file_operations psample_proc_size_file_ops = { + owner: THIS_MODULE, + open: psample_proc_size_open, + read: seq_read, + llseek: seq_lseek, + write: psample_proc_size_write, + release: single_release, +}; + +/* + * psample debug Proc Read Entry + */ +static int +psample_proc_debug_show(struct seq_file *m, void *v) +{ + seq_printf(m, "BCM KNET %s Callback Config\n", PSAMPLE_CB_NAME); + seq_printf(m, " debug: 0x%x\n", debug); + seq_printf(m, " cmic_type: %d\n", g_psample_info.hw.cmic_type); + seq_printf(m, " dcb_type: %d\n", g_psample_info.hw.dcb_type); + seq_printf(m, " dcb_size: %d\n", g_psample_info.hw.dcb_size); + seq_printf(m, " pkt_hdr_size: %d\n", g_psample_info.hw.pkt_hdr_size); + seq_printf(m, " cdma_channels: %d\n", g_psample_info.hw.cdma_channels); + + return 0; +} + +static int +psample_proc_debug_open(struct inode * inode, struct file * file) +{ + return single_open(file, psample_proc_debug_show, NULL); +} + +/* + * psample debug Proc Write Entry + * + * Syntax: + * debug= + * + * Where corresponds to the debug module parameter. + * + * Examples: + * debug=0x1 + */ +static ssize_t +psample_proc_debug_write(struct file *file, const char *buf, + size_t count, loff_t *loff) +{ + char debug_str[40]; + char *ptr; + + if (count > sizeof(debug_str)) { + count = sizeof(debug_str) - 1; + debug_str[count] = '\0'; + } + if (copy_from_user(debug_str, buf, count)) { + return -EFAULT; + } + + if ((ptr = strstr(debug_str, "debug=")) != NULL) { + ptr += 6; + debug = simple_strtol(ptr, NULL, 0); + } else { + gprintk("Warning: unknown configuration setting\n"); + } + + return count; +} + +struct file_operations psample_proc_debug_file_ops = { + owner: THIS_MODULE, + open: psample_proc_debug_open, + read: seq_read, + llseek: seq_lseek, + write: psample_proc_debug_write, + release: single_release, +}; + +static int +psample_proc_stats_show(struct seq_file *m, void *v) +{ + seq_printf(m, "BCM KNET %s Callback Stats\n", PSAMPLE_CB_NAME); + seq_printf(m, " DCB type %d\n", g_psample_info.hw.dcb_type); + seq_printf(m, " pkts filter psample cb %10lu\n", g_psample_stats.pkts_f_psample_cb); + seq_printf(m, " pkts sent to psample module %10lu\n", g_psample_stats.pkts_f_psample_mod); + seq_printf(m, " pkts handled by psample %10lu\n", g_psample_stats.pkts_f_handled); + seq_printf(m, " pkts pass through %10lu\n", g_psample_stats.pkts_f_pass_through); + seq_printf(m, " pkts drop no psample group %10lu\n", g_psample_stats.pkts_d_no_group); + seq_printf(m, " pkts drop sampling disabled %10lu\n", g_psample_stats.pkts_d_sampling_disabled); + seq_printf(m, " pkts drop no skb %10lu\n", g_psample_stats.pkts_d_no_skb); + seq_printf(m, " pkts drop psample not ready %10lu\n", g_psample_stats.pkts_d_not_ready); + seq_printf(m, " pkts drop metadata parse error %10lu\n", g_psample_stats.pkts_d_metadata); + seq_printf(m, " pkts with invalid src port %10lu\n", g_psample_stats.pkts_d_meta_srcport); + seq_printf(m, " pkts with invalid dst port %10lu\n", g_psample_stats.pkts_d_meta_dstport); + seq_printf(m, " pkts with invalid orig pkt sz %10lu\n", g_psample_stats.pkts_d_invalid_size); + return 0; +} + +static int +psample_proc_stats_open(struct inode * inode, struct file * file) +{ + return single_open(file, psample_proc_stats_show, NULL); +} + +struct file_operations psample_proc_stats_file_ops = { + owner: THIS_MODULE, + open: psample_proc_stats_open, + read: seq_read, + llseek: seq_lseek, + write: NULL, + release: single_release, +}; + +int psample_cleanup(void) +{ + remove_proc_entry("stats", psample_proc_root); + remove_proc_entry("rate", psample_proc_root); + remove_proc_entry("size", psample_proc_root); + remove_proc_entry("debug", psample_proc_root); + return 0; +} + +int psample_init(void) +{ + #define PROCFS_MAX_PATH 1024 + char psample_procfs_path[PROCFS_MAX_PATH]; + struct proc_dir_entry *entry; + + /* create procfs for psample */ + snprintf(psample_procfs_path, PROCFS_MAX_PATH, "bcm/knet-cb"); + proc_mkdir(psample_procfs_path, NULL); + snprintf(psample_procfs_path, PROCFS_MAX_PATH, "%s/%s", psample_procfs_path, PSAMPLE_CB_NAME); + psample_proc_root = proc_mkdir(psample_procfs_path, NULL); + + /* create procfs for psample stats */ + PROC_CREATE(entry, "stats", 0666, psample_proc_root, &psample_proc_stats_file_ops); + if (entry == NULL) { + gprintk("%s: Unable to create procfs entry '/procfs/%s/stats'\n", __func__, psample_procfs_path); + return -1; + } + + /* create procfs for setting sample rates */ + PROC_CREATE(entry, "rate", 0666, psample_proc_root, &psample_proc_rate_file_ops); + if (entry == NULL) { + gprintk("%s: Unable to create procfs entry '/procfs/%s/rate'\n", __func__, psample_procfs_path); + return -1; + } + + /* create procfs for setting sample size */ + PROC_CREATE(entry, "size", 0666, psample_proc_root, &psample_proc_size_file_ops); + if (entry == NULL) { + gprintk("%s: Unable to create procfs entry '/procfs/%s/size'\n", __func__, psample_procfs_path); + return -1; + } + + /* create procfs for debug log */ + PROC_CREATE(entry, "debug", 0666, psample_proc_root, &psample_proc_debug_file_ops); + if (entry == NULL) { + gprintk("%s: Unable to create procfs entry '/procfs/%s/debug'\n", __func__, psample_procfs_path); + return -1; + } + + /* clear data structs */ + memset(&g_psample_stats, 0, sizeof(psample_stats_t)); + memset(&g_psample_info, 0, sizeof(psample_info_t)); + + /* setup psample_info struct */ + INIT_LIST_HEAD(&g_psample_info.netif_list); + spin_lock_init(&g_psample_info.lock); + + /* get net namespace */ + g_psample_info.netns = get_net_ns_by_pid(current->pid); + if (!g_psample_info.netns) { + gprintk("%s: Could not get network namespace for pid %d\n", __func__, current->pid); + return (-1); + } + PSAMPLE_CB_DBG_PRINT("%s: current->pid %d, netns 0x%p, sample_size %d\n", __func__, + current->pid, g_psample_info.netns, psample_size); + + return 0; +} diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/psample-cb.h b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/psample-cb.h new file mode 100644 index 000000000000..8f9398c51692 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/psample-cb.h @@ -0,0 +1,58 @@ +/* + * Copyright 2017 Broadcom + * + * 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. + */ +/* + * $Id: psample_cb.h $ + * $Copyright: (c) 2019 Broadcom Corp. + * All Rights Reserved.$ + */ +#ifndef __PSAMPLE_CB_H__ +#define __PSAMPLE_CB_H__ + +#include +#include +#include + +#define PSAMPLE_CB_NAME "psample" + +extern int +psample_init(void); + +extern int +psample_cleanup(void); + +extern int +psample_filter_cb(uint8_t * pkt, int size, int dev_no, void *pkt_meta, + int chan, kcom_filter_t *kf); + +/* psample data per interface */ +typedef struct { + struct list_head list; + struct net_device *dev; + uint16 id; + uint8 port; + uint16 vlan; + uint16 qnum; + uint32 sample_rate; + uint32 sample_size; +} psample_netif_t; + +extern int +psample_netif_create_cb(int unit, kcom_netif_t *netif, struct net_device *dev); + +extern int +psample_netif_destroy_cb(int unit, kcom_netif_t *netif, struct net_device *dev); + +#endif /* __PSAMPLE_CB_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/psample/Makefile b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/psample/Makefile new file mode 100644 index 000000000000..631590104cd8 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/psample/Makefile @@ -0,0 +1,64 @@ +# +# Copyright 2017 Broadcom +# +# 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. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.3 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ +# +LOCALDIR = systems/linux/kernel/modules/psample + +include ${SDK}/make/Make.config + +LIBS = $(LIBDIR)/libkern.a + +ifeq ($(kernel_version),2_4) +MODULE = $(LIBDIR)/psample.o +else +KERNEL_MODULE_DIR = kernel_module + +THIS_MOD_NAME := psample +MODULE = $(LIBDIR)/$(THIS_MOD_NAME).o +KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko + +build: $(MODULE) $(KMODULE) +endif + +KBUILD_EXTRA_SYMBOLS := ${BLDDIR}/../bcm-knet/kernel_module/Module.symvers + +# BCM Network Device + +$(MODULE): $(BLDDIR)/.tree $(BOBJS) $(LIBS) + $(LD) $(MODULE_LDFLAGS) -r -d $(BOBJS) $(LIBS) -o $@ +ifneq ($(kernel_version),2_4) +$(KMODULE): $(MODULE) + rm -fr $(BLDDIR)/$(KERNEL_MODULE_DIR) + mkdir $(BLDDIR)/$(KERNEL_MODULE_DIR) + cp ${SDK}/make/Makefile.linux-kmodule $(BLDDIR)/$(KERNEL_MODULE_DIR)/Makefile + cat ${KBUILD_EXTRA_SYMBOLS} > $(BLDDIR)/$(KERNEL_MODULE_DIR)/Module.symvers + MOD_NAME=$(THIS_MOD_NAME) $(MAKE) -C $(BLDDIR)/$(KERNEL_MODULE_DIR) $(THIS_MOD_NAME).ko +endif + +# Make.depend is before clean:: so that Make.depend's clean:: runs first. + +include ${SDK}/make/Make.depend + +clean:: + $(RM) $(BLDDIR)/version.c $(BLDDIR)/version.o + $(RM) $(BOBJS) $(MODULE) + +ifneq ($(kernel_version),2_4) +.PHONY: build +endif diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/psample/psample.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/psample/psample.c new file mode 100644 index 000000000000..e1d4e2353b09 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/psample/psample.c @@ -0,0 +1,302 @@ +/* + * net/psample/psample.c - Netlink channel for packet sampling + * Copyright (c) 2017 Yotam Gigi + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PSAMPLE_MAX_PACKET_SIZE 0xffff + +static LIST_HEAD(psample_groups_list); +static DEFINE_SPINLOCK(psample_groups_lock); + +/* multicast groups */ +enum psample_nl_multicast_groups { + PSAMPLE_NL_MCGRP_CONFIG, + PSAMPLE_NL_MCGRP_SAMPLE, +}; + +static const struct genl_multicast_group psample_nl_mcgrps[] = { + [PSAMPLE_NL_MCGRP_CONFIG] = { .name = PSAMPLE_NL_MCGRP_CONFIG_NAME }, + [PSAMPLE_NL_MCGRP_SAMPLE] = { .name = PSAMPLE_NL_MCGRP_SAMPLE_NAME }, +}; + +static struct genl_family psample_nl_family __ro_after_init; + +static int psample_group_nl_fill(struct sk_buff *msg, + struct psample_group *group, + enum psample_command cmd, u32 portid, u32 seq, + int flags) +{ + void *hdr; + int ret; + + hdr = genlmsg_put(msg, portid, seq, &psample_nl_family, flags, cmd); + if (!hdr) + return -EMSGSIZE; + + ret = nla_put_u32(msg, PSAMPLE_ATTR_SAMPLE_GROUP, group->group_num); + if (ret < 0) + goto error; + + ret = nla_put_u32(msg, PSAMPLE_ATTR_GROUP_REFCOUNT, group->refcount); + if (ret < 0) + goto error; + + ret = nla_put_u32(msg, PSAMPLE_ATTR_GROUP_SEQ, group->seq); + if (ret < 0) + goto error; + + genlmsg_end(msg, hdr); + return 0; + +error: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int psample_nl_cmd_get_group_dumpit(struct sk_buff *msg, + struct netlink_callback *cb) +{ + struct psample_group *group; + int start = cb->args[0]; + int idx = 0; + int err; + + spin_lock(&psample_groups_lock); + list_for_each_entry(group, &psample_groups_list, list) { + if (!net_eq(group->net, sock_net(msg->sk))) + continue; + if (idx < start) { + idx++; + continue; + } + err = psample_group_nl_fill(msg, group, PSAMPLE_CMD_NEW_GROUP, + NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, NLM_F_MULTI); + if (err) + break; + idx++; + } + + spin_unlock(&psample_groups_lock); + cb->args[0] = idx; + return msg->len; +} + +static const struct genl_ops psample_nl_ops[] = { + { + .cmd = PSAMPLE_CMD_GET_GROUP, + .dumpit = psample_nl_cmd_get_group_dumpit, + /* can be retrieved by unprivileged users */ + } +}; + +static struct genl_family psample_nl_family __ro_after_init = { + .name = PSAMPLE_GENL_NAME, + .version = PSAMPLE_GENL_VERSION, + .maxattr = PSAMPLE_ATTR_MAX, + .netnsok = true, + .module = THIS_MODULE, + .mcgrps = psample_nl_mcgrps, + .ops = psample_nl_ops, + .n_ops = ARRAY_SIZE(psample_nl_ops), + .n_mcgrps = ARRAY_SIZE(psample_nl_mcgrps), +}; + +static void psample_group_notify(struct psample_group *group, + enum psample_command cmd) +{ + struct sk_buff *msg; + int err; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!msg) + return; + + err = psample_group_nl_fill(msg, group, cmd, 0, 0, NLM_F_MULTI); + if (!err) + genlmsg_multicast_netns(&psample_nl_family, group->net, msg, 0, + PSAMPLE_NL_MCGRP_CONFIG, GFP_ATOMIC); + else + nlmsg_free(msg); +} + +static struct psample_group *psample_group_create(struct net *net, + u32 group_num) +{ + struct psample_group *group; + + group = kzalloc(sizeof(*group), GFP_ATOMIC); + if (!group) + return NULL; + + group->net = net; + group->group_num = group_num; + list_add_tail(&group->list, &psample_groups_list); + + psample_group_notify(group, PSAMPLE_CMD_NEW_GROUP); + return group; +} + +static void psample_group_destroy(struct psample_group *group) +{ + psample_group_notify(group, PSAMPLE_CMD_DEL_GROUP); + list_del(&group->list); + kfree(group); +} + +static struct psample_group * +psample_group_lookup(struct net *net, u32 group_num) +{ + struct psample_group *group; + + list_for_each_entry(group, &psample_groups_list, list) + if ((group->group_num == group_num) && (group->net == net)) + return group; + return NULL; +} + +struct psample_group *psample_group_get(struct net *net, u32 group_num) +{ + struct psample_group *group; + + spin_lock(&psample_groups_lock); + + group = psample_group_lookup(net, group_num); + if (!group) { + group = psample_group_create(net, group_num); + if (!group) + goto out; + } + group->refcount++; + +out: + spin_unlock(&psample_groups_lock); + return group; +} +EXPORT_SYMBOL_GPL(psample_group_get); + +void psample_group_put(struct psample_group *group) +{ + spin_lock(&psample_groups_lock); + + if (--group->refcount == 0) + psample_group_destroy(group); + + spin_unlock(&psample_groups_lock); +} +EXPORT_SYMBOL_GPL(psample_group_put); + +void psample_sample_packet(struct psample_group *group, struct sk_buff *skb, + u32 trunc_size, int in_ifindex, int out_ifindex, + u32 sample_rate) +{ + struct sk_buff *nl_skb; + int data_len; + int meta_len; + void *data; + int ret; + + meta_len = (in_ifindex ? nla_total_size(sizeof(u16)) : 0) + + (out_ifindex ? nla_total_size(sizeof(u16)) : 0) + + nla_total_size(sizeof(u32)) + /* sample_rate */ + nla_total_size(sizeof(u32)) + /* orig_size */ + nla_total_size(sizeof(u32)) + /* group_num */ + nla_total_size(sizeof(u32)); /* seq */ + + data_len = min(skb->len, trunc_size); + if (meta_len + nla_total_size(data_len) > PSAMPLE_MAX_PACKET_SIZE) + data_len = PSAMPLE_MAX_PACKET_SIZE - meta_len - NLA_HDRLEN + - NLA_ALIGNTO; + + nl_skb = genlmsg_new(meta_len + data_len, GFP_ATOMIC); + if (unlikely(!nl_skb)) + return; + + data = genlmsg_put(nl_skb, 0, 0, &psample_nl_family, 0, + PSAMPLE_CMD_SAMPLE); + if (unlikely(!data)) + goto error; + + if (in_ifindex) { + ret = nla_put_u16(nl_skb, PSAMPLE_ATTR_IIFINDEX, in_ifindex); + if (unlikely(ret < 0)) + goto error; + } + + if (out_ifindex) { + ret = nla_put_u16(nl_skb, PSAMPLE_ATTR_OIFINDEX, out_ifindex); + if (unlikely(ret < 0)) + goto error; + } + + ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_SAMPLE_RATE, sample_rate); + if (unlikely(ret < 0)) + goto error; + + ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_ORIGSIZE, skb->len); + if (unlikely(ret < 0)) + goto error; + + ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_SAMPLE_GROUP, group->group_num); + if (unlikely(ret < 0)) + goto error; + + ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_GROUP_SEQ, group->seq++); + if (unlikely(ret < 0)) + goto error; + + if (data_len) { + int nla_len = nla_total_size(data_len); + struct nlattr *nla; + + nla = (struct nlattr *)skb_put(nl_skb, nla_len); + nla->nla_type = PSAMPLE_ATTR_DATA; + nla->nla_len = nla_attr_size(data_len); + + if (skb_copy_bits(skb, 0, nla_data(nla), data_len)) + goto error; + } + + genlmsg_end(nl_skb, data); + genlmsg_multicast_netns(&psample_nl_family, group->net, nl_skb, 0, + PSAMPLE_NL_MCGRP_SAMPLE, GFP_ATOMIC); + + return; +error: + pr_err_ratelimited("Could not create psample log message\n"); + nlmsg_free(nl_skb); +} +EXPORT_SYMBOL_GPL(psample_sample_packet); + +static int __init psample_module_init(void) +{ + return genl_register_family(&psample_nl_family); +} + +static void __exit psample_module_exit(void) +{ + genl_unregister_family(&psample_nl_family); +} + +module_init(psample_module_init); +module_exit(psample_module_exit); + +MODULE_AUTHOR("Yotam Gigi "); +MODULE_DESCRIPTION("netlink channel for packet sampling"); +MODULE_LICENSE("GPL v2"); diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile index 0e6226544334..20d83735fcce 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile @@ -91,6 +91,9 @@ KNET_CB := $(DEST_DIR)/$(KNET_CB_LOCAL) BCM_KNET_LOCAL :=linux-bcm-knet.$(KOBJ) BCM_KNET=$(DEST_DIR)/$(BCM_KNET_LOCAL) +PSAMPLE_LOCAL := psample.$(KOBJ) +PSAMPLE := $(DEST_DIR)/$(PSAMPLE_LOCAL) + ifeq (,$(findstring DELIVER,$(MAKECMDGOALS))) .DEFAULT_GOAL := all all_targets := kernel_modules $(KERNEL_BDE) $(USER_BDE) @@ -126,6 +129,15 @@ all_targets +=$(LOCAL_TARGETS) endif endif +ifdef BUILD_PSAMPLE +all_targets += $(PSAMPLE) +ADD_TO_CFLAGS += -DPSAMPLE_SUPPORT +ifeq ($(NO_LOCAL_TARGETS),) +LOCAL_TARGETS +=$(patsubst %,../$(platform)/%,$(PSAMPLE_LOCAL)) +all_targets +=$(LOCAL_TARGETS) +endif +endif + ADD_TO_CFLAGS += -I$(SDK)/systems/linux/kernel/modules/include COND_KNET_LIBS = libuser.$(libext) endif @@ -159,6 +171,10 @@ kernel_modules: ifeq ($(BUILD_KNET),1) $(MAKE) -j1 -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ subdirs="shared bcm-knet" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" +ifdef BUILD_PSAMPLE + $(MAKE) -j1 -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ + subdirs="psample" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" +endif ifdef BUILD_KNET_CB $(MAKE) -j1 -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ subdirs="knet-cb" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" @@ -178,6 +194,10 @@ $(BCM_KNET): $(KERN_BLDROOT)/linux-bcm-knet.$(KOBJ) $(KNET_CB): $(KERN_BLDROOT)/linux-knet-cb.$(KOBJ) $(OBJCOPY) --strip-debug $< $@ +$(PSAMPLE): $(KERN_BLDROOT)/psample.$(KOBJ) + $(OBJCOPY) --strip-debug $< $@ + + ifeq ($(NO_LOCAL_TARGETS),) $(foreach targ,$(LOCAL_TARGETS),$(eval $(call LOCAL_TARGET_DEF,$(targ)))) endif @@ -194,6 +214,7 @@ clean:: $(RM) $(KERN_BLDROOT)/linux-user-bde.$(KOBJ) $(RM) $(KERN_BLDROOT)/linux-bcm-knet.$(KOBJ) $(RM) $(KERN_BLDROOT)/linux-knet-cb.$(KOBJ) + $(RM) $(KERN_BLDROOT)/psample.$(KOBJ) $(RM) $(LOCAL_TARGETS) distclean:: clean diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/iproc/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/iproc/Makefile index 7a8b4a8b0c4d..03300ff8a046 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/user/iproc/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/user/iproc/Makefile @@ -44,7 +44,7 @@ endif export SDK -override kernel_version=4_4 +override kernel_version=4_14 platform=iproc IPROC_BUILD=1 diff --git a/sonic-slave-stretch/Dockerfile.j2 b/sonic-slave-stretch/Dockerfile.j2 index 133238622f76..08e002624abb 100644 --- a/sonic-slave-stretch/Dockerfile.j2 +++ b/sonic-slave-stretch/Dockerfile.j2 @@ -291,7 +291,9 @@ RUN apt-get update && apt-get install -y \ automake1.11 \ libselinux1-dev \ # For kdump-tools - liblzo2-dev + liblzo2-dev \ +# For SAI3.7 + libprotobuf-dev ## Config dpkg ## install the configuration file if it’s currently missing From 1e05a41c7f8e8f8b06cc9dd6c6de510241f5cb58 Mon Sep 17 00:00:00 2001 From: Polly Hsu Date: Thu, 19 Dec 2019 03:09:19 +0800 Subject: [PATCH 260/278] [device][accton]: Update for AS7326-56X complying the BCM SAI 3.5.3.1m-26 (#3830) * [device][accton]: Update for AS7326-56X complying the Broadcom SAI latest version 3.5.3.1m-26 * Update Accton-AS7326-56X to adapt xxx.config.bcm based on the latest update of Device-Specific File Directory Structure. * Update Accton-AS7326-56X LED BIN complying the Broadcom SAI latest version 3.5.3.1m-26 Signed-off-by: polly_hsu@edge-core.com * [device][accton]: Merge the SDK config with #3103 (Fix Accton as7326 port breakouk) Signed-off-by: Polly Hsu --- .../Accton-AS7326-56X/sai.profile | 2 +- .../td3-as7326-48x25G+8x100G.config.bcm | 3 +++ .../x86_64-accton_as7326_56x-r0/custom_led.bin | Bin 0 -> 1092 bytes .../led_proc_init.soc | 6 ++++++ .../linkscan_led_fw.bin | Bin 0 -> 4716 bytes 5 files changed, 10 insertions(+), 1 deletion(-) mode change 100644 => 100755 device/accton/x86_64-accton_as7326_56x-r0/Accton-AS7326-56X/sai.profile create mode 100755 device/accton/x86_64-accton_as7326_56x-r0/custom_led.bin create mode 100755 device/accton/x86_64-accton_as7326_56x-r0/led_proc_init.soc create mode 100755 device/accton/x86_64-accton_as7326_56x-r0/linkscan_led_fw.bin diff --git a/device/accton/x86_64-accton_as7326_56x-r0/Accton-AS7326-56X/sai.profile b/device/accton/x86_64-accton_as7326_56x-r0/Accton-AS7326-56X/sai.profile old mode 100644 new mode 100755 index 0e465ce12edd..47e3107477a2 --- a/device/accton/x86_64-accton_as7326_56x-r0/Accton-AS7326-56X/sai.profile +++ b/device/accton/x86_64-accton_as7326_56x-r0/Accton-AS7326-56X/sai.profile @@ -1 +1 @@ -SAI_INIT_CONFIG_FILE=/etc/bcm/td3-as7326-48x25G+8x100G.config.bcm +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td3-as7326-48x25G+8x100G.config.bcm diff --git a/device/accton/x86_64-accton_as7326_56x-r0/Accton-AS7326-56X/td3-as7326-48x25G+8x100G.config.bcm b/device/accton/x86_64-accton_as7326_56x-r0/Accton-AS7326-56X/td3-as7326-48x25G+8x100G.config.bcm index 2b7b6fb08007..1a4b7da32df3 100755 --- a/device/accton/x86_64-accton_as7326_56x-r0/Accton-AS7326-56X/td3-as7326-48x25G+8x100G.config.bcm +++ b/device/accton/x86_64-accton_as7326_56x-r0/Accton-AS7326-56X/td3-as7326-48x25G+8x100G.config.bcm @@ -17,6 +17,7 @@ l2xmsg_mode=1 bcm_num_cos=8 bcm_stat_interval=2000000 cdma_timeout_usec=3000000 +ifp_inports_support_enable=1 ipv6_lpm_128b_enable=0x1 l3_max_ecmp_mode=1 l3_alpm_enable=2 @@ -24,11 +25,13 @@ lpm_scaling_enable=0 max_vp_lags=0 miim_intr_enable=0 module_64ports=1 +port_flex_enable=1 schan_intr_enable=0 stable_size=0x5500000 tdma_timeout_usec=3000000 skip_L2_USER_ENTRY=0 bcm_tunnel_term_compatible_mode=1 +l3_alpm_ipv6_128b_bkt_rsvd=1 dport_map_port_1=6 dport_map_port_2=2 diff --git a/device/accton/x86_64-accton_as7326_56x-r0/custom_led.bin b/device/accton/x86_64-accton_as7326_56x-r0/custom_led.bin new file mode 100755 index 0000000000000000000000000000000000000000..8495c821680117741b78205c42c959878fbfd2b4 GIT binary patch literal 1092 zcmZwGT~E_c7zgmvuCxO(gdj5Th#e(_w-8`NVW^B14rWAArU)zu8^lcU0>ujiUncVd zs3QhCjS1d)VTj0`B=Z}r(F-FtBV2f4OqOT@8k71j8wQL`emOaPdY*sJNt;@YEDO{| zi9#IV@+V|8^uAAUMm@iDQd!!&VkJ?TR#O*sQj*I3DIBY+|A9(TuY7#P>UQp}{@ymL z-*s;#d1|h)dEHIuno4bRj*U^GD1q$qU?8u2DX6)!KL74aC2;P+_Icnn{OfH zU@IZ>z!5@tuz&zrAc6!|ut6RifP5%|Lr@HMI09vG6l8EfIVey8)ldVqPzR0B1WsrM zyaI7S8=QcXa0=SN4ISVC6*{2{7<9vFI0I*)7tX;&=!Z)%0K;$@Mqm^I5QH%phpTW6 zCg3{UfSWJ{x8OF+z%1N>yKoQgLl_=F1dPlT2@Tr0R_nA{w$L%z9cSrz?zFX5Ok~&c z2_j3i7M+v1Brh9ZCcAg*S#6)+2sOE%qD1t57mEG9Ww03JxvB2RWV;DA!ABdniw zvEo5*u)(UYU+D;kSR zVuDvVt8R{tHG}c1RwXY13`j|!47@s7S1W%^#zc#|`A@MP)T9QOrV5n92nZLvz z(irEgPPEYT%-D(`xmfS(@pbM`Ui651RN@m{EGBUu!wOZ?&rcyuP)WV0r{}YVn-f$% zsWLxDRkMF=r+;gvzYqQGy6ZpvrN8}o^j{~t37$-XHIv{q2#-YUt02kOOPRav#vHTo zRF#l?7^7L|uuqK*cYX^^&<5mJ<8%sl@=JTZ{&TX69^1bB7~Vd;g5R@4vqO#%N4^!= s7Tw3zk!9}I9A`o~u^4&Q$1l@&kC?_@veX(rr}jGh7!6>K&CmjW02uKW<^TWy literal 0 HcmV?d00001 diff --git a/device/accton/x86_64-accton_as7326_56x-r0/led_proc_init.soc b/device/accton/x86_64-accton_as7326_56x-r0/led_proc_init.soc new file mode 100755 index 000000000000..01b49772c0ba --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/led_proc_init.soc @@ -0,0 +1,6 @@ +#led auto off +#led stop +m0 load 0 0x0 /usr/share/sonic/platform/linkscan_led_fw.bin +m0 load 0 0x3800 /usr/share/sonic/platform/custom_led.bin +led auto on +led start diff --git a/device/accton/x86_64-accton_as7326_56x-r0/linkscan_led_fw.bin b/device/accton/x86_64-accton_as7326_56x-r0/linkscan_led_fw.bin new file mode 100755 index 0000000000000000000000000000000000000000..a6a4794ecc2bfa213cd2dfcbb38f743421708819 GIT binary patch literal 4716 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 Date: Thu, 19 Dec 2019 07:15:27 -0800 Subject: [PATCH 261/278] [caclmgrd] Fix application of IPv6 service ACL rules (#3917) --- files/image_config/caclmgrd/caclmgrd | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/files/image_config/caclmgrd/caclmgrd b/files/image_config/caclmgrd/caclmgrd index 5e8d83074de1..6226bb16768f 100755 --- a/files/image_config/caclmgrd/caclmgrd +++ b/files/image_config/caclmgrd/caclmgrd @@ -194,13 +194,14 @@ class ControlPlaneAclManager(object): continue # If we haven't determined the IP version for this ACL table yet, - # try to do it now. We determine heuristically based on whether the - # src IP is an IPv4 or IPv6 address. - if not table_ip_version and "SRC_IP" in rule_props and rule_props["SRC_IP"]: - ip_addr = ipaddress.IPAddress(rule_props["SRC_IP"].split("/")[0]) - if isinstance(ip_addr, ipaddress.IPv6Address): + # try to do it now. We attempt to determine heuristically based on + # whether the src or dst IP of this rule is an IPv4 or IPv6 address. + if not table_ip_version: + if (("SRC_IPV6" in rule_props and rule_props["SRC_IPV6"]) or + ("DST_IPV6" in rule_props and rule_props["DST_IPV6"])): table_ip_version = 6 - elif isinstance(ip_addr, ipaddress.IPv4Address): + elif (("SRC_IP" in rule_props and rule_props["SRC_IP"]) or + ("DST_IP" in rule_props and rule_props["DST_IP"])): table_ip_version = 4 # If we were unable to determine whether this ACL table contains From b6ad09aa352370e6e69fd609802dfd74ea8cd00e Mon Sep 17 00:00:00 2001 From: Stepan Blyshchak <38952541+stepanblyschak@users.noreply.github.com> Date: Mon, 23 Dec 2019 11:15:08 +0200 Subject: [PATCH 262/278] [syncd.sh] remove chipdown on mellanox (#3926) ASIC reset events are captured by hw-mgmt and hw-mgmt calls chipup/chipdown internally without OS iteraction Signed-off-by: Stepan Blyschak --- files/scripts/syncd.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/files/scripts/syncd.sh b/files/scripts/syncd.sh index 89f15f0f413f..05e5552a64b1 100755 --- a/files/scripts/syncd.sh +++ b/files/scripts/syncd.sh @@ -111,7 +111,6 @@ start() { /bin/systemctl stop pmon debug "pmon is active while syncd starting, stop it first" fi - /usr/bin/hw-management.sh chipdown fi if [[ x"$BOOT_TYPE" == x"fast" ]]; then From ed2d5f8a32f1deffb6e8a59c4b153b36f7c30e16 Mon Sep 17 00:00:00 2001 From: Wataru Ishida <5915117+ishidawataru@users.noreply.github.com> Date: Mon, 23 Dec 2019 10:27:22 -0800 Subject: [PATCH 263/278] [broadcom]: respect the current network namespace when creating netdev (#3896) https://github.com/Broadcom-Switch/OpenNSL/issues/26 Signed-off-by: Wataru Ishida --- .../systems/linux/kernel/modules/bcm-knet/bcm-knet.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c index 0c91c3ecd5f7..077386e6dcbc 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c @@ -6165,6 +6165,10 @@ bkn_init_ndev(u8 *mac, char *name) strncpy(dev->name, name, IFNAMSIZ-1); } +#ifdef CONFIG_NET_NS + dev_net_set(dev, current->nsproxy->net_ns); +#endif + /* Register the kernel Ethernet device */ if (register_netdev(dev)) { DBG_WARN(("Error registering Ethernet device.\n")); From 183c945ab109d541083123277d9553863cd44df8 Mon Sep 17 00:00:00 2001 From: Stepan Blyshchak <38952541+stepanblyschak@users.noreply.github.com> Date: Mon, 23 Dec 2019 20:34:22 +0200 Subject: [PATCH 264/278] [slave.mk] use curl instead of wget (#3939) wget creates empty file on failure which makes subsequent make runs think that file is already there and won't try to download it again. e.g.: $ make target/files/stretch/fw-SPC-rel-13_2000_2602-EVB.mfa ... Fails to download ... $ ls target/files/stretch/fw-SPC-rel-13_2000_2602-EVB.mfa target/files/stretch/fw-SPC-rel-13_2000_2602-EVB.mfa $ make target/files/stretch/fw-SPC-rel-13_2000_2602-EVB.mfa make: `target/files/stretch/fw-SPC-rel-13_2000_2602-EVB.mfa' is up to date. Signed-off-by: Stepan Blyschak --- slave.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/slave.mk b/slave.mk index 44b903ddf9c9..f62be5672221 100644 --- a/slave.mk +++ b/slave.mk @@ -256,7 +256,7 @@ SONIC_TARGET_LIST += $(addprefix $(FILES_PATH)/, $(SONIC_COPY_FILES)) $(addprefix $(DEBS_PATH)/, $(SONIC_ONLINE_DEBS)) : $(DEBS_PATH)/% : .platform $(HEADER) $(foreach deb,$* $($*_DERIVED_DEBS), \ - { wget --no-use-server-timestamps -O $(DEBS_PATH)/$(deb) $($(deb)_URL) $(LOG) || exit 1 ; } ; ) + { curl -f -o $(DEBS_PATH)/$(deb) $($(deb)_URL) $(LOG) || { exit 1 ; } } ; ) $(FOOTER) SONIC_TARGET_LIST += $(addprefix $(DEBS_PATH)/, $(SONIC_ONLINE_DEBS)) @@ -269,7 +269,7 @@ SONIC_TARGET_LIST += $(addprefix $(DEBS_PATH)/, $(SONIC_ONLINE_DEBS)) # SONIC_ONLINE_FILES += $(SOME_NEW_FILE) $(addprefix $(FILES_PATH)/, $(SONIC_ONLINE_FILES)) : $(FILES_PATH)/% : .platform $(HEADER) - wget --no-use-server-timestamps -O $@ $($*_URL) $(LOG) + curl -f -o $@ $($*_URL) $(LOG) $(FOOTER) SONIC_TARGET_LIST += $(addprefix $(FILES_PATH)/, $(SONIC_ONLINE_FILES)) @@ -631,7 +631,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ # Pass initramfs and linux kernel explicitly. They are used for all platforms export debs_path="$(STRETCH_DEBS_PATH)" export files_path="$(FILES_PATH)" - export python_debs_path="$(PYTHON_DEBS_PATH)" + export python_debs_path="$(PYTHON_DEBS_PATH)" export initramfs_tools="$(STRETCH_DEBS_PATH)/$(INITRAMFS_TOOLS)" export linux_kernel="$(STRETCH_DEBS_PATH)/$(LINUX_KERNEL)" export onie_recovery_image="$(FILES_PATH)/$(ONIE_RECOVERY_IMAGE)" From 87f70108cb240c484dff6913500e56eda8c1bdb5 Mon Sep 17 00:00:00 2001 From: Prabhu Sreenivasan <45380242+PrabhuSreenivasan@users.noreply.github.com> Date: Tue, 24 Dec 2019 11:17:16 +0530 Subject: [PATCH 265/278] SONiC Management Framework Release 1.0 (#3488) * Added sonic-mgmt-framework as submodule / docker * fix build issues * update sonic-mgmt-framework submodule branch to master * Merged changes 70007e6d2ba3a4c0b371cd693ccc63e0a8906e77..00d4fcfed6a759e40d7b92120ea0ee1f08300fc6 00d4fcfed6a759e40d7b92120ea0ee1f08300fc6 Modified environemnt variables * Changes to build sonic-mgmt-framework docker * bumped up sonic-mgmt-framework commit-id * version bump for sonic-mgmt-framework commit-it * bumped up sonic-mgmt-framework commit-id * Add python packages to docker * Build fix for docker with python packages * added libyang as dependent package * Allow building images on NFS-mounted clones Prior to this change, `build_debian.sh` would generate a Debian filesystem in `./fsroot`. This needs root permissions, and one of the tests that is performed is whether the user can create a character special file in the filesystem (using mknod). On most NFS deployments, `root` is the least privileged user, and cannot run mknod. Also, attempting to run commands like rm or mv as root would fail due to permission errors, since the root user gets mapped to an unprivileged user like `nobody`. This commit changes the location of the Debian filesystem to `/fsroot`, which is a tmpfs mount within the slave Docker. The default squashfs, docker tarball and zip files are also created within /tmp, before being copied back to /sonic as the regular user. The side effect of this change is that the contents of `/fsroot` are no longer available once the slave container exits, however they are available within the squashfs image. Signed-off-by: Nirenjan Krishnan * bumped up sonc-mgmt-framework commit to include PR #18 * REST Server startup script is enahnced to read the settings from ConfigDB. Below table provides mapping of db field to command line argument name. ============================================================ ConfigDB entry key Field name REST Server argument ============================================================ REST_SERVER|default port -port REST_SERVER|default client_auth -client_auth REST_SERVER|default log_level -v DEVICE_METADATA|x509 server_crt -cert DEVICE_METADATA|x509 server_key -key DEVICE_METADATA|x509 ca_crt -cacert ============================================================ * Replace src/telemetry as submodule to sonic-telemetry * Update telemetry commit HEAD * Update sonic-telemetry commit HEAD * libyang env path update * Add libyang dependency to telemetry * Add scripts to create JSON files for CLI backend Scripts to create /var/platform/syseeprom and /var/platform/system, which are back-end files for CLI, for system EEPROM and system information. Signed-off-by: Howard Persh * In startup script, create directory where CLI back-end files live Signed-off-by: Howard Persh * build dependency pkgs added to docker for build failure fix * Changes to fix build issue for mgmt framework * Fix exec path issue with telemetry * s5232[device] PSU detecttion and default led state support * Processing of first boot in rc.local should not have premature exit Signed-off-by: Howard Persh * docker mount options added for platform, system features * bumped up sonic-mgmt-framework commit id to pick 23rd July 2019 changes * Added mount options for telemetry docker to get access for system and platform info. * Update commit for sonic-utilities * [dell]: Corrected dport map and renamed config files for S5232F * Fix telemetry submodule commit * added support for sonic-cli console * [Dell S5232F, Z9264F] Harden FPGA driver kernel module For Dell S5232F and Z9264F platforms, be more strict when checking state in ISR of FPGA driver, to harden against spurious interrupts. Signed-off-by: Howard Persh * update mgmt-framework submodule to 27th Aug commit. * remove changes not related to mgmt-framework and sonic-telemetry * Revert "Replace src/telemetry as submodule to sonic-telemetry" This reverts commit 11c31929759a17122782d4944066a6ac8453b78d. * Revert "Replace src/telemetry as submodule to sonic-telemetry" This reverts commit 11c31929759a17122782d4944066a6ac8453b78d. * make submodule changes and remove a change not related to PR * more changes * Update .gitmodules * Update Dockerfile.j2 * Update .gitmodules * Update .gitmodules * Update .gitmodules reverting experimental change * Removed syspoll for release_1.0 Signed-off-by: Jeff Yin <29264773+jeff-yin@users.noreply.github.com> * Update docker-sonic-mgmt-framework.mk * Update sonic-mgmt-framework.mk * Update sonic-mgmt-framework.mk * Update docker-sonic-mgmt-framework.mk * Update docker-sonic-mgmt-framework.mk * Revert "Processing of first boot in rc.local should not have premature exit" This reverts commit e99a91ffc28a0fd13f4ad458719d2511c3665431. * Remove old telemetry directory * Update docker-sonic-mgmt-framework.mk * Resolving merge conflict with Azure * Reverting the wrong merge * Use CVL_SCHEMA_PATH instead of changing directory for telemetry startup * Add missing export * Add python mmh3 to slave dockerfile * Remove sonic-mgmt-framework build dep for telemetry, fix dialout startup issues * Provided flag to disable compiling mgmt-framework * Update sonic-utilites point latest commit id * Point sonic-utilities to Azure accepted SHA * Updating mgmt framework to right sha * Add sonic-telemetry submodule * Update the mgmt-framework commit id Co-authored-by: jghalam Co-authored-by: Partha Dutta <51353699+dutta-partha@users.noreply.github.com> Co-authored-by: srideepDell Co-authored-by: nirenjan Co-authored-by: Sachin Holla <51310506+sachinholla@users.noreply.github.com> Co-authored-by: Eric Seifert Co-authored-by: Howard Persh Co-authored-by: Jeff Yin <29264773+jeff-yin@users.noreply.github.com> Co-authored-by: Arunsundar Kannan <31632515+arunsundark@users.noreply.github.com> Co-authored-by: rvasanthm <51932293+rvasanthm@users.noreply.github.com> Co-authored-by: Ashok Daparthi-Dell Co-authored-by: anand-kumar-subramanian <51383315+anand-kumar-subramanian@users.noreply.github.com> --- .gitmodules | 6 +++ .../docker-sonic-mgmt-framework/Dockerfile.j2 | 42 +++++++++++++++ .../base_image_files/sonic-cli | 4 ++ .../rest-server.sh | 52 +++++++++++++++++++ dockers/docker-sonic-mgmt-framework/start.sh | 10 ++++ .../supervisord.conf | 28 ++++++++++ dockers/docker-sonic-telemetry/dialout.sh | 2 +- .../docker-sonic-telemetry/supervisord.conf | 4 +- dockers/docker-sonic-telemetry/telemetry.sh | 1 + .../build_templates/mgmt-framework.service.j2 | 14 +++++ files/image_config/platform/rc.local | 3 ++ rules/config | 3 ++ rules/docker-sonic-mgmt-framework.mk | 34 ++++++++++++ rules/docker-telemetry.mk | 1 + rules/sonic-mgmt-framework.mk | 16 ++++++ rules/telemetry.mk | 4 +- sonic-slave-stretch/Dockerfile.j2 | 3 ++ src/sonic-mgmt-framework | 1 + src/sonic-telemetry | 1 + src/telemetry/Makefile | 20 ------- src/telemetry/debian/changelog | 5 -- src/telemetry/debian/compat | 1 - src/telemetry/debian/control | 17 ------ src/telemetry/debian/rules | 3 -- src/telemetry/debian/telemetry.init.d | 14 ----- 25 files changed, 225 insertions(+), 64 deletions(-) create mode 100644 dockers/docker-sonic-mgmt-framework/Dockerfile.j2 create mode 100755 dockers/docker-sonic-mgmt-framework/base_image_files/sonic-cli create mode 100755 dockers/docker-sonic-mgmt-framework/rest-server.sh create mode 100755 dockers/docker-sonic-mgmt-framework/start.sh create mode 100644 dockers/docker-sonic-mgmt-framework/supervisord.conf create mode 100644 files/build_templates/mgmt-framework.service.j2 create mode 100644 rules/docker-sonic-mgmt-framework.mk create mode 100644 rules/sonic-mgmt-framework.mk create mode 160000 src/sonic-mgmt-framework create mode 160000 src/sonic-telemetry delete mode 100644 src/telemetry/Makefile delete mode 100644 src/telemetry/debian/changelog delete mode 100644 src/telemetry/debian/compat delete mode 100644 src/telemetry/debian/control delete mode 100755 src/telemetry/debian/rules delete mode 100644 src/telemetry/debian/telemetry.init.d diff --git a/.gitmodules b/.gitmodules index b2ffb2b26fff..0cccf14a8e94 100644 --- a/.gitmodules +++ b/.gitmodules @@ -66,6 +66,12 @@ [submodule "platform/mellanox/mlnx-sai/SAI-Implementation"] path = platform/mellanox/mlnx-sai/SAI-Implementation url = https://github.com/Mellanox/SAI-Implementation +[submodule "src/sonic-mgmt-framework"] + path = src/sonic-mgmt-framework + url = https://github.com/Azure/sonic-mgmt-framework +[submodule "src/sonic-telemetry"] + path = src/sonic-telemetry + url = https://github.com/Azure/sonic-telemetry [submodule "Switch-SDK-drivers"] path = platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers url = https://github.com/Mellanox/Switch-SDK-drivers diff --git a/dockers/docker-sonic-mgmt-framework/Dockerfile.j2 b/dockers/docker-sonic-mgmt-framework/Dockerfile.j2 new file mode 100644 index 000000000000..08c819c1cc14 --- /dev/null +++ b/dockers/docker-sonic-mgmt-framework/Dockerfile.j2 @@ -0,0 +1,42 @@ +FROM docker-config-engine-stretch + +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 +RUN pip install connexion==1.1.15 \ + setuptools==21.0.0 \ + grpcio-tools==1.20.0 \ + pyangbind==0.6.0 \ + certifi==2017.4.17 \ + python-dateutil==2.6.0 \ + six==1.11.0 \ + urllib3==1.21.1 + + + +## Install redis-tools dependencies +## TODO: implicitly install dependencies +RUN apt-get -y install libjemalloc1 libatomic1 liblua5.1-0 lua-bitop lua-cjson + +COPY \ +{% for deb in docker_sonic_mgmt_framework_debs.split(' ') -%} +debs/{{ deb }}{{' '}} +{%- endfor -%} +debs/ + +RUN dpkg -i \ +{% for deb in docker_sonic_mgmt_framework_debs.split(' ') -%} +debs/{{ deb }}{{' '}} +{%- endfor %} + +COPY ["start.sh", "rest-server.sh", "/usr/bin/"] +COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] + +RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y +RUN rm -rf /debs + +ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-sonic-mgmt-framework/base_image_files/sonic-cli b/dockers/docker-sonic-mgmt-framework/base_image_files/sonic-cli new file mode 100755 index 000000000000..6675e3badbaf --- /dev/null +++ b/dockers/docker-sonic-mgmt-framework/base_image_files/sonic-cli @@ -0,0 +1,4 @@ +#!/bin/bash + +docker exec -it mgmt-framework /usr/sbin/cli/clish_start "$@" + diff --git a/dockers/docker-sonic-mgmt-framework/rest-server.sh b/dockers/docker-sonic-mgmt-framework/rest-server.sh new file mode 100755 index 000000000000..f2a29c9b1ed2 --- /dev/null +++ b/dockers/docker-sonic-mgmt-framework/rest-server.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +# Startup script for SONiC Management REST Server + +SERVER_PORT= +LOG_LEVEL= +CLIENT_AUTH= +SERVER_CRT= +SERVER_KEY= +CA_CERT= + +# Read basic server settings from REST_SERVER|default entry +HAS_REST_CONFIG=$(sonic-cfggen -d -v "1 if REST_SERVER and REST_SERVER['default']") +if [ "$HAS_REST_CONFIG" == "1" ]; then + SERVER_PORT=$(sonic-cfggen -d -v "REST_SERVER['default']['port']") + CLIENT_AUTH=$(sonic-cfggen -d -v "REST_SERVER['default']['client_auth']") + LOG_LEVEL=$(sonic-cfggen -d -v "REST_SERVER['default']['log_level']") +fi + +# Read certificate file paths from DEVICE_METADATA|x509 entry. +HAS_X509_CONFIG=$(sonic-cfggen -d -v "1 if DEVICE_METADATA and DEVICE_METADATA['x509']") +if [ "$HAS_X509_CONFIG" == "1" ]; then + SERVER_CRT=$(sonic-cfggen -d -v "DEVICE_METADATA['x509']['server_crt']") + SERVER_KEY=$(sonic-cfggen -d -v "DEVICE_METADATA['x509']['server_key']") + CA_CRT=$(sonic-cfggen -d -v "DEVICE_METADATA['x509']['ca_crt']") +fi + +# Create temporary server certificate if they not configured in ConfigDB +if [ -z $SERVER_CRT ] && [ -z $SERVER_KEY ]; then + echo "Generating temporary TLS server certificate ..." + (cd /tmp && /usr/sbin/generate_cert --host="localhost,127.0.0.1") + SERVER_CRT=/tmp/cert.pem + SERVER_KEY=/tmp/key.pem +fi + + +REST_SERVER_ARGS="-ui /rest_ui -logtostderr" +[ ! -z $SERVER_PORT ] && REST_SERVER_ARGS+=" -port $SERVER_PORT" +[ ! -z $LOG_LEVEL ] && REST_SERVER_ARGS+=" -v $LOG_LEVEL" +[ ! -z $CLIENT_AUTH ] && REST_SERVER_ARGS+=" -client_auth $CLIENT_AUTH" +[ ! -z $SERVER_CRT ] && REST_SERVER_ARGS+=" -cert $SERVER_CRT" +[ ! -z $SERVER_KEY ] && REST_SERVER_ARGS+=" -key $SERVER_KEY" +[ ! -z $CA_CRT ] && REST_SERVER_ARGS+=" -cacert $CA_CRT" + +echo "REST_SERVER_ARGS = $REST_SERVER_ARGS" + + +export CVL_SCHEMA_PATH=/usr/sbin/schema +export LIBYANG_EXTENSIONS_PLUGINS_DIR=/usr/lib/x86_64-linux-gnu/libyang/extensions +export LIBYANG_USER_TYPES_PLUGINS_DIR=/usr/lib/x86_64-linux-gnu/libyang/user_types + +exec /usr/sbin/rest_server ${REST_SERVER_ARGS} diff --git a/dockers/docker-sonic-mgmt-framework/start.sh b/dockers/docker-sonic-mgmt-framework/start.sh new file mode 100755 index 000000000000..24d355670e87 --- /dev/null +++ b/dockers/docker-sonic-mgmt-framework/start.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +mkdir -p /var/sonic +echo "# Config files managed by sonic-config-engine" > /var/sonic/config_status + +rm -f /var/run/rsyslogd.pid + +supervisorctl start rsyslogd + +supervisorctl start rest-server diff --git a/dockers/docker-sonic-mgmt-framework/supervisord.conf b/dockers/docker-sonic-mgmt-framework/supervisord.conf new file mode 100644 index 000000000000..e26f815f5fb9 --- /dev/null +++ b/dockers/docker-sonic-mgmt-framework/supervisord.conf @@ -0,0 +1,28 @@ +[supervisord] +logfile_maxbytes=1MB +logfile_backups=2 +nodaemon=true + +[program:start.sh] +command=/usr/bin/start.sh +priority=1 +autostart=true +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +[program:rsyslogd] +command=/usr/sbin/rsyslogd -n +priority=2 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +[program:rest-server] +command=/usr/bin/rest-server.sh +priority=3 +autostart=false +autorestart=true +stdout_logfile=syslog +stderr_logfile=syslog diff --git a/dockers/docker-sonic-telemetry/dialout.sh b/dockers/docker-sonic-telemetry/dialout.sh index 8683e8edae8e..485c3292d0df 100755 --- a/dockers/docker-sonic-telemetry/dialout.sh +++ b/dockers/docker-sonic-telemetry/dialout.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # Start with default config - +export CVL_SCHEMA_PATH=/usr/sbin/schema exec /usr/sbin/dialout_client_cli -insecure -logtostderr -v 2 diff --git a/dockers/docker-sonic-telemetry/supervisord.conf b/dockers/docker-sonic-telemetry/supervisord.conf index b6a01de58a7b..e1346fe7db4e 100644 --- a/dockers/docker-sonic-telemetry/supervisord.conf +++ b/dockers/docker-sonic-telemetry/supervisord.conf @@ -6,8 +6,8 @@ nodaemon=true [eventlistener:supervisor-proc-exit-listener] command=/usr/bin/supervisor-proc-exit-listener events=PROCESS_STATE_EXITED -autostart=always -autorestart=unexpected +autostart=true +autorestart=false [program:start.sh] command=/usr/bin/start.sh diff --git a/dockers/docker-sonic-telemetry/telemetry.sh b/dockers/docker-sonic-telemetry/telemetry.sh index 8cfd8a531cca..8b29b4d616a5 100755 --- a/dockers/docker-sonic-telemetry/telemetry.sh +++ b/dockers/docker-sonic-telemetry/telemetry.sh @@ -6,6 +6,7 @@ X509=`sonic-cfggen -d -v "DEVICE_METADATA['x509']"` TELEMETRY=`sonic-cfggen -d -v 'TELEMETRY.keys() | join(" ") if TELEMETRY'` TELEMETRY_ARGS=" -logtostderr" +export CVL_SCHEMA_PATH=/usr/sbin/schema if [ -n "$X509" ]; then SERVER_CRT=`sonic-cfggen -d -v "DEVICE_METADATA['x509']['server_crt']"` diff --git a/files/build_templates/mgmt-framework.service.j2 b/files/build_templates/mgmt-framework.service.j2 new file mode 100644 index 000000000000..d0a030347b51 --- /dev/null +++ b/files/build_templates/mgmt-framework.service.j2 @@ -0,0 +1,14 @@ +[Unit] +Description=Management Framework container +Requires=swss.service +After=swss.service +Before=ntp-config.service + +[Service] +User={{ sonicadmin_user }} +ExecStartPre=/usr/bin/{{docker_container_name}}.sh start +ExecStart=/usr/bin/{{docker_container_name}}.sh wait +ExecStop=/usr/bin/{{docker_container_name}}.sh stop + +[Install] +WantedBy=multi-user.target diff --git a/files/image_config/platform/rc.local b/files/image_config/platform/rc.local index b74e9f40c4b0..d64ec1bb7916 100755 --- a/files/image_config/platform/rc.local +++ b/files/image_config/platform/rc.local @@ -331,4 +331,7 @@ if [ -f $FIRST_BOOT_FILE ]; then firsttime_exit fi +# Create dir where following scripts put their output files +mkdir -p /var/platform + exit 0 diff --git a/rules/config b/rules/config index c158fcc27726..a559a5b2fc88 100644 --- a/rules/config +++ b/rules/config @@ -101,3 +101,6 @@ DEFAULT_VS_PREPARE_MEM = yes # ENABLE_SYSTEM_SFLOW - build docker-sonic-sflow for sFlow support ENABLE_SFLOW = y + +# ENABLE_MGMT_FRAMEWORK - build docker-sonic-mgt-framework for CLI and REST server support +ENABLE_MGMT_FRAMEWORK = y diff --git a/rules/docker-sonic-mgmt-framework.mk b/rules/docker-sonic-mgmt-framework.mk new file mode 100644 index 000000000000..eb99f37875fc --- /dev/null +++ b/rules/docker-sonic-mgmt-framework.mk @@ -0,0 +1,34 @@ +# docker image for mgmt-framework + +DOCKER_MGMT_FRAMEWORK_STEM = docker-sonic-mgmt-framework +DOCKER_MGMT_FRAMEWORK = $(DOCKER_MGMT_FRAMEWORK_STEM).gz +DOCKER_MGMT_FRAMEWORK_DBG = $(DOCKER_MGMT_FRAMEWORK_STEM)-$(DBG_IMAGE_MARK).gz + +$(DOCKER_MGMT_FRAMEWORK)_PATH = $(DOCKERS_PATH)/$(DOCKER_MGMT_FRAMEWORK_STEM) + +$(DOCKER_MGMT_FRAMEWORK)_DEPENDS += $(REDIS_TOOLS) $(SONIC_MGMT_FRAMEWORK) +$(DOCKER_MGMT_FRAMEWORK)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_DEPENDS) +$(DOCKER_MGMT_FRAMEWORK)_DBG_DEPENDS += $(REDIS_TOOLS) $(SONIC_MGMT_FRAMEWORK_DBG) + +SONIC_DOCKER_IMAGES += $(DOCKER_MGMT_FRAMEWORK) +$(DOCKER_MGMT_FRAMEWORK)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_STRETCH) +$(DOCKER_MGMT_FRAMEWORK)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_IMAGE_PACKAGES) + +ifeq ($(ENABLE_MGMT_FRAMEWORK), y) +SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_MGMT_FRAMEWORK) +SONIC_STRETCH_DOCKERS += $(DOCKER_MGMT_FRAMEWORK) +endif + +SONIC_DOCKER_DBG_IMAGES += $(DOCKER_MGMT_FRAMEWORK_DBG) +ifeq ($(ENABLE_MGMT_FRAMEWORK), y) +SONIC_INSTALL_DOCKER_DBG_IMAGES += $(DOCKER_MGMT_FRAMEWORK_DBG) +SONIC_STRETCH_DBG_DOCKERS += $(DOCKER_MGMT_FRAMEWORK_DBG) +endif + +$(DOCKER_MGMT_FRAMEWORK)_CONTAINER_NAME = mgmt-framework +$(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += --net=host --privileged -t +$(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro +$(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += -v /etc:/host_etc:ro +$(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += --mount type=bind,source="/var/platform/",target="/mnt/platform/" + +$(DOCKER_MGMT_FRAMEWORK)_BASE_IMAGE_FILES += sonic-cli:/usr/bin/sonic-cli diff --git a/rules/docker-telemetry.mk b/rules/docker-telemetry.mk index defeb4d00821..799bef1b1735 100644 --- a/rules/docker-telemetry.mk +++ b/rules/docker-telemetry.mk @@ -27,5 +27,6 @@ endif $(DOCKER_TELEMETRY)_CONTAINER_NAME = telemetry $(DOCKER_TELEMETRY)_RUN_OPT += --net=host --privileged -t $(DOCKER_TELEMETRY)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro +$(DOCKER_TELEMETRY)_RUN_OPT += --mount type=bind,source="/var/platform/",target="/mnt/platform/" $(DOCKER_TELEMETRY)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) diff --git a/rules/sonic-mgmt-framework.mk b/rules/sonic-mgmt-framework.mk new file mode 100644 index 000000000000..a57ce6b1b083 --- /dev/null +++ b/rules/sonic-mgmt-framework.mk @@ -0,0 +1,16 @@ +# SONiC mgmt-framework package + +ifeq ($(ENABLE_MGMT_FRAMEWORK), y) + +SONIC_MGMT_FRAMEWORK = sonic-mgmt-framework_1.0-01_amd64.deb +$(SONIC_MGMT_FRAMEWORK)_SRC_PATH = $(SRC_PATH)/sonic-mgmt-framework +$(SONIC_MGMT_FRAMEWORK)_DEPENDS = $(LIBYANG_DEV) $(LIBYANG) +$(SONIC_MGMT_FRAMEWORK)_RDEPENDS = $(LIBYANG) +SONIC_DPKG_DEBS += $(SONIC_MGMT_FRAMEWORK) + +SONIC_MGMT_FRAMEWORK_DBG = sonic-mgmt-framework-dbg_1.0-01_amd64.deb +$(SONIC_MGMT_FRAMEWORK_DBG)_DEPENDS += $(SONIC_MGMT_FRAMEWORK) +$(SONIC_MGMT_FRAMEWORK_DBG)_RDEPENDS += $(SONIC_MGMT_FRAMEWORK) +$(eval $(call add_derived_package,$(SONIC_MGMT_FRAMEWORK),$(SONIC_MGMT_FRAMEWORK_DBG))) + +endif diff --git a/rules/telemetry.mk b/rules/telemetry.mk index 1d903e603251..0b4421b11942 100644 --- a/rules/telemetry.mk +++ b/rules/telemetry.mk @@ -1,5 +1,7 @@ # SONiC telemetry package SONIC_TELEMETRY = sonic-telemetry_0.1_$(CONFIGURED_ARCH).deb -$(SONIC_TELEMETRY)_SRC_PATH = $(SRC_PATH)/telemetry +$(SONIC_TELEMETRY)_SRC_PATH = $(SRC_PATH)/sonic-telemetry +$(SONIC_TELEMETRY)_DEPENDS = $(LIBYANG_DEV) $(LIBYANG) +$(SONIC_TELEMETRY)_RDEPENDS = $(LIBYANG) SONIC_DPKG_DEBS += $(SONIC_TELEMETRY) diff --git a/sonic-slave-stretch/Dockerfile.j2 b/sonic-slave-stretch/Dockerfile.j2 index 08e002624abb..d0e3775396dc 100644 --- a/sonic-slave-stretch/Dockerfile.j2 +++ b/sonic-slave-stretch/Dockerfile.j2 @@ -362,6 +362,9 @@ RUN pip install mockredispy==2.9.3 RUN pip install pytest-runner==4.4 RUN pip install setuptools==40.8.0 +# For mgmt-framework build +RUN pip install mmh3 + # Install dependencies for isc-dhcp-relay build RUN apt-get -y build-dep isc-dhcp diff --git a/src/sonic-mgmt-framework b/src/sonic-mgmt-framework new file mode 160000 index 000000000000..8b199a9f822c --- /dev/null +++ b/src/sonic-mgmt-framework @@ -0,0 +1 @@ +Subproject commit 8b199a9f822ca42564a7a89da0cab3133684bd12 diff --git a/src/sonic-telemetry b/src/sonic-telemetry new file mode 160000 index 000000000000..aaa9188fda4b --- /dev/null +++ b/src/sonic-telemetry @@ -0,0 +1 @@ +Subproject commit aaa9188fda4b6f36dd5da00cdb240933fedae5ce diff --git a/src/telemetry/Makefile b/src/telemetry/Makefile deleted file mode 100644 index 91a822d4f93c..000000000000 --- a/src/telemetry/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -export GOPATH=/tmp/go - -INSTALL := /usr/bin/install - -all: sonic-telemetry - -sonic-telemetry: - /usr/local/go/bin/go get -v github.com/Azure/sonic-telemetry/telemetry - /usr/local/go/bin/go get -v github.com/Azure/sonic-telemetry/dialout/dialout_client_cli - -install: - $(INSTALL) -D ${GOPATH}/bin/telemetry $(DESTDIR)/usr/sbin/telemetry - $(INSTALL) -D ${GOPATH}/bin/dialout_client_cli $(DESTDIR)/usr/sbin/dialout_client_cli - -deinstall: - rm $(DESTDIR)/usr/sbin/telemetry - rm $(DESTDIR)/usr/sbin/dialout_client_cli - -clean: - rm -fr ${GOPATH} diff --git a/src/telemetry/debian/changelog b/src/telemetry/debian/changelog deleted file mode 100644 index 77dab629040e..000000000000 --- a/src/telemetry/debian/changelog +++ /dev/null @@ -1,5 +0,0 @@ -sonic-telemetry (0.1) UNRELEASED; urgency=medium - - * Initial release. - - -- Jipan Yang Sat, 24 Mar 2018 12:48:22 -0700 diff --git a/src/telemetry/debian/compat b/src/telemetry/debian/compat deleted file mode 100644 index ec635144f600..000000000000 --- a/src/telemetry/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/src/telemetry/debian/control b/src/telemetry/debian/control deleted file mode 100644 index f1b6a7c07282..000000000000 --- a/src/telemetry/debian/control +++ /dev/null @@ -1,17 +0,0 @@ -Source: sonic-telemetry -Section: devel -Priority: optional -Maintainer: Jipan Yang -Build-Depends: debhelper (>= 8.0.0), - dh-systemd -Standards-Version: 3.9.3 -Homepage: https://github.com/Azure/sonic-telemetry -XS-Go-Import-Path: github.com/Azure/sonic-telemetry - -Package: sonic-telemetry -Architecture: any -Built-Using: ${misc:Built-Using} -Depends: ${misc:Depends}, - ${shlibs:Depends} -Description: SONiC telemetry - sonic-telemetry \ No newline at end of file diff --git a/src/telemetry/debian/rules b/src/telemetry/debian/rules deleted file mode 100755 index 3995a26d7fcd..000000000000 --- a/src/telemetry/debian/rules +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/make -f -%: - dh $@ --with systemd diff --git a/src/telemetry/debian/telemetry.init.d b/src/telemetry/debian/telemetry.init.d deleted file mode 100644 index 2fea32e17c49..000000000000 --- a/src/telemetry/debian/telemetry.init.d +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# -### BEGIN INIT INFO -# Provides: sonic-telemetry -# Required-Start: $local_fs $network $remote_fs $syslog -# Required-Stop: $local_fs $network $remote_fs $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: start and stop the telemetry -# Description: sonic-telemetry is an implementation of sonic telemetry daemon in Go -### END INIT INFO -# - -exit 0 From baea7e2a24d5e948ef47b3922839ff8066a16766 Mon Sep 17 00:00:00 2001 From: Stepan Blyshchak <38952541+stepanblyschak@users.noreply.github.com> Date: Fri, 27 Dec 2019 19:26:51 +0200 Subject: [PATCH 266/278] [slave.mk] make curl follow HTTP redirects (#3947) Fix an issue with SONIC_ONLINE_DEBS with curl by instructing curl to follow http redirects Signed-off-by: Stepan Blyschak --- slave.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slave.mk b/slave.mk index f62be5672221..382b03607186 100644 --- a/slave.mk +++ b/slave.mk @@ -256,7 +256,7 @@ SONIC_TARGET_LIST += $(addprefix $(FILES_PATH)/, $(SONIC_COPY_FILES)) $(addprefix $(DEBS_PATH)/, $(SONIC_ONLINE_DEBS)) : $(DEBS_PATH)/% : .platform $(HEADER) $(foreach deb,$* $($*_DERIVED_DEBS), \ - { curl -f -o $(DEBS_PATH)/$(deb) $($(deb)_URL) $(LOG) || { exit 1 ; } } ; ) + { curl -L -f -o $(DEBS_PATH)/$(deb) $($(deb)_URL) $(LOG) || { exit 1 ; } } ; ) $(FOOTER) SONIC_TARGET_LIST += $(addprefix $(DEBS_PATH)/, $(SONIC_ONLINE_DEBS)) @@ -269,7 +269,7 @@ SONIC_TARGET_LIST += $(addprefix $(DEBS_PATH)/, $(SONIC_ONLINE_DEBS)) # SONIC_ONLINE_FILES += $(SOME_NEW_FILE) $(addprefix $(FILES_PATH)/, $(SONIC_ONLINE_FILES)) : $(FILES_PATH)/% : .platform $(HEADER) - curl -f -o $@ $($*_URL) $(LOG) + curl -L -f -o $@ $($*_URL) $(LOG) $(FOOTER) SONIC_TARGET_LIST += $(addprefix $(FILES_PATH)/, $(SONIC_ONLINE_FILES)) From 86ab2aee06e931cf1fb21d86de150371cf0cea60 Mon Sep 17 00:00:00 2001 From: Dong Zhang <41927498+dzhangalibaba@users.noreply.github.com> Date: Fri, 27 Dec 2019 09:30:47 -0800 Subject: [PATCH 267/278] [swsssdk-py] submodule update for sonic-py-swsssdk (#3929) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit update multiDB changes in sonic-py-swsssdk, including: - read portchannel name from LAG_NAME_MAP_TABLE in COUNTERS_DB (#51) - Revert "read portchannel name from LAG_NAME_MAP_TABLE in COUNTERS_DB (#51)" (#57) - [MultiDB] sonic-db-cli should support EVAL operation, app script use … (#58) PR #3928 needs this swsssdk-py changes to work Signed-off-by: Dong Zhang d.zhang@alibaba-inc.com --- src/sonic-py-swsssdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-py-swsssdk b/src/sonic-py-swsssdk index bc3964b788c3..ccc1307aae0b 160000 --- a/src/sonic-py-swsssdk +++ b/src/sonic-py-swsssdk @@ -1 +1 @@ -Subproject commit bc3964b788c3a4a45f2b359a5df5934ecdee84c2 +Subproject commit ccc1307aae0b017a5c0d92385c9df67379da6d22 From 18cb5c6765a694467ab4eca733efab9ab9ad00b6 Mon Sep 17 00:00:00 2001 From: Stepan Blyshchak <38952541+stepanblyschak@users.noreply.github.com> Date: Fri, 27 Dec 2019 19:38:39 +0200 Subject: [PATCH 268/278] [swss] submodule update (#3925) 9f6efa0 [port/buffer] introduce a sync mechanism to protect port PG/queue from changes under PFC storm (#1143) 823e426 [aclorch] Enable DSCP rules on IPv6 mirror tables (#1146) b8745f8 [bitmap_vnet]: Fix removal flow for tunnel route (#1139) 03be983 Increase ip2me CIR/CBR for faster in-band file transfers (#1000) a4a1d3b [vnet]: Update VNET route table size to 40K for BITMAP implementation (#1132) efe142a Fix bug: Wrong condition for mac address (#1142) 7bf63a0 [teammgrd]during warm-reboot teamd need to recover system-id from saved lacp-pdu (#1003) 8b4cfb6 Cleanup configure.ac from BFN specific code (#1133) b931751 [teamsyncd]: Add retry logic in teamsyncd to avoid team handler init failure (#854) Signed-off-by: Stepan Blyschak --- src/sonic-swss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-swss b/src/sonic-swss index fc085ee70df1..9f6efa088d86 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit fc085ee70df1b6e4edf512bcfac212be429ab021 +Subproject commit 9f6efa088d8645572b82af590f20e8d60e9be285 From bd72844f758dbe424a07f4b4fe98d326764f2725 Mon Sep 17 00:00:00 2001 From: Guohan Lu Date: Sat, 28 Dec 2019 21:21:09 +0000 Subject: [PATCH 269/278] [kvm]: increase the kvm installer size to 2G for dbg image Signed-off-by: Guohan Lu --- scripts/build_kvm_image.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build_kvm_image.sh b/scripts/build_kvm_image.sh index a8ae21c9777a..5a56ac46efce 100755 --- a/scripts/build_kvm_image.sh +++ b/scripts/build_kvm_image.sh @@ -31,7 +31,7 @@ create_disk() prepare_installer_disk() { - fallocate -l 1024M $INSTALLER_DISK + fallocate -l 2048M $INSTALLER_DISK mkfs.vfat $INSTALLER_DISK From 78db0804d3a0ab9cf54a7ddf4c4d00c7ecd8751d Mon Sep 17 00:00:00 2001 From: Renuka Manavalan <47282725+renukamanavalan@users.noreply.github.com> Date: Mon, 30 Dec 2019 13:01:03 -0800 Subject: [PATCH 270/278] corefile uploader: Updates per review comments offline (#3915) * Updates per review comments 1) core_uploader service waits for syslog.service 2) core_uploader service enabled for restart on failure 3) Use mtime instead of file size + ample time to be robust. * Avoid reloading already uploaded file, by marking the names with a prefix. * Updated failing path. 1) If rc file is missing or required data missing, it periodically logs error in forever loop. 2) If upload fails, retry every hour with a error log, forever. * Fix few bugs * The binary update_json.py will come from sonic-utilities. --- .../build_templates/sonic_debian_extension.j2 | 1 - .../corefile_uploader/core_uploader.py | 47 +++++++++------- .../corefile_uploader/core_uploader.service | 6 +- .../corefile_uploader/update_json.py | 55 ------------------- 4 files changed, 32 insertions(+), 77 deletions(-) delete mode 100755 files/image_config/corefile_uploader/update_json.py diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index b63b5addac4b..a007745406e4 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -225,7 +225,6 @@ sudo cp $IMAGE_CONFIGS/hostcfgd/*.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/ sudo cp $IMAGE_CONFIGS/corefile_uploader/core_uploader.service $FILESYSTEM_ROOT/etc/systemd/system/ sudo LANG=C chroot $FILESYSTEM_ROOT systemctl disable core_uploader.service sudo cp $IMAGE_CONFIGS/corefile_uploader/core_uploader.py $FILESYSTEM_ROOT/usr/bin/ -sudo cp $IMAGE_CONFIGS/corefile_uploader/update_json.py $FILESYSTEM_ROOT/usr/bin/ sudo cp $IMAGE_CONFIGS/corefile_uploader/core_analyzer.rc.json $FILESYSTEM_ROOT_ETC_SONIC/ sudo chmod og-rw $FILESYSTEM_ROOT_ETC_SONIC/core_analyzer.rc.json sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install azure-storage diff --git a/files/image_config/corefile_uploader/core_uploader.py b/files/image_config/corefile_uploader/core_uploader.py index 676ff9583b06..2ae91ce0896b 100755 --- a/files/image_config/corefile_uploader/core_uploader.py +++ b/files/image_config/corefile_uploader/core_uploader.py @@ -36,7 +36,11 @@ HOURS_4 = (4 * 60 * 60) PAUSE_ON_FAIL = (60 * 60) +WAIT_FILE_WRITE1 = (10 * 60) +WAIT_FILE_WRITE2= (5 * 60) +POLL_SLEEP = (60 * 60) MAX_RETRIES = 5 +UPLOAD_PREFIX = "UPLOADED_" log_level = syslog.LOG_DEBUG @@ -116,7 +120,7 @@ def run(self): self.observer.start() try: while True: - time.sleep(5) + time.sleep(POLL_SLEEP) except: self.observer.stop() log_err("Error in watcher") @@ -179,29 +183,33 @@ def on_any_event(event): elif event.event_type == 'created': # Take any action here when a file is first created. log_debug("Received create event - " + event.src_path) + Handler.wait_for_file_write_complete(event.src_path) Handler.handle_file(event.src_path) @staticmethod def wait_for_file_write_complete(path): - ct_size = -1 + mtime = 0 - while ct_size != os.path.getsize(path): - ct_size = os.path.getsize(path) - time.sleep(2) + # Sleep for ample time enough for file dump to complete. + time.sleep(WAIT_FILE_WRITE1) - time.sleep(2) - if ct_size != os.path.getsize(path): + # Give another chance & poll until mtime stabilizes + while mtime != os.stat(path).st_mtime: + mtime = os.stat(path).st_mtime + time.sleep(10) + + # A safety pause for double confirmation + time.sleep(WAIT_FILE_WRITE2) + if mtime != os.stat(path).st_mtime: raise Exception("Dump file creation is too slow: " + path) + # Give up as something is terribly wrong with this file. log_debug("File write complete - " + path) @staticmethod def handle_file(path): - - Handler.wait_for_file_write_complete(path) - lpath = "/".join(cwd) make_new_dir(lpath) os.chdir(lpath) @@ -221,18 +229,18 @@ def handle_file(path): tar.close() log_debug("Tar file for upload created: " + tarf_name) - Handler.upload_file(tarf_name, tarf_name) + Handler.upload_file(tarf_name, tarf_name, path) log_debug("File uploaded - " + path) os.chdir(INIT_CWD) @staticmethod - def upload_file(fname, fpath): + def upload_file(fname, fpath, coref): daemonname = fname.split(".")[0] i = 0 fail_msg = "" - while i <= MAX_RETRIES: + while True: try: svc = FileService(account_name=acctname, account_key=acctkey) @@ -246,14 +254,15 @@ def upload_file(fname, fpath): svc.create_file_from_path(sharename, "/".join(l), fname, fpath) log_debug("Remote file created: name{} path{}".format(fname, fpath)) + newcoref = os.path.dirname(coref) + "/" + UPLOAD_PREFIX + os.path.basename(coref) + os.rename(coref, newcoref) break - except Exception as e: - log_err("core uploader failed: Failed during upload (" + str(e) +")") - fail_msg = str(e) + except Exception as ex: + log_err("core uploader failed: Failed during upload (" + coref + ") err: ("+ str(ex) +") retry:" + str(i)) + if not os.path.exists(fpath): + break i += 1 - if i >= MAX_RETRIES: - raise Exception("Failed while uploading. msg(" + fail_msg + ") after " + str(i) + " retries") time.sleep(PAUSE_ON_FAIL) @@ -261,7 +270,7 @@ def upload_file(fname, fpath): def scan(): for e in os.listdir(CORE_FILE_PATH): fl = CORE_FILE_PATH + e - if os.path.isfile(fl): + if os.path.isfile(fl) and not e.startswith(UPLOAD_PREFIX): Handler.handle_file(fl) diff --git a/files/image_config/corefile_uploader/core_uploader.service b/files/image_config/corefile_uploader/core_uploader.service index 5c061e72a16e..09ac1bd5191f 100644 --- a/files/image_config/corefile_uploader/core_uploader.service +++ b/files/image_config/corefile_uploader/core_uploader.service @@ -1,11 +1,13 @@ [Unit] Description=Host core file uploader daemon -Requires=updategraph.service -After=updategraph.service +Requires=syslog.service +After=syslog.service [Service] Type=simple ExecStart=/usr/bin/core_uploader.py +StandardOutput=null +Restart=on-failure [Install] WantedBy=multi-user.target diff --git a/files/image_config/corefile_uploader/update_json.py b/files/image_config/corefile_uploader/update_json.py deleted file mode 100755 index 03bb39aa4ec8..000000000000 --- a/files/image_config/corefile_uploader/update_json.py +++ /dev/null @@ -1,55 +0,0 @@ -#! /usr/bin/env python - -import os -import sys -import json -import argparse - -TMP_SUFFIX = ".tmp" -BAK_SUFFIX = ".bak" - -def dict_update(dst, patch): - for k in patch.keys(): - if type(patch[k]) == dict: - dst[k] = dict_update(dst[k], patch[k]) - else: - dst[k] = patch[k] - return dst - -def do_update(rcf, patchf): - dst = {} - patch = {} - - tmpf = rcf + TMP_SUFFIX - bakf = rcf + BAK_SUFFIX - - with open(rcf, "r") as f: - dst = json.load(f) - - with open(patchf, "r") as f: - patch = json.load(f) - - dst = dict_update(dst, patch) - - with open(tmpf, "w") as f: - json.dump(dst, f, indent = 4) - - os.rename(rcf, bakf) - os.rename(tmpf, rcf) - - -def main(): - parser=argparse.ArgumentParser(description="Update JSON based file") - parser.add_argument("-r", "--rc", help="JSON file to be updated") - parser.add_argument("-p", "--patch", help="JSON file holding patch") - args = parser.parse_args() - - if not args.rc or not args.patch: - raise Exception("check usage") - - do_update(args.rc, args.patch) - -if __name__ == '__main__': - main() - - From 08cde0600c2dc5015894a56fe8ba4f5da49f85c9 Mon Sep 17 00:00:00 2001 From: ciju-juniper <53076238+ciju-juniper@users.noreply.github.com> Date: Tue, 31 Dec 2019 07:39:32 +0530 Subject: [PATCH 271/278] [Juniper][QFX5210] Adding qos.json (#3946) Adding buffers.json.j2, buffers_defaults_t1.j2 and qos.json.j2 for qfx5210 platform. Signed-off-by: Ciju Rajan K --- .../Juniper-QFX5210-64C/buffers.json.j2 | 1 + .../buffers_defaults_t1.j2 | 46 +++++++++++++++++++ .../Juniper-QFX5210-64C/qos.json.j2 | 1 + 3 files changed, 48 insertions(+) create mode 100644 device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/buffers.json.j2 create mode 100644 device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/buffers_defaults_t1.j2 create mode 100644 device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/qos.json.j2 diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/buffers.json.j2 b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/buffers.json.j2 new file mode 100644 index 000000000000..a9a01d707ebf --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/buffers.json.j2 @@ -0,0 +1 @@ +{%- include 'buffers_config.j2' %} diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/buffers_defaults_t1.j2 b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/buffers_defaults_t1.j2 new file mode 100644 index 000000000000..3442612f70b2 --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/buffers_defaults_t1.j2 @@ -0,0 +1,46 @@ +{%- set default_cable = '5m' %} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {%- for port_idx in range(0,64) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %} + {%- endfor %} +{%- endmacro %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "33329088", + "type": "ingress", + "mode": "dynamic", + "xoff": "7827456" + }, + "egress_lossy_pool": { + "size": "26663272", + "type": "egress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "42349632", + "type": "egress", + "mode": "static" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "static_th":"44302336" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"0", + "static_th":"42349632" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"1664", + "dynamic_th":"-1" + } + }, +{%- endmacro %} diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/qos.json.j2 b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/qos.json.j2 new file mode 100644 index 000000000000..3e548325ea30 --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/qos.json.j2 @@ -0,0 +1 @@ +{%- include 'qos_config.j2' %} From 24a0c464648fa8d9e53d4cdfdaae7c12eaaaf95f Mon Sep 17 00:00:00 2001 From: Joe LeVeque Date: Mon, 30 Dec 2019 18:25:57 -0800 Subject: [PATCH 272/278] [monit] Build from source and patch to use MemAvailable value if available on system (#3875) --- .gitignore | 3 + build_debian.sh | 5 -- .../build_templates/sonic_debian_extension.j2 | 8 +++ files/image_config/monit/conf.d/sonic-host | 22 ++++++ files/image_config/monit/monitrc | 19 +---- rules/monit.mk | 14 ++++ slave.mk | 3 +- src/monit/Makefile | 33 +++++++++ ...ry_sysdep-Use-MemAvailable-value-if-.patch | 70 +++++++++++++++++++ src/monit/patch/series | 2 + 10 files changed, 157 insertions(+), 22 deletions(-) create mode 100644 files/image_config/monit/conf.d/sonic-host create mode 100644 rules/monit.mk create mode 100644 src/monit/Makefile create mode 100644 src/monit/patch/0001-used_system_memory_sysdep-Use-MemAvailable-value-if-.patch create mode 100644 src/monit/patch/series diff --git a/.gitignore b/.gitignore index 739454168796..1f921971d8bb 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,9 @@ src/lldpd/* !src/lldpd/patch/ src/lm-sensors/* !src/lm-sensors/Makefile +src/monit/* +!src/monit/Makefile +!src/monit/patch/ src/mpdecimal/* !src/mpdecimal/Makefile src/python-click/* diff --git a/build_debian.sh b/build_debian.sh index 666e140416c9..335dab8ba89f 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -240,7 +240,6 @@ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y in openssh-server \ python \ python-setuptools \ - monit \ python-apt \ traceroute \ iputils-ping \ @@ -348,10 +347,6 @@ EOF sudo sed -i 's/^ListenAddress ::/#ListenAddress ::/' $FILESYSTEM_ROOT/etc/ssh/sshd_config sudo sed -i 's/^#ListenAddress 0.0.0.0/ListenAddress 0.0.0.0/' $FILESYSTEM_ROOT/etc/ssh/sshd_config -## Config monit -sudo cp files/image_config/monit/monitrc $FILESYSTEM_ROOT/etc/monit/ -sudo chmod 600 $FILESYSTEM_ROOT/etc/monit/monitrc - ## Config sysctl sudo mkdir -p $FILESYSTEM_ROOT/var/core sudo augtool --autosave " diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index a007745406e4..e5dd9d9e0912 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -172,6 +172,14 @@ sudo sed -i -e '/^passwd/s/ tacplus//' $FILESYSTEM_ROOT/etc/nsswitch.conf sudo DEBIAN_FRONTEND=noninteractive dpkg --root=$FILESYSTEM_ROOT -i $debs_path/kdump-tools_*.deb || \ sudo LANG=C DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=truechroot $FILESYSTEM_ROOT apt-get -q --no-install-suggests --no-install-recommends --force-no install +# Install custom-built monit package and SONiC configuration files +sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/monit_*.deb || \ + sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f +sudo cp $IMAGE_CONFIGS/monit/monitrc $FILESYSTEM_ROOT/etc/monit/ +sudo chmod 600 $FILESYSTEM_ROOT/etc/monit/monitrc +sudo cp $IMAGE_CONFIGS/monit/conf.d/* $FILESYSTEM_ROOT/etc/monit/conf.d/ +sudo chmod 600 $FILESYSTEM_ROOT/etc/monit/conf.d/* + # Copy crontabs sudo cp -f $IMAGE_CONFIGS/cron.d/* $FILESYSTEM_ROOT/etc/cron.d/ diff --git a/files/image_config/monit/conf.d/sonic-host b/files/image_config/monit/conf.d/sonic-host new file mode 100644 index 000000000000..8eaa1671d821 --- /dev/null +++ b/files/image_config/monit/conf.d/sonic-host @@ -0,0 +1,22 @@ +############################################################################### +## Monit configuration for SONiC host OS +## +## This includes system-level monitoring as well as processes which +## run in the host OS (i.e., not inside a Docker container) +############################################################################### + +check filesystem root-overlay with path / + if space usage > 90% for 5 times within 10 cycles then alert + +check filesystem var-log with path /var/log + if space usage > 90% for 5 times within 10 cycles then alert + +check system $HOST + if memory usage > 90% for 5 times within 10 cycles then alert + if cpu usage (user) > 90% for 5 times within 10 cycles then alert + if cpu usage (system) > 90% for 5 times within 10 cycles then alert + +check process rsyslog with pidfile /var/run/rsyslogd.pid + start program = "/bin/systemctl start rsyslog.service" + stop program = "/bin/systemctl stop rsyslog.service" + if totalmem > 800 MB for 5 times within 10 cycles then restart diff --git a/files/image_config/monit/monitrc b/files/image_config/monit/monitrc index f9350733fa44..7864069e3af1 100644 --- a/files/image_config/monit/monitrc +++ b/files/image_config/monit/monitrc @@ -24,8 +24,7 @@ ## Set syslog logging. If you want to log to a standalone log file instead, ## specify the full path to the log file # -# set logfile /var/log/monit.log -set logfile syslog + set logfile syslog # # ## Set the location of the Monit lock file which stores the process id of the @@ -153,8 +152,8 @@ set logfile syslog ## commands to a running Monit daemon. See the Monit Wiki if you want to ## enable SSL for the HTTP interface. # -set httpd unixsocket /var/run/monit.sock and - allow localhost # allow localhost to connect to the server and + set httpd unixsocket /var/run/monit.sock and + allow localhost # allow localhost to connect to the server # ############################################################################### ## Services @@ -294,15 +293,3 @@ set httpd unixsocket /var/run/monit.sock and include /etc/monit/conf.d/* include /etc/monit/conf-enabled/* # -check filesystem root-overlay with path / - if space usage > 90% for 5 times within 10 cycles then alert -check filesystem var-log with path /var/log - if space usage > 90% for 5 times within 10 cycles then alert -check system $HOST - if memory usage > 90% for 5 times within 10 cycles then alert - if cpu usage (user) > 90% for 5 times within 10 cycles then alert - if cpu usage (system) > 90% for 5 times within 10 cycles then alert -check process rsyslog with pidfile /var/run/rsyslogd.pid - start program = "/bin/systemctl start rsyslog.service" - stop program = "/bin/systemctl stop rsyslog.service" - if totalmem > 800 MB for 5 times within 10 cycles then restart diff --git a/rules/monit.mk b/rules/monit.mk new file mode 100644 index 000000000000..d4c73453e4a6 --- /dev/null +++ b/rules/monit.mk @@ -0,0 +1,14 @@ +# monit package + +MONIT_VERSION = 5.20.0-6 + +export MONIT_VERSION + +MONIT = monit_$(MONIT_VERSION)_$(CONFIGURED_ARCH).deb +$(MONIT)_SRC_PATH = $(SRC_PATH)/monit +SONIC_MAKE_DEBS += $(MONIT) + +SONIC_STRETCH_DEBS += $(MONIT) + +MONIT_DBG = monit-dbgsym_$(MONIT_VERSION)_$(CONFIGURED_ARCH).deb +$(eval $(call add_derived_package,$(MONIT),$(MONIT_DBG))) diff --git a/slave.mk b/slave.mk index 382b03607186..9a34e5379b14 100644 --- a/slave.mk +++ b/slave.mk @@ -617,7 +617,8 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ $(IFUPDOWN2) \ $(KDUMP_TOOLS) \ $(LIBPAM_TACPLUS) \ - $(LIBNSS_TACPLUS)) \ + $(LIBNSS_TACPLUS) \ + $(MONIT)) \ $$(addprefix $(TARGET_PATH)/,$$($$*_DOCKERS)) \ $$(addprefix $(FILES_PATH)/,$$($$*_FILES)) \ $(if $(findstring y,$(ENABLE_ZTP)),$(addprefix $(DEBS_PATH)/,$(SONIC_ZTP))) \ diff --git a/src/monit/Makefile b/src/monit/Makefile new file mode 100644 index 000000000000..4ad9edd79143 --- /dev/null +++ b/src/monit/Makefile @@ -0,0 +1,33 @@ +.ONESHELL: +SHELL = /bin/bash +.SHELLFLAGS += -e + +MAIN_TARGET = monit_$(MONIT_VERSION)_$(CONFIGURED_ARCH).deb +DERIVED_TARGETS = monit-dbgsym_$(MONIT_VERSION)_$(CONFIGURED_ARCH).deb + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # Remove any stale files + rm -rf ./monit + + # Clone monit repo + git clone https://salsa.debian.org/sk-guest/monit.git + pushd ./monit + + # Reset HEAD to the commit of the proper tag + # NOTE: Using "git checkout " here detaches our HEAD, + # which stg doesn't like, so we use this method instead + # NOTE: For some reason, tags in the Debian monit repo are prefixed with "1%" + git reset --hard debian/1\%$(MONIT_VERSION) + + # Apply patches + stg init + stg import -s ../patch/series + + # Build source and Debian packages + dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + popd + + # Move the newly-built .deb packages to the destination directory + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/src/monit/patch/0001-used_system_memory_sysdep-Use-MemAvailable-value-if-.patch b/src/monit/patch/0001-used_system_memory_sysdep-Use-MemAvailable-value-if-.patch new file mode 100644 index 000000000000..9c67d153cbbb --- /dev/null +++ b/src/monit/patch/0001-used_system_memory_sysdep-Use-MemAvailable-value-if-.patch @@ -0,0 +1,70 @@ +From c392362c9c1d57256b7e8ab7c77926824677fd73 Mon Sep 17 00:00:00 2001 +From: Joe LeVeque +Date: Tue, 19 Nov 2019 01:51:13 +0000 +Subject: [PATCH] [used_system_memory_sysdep] Use 'MemAvailable' value if + available + +--- + src/process/sysdep_LINUX.c | 35 +++++++++++++++++++++++------------ + 1 file changed, 23 insertions(+), 12 deletions(-) + +diff --git a/src/process/sysdep_LINUX.c b/src/process/sysdep_LINUX.c +index 0d18f85..221e785 100644 +--- a/src/process/sysdep_LINUX.c ++++ b/src/process/sysdep_LINUX.c +@@ -335,6 +335,7 @@ int getloadavg_sysdep(double *loadv, int nelem) { + boolean_t used_system_memory_sysdep(SystemInfo_T *si) { + char *ptr; + char buf[2048]; ++ unsigned long mem_available = 0UL; + unsigned long mem_free = 0UL; + unsigned long buffers = 0UL; + unsigned long cached = 0UL; +@@ -343,22 +344,32 @@ boolean_t used_system_memory_sysdep(SystemInfo_T *si) { + unsigned long swap_free = 0UL; + + if (! file_readProc(buf, sizeof(buf), "meminfo", -1, NULL)) { +- LogError("system statistic error -- cannot get real memory free amount\n"); ++ LogError("system statistic error -- cannot read /proc/meminfo\n"); + goto error; + } + +- /* Memory */ +- if (! (ptr = strstr(buf, "MemFree:")) || sscanf(ptr + 8, "%ld", &mem_free) != 1) { +- LogError("system statistic error -- cannot get real memory free amount\n"); +- goto error; ++ /* ++ * Memory ++ * ++ * First, check if the "MemAvailable" value is available on this system. If it is, we will ++ * use it. Otherwise we will attempt to calculate the amount of available memory ourself. ++ */ ++ if ((ptr = strstr(buf, "MemAvailable:")) && sscanf(ptr + 13, "%ld", &mem_available) == 1) { ++ si->total_mem = systeminfo.mem_max - (uint64_t)mem_available * 1024; ++ } else { ++ DEBUG("'MemAvailable' value not available on this system. Attempting to calculate available memory manually...\n"); ++ if (! (ptr = strstr(buf, "MemFree:")) || sscanf(ptr + 8, "%ld", &mem_free) != 1) { ++ LogError("system statistic error -- cannot get real memory free amount\n"); ++ goto error; ++ } ++ if (! (ptr = strstr(buf, "Buffers:")) || sscanf(ptr + 8, "%ld", &buffers) != 1) ++ DEBUG("system statistic error -- cannot get real memory buffers amount\n"); ++ if (! (ptr = strstr(buf, "Cached:")) || sscanf(ptr + 7, "%ld", &cached) != 1) ++ DEBUG("system statistic error -- cannot get real memory cache amount\n"); ++ if (! (ptr = strstr(buf, "SReclaimable:")) || sscanf(ptr + 13, "%ld", &slabreclaimable) != 1) ++ DEBUG("system statistic error -- cannot get slab reclaimable memory amount\n"); ++ si->total_mem = systeminfo.mem_max - (uint64_t)(mem_free + buffers + cached + slabreclaimable) * 1024; + } +- if (! (ptr = strstr(buf, "Buffers:")) || sscanf(ptr + 8, "%ld", &buffers) != 1) +- DEBUG("system statistic error -- cannot get real memory buffers amount\n"); +- if (! (ptr = strstr(buf, "Cached:")) || sscanf(ptr + 7, "%ld", &cached) != 1) +- DEBUG("system statistic error -- cannot get real memory cache amount\n"); +- if (! (ptr = strstr(buf, "SReclaimable:")) || sscanf(ptr + 13, "%ld", &slabreclaimable) != 1) +- DEBUG("system statistic error -- cannot get slab reclaimable memory amount\n"); +- si->total_mem = systeminfo.mem_max - (uint64_t)(mem_free + buffers + cached + slabreclaimable) * 1024; + + /* Swap */ + if (! (ptr = strstr(buf, "SwapTotal:")) || sscanf(ptr + 10, "%ld", &swap_total) != 1) { +-- +2.17.1 + diff --git a/src/monit/patch/series b/src/monit/patch/series new file mode 100644 index 000000000000..15fcdd50c8a5 --- /dev/null +++ b/src/monit/patch/series @@ -0,0 +1,2 @@ +# This series applies on GIT commit dc9bc1c949125140d967edfc598dfad47eedc552 +0001-used_system_memory_sysdep-Use-MemAvailable-value-if-.patch From ea1128741c28f89294c4296110dcd33dde7458d9 Mon Sep 17 00:00:00 2001 From: noaOrMlnx <58519608+noaOrMlnx@users.noreply.github.com> Date: Tue, 31 Dec 2019 17:01:08 +0200 Subject: [PATCH 273/278] [Mellanox] Update FW/SDK: 13/29.2000.2696 and 4.3.2904 (#3948) --- platform/mellanox/fw.mk | 4 ++-- platform/mellanox/sdk-src/sx-kernel/Makefile | 1 - .../sdk-src/sx-kernel/Switch-SDK-drivers | 2 +- .../sx_kernel_makefile_sonic_build.patch | 18 ------------------ platform/mellanox/sdk.mk | 2 +- 5 files changed, 4 insertions(+), 23 deletions(-) delete mode 100644 platform/mellanox/sdk-src/sx-kernel/sx_kernel_makefile_sonic_build.patch diff --git a/platform/mellanox/fw.mk b/platform/mellanox/fw.mk index 9d506c1f5bdd..eb1a58cfda9d 100644 --- a/platform/mellanox/fw.mk +++ b/platform/mellanox/fw.mk @@ -11,12 +11,12 @@ else FW_FROM_URL = n endif -MLNX_SPC_FW_VERSION = 13.2000.2602 +MLNX_SPC_FW_VERSION = 13.2000.2696 MLNX_SPC_FW_FILE = fw-SPC-rel-$(subst .,_,$(MLNX_SPC_FW_VERSION))-EVB.mfa $(MLNX_SPC_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC_FW_FILE) -MLNX_SPC2_FW_VERSION = 29.2000.2602 +MLNX_SPC2_FW_VERSION = 29.2000.2696 MLNX_SPC2_FW_FILE = fw-SPC2-rel-$(subst .,_,$(MLNX_SPC2_FW_VERSION))-EVB.mfa $(MLNX_SPC2_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC2_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC2_FW_FILE) diff --git a/platform/mellanox/sdk-src/sx-kernel/Makefile b/platform/mellanox/sdk-src/sx-kernel/Makefile index 9e979879fef8..422f2ae95aae 100644 --- a/platform/mellanox/sdk-src/sx-kernel/Makefile +++ b/platform/mellanox/sdk-src/sx-kernel/Makefile @@ -19,7 +19,6 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : fi # build - patch -p1 < ../sx_kernel_makefile_sonic_build.patch debuild -e KVERSION=$(KVERSION) -e KSRC_EXT=/lib/modules/$(KVERSION)/source/ -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) diff --git a/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers b/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers index 87f7a7911275..c08b5bb3810f 160000 --- a/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers +++ b/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers @@ -1 +1 @@ -Subproject commit 87f7a7911275285abc63c24ba39aa4af4c4b4678 +Subproject commit c08b5bb3810fe7da2811622aa7003ac9cc95344b diff --git a/platform/mellanox/sdk-src/sx-kernel/sx_kernel_makefile_sonic_build.patch b/platform/mellanox/sdk-src/sx-kernel/sx_kernel_makefile_sonic_build.patch deleted file mode 100644 index e7c87d079922..000000000000 --- a/platform/mellanox/sdk-src/sx-kernel/sx_kernel_makefile_sonic_build.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff --git a/makefile b/makefile -index f23f0ac..a16b2ce 100644 ---- a/makefile -+++ b/makefile -@@ -93,10 +93,10 @@ V ?= 1 - - ifneq ($(findstring 3.10,$(KVERSION))$(findstring 3.13,$(KVERSION))$(findstring 3.14,$(KVERSION))$(findstring 3.16,$(KVERSION)),) - MLNX_LINUX_AUTOCONF_FILE = include/generated/autoconf.h --MLNX_LINUX_EXTRA_INCLUDE_FILES = -include include/linux/kconfig.h -+MLNX_LINUX_EXTRA_INCLUDE_FILES = -include $(KSRC_EXT)/include/linux/kconfig.h - MLNX_LINUX_EXTRA_INCLUDE_FOLDERS = \ -- -Iarch/$$(SRCARCH)/include/uapi \ -- -Iinclude/uapi \ -+ -I$(KSRC_EXT)/arch/$$(SRCARCH)/include/uapi \ -+ -I$(KSRC_EXT)/include/uapi \ - -Iarch/$$(SRCARCH)/include/generated/uapi \ - -Iarch/$$(SRCARCH)/include/generated \ - -Iinclude/generated/uapi diff --git a/platform/mellanox/sdk.mk b/platform/mellanox/sdk.mk index 73568ce84596..55a5b08bba31 100644 --- a/platform/mellanox/sdk.mk +++ b/platform/mellanox/sdk.mk @@ -1,5 +1,5 @@ MLNX_SDK_BASE_PATH = $(PLATFORM_PATH)/sdk-src/sx-kernel/Switch-SDK-drivers/bin/ -MLNX_SDK_VERSION = 4.3.2602 +MLNX_SDK_VERSION = 4.3.2904 MLNX_SDK_ISSU_VERSION = 101 MLNX_SDK_DEB_VERSION = $(subst _,.,$(MLNX_SDK_VERSION)) From 476be913c1238e07f1f4004638ee76dadb177cd5 Mon Sep 17 00:00:00 2001 From: lguohan Date: Tue, 31 Dec 2019 16:30:10 -0800 Subject: [PATCH 274/278] [docker-base-stretch]: Do not check expire for stretch-backports repo (#3958) * [docker-base-stretch]: Do not check expire for stretch-backports repo Signed-off-by: Guohan Lu --- build_debian.sh | 2 +- dockers/docker-base-stretch/Dockerfile.j2 | 1 + dockers/docker-base-stretch/aptconf_archive_expired_release | 3 +++ files/apt/apt.conf.d/no-check-valid-until | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 dockers/docker-base-stretch/aptconf_archive_expired_release create mode 100644 files/apt/apt.conf.d/no-check-valid-until diff --git a/build_debian.sh b/build_debian.sh index 335dab8ba89f..39b984edec4e 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -107,7 +107,7 @@ sudo LANG=C chroot $FILESYSTEM_ROOT mount proc /proc -t proc ## Pointing apt to public apt mirrors and getting latest packages, needed for latest security updates sudo cp files/apt/sources.list.$CONFIGURED_ARCH $FILESYSTEM_ROOT/etc/apt/sources.list -sudo cp files/apt/apt.conf.d/{81norecommends,apt-{clean,gzip-indexes,no-languages}} $FILESYSTEM_ROOT/etc/apt/apt.conf.d/ +sudo cp files/apt/apt.conf.d/{81norecommends,apt-{clean,gzip-indexes,no-languages},no-check-valid-until} $FILESYSTEM_ROOT/etc/apt/apt.conf.d/ sudo LANG=C chroot $FILESYSTEM_ROOT bash -c 'apt-mark auto `apt-mark showmanual`' ## Note: set lang to prevent locale warnings in your chroot diff --git a/dockers/docker-base-stretch/Dockerfile.j2 b/dockers/docker-base-stretch/Dockerfile.j2 index 3b3ede376d12..d8188a06afd6 100644 --- a/dockers/docker-base-stretch/Dockerfile.j2 +++ b/dockers/docker-base-stretch/Dockerfile.j2 @@ -34,6 +34,7 @@ COPY ["sources.list.arm64", "/etc/apt/sources.list"] COPY ["sources.list", "/etc/apt/sources.list"] {% endif %} COPY ["no_install_recommend_suggest", "/etc/apt/apt.conf.d"] +COPY ["aptconf_archive_expired_release", "/etc/apt/apt.conf.d"] # Update apt cache and # pre-install fundamental packages diff --git a/dockers/docker-base-stretch/aptconf_archive_expired_release b/dockers/docker-base-stretch/aptconf_archive_expired_release new file mode 100644 index 000000000000..67bc409b2174 --- /dev/null +++ b/dockers/docker-base-stretch/aptconf_archive_expired_release @@ -0,0 +1,3 @@ +# Instruct apt-get to override expired releases repo list for jessie archives + +Acquire::Check-Valid-Until "0"; diff --git a/files/apt/apt.conf.d/no-check-valid-until b/files/apt/apt.conf.d/no-check-valid-until new file mode 100644 index 000000000000..97b9c9005181 --- /dev/null +++ b/files/apt/apt.conf.d/no-check-valid-until @@ -0,0 +1 @@ +Acquire::Check-Valid-Until "false"; From 0dae59ac301f18e7dad948282addf961b69d82fc Mon Sep 17 00:00:00 2001 From: Dong Zhang <41927498+dzhangalibaba@users.noreply.github.com> Date: Thu, 2 Jan 2020 14:46:25 -0800 Subject: [PATCH 275/278] [MultiDB]except src and dockers : replace redis-cli with sonic-db-cli and use new DBConnector (#3928) * [MultiDB]except src and dockers : replace redis-cli with sonic-db-cli and use new DBConnector * fix vs tests along with swss vs tests together --- .../x86_64-mlnx_msn2700-r0/plugins/sfputil.py | 9 ++--- files/build_templates/docker_image_ctl.j2 | 34 +++++++++---------- files/image_config/config-setup/config-setup | 11 +++--- files/image_config/updategraph/updategraph | 10 +++--- .../warmboot-finalizer/finalize-warmboot.sh | 10 +++--- files/scripts/configdb-load.sh | 2 +- files/scripts/swss.sh | 26 +++++++------- files/scripts/syncd.sh | 12 +++---- .../s9180-32x/utils/qsfp_monitor.sh | 2 +- .../s9280-64x/utils/qsfp_monitor.sh | 2 +- .../s8810-32q/utils/qsfp_monitor.sh | 2 +- .../s8900-54xc/utils/qsfp_monitor.sh | 2 +- .../s8900-64xc/utils/qsfp_monitor.sh | 2 +- .../s9100/utils/qsfp_monitor.sh | 2 +- .../s9200-64x/utils/qsfp_monitor.sh | 2 +- .../s9130-32x/utils/qsfp_monitor.sh | 2 +- .../s9230-64x/utils/qsfp_monitor.sh | 2 +- 17 files changed, 60 insertions(+), 72 deletions(-) diff --git a/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py b/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py index e41ac2924da2..7c4f33f74973 100644 --- a/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py +++ b/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py @@ -22,8 +22,6 @@ SFP_I2C_PAGE_SIZE = 256 # parameters for DB connection -REDIS_HOSTNAME = "localhost" -REDIS_PORT = 6379 REDIS_TIMEOUT_USECS = 0 # parameters for SFP presence @@ -190,10 +188,9 @@ def get_transceiver_change_event(self, timeout=0): if self.db_sel == None: from swsscommon import swsscommon - self.state_db = swsscommon.DBConnector(swsscommon.STATE_DB, - REDIS_HOSTNAME, - REDIS_PORT, - REDIS_TIMEOUT_USECS) + self.state_db = swsscommon.DBConnector("STATE_DB", + REDIS_TIMEOUT_USECS, + True)) # Subscribe to state table for SFP change notifications self.db_sel = swsscommon.Select() diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 index 167a392730e4..df236f6523e8 100644 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -63,20 +63,20 @@ function preStartAction() docker cp /tmp/dump.rdb database:/var/lib/redis/ fi {%- elif docker_container_name == "snmp" %} - docker exec -i database redis-cli -n 6 HSET 'DEVICE_METADATA|localhost' chassis_serial_number $(decode-syseeprom -s) - vrfenabled=`/usr/bin/redis-cli -n 4 hget "MGMT_VRF_CONFIG|vrf_global" mgmtVrfEnabled` - v1SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" DestIp` - v1SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" DestPort` - v1Vrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" vrf` - v1Comm=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" Community` - v2SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" DestIp` - v2SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" DestPort` - v2Vrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" vrf` - v2Comm=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" Community` - v3SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" DestIp` - v3SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" DestPort` - v3Vrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" vrf` - v3Comm=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" Community` + sonic-db-cli STATE_DB HSET 'DEVICE_METADATA|localhost' chassis_serial_number $(decode-syseeprom -s) + vrfenabled=`sonic-db-cli CONFIG_DB hget "MGMT_VRF_CONFIG|vrf_global" mgmtVrfEnabled` + v1SnmpTrapIp=`sonic-db-cli CONFIG_DB hget "SNMP_TRAP_CONFIG|v1TrapDest" DestIp` + v1SnmpTrapPort=`sonic-db-cli CONFIG_DB hget "SNMP_TRAP_CONFIG|v1TrapDest" DestPort` + v1Vrf=`sonic-db-cli CONFIG_DB hget "SNMP_TRAP_CONFIG|v1TrapDest" vrf` + v1Comm=`sonic-db-cli CONFIG_DB hget "SNMP_TRAP_CONFIG|v1TrapDest" Community` + v2SnmpTrapIp=`sonic-db-cli CONFIG_DB hget "SNMP_TRAP_CONFIG|v2TrapDest" DestIp` + v2SnmpTrapPort=`sonic-db-cli CONFIG_DB hget "SNMP_TRAP_CONFIG|v2TrapDest" DestPort` + v2Vrf=`sonic-db-cli CONFIG_DB hget "SNMP_TRAP_CONFIG|v2TrapDest" vrf` + v2Comm=`sonic-db-cli CONFIG_DB hget "SNMP_TRAP_CONFIG|v2TrapDest" Community` + v3SnmpTrapIp=`sonic-db-cli CONFIG_DB hget "SNMP_TRAP_CONFIG|v3TrapDest" DestIp` + v3SnmpTrapPort=`sonic-db-cli CONFIG_DB hget "SNMP_TRAP_CONFIG|v3TrapDest" DestPort` + v3Vrf=`sonic-db-cli CONFIG_DB hget "SNMP_TRAP_CONFIG|v3TrapDest" vrf` + v3Comm=`sonic-db-cli CONFIG_DB hget "SNMP_TRAP_CONFIG|v3TrapDest" Community` if [ "${v1SnmpTrapIp}" != "" ] then @@ -113,7 +113,7 @@ function preStartAction() fi echo -n "" > /tmp/snmpagentaddr.yml - keys=`/usr/bin/redis-cli -n 4 keys "SNMP_AGENT_ADDRESS_CONFIG|*"` + keys=`sonic-db-cli CONFIG_DB keys "SNMP_AGENT_ADDRESS_CONFIG|*"` count=1 for key in $keys;do ip=`echo $key|cut -d "|" -f2` @@ -151,10 +151,10 @@ function postStartAction() if [[ "$BOOT_TYPE" == "fast" ]]; then # set the key to expire in 3 minutes - redis-cli -n 6 SET "FAST_REBOOT|system" "1" "EX" "180" + sonic-db-cli STATE_DB SET "FAST_REBOOT|system" "1" "EX" "180" fi - redis-cli -n 4 SET "CONFIG_DB_INITIALIZED" "1" + sonic-db-cli CONFIG_DB SET "CONFIG_DB_INITIALIZED" "1" fi if [[ -x /usr/bin/db_migrator.py ]]; then diff --git a/files/image_config/config-setup/config-setup b/files/image_config/config-setup/config-setup index bd497d06b257..f19abd266e95 100755 --- a/files/image_config/config-setup/config-setup +++ b/files/image_config/config-setup/config-setup @@ -25,7 +25,6 @@ ########################################################################### # Initialize constants -CONFIG_DB_INDEX=4 UPDATEGRAPH_CONF=/etc/sonic/updategraph.conf CONFIG_DB_JSON=/etc/sonic/config_db.json MINGRAPH_FILE=/etc/sonic/minigraph.xml @@ -107,9 +106,9 @@ reload_minigraph() if [ ! -f /etc/sonic/init_cfg.json ]; then echo "{}" > /etc/sonic/init_cfg.json fi - redis-cli -n $CONFIG_DB_INDEX FLUSHDB + sonic-db-cli CONFIG_DB FLUSHDB sonic-cfggen -H -m -j /etc/sonic/init_cfg.json --write-to-db - redis-cli -n $CONFIG_DB_INDEX SET "CONFIG_DB_INITIALIZED" "1" + sonic-db-cli CONFIG_DB SET "CONFIG_DB_INITIALIZED" "1" if [ -f /etc/sonic/acl.json ]; then acl-loader update full /etc/sonic/acl.json fi @@ -138,7 +137,7 @@ function copy_config_files_and_directories() # Check if SONiC swich has booted after a warm reboot request check_system_warm_boot() { - SYSTEM_WARM_START=`/usr/bin/redis-cli -n 6 hget "WARM_RESTART_ENABLE_TABLE|system" enable` + SYSTEM_WARM_START=`sonic-db-cli STATE_DB hget "WARM_RESTART_ENABLE_TABLE|system" enable` # SYSTEM_WARM_START could be empty, always make WARM_BOOT meaningful. if [[ x"$SYSTEM_WARM_START" == x"true" ]]; then WARM_BOOT="true" @@ -187,7 +186,7 @@ load_config() return 1 fi - redis-cli -n $CONFIG_DB_INDEX FLUSHDB + sonic-db-cli CONFIG_DB FLUSHDB sonic-cfggen -j ${CONFIG_FILE} --write-to-db if [ $? -ne 0 ]; then return $? @@ -198,7 +197,7 @@ load_config() /usr/bin/db_migrator.py -o migrate fi - redis-cli -n $CONFIG_DB_INDEX SET "CONFIG_DB_INITIALIZED" "1" + sonic-db-cli CONFIG_DB SET "CONFIG_DB_INITIALIZED" "1" return 0 } diff --git a/files/image_config/updategraph/updategraph b/files/image_config/updategraph/updategraph index b2bd027e82e7..a24d452b1ad2 100755 --- a/files/image_config/updategraph/updategraph +++ b/files/image_config/updategraph/updategraph @@ -1,16 +1,14 @@ #!/bin/bash -CONFIG_DB_INDEX=4 - reload_minigraph() { echo "Reloading minigraph..." if [ ! -f /etc/sonic/init_cfg.json ]; then echo "{}" > /etc/sonic/init_cfg.json fi - redis-cli -n $CONFIG_DB_INDEX FLUSHDB + sonic-db-cli CONFIG_DB FLUSHDB sonic-cfggen -H -m -j /etc/sonic/init_cfg.json --write-to-db - redis-cli -n $CONFIG_DB_INDEX SET "CONFIG_DB_INITIALIZED" "1" + sonic-db-cli CONFIG_DB SET "CONFIG_DB_INITIALIZED" "1" if [ -f /etc/sonic/acl.json ]; then acl-loader update full /etc/sonic/acl.json fi @@ -77,9 +75,9 @@ if [ "$src" = "dhcp" ]; then else cp -f /tmp/device_meta.json /etc/sonic/config_db.json fi - redis-cli -n $CONFIG_DB_INDEX FLUSHDB + sonic-db-cli CONFIG_DB FLUSHDB sonic-cfggen -j /etc/sonic/config_db.json --write-to-db - redis-cli -n $CONFIG_DB_INDEX SET "CONFIG_DB_INITIALIZED" "1" + sonic-db-cli CONFIG_DB SET "CONFIG_DB_INITIALIZED" "1" if [ "$dhcp_as_static" = "true" ]; then sed -i "/enabled=/d" /etc/sonic/updategraph.conf echo "enabled=false" >> /etc/sonic/updategraph.conf diff --git a/files/image_config/warmboot-finalizer/finalize-warmboot.sh b/files/image_config/warmboot-finalizer/finalize-warmboot.sh index 32c9c8444cc3..eec50ccef692 100755 --- a/files/image_config/warmboot-finalizer/finalize-warmboot.sh +++ b/files/image_config/warmboot-finalizer/finalize-warmboot.sh @@ -20,7 +20,7 @@ function debug() function check_warm_boot() { - WARM_BOOT=`/usr/bin/redis-cli -n 6 hget "WARM_RESTART_ENABLE_TABLE|system" enable` + WARM_BOOT=`sonic-db-cli STATE_DB hget "WARM_RESTART_ENABLE_TABLE|system" enable` } @@ -29,12 +29,10 @@ function wait_for_database_service() debug "Wait for database to become ready..." # Wait for redis server start before database clean - until [[ $(/usr/bin/docker exec database redis-cli ping | grep -c PONG) -gt 0 ]]; - do sleep 1; - done + /usr/bin/docker exec database ping_pong_db_insts # Wait for configDB initialization - until [[ $(/usr/bin/docker exec database redis-cli -n 4 GET "CONFIG_DB_INITIALIZED") ]]; + until [[ $(sonic-db-cli CONFIG_DB GET "CONFIG_DB_INITIALIZED") ]]; do sleep 1; done @@ -44,7 +42,7 @@ function wait_for_database_service() function get_component_state() { - /usr/bin/redis-cli -n 6 hget "WARM_RESTART_TABLE|$1" state + sonic-db-cli STATE_DB hget "WARM_RESTART_TABLE|$1" state } diff --git a/files/scripts/configdb-load.sh b/files/scripts/configdb-load.sh index 5ba2e0e0bc7f..e7080eb40f3d 100755 --- a/files/scripts/configdb-load.sh +++ b/files/scripts/configdb-load.sh @@ -10,4 +10,4 @@ if [ -r /etc/sonic/config_db.json ]; then sonic-cfggen -j /etc/sonic/config_db.json --write-to-db fi -redis-cli -n 4 SET "CONFIG_DB_INITIALIZED" "1" +sonic-db-cli CONFIG_DB SET "CONFIG_DB_INITIALIZED" "1" diff --git a/files/scripts/swss.sh b/files/scripts/swss.sh index 93f311019d66..a14d03e40f50 100755 --- a/files/scripts/swss.sh +++ b/files/scripts/swss.sh @@ -31,8 +31,8 @@ function unlock_service_state_change() function check_warm_boot() { - SYSTEM_WARM_START=`/usr/bin/redis-cli -n 6 hget "WARM_RESTART_ENABLE_TABLE|system" enable` - SERVICE_WARM_START=`/usr/bin/redis-cli -n 6 hget "WARM_RESTART_ENABLE_TABLE|${SERVICE}" enable` + SYSTEM_WARM_START=`sonic-db-cli STATE_DB hget "WARM_RESTART_ENABLE_TABLE|system" enable` + SERVICE_WARM_START=`sonic-db-cli STATE_DB hget "WARM_RESTART_ENABLE_TABLE|${SERVICE}" enable` if [[ x"$SYSTEM_WARM_START" == x"true" ]] || [[ x"$SERVICE_WARM_START" == x"true" ]]; then WARM_BOOT="true" else @@ -43,7 +43,7 @@ function check_warm_boot() function validate_restore_count() { if [[ x"$WARM_BOOT" == x"true" ]]; then - RESTORE_COUNT=`/usr/bin/redis-cli -n 6 hget "WARM_RESTART_TABLE|orchagent" restore_count` + RESTORE_COUNT=`sonic-db-cli STATE_DB hget "WARM_RESTART_TABLE|orchagent" restore_count` # We have to make sure db data has not been flushed. if [[ -z "$RESTORE_COUNT" ]]; then WARM_BOOT="false" @@ -54,12 +54,10 @@ function validate_restore_count() function wait_for_database_service() { # Wait for redis server start before database clean - until [[ $(/usr/bin/docker exec database redis-cli ping | grep -c PONG) -gt 0 ]]; - do sleep 1; - done + /usr/bin/docker exec database ping_pong_db_insts # Wait for configDB initialization - until [[ $(/usr/bin/docker exec database redis-cli -n 4 GET "CONFIG_DB_INITIALIZED") ]]; + until [[ $(sonic-db-cli CONFIG_DB GET "CONFIG_DB_INITIALIZED") ]]; do sleep 1; done } @@ -69,7 +67,7 @@ function wait_for_database_service() # $2 the string of a list of table prefixes function clean_up_tables() { - redis-cli -n $1 EVAL " + sonic-db-cli $1 EVAL " local tables = {$2} for i = 1, table.getn(tables) do local matches = redis.call('KEYS', tables[i]) @@ -114,11 +112,11 @@ start() { # Don't flush DB during warm boot if [[ x"$WARM_BOOT" != x"true" ]]; then debug "Flushing APP, ASIC, COUNTER, CONFIG, and partial STATE databases ..." - /usr/bin/docker exec database redis-cli -n 0 FLUSHDB - /usr/bin/docker exec database redis-cli -n 1 FLUSHDB - /usr/bin/docker exec database redis-cli -n 2 FLUSHDB - /usr/bin/docker exec database redis-cli -n 5 FLUSHDB - clean_up_tables 6 "'PORT_TABLE*', 'MGMT_PORT_TABLE*', 'VLAN_TABLE*', 'VLAN_MEMBER_TABLE*', 'LAG_TABLE*', 'LAG_MEMBER_TABLE*', 'INTERFACE_TABLE*', 'MIRROR_SESSION*', 'VRF_TABLE*', 'FDB_TABLE*'" + sonic-db-cli APPL_DB FLUSHDB + sonic-db-cli ASIC_DB FLUSHDB + sonic-db-cli COUNTERS_DB FLUSHDB + sonic-db-cli FLEX_COUNTER_DB FLUSHDB + clean_up_tables STATE_DB "'PORT_TABLE*', 'MGMT_PORT_TABLE*', 'VLAN_TABLE*', 'VLAN_MEMBER_TABLE*', 'LAG_TABLE*', 'LAG_MEMBER_TABLE*', 'INTERFACE_TABLE*', 'MIRROR_SESSION*', 'VRF_TABLE*', 'FDB_TABLE*'" fi # start service docker @@ -166,7 +164,7 @@ stop() { # encountered error, e.g. syncd crashed. And swss needs to # be restarted. debug "Clearing FAST_REBOOT flag..." - clean_up_tables 6 "'FAST_REBOOT*'" + clean_up_tables STATE_DB "'FAST_REBOOT*'" # Unlock has to happen before reaching out to peer service unlock_service_state_change diff --git a/files/scripts/syncd.sh b/files/scripts/syncd.sh index 05e5552a64b1..4b47e7ad4c45 100755 --- a/files/scripts/syncd.sh +++ b/files/scripts/syncd.sh @@ -30,8 +30,8 @@ function unlock_service_state_change() function check_warm_boot() { - SYSTEM_WARM_START=`/usr/bin/redis-cli -n 6 hget "WARM_RESTART_ENABLE_TABLE|system" enable` - SERVICE_WARM_START=`/usr/bin/redis-cli -n 6 hget "WARM_RESTART_ENABLE_TABLE|${SERVICE}" enable` + SYSTEM_WARM_START=`sonic-db-cli STATE_DB hget "WARM_RESTART_ENABLE_TABLE|system" enable` + SERVICE_WARM_START=`sonic-db-cli STATE_DB hget "WARM_RESTART_ENABLE_TABLE|${SERVICE}" enable` # SYSTEM_WARM_START could be empty, always make WARM_BOOT meaningful. if [[ x"$SYSTEM_WARM_START" == x"true" ]] || [[ x"$SERVICE_WARM_START" == x"true" ]]; then WARM_BOOT="true" @@ -43,12 +43,10 @@ function check_warm_boot() function wait_for_database_service() { # Wait for redis server start before database clean - until [[ $(/usr/bin/docker exec database redis-cli ping | grep -c PONG) -gt 0 ]]; - do sleep 1; - done + /usr/bin/docker exec database ping_pong_db_insts # Wait for configDB initialization - until [[ $(/usr/bin/docker exec database redis-cli -n 4 GET "CONFIG_DB_INITIALIZED") ]]; + until [[ $(sonic-db-cli CONFIG_DB GET "CONFIG_DB_INITIALIZED") ]]; do sleep 1; done } @@ -65,7 +63,7 @@ function getBootType() ;; *SONIC_BOOT_TYPE=fast*|*fast-reboot*) # check that the key exists - if [[ $(redis-cli -n 6 GET "FAST_REBOOT|system") == "1" ]]; then + if [[ $(sonic-db-cli STATE_DB GET "FAST_REBOOT|system") == "1" ]]; then TYPE='fast' else TYPE='cold' diff --git a/platform/barefoot/sonic-platform-modules-ingrasys/s9180-32x/utils/qsfp_monitor.sh b/platform/barefoot/sonic-platform-modules-ingrasys/s9180-32x/utils/qsfp_monitor.sh index 249f179216a6..7776493bc20a 100755 --- a/platform/barefoot/sonic-platform-modules-ingrasys/s9180-32x/utils/qsfp_monitor.sh +++ b/platform/barefoot/sonic-platform-modules-ingrasys/s9180-32x/utils/qsfp_monitor.sh @@ -65,7 +65,7 @@ function _docker_swss_check { while true do # Check if syncd starts - result=`docker exec -i swss bash -c "echo -en \"SELECT 1\\nHLEN HIDDEN\" | redis-cli | sed -n 2p"` #TBD FIX ME + result=`sonic-db-cli ASIC_DB HLEN HIDDEN` if [ "$result" == "3" ]; then return fi diff --git a/platform/barefoot/sonic-platform-modules-ingrasys/s9280-64x/utils/qsfp_monitor.sh b/platform/barefoot/sonic-platform-modules-ingrasys/s9280-64x/utils/qsfp_monitor.sh index 23a3fd066bee..9213d115f656 100755 --- a/platform/barefoot/sonic-platform-modules-ingrasys/s9280-64x/utils/qsfp_monitor.sh +++ b/platform/barefoot/sonic-platform-modules-ingrasys/s9280-64x/utils/qsfp_monitor.sh @@ -66,7 +66,7 @@ function _docker_swss_check { while true do # Check if syncd starts - result=`docker exec -i swss bash -c "echo -en \"SELECT 1\\nHLEN HIDDEN\" | redis-cli | sed -n 2p"` #TBD FIX ME + result=`sonic-db-cli ASIC_DB HLEN HIDDEN` if [ "$result" == "3" ]; then return fi diff --git a/platform/broadcom/sonic-platform-modules-ingrasys/s8810-32q/utils/qsfp_monitor.sh b/platform/broadcom/sonic-platform-modules-ingrasys/s8810-32q/utils/qsfp_monitor.sh index 249f179216a6..7776493bc20a 100755 --- a/platform/broadcom/sonic-platform-modules-ingrasys/s8810-32q/utils/qsfp_monitor.sh +++ b/platform/broadcom/sonic-platform-modules-ingrasys/s8810-32q/utils/qsfp_monitor.sh @@ -65,7 +65,7 @@ function _docker_swss_check { while true do # Check if syncd starts - result=`docker exec -i swss bash -c "echo -en \"SELECT 1\\nHLEN HIDDEN\" | redis-cli | sed -n 2p"` #TBD FIX ME + result=`sonic-db-cli ASIC_DB HLEN HIDDEN` if [ "$result" == "3" ]; then return fi diff --git a/platform/broadcom/sonic-platform-modules-ingrasys/s8900-54xc/utils/qsfp_monitor.sh b/platform/broadcom/sonic-platform-modules-ingrasys/s8900-54xc/utils/qsfp_monitor.sh index 7f50d137bcb7..0a4ba20ab767 100644 --- a/platform/broadcom/sonic-platform-modules-ingrasys/s8900-54xc/utils/qsfp_monitor.sh +++ b/platform/broadcom/sonic-platform-modules-ingrasys/s8900-54xc/utils/qsfp_monitor.sh @@ -67,7 +67,7 @@ function _docker_swss_check { while true do # Check if syncd starts - result=`docker exec -i swss bash -c "echo -en \"SELECT 1\\nHLEN HIDDEN\" | redis-cli | sed -n 2p"` #TBD FIX ME + result=`sonic-db-cli ASIC_DB HLEN HIDDEN` if [ "$result" == "3" ]; then return fi diff --git a/platform/broadcom/sonic-platform-modules-ingrasys/s8900-64xc/utils/qsfp_monitor.sh b/platform/broadcom/sonic-platform-modules-ingrasys/s8900-64xc/utils/qsfp_monitor.sh index 36f9e53ef108..b3192f2efb7a 100644 --- a/platform/broadcom/sonic-platform-modules-ingrasys/s8900-64xc/utils/qsfp_monitor.sh +++ b/platform/broadcom/sonic-platform-modules-ingrasys/s8900-64xc/utils/qsfp_monitor.sh @@ -67,7 +67,7 @@ function _docker_swss_check { while true do # Check if syncd starts - result=`docker exec -i swss bash -c "echo -en \"SELECT 1\\nHLEN HIDDEN\" | redis-cli | sed -n 2p"` #TBD FIX ME + result=`sonic-db-cli ASIC_DB HLEN HIDDEN` if [ "$result" == "3" ]; then return fi diff --git a/platform/broadcom/sonic-platform-modules-ingrasys/s9100/utils/qsfp_monitor.sh b/platform/broadcom/sonic-platform-modules-ingrasys/s9100/utils/qsfp_monitor.sh index 249f179216a6..7776493bc20a 100755 --- a/platform/broadcom/sonic-platform-modules-ingrasys/s9100/utils/qsfp_monitor.sh +++ b/platform/broadcom/sonic-platform-modules-ingrasys/s9100/utils/qsfp_monitor.sh @@ -65,7 +65,7 @@ function _docker_swss_check { while true do # Check if syncd starts - result=`docker exec -i swss bash -c "echo -en \"SELECT 1\\nHLEN HIDDEN\" | redis-cli | sed -n 2p"` #TBD FIX ME + result=`sonic-db-cli ASIC_DB HLEN HIDDEN` if [ "$result" == "3" ]; then return fi diff --git a/platform/broadcom/sonic-platform-modules-ingrasys/s9200-64x/utils/qsfp_monitor.sh b/platform/broadcom/sonic-platform-modules-ingrasys/s9200-64x/utils/qsfp_monitor.sh index 51c49c1152f5..47cfbb3ea008 100755 --- a/platform/broadcom/sonic-platform-modules-ingrasys/s9200-64x/utils/qsfp_monitor.sh +++ b/platform/broadcom/sonic-platform-modules-ingrasys/s9200-64x/utils/qsfp_monitor.sh @@ -66,7 +66,7 @@ function _docker_swss_check { while true do # Check if syncd starts - result=`docker exec -i swss bash -c "echo -en \"SELECT 1\\nHLEN HIDDEN\" | redis-cli | sed -n 2p"` #TBD FIX ME + result=`sonic-db-cli ASIC_DB HLEN HIDDEN` if [ "$result" == "3" ]; then return fi diff --git a/platform/nephos/sonic-platform-modules-ingrasys/s9130-32x/utils/qsfp_monitor.sh b/platform/nephos/sonic-platform-modules-ingrasys/s9130-32x/utils/qsfp_monitor.sh index 249f179216a6..7776493bc20a 100755 --- a/platform/nephos/sonic-platform-modules-ingrasys/s9130-32x/utils/qsfp_monitor.sh +++ b/platform/nephos/sonic-platform-modules-ingrasys/s9130-32x/utils/qsfp_monitor.sh @@ -65,7 +65,7 @@ function _docker_swss_check { while true do # Check if syncd starts - result=`docker exec -i swss bash -c "echo -en \"SELECT 1\\nHLEN HIDDEN\" | redis-cli | sed -n 2p"` #TBD FIX ME + result=`sonic-db-cli ASIC_DB HLEN HIDDEN` if [ "$result" == "3" ]; then return fi diff --git a/platform/nephos/sonic-platform-modules-ingrasys/s9230-64x/utils/qsfp_monitor.sh b/platform/nephos/sonic-platform-modules-ingrasys/s9230-64x/utils/qsfp_monitor.sh index 23a3fd066bee..9213d115f656 100755 --- a/platform/nephos/sonic-platform-modules-ingrasys/s9230-64x/utils/qsfp_monitor.sh +++ b/platform/nephos/sonic-platform-modules-ingrasys/s9230-64x/utils/qsfp_monitor.sh @@ -66,7 +66,7 @@ function _docker_swss_check { while true do # Check if syncd starts - result=`docker exec -i swss bash -c "echo -en \"SELECT 1\\nHLEN HIDDEN\" | redis-cli | sed -n 2p"` #TBD FIX ME + result=`sonic-db-cli ASIC_DB HLEN HIDDEN` if [ "$result" == "3" ]; then return fi From 122124679dbcb5210efd29b9535d7f2f81b74230 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Fri, 3 Jan 2020 16:35:08 -0800 Subject: [PATCH 276/278] Update bgpcfgd with vrf support (#3952) * Implement path traversal just once * Add support of vrf to bgpcfgd --- dockers/docker-fpm-frr/bgpcfgd | 72 +++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/dockers/docker-fpm-frr/bgpcfgd b/dockers/docker-fpm-frr/bgpcfgd index 120e07fcdbe2..4211f49d2272 100755 --- a/dockers/docker-fpm-frr/bgpcfgd +++ b/dockers/docker-fpm-frr/bgpcfgd @@ -120,29 +120,23 @@ class Directory(object): self.data = defaultdict(dict) self.notify = defaultdict(lambda: defaultdict(list)) - def path_exist(self, slot, path): + def path_traverse(self, slot, path): if slot not in self.data: - return False + return False, None elif path == '': - return True + return True, self.data[slot] d = self.data[slot] for p in path.split("/"): if p not in d: - return False + return False, None d = d[p] - return True + return True, d + + def path_exist(self, slot, path): + return self.path_traverse(slot, path)[0] def get_path(self, slot, path): - if slot not in self.data: - return None - elif path == '': - return self.data[slot] - d = self.data[slot] - for p in path.split("/"): - if p not in d: - return None - d = d[p] - return d + return self.path_traverse(slot, path)[1] def put(self, slot, key, value): self.data[slot][key] = value @@ -289,6 +283,8 @@ class BGPPeerMgr(Manager): } def set_handler(self, key, data): + key = self.normalize_key(key) + vrf, nbr = key.split('|', 1) if key not in self.peers: cmd = None neigmeta = self.directory.get_slot("neigmeta") @@ -298,14 +294,14 @@ class BGPPeerMgr(Manager): cmd = self.templates["add"].render( DEVICE_METADATA=self.directory.get_slot("meta"), DEVICE_NEIGHBOR_METADATA=neigmeta, - neighbor_addr=key, + neighbor_addr=nbr, bgp_session=data ) except: syslog.syslog(syslog.LOG_ERR, 'Peer {}. Error in rendering the template for "SET" command {}'.format(key, data)) return True if cmd is not None: - rc = self.apply_op(cmd) + rc = self.apply_op(cmd, vrf) if rc: self.peers.add(key) syslog.syslog(syslog.LOG_INFO, 'Peer {} added with attributes {}'.format(key, data)) @@ -316,13 +312,13 @@ class BGPPeerMgr(Manager): # commands for the peers only if "admin_status" in data: if data['admin_status'] == 'up': - rc = self.apply_op(self.templates["no shutdown"].render(neighbor_addr=key)) + rc = self.apply_op(self.templates["no shutdown"].render(neighbor_addr=nbr), vrf) if rc: syslog.syslog(syslog.LOG_INFO, 'Peer {} admin state is set to "up"'.format(key)) else: syslog.syslog(syslog.LOG_ERR, "Peer {} admin state wasn't set to 'up'.".format(key)) elif data['admin_status'] == 'down': - rc = self.apply_op(self.templates["shutdown"].render(neighbor_addr=key)) + rc = self.apply_op(self.templates["shutdown"].render(neighbor_addr=nbr), vrf) if rc: syslog.syslog(syslog.LOG_INFO, 'Peer {} admin state is set to "down"'.format(key)) else: @@ -334,23 +330,28 @@ class BGPPeerMgr(Manager): return True def del_handler(self, key): + key = self.normalize_key(key) + vrf, nbr = key.split('|', 1) if key not in self.peers: syslog.syslog(syslog.LOG_WARNING, 'Peer {} has not been found'.format(key)) return - cmd = self.templates["delete"].render(neighbor_addr=key) - rc = self.apply_op(cmd) + cmd = self.templates["delete"].render(neighbor_addr=nbr) + rc = self.apply_op(cmd, vrf) if rc: syslog.syslog(syslog.LOG_INFO, 'Peer {} has been removed'.format(key)) self.peers.remove(key) else: syslog.syslog(syslog.LOG_ERR, "Peer {} hasn't been removed".format(key)) - def apply_op(self, cmd): + def apply_op(self, cmd, vrf): bgp_asn = self.directory.get_slot("meta")["localhost"]["bgp_asn"] fd, tmp_filename = tempfile.mkstemp(dir='/tmp') os.close(fd) with open(tmp_filename, 'w') as fp: - fp.write('router bgp %s\n' % bgp_asn) + if vrf == 'default': + fp.write('router bgp %s\n' % bgp_asn) + else: + fp.write('router bgp %s vrf %s\n' % (bgp_asn, vrf)) fp.write("%s\n" % cmd) command = ["vtysh", "-f", tmp_filename] @@ -358,14 +359,31 @@ class BGPPeerMgr(Manager): os.remove(tmp_filename) return rc == 0 + @staticmethod + def normalize_key(key): + if '|' not in key: + return 'default|' + key + else: + return key + @staticmethod def load_peers(): - peers = set() - command = ["vtysh", "-c", "show bgp neighbors json"] + vrfs = [] + command = ["vtysh", "-c", "show bgp vrfs json"] rc, out, err = run_command(command) if rc == 0: - js_bgp = json.loads(out) - peers = set(js_bgp.keys()) + js_vrf = json.loads(out) + vrfs = js_vrf['vrfs'].keys() + + peers = set() + for vrf in vrfs: + command = ["vtysh", "-c", 'show bgp vrf {} neighbors json'.format(vrf)] + rc, out, err = run_command(command) + if rc == 0: + js_bgp = json.loads(out) + for nbr in js_bgp.keys(): + peers.add((vrf, nbr)) + return peers From df04809cb878ca69d408448c82da8f57f696bd9f Mon Sep 17 00:00:00 2001 From: tahmed-dev <56694863+tahmed-dev@users.noreply.github.com> Date: Mon, 6 Jan 2020 17:01:28 -0800 Subject: [PATCH 277/278] [libnl]: Debian Packaging libnl version 3.5.0 (#3967) Packaging libnl 3.5.0 based off libnl 3.2.27 packaging. libnl contains various bug fixes that are nice to have. pull-request: https://github.com/Azure/sonic-buildimage/pull/3967 signed-off-by: Tamer Ahmed --- .gitignore | 16 + rules/libnl3.mk | 4 +- src/libnl3/Makefile | 9 +- src/libnl3/debian/README.Debian | 17 + src/libnl3/debian/README.source | 10 + src/libnl3/debian/changelog | 1043 +++++++++ src/libnl3/debian/compat | 1 + src/libnl3/debian/control | 245 ++ src/libnl3/debian/copyright | 160 ++ src/libnl3/debian/gbp.conf | 16 + src/libnl3/debian/libnl-3-200-udeb.install | 1 + src/libnl3/debian/libnl-3-200.install | 3 + src/libnl3/debian/libnl-3-200.symbols | 661 ++++++ src/libnl3/debian/libnl-3-dev.install | 5 + src/libnl3/debian/libnl-cli-3-200.install | 4 + src/libnl3/debian/libnl-cli-3-200.symbols | 226 ++ src/libnl3/debian/libnl-cli-3-dev.install | 3 + .../debian/libnl-genl-3-200-udeb.install | 2 + src/libnl3/debian/libnl-genl-3-200.install | 2 + src/libnl3/debian/libnl-genl-3-200.symbols | 88 + src/libnl3/debian/libnl-genl-3-dev.install | 4 + src/libnl3/debian/libnl-idiag-3-200.install | 1 + src/libnl3/debian/libnl-idiag-3-200.symbols | 206 ++ src/libnl3/debian/libnl-idiag-3-dev.install | 3 + src/libnl3/debian/libnl-nf-3-200.install | 1 + src/libnl3/debian/libnl-nf-3-200.symbols | 620 +++++ src/libnl3/debian/libnl-nf-3-dev.install | 3 + src/libnl3/debian/libnl-route-3-200.install | 1 + src/libnl3/debian/libnl-route-3-200.symbols | 2051 +++++++++++++++++ src/libnl3/debian/libnl-route-3-dev.install | 3 + src/libnl3/debian/libnl-utils.install | 1 + src/libnl3/debian/libnl-utils.manpages | 1 + src/libnl3/debian/libnl-xfrm-3-200.install | 1 + src/libnl3/debian/libnl-xfrm-3-200.symbols | 484 ++++ src/libnl3/debian/libnl-xfrm-3-dev.install | 3 + src/libnl3/debian/patches/series | 0 src/libnl3/debian/rules | 39 + src/libnl3/debian/source/format | 1 + src/libnl3/debian/watch | 2 + 39 files changed, 5934 insertions(+), 7 deletions(-) create mode 100644 src/libnl3/debian/README.Debian create mode 100644 src/libnl3/debian/README.source create mode 100644 src/libnl3/debian/changelog create mode 100644 src/libnl3/debian/compat create mode 100644 src/libnl3/debian/control create mode 100644 src/libnl3/debian/copyright create mode 100644 src/libnl3/debian/gbp.conf create mode 100644 src/libnl3/debian/libnl-3-200-udeb.install create mode 100755 src/libnl3/debian/libnl-3-200.install create mode 100644 src/libnl3/debian/libnl-3-200.symbols create mode 100755 src/libnl3/debian/libnl-3-dev.install create mode 100755 src/libnl3/debian/libnl-cli-3-200.install create mode 100644 src/libnl3/debian/libnl-cli-3-200.symbols create mode 100644 src/libnl3/debian/libnl-cli-3-dev.install create mode 100755 src/libnl3/debian/libnl-genl-3-200-udeb.install create mode 100755 src/libnl3/debian/libnl-genl-3-200.install create mode 100644 src/libnl3/debian/libnl-genl-3-200.symbols create mode 100755 src/libnl3/debian/libnl-genl-3-dev.install create mode 100644 src/libnl3/debian/libnl-idiag-3-200.install create mode 100644 src/libnl3/debian/libnl-idiag-3-200.symbols create mode 100644 src/libnl3/debian/libnl-idiag-3-dev.install create mode 100644 src/libnl3/debian/libnl-nf-3-200.install create mode 100644 src/libnl3/debian/libnl-nf-3-200.symbols create mode 100644 src/libnl3/debian/libnl-nf-3-dev.install create mode 100644 src/libnl3/debian/libnl-route-3-200.install create mode 100644 src/libnl3/debian/libnl-route-3-200.symbols create mode 100644 src/libnl3/debian/libnl-route-3-dev.install create mode 100644 src/libnl3/debian/libnl-utils.install create mode 100644 src/libnl3/debian/libnl-utils.manpages create mode 100644 src/libnl3/debian/libnl-xfrm-3-200.install create mode 100644 src/libnl3/debian/libnl-xfrm-3-200.symbols create mode 100644 src/libnl3/debian/libnl-xfrm-3-dev.install create mode 100644 src/libnl3/debian/patches/series create mode 100755 src/libnl3/debian/rules create mode 100644 src/libnl3/debian/source/format create mode 100644 src/libnl3/debian/watch diff --git a/.gitignore b/.gitignore index 1f921971d8bb..fbf646fcd40f 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,8 @@ src/isc-dhcp/* !src/isc-dhcp/Makefile !src/isc-dhcp/patch/ src/libnl3/* +!src/libnl3/debian +src/libnl3/debian/libnl-*/ !src/libnl3/Makefile src/libteam/* !src/libteam/Makefile @@ -140,3 +142,17 @@ src/sonic-daemon-base/sonic_daemon_base.egg-info # Misc. files files/initramfs-tools/arista-convertfs files/initramfs-tools/union-mount + +# Debian byproduct files +src/**/debian/stamp-*/ +src/**/debian/*.log +src/**/debian/*.substvars +src/**/debian/.debhelper/ +src/**/debian/tmp/ +src/**/debian/autoreconf.* +src/**/debian/build/ +src/**/debian/files +src/**/debian/stamp-autotools-files + +# .o files +src/**/*.o diff --git a/rules/libnl3.mk b/rules/libnl3.mk index 897b6c34482f..cdd807b2f5c8 100644 --- a/rules/libnl3.mk +++ b/rules/libnl3.mk @@ -1,7 +1,7 @@ # libnl3 -LIBNL3_VERSION_BASE = 3.2.27 -LIBNL3_VERSION = $(LIBNL3_VERSION_BASE)-2 +LIBNL3_VERSION_BASE = 3.5.0 +LIBNL3_VERSION = $(LIBNL3_VERSION_BASE)-1 export LIBNL3_VERSION_BASE export LIBNL3_VERSION diff --git a/src/libnl3/Makefile b/src/libnl3/Makefile index c9fc72f50f74..a0e9891c9efc 100644 --- a/src/libnl3/Makefile +++ b/src/libnl3/Makefile @@ -16,12 +16,11 @@ DERIVED_TARGETS = libnl-3-dev_$(LIBNL3_VERSION)_$(CONFIGURED_ARCH).deb \ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : # Obtaining the libnl3 rm -rf ./libnl3-$(LIBNL3_VERSION_BASE) - wget -O libnl3_$(LIBNL3_VERSION_BASE).orig.tar.gz -N "https://sonicstorage.blob.core.windows.net/packages/libnl3_$(LIBNL3_VERSION_BASE).orig.tar.gz?sv=2015-04-05&sr=b&sig=b4DnqrIsyVBDLmYhw7qwfaUJWqGCX2lDVMmmx7ihfrU%3D&se=2028-06-16T21%3A06%3A00Z&sp=r" - wget -O libnl3_$(LIBNL3_VERSION).dsc -N "https://sonicstorage.blob.core.windows.net/packages/libnl3_$(LIBNL3_VERSION).dsc?sv=2015-04-05&sr=b&sig=AWTX45oDbeGA%2BRJZyiCcHmeIfCAgSeNV3IqopOBaRDg%3D&se=2028-06-16T21%3A05%3A30Z&sp=r" - wget -O libnl3_$(LIBNL3_VERSION).debian.tar.xz -N "https://sonicstorage.blob.core.windows.net/packages/libnl3_$(LIBNL3_VERSION).debian.tar.xz?sv=2015-04-05&sr=b&sig=upIZ9dp5WEcLqp3ODeWKJXq5pJWCfeT0TIM0bx76wxM%3D&se=2028-06-16T21%3A04%3A44Z&sp=r" - dpkg-source -x libnl3_$(LIBNL3_VERSION).dsc + git clone https://github.com/thom311/libnl libnl3-$(LIBNL3_VERSION_BASE) + pushd libnl3-$(LIBNL3_VERSION_BASE) + git checkout tags/libnl$(subst .,_,$(LIBNL3_VERSION_BASE)) - pushd ./libnl3-$(LIBNL3_VERSION_BASE) + ln -s ../debian debian dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) popd diff --git a/src/libnl3/debian/README.Debian b/src/libnl3/debian/README.Debian new file mode 100644 index 000000000000..002e249bbfcb --- /dev/null +++ b/src/libnl3/debian/README.Debian @@ -0,0 +1,17 @@ + +libnl versions explained +======================== + +Once libnl3 hits the archive there will exist 3 versions of libnl. +libnl1 with libnl-dev - up until March 2011 the stable version +libnl2 with libnl2-dev - development version that resulted in +libnl3 with libnl3-dev - the new stable (API and ABI wise) version + +libnl1 has currently a lot of users in the archive and a lot of changes +happened since its last upstream release in 2008-01. + +The plan is therefore to introduce libnl3, port the two users of libnl2 +(freesmartphone.org libs and powertop) to it, remove libnl2 and don't touch +libnl1 and libnl-dev for now. + + -- Heiko Stuebner Sat, 21 May 2011 19:25:13 +0200 diff --git a/src/libnl3/debian/README.source b/src/libnl3/debian/README.source new file mode 100644 index 000000000000..f6e8ee70da94 --- /dev/null +++ b/src/libnl3/debian/README.source @@ -0,0 +1,10 @@ +This package uses the simple-patchsys of cdbs. + +The following patches are used: +0001: Fixes the header inclusion in the Makefiles. + This for example make distcheck +0002: Includes all generated libraries as linktargets in the pkg-config file. + Reason: Currently libnl3 generates a bunch of child libraries. + These don't get individual .pc files from upstream at the moment but + programs linking against libnl3 using the .pc file mostly need these + additional libraries too. diff --git a/src/libnl3/debian/changelog b/src/libnl3/debian/changelog new file mode 100644 index 000000000000..c51ae1121796 --- /dev/null +++ b/src/libnl3/debian/changelog @@ -0,0 +1,1043 @@ +libnl3 (3.5.0-1) unstable; urgency=low + + [ skuklinski ] + * route/link: IFLA_VLAN_PROTOCOL added to vlan_put_attrs + + [ Thomas Haller ] + * rtnl/link: indicate capability NL_CAPABILITY_RTNL_LINK_VLAN_PROTOCOL_SERIALZE + + [ David Ahern ] + * route/vrf: add VRF support + * neigh: add support for NTF_SELF + + [ Beniamino Galvani ] + * route/link: fix parsing of 'remote' attribute for GRE links + + [ Thomas Haller ] + * route/vlan: allow clearing vlan ingress map + + [ David Ahern ] + * link/neigh: add flags option to link and neighbor caches + + [ Thomas Haller ] + * gitignore: ignore test binaries in "tests/" + + [ Beniamino Galvani ] + * route/link: add macvtap support + * route/link: fix dump of parent link for some link types + * route/link: add ipv6 support to vxlan links + + [ Tobias Jungel ] + * route/link: corrected array size for inet_policy + + [ David Ahern ] + * route/link: add link info compare operation + * route/link/vxlan: trivial rename VXLAN_HAS_ prefix and vxi_mask + * route/link/vxlan: add support for link_info compare + + [ Andrew Vagin ] + * libnl: don't use out-of-scope buffer in nl_send_iovec() + + [ David Ahern ] + * link: add AF operation to append attributes to a GETLINK message + * lib: handle family-based parsing of IFLA_AF_SPEC attribute + + [ Thomas Haller ] + * include/linux: update copy of kernel headers + + [ David Ahern ] + * bridge: add support for VLANs + + [ Tobias Jungel ] + * route/link: handle RTEXT_FILTER_BRVLAN_COMPRESSED + * route/link/bridge: fixed return type + + [ Quentin Armitage ] + * route/link: add support for IN6_ADDR_GEN_MODE_STABLE_PRIVACY + + [ Amit Khatri ] + * lib/route: potential memory leak in pktloc.c + + [ Nick Lewycky ] + * remove null dereference from netlink/link.h + + [ David Ahern ] + * lib: update ce-mask to uint64_t + + [ Thomas Haller ] + * libnl: add nl_object_diff64() to libnl-3.sym + * lib/utils: add NL_CAPABILITY_NL_OBJECT_DIFF64 capability + + [ Przemyslaw Szczerbik ] + * lib: add type casting for nla_for_each_nested macro + + [ Tobias Klauser ] + * build: move -rdynamic from CPPFLAGS to LDFLAGS + + [ Thomas Haller ] + * route: sort entries in libnl-route-3.sym by name + + [ Haishuang Yan ] + * ipgre: add support for gretap tunnel + + [ Thadeu Lima de Souza Cascardo ] + * sit: add 6RD support + + [ Thomas Haller ] + * sit/trivial: whitespace + * sit: don't print ip6rd_prefix as integer in sit_dump_details() + * sit: refactor IS_SIT_LINK_ASSERT() + * sit: fix invalid declaration of rtnl_link_sit_get_proto() in sit.h + * sit: add public API for sit 6RD support + + [ Jonas Johansson ] + * neigh: support neighbour flag NTF_SELF + * neigh: add function to look up neighbour (fdb) by ifindex, mac and vlan + + [ Jef Oliver ] + * link: support RTEXT_FILTER_VF + + [ Thomas Haller ] + * link: allow overwriting IFLA_EXT_MASK flag in ao_get_af() function + + [ Przemyslaw Szczerbik ] + * lib: return error on Netlink attribute length overflow + + [ Thomas Egerer ] + * xfrm: fix buffer overflow when copying keys + * xfrm: check length of alg_name before strcpying it + * xfrm: make character pointers in setters const + * xfrm: fix segfault when using encapsulation templates + + [ Thomas Haller ] + * xfrm: reuse encap data in xfrmnl_sa_set_encap_tmpl() + + [ Thomas Egerer ] + * xfrm: fix memory leak for encap original address + * xfrm: attach only one xfrm alg attribute to netlink message + + [ Thomas Haller ] + * xfrm: fix memleak in build_xfrm_sa_message() error-path + + [ Sabrina Dubroca ] + * pass flags through ->io_compare op + * vxlan: properly handle LOOSE_COMPARISON in ->io_compare + * import macsec uapi headers + * lib/route: add macsec support + + [ Thomas Haller ] + * xfrm: allow avoiding buffer overflow for key in xfrmnl_sa_get_*_params() + * route/addr: fix ID comparison for AF_INET and AF_INET6 addresses + * route/addr: fix handling peer addresses for IPv4 addresses + * route/addr: add capability NL_CAPABILITY_RTNL_ADDR_PEER_FIX to indicate address fixes + * build: fix adding macsec files to include/Makefile.am + * libnl-3.2.28-rc1 release + * libnl-3.2.28 release + + [ Craig Gallek ] + * build: fixup headers for C++ inclusion + + [ Peter Wu ] + * trivial: whitespace-only fixes for src and lib + * cli: add noreturn attributes + * xfrm: fix memleak in another error path of build_xfrm_sa_message + * exp: fix a GCC 6 -Wmisleading-indentation warning + * doc: fix URLs and typo + + [ Tobias Jungel ] + * route/addr: address attributes based on object + + [ Thomas Haller ] + * lib: capability NL_CAPABILITY_RTNL_ADDR_PEER_ID_FIX for ID comparison of v4 addresses + * nl-addr: avoid read-out-of-bound in nl_addr_fill_sockaddr() + + [ André Draszik ] + * lib: add utility function nl_strerror_l() + * lib: switch to using strerror_l() instead of strerror_r() + * src: switch to using strerror_l() instead of strerror_r() + + [ Jeff Squyres ] + * compat: add linux/socket.h for __kernel_sa_family_t + + [ Jef Oliver ] + * lib/route: allow override of message type during link change + * lib/route: set IFLA_PROTINFO attribute in request message + * lib/route: modify link/bridge to set attributes + + [ Davide Caratti ] + * macsec: fix endianness of 'sci' parameter + * macsec: fix maximum ICV length + * remove multiple implementations of htonll(), ntohll() + + [ Jef Oliver ] + * lib/route: Fix appending IFLA_BRPORT_FASTLEAVE + * lib/route: Add port state translation functions + * lib/route: Extend Bridge Flags + * lib/route: Allow override of IFLA_AF_SPEC nesting + * lib/route: Support IFLA_BRIDGE_MODE + + [ Thomas Haller ] + * trivial: whitespace + * bridge: change return values for rtnl_link_bridge_get_hwmode() + + [ Michael Braun ] + * macvlan: add support for "source" mode + + [ Thomas Haller ] + * macvlan: adjust types and merge MACVLAN_HAS_MACCOUNT and MACVLAN_HAS_MACDATA + + [ Brandon Carpenter ] + * vxlan: add support for additional VXLAN attributes. + + [ Thomas Haller ] + * vxlan: fix exporting new symbols + * vxlan: remove redundant enable/disable API from vxlan + * vxlan: restore previous VXLAN_ATTR flag values + * vxlan: don't store vxlan flags as ce_mask + * vxlan: refactor setting/getting vxlan flags + * vxlan: fix error code for missing attribute + + [ Jef Oliver ] + * lib/route: Export correct ipgre functionality + + [ Thomas Haller ] + * lib/route: preserve old ABI for rtnl_link_get_pmtudisc() + + [ Thomas Egerer ] + * xfrm: fix xfrm security context management + * xfrm: add capability reference to xfrmnl_sa_set_* + + [ Thomas Haller ] + * xfrm: remove unused struct xfrmnl_sec_ctx from header files + + [ Jef Oliver ] + * lib/route: SRIOV Parse and Read support + * lib/route: SRIOV Clone Support + * lib/route: SRIOV Utility Functions + * lib/route: SRIOV Info Dump Functions + * lib/route: SRIOV Set Functionality + + [ Thomas Haller ] + * route: remove symbols of internal API from ABI + + [ Tobias Klauser ] + * lib/route: keep link stats minlen compatible with kernel < 4.6 + + [ Thomas Haller ] + * utils: add internal _nl_offset_plus_sizeof() macro + * lib/route: use _nl_offset_plus_sizeof() macro for minlen field for rtln_link_policy + + [ Jonas Johansson ] + * Add PPP support + * ppp: update code after review + * ppp: rename local struct ppp_info* variables; pi -> info + * ppp: fix type of file descriptor; uint32_t -> int32_t + + [ Thomas Haller ] + * ppp: fix API in ppp.h header + + [ Sushma Sitaram ] + * route/cls: support setting of selector fields + + [ Tobias Klauser ] + * src: nl-link-stats: use correct rtnl link stats maximum + * lib/route: add rx_nohandler link stats field + + [ Thomas Haller ] + * nl-link-stats: prefer RTNL_LINK_STATS_MAX over __RTNL_LINK_STATS_MAX + * lib/route: pass sizeof() argument to nl_memcpy() + * link: set ifi_change flags for rtnl_link_build_add_request() + * lib: use MSG_PEEK by default for nl_recvmsgs() + + [ Tobias Jungel ] + * cache_mngr: add include callback v2 + + [ Tobias Klauser ] + * cache: fix GCC warning and avoid variable shadowing + + [ Sushma Sitaram ] + * route/act: add gact tc action + + [ Tobias Klauser ] + * link: add support for IFLA_CARRIER_CHANGES + * link: add support for IFLA_PHYS_PORT_NAME + * link: add support for IFLA_PHYS_SWITCH_ID + * link: add support for IFLA_GSO_MAX_SEGS and IFLA_GSO_MAX_SIZE + * link: fix documentation for rtnl_link_get_carrier_changes + + [ Thomas Haller ] + * libnl-3.2.29-rc1 release + * utils/trivial: rename internal _nl_offset_plus_sizeof() macro to _nl_offsetofend() + + [ Beniamino Galvani ] + * Revert "macsec: fix endianness of 'sci' parameter" + * macsec: document byte order for the SCI and port attributes + + [ Thomas Haller ] + * macsec: fix endianness of sci during dump() + * libnl-3.2.29 release + + [ Tobias Klauser ] + * route/tc: Remove unused function tca_set_kind() + + [ Laine Stump ] + * sriov: fix crash in rtnl_link_sriov_parse_vflist + + [ Thomas Haller ] + * sriov: avoid buffer overrun in rtnl_link_sriov_parse_vflist() + + [ Nick Kralevich ] + * lib/utils.c: lazy initialize user_hz and psched_hz + + [ Thomas Haller ] + * lib/utils.c: ensure calling get_psched_settings() for nl_us2ticks()/nl_ticks2us() + * lib/utils.c: add mutex to get_psched_settings() + + [ Nick Kralevich ] + * fopen: add O_CLOEXEC + + [ Thomas Haller ] + * lib/attr.c: check for valid length argument in nla_reserve() + + [ Tobias Klauser ] + * sit: Fix invalid function prototypes in public header + * sriov: Add missing prototype for rtnl_link_vf_vlan_free() + * qdisc/red: Add missing prototypes for rtnl_red_set_limit() and rtnl_red_get_limit() + * fib_lookup: Add missing prototypes to public header + * link/inet6: Include own public header for function prototypes + * link/ipip: Include own public header for function prototypes + * link/ipip: Add missing prototype for rtnl_link_is_ipip() + * link/ipvti: Include own public header for function prototypes + * link/ipvti: Fix and add function prototypes in public header + * link/macsec: Include own public header for function prototypes + * link/sit: Add missing prototype for rtnl_link_is_sit() + * link/ipgre: Add prototype for ABI-preserving wrapper rtnl_link_get_pmtudisc() + * netfilter/queue: Add missing prototype for nfnl_queue_msg_build_verdict_batch() + * netfilter/exp: Add missing function prototypes + * idiag/req: Add missing function prototype + * xfrm/ae: Include own public header for function prototypes + * xfrm/lifetime: Include own public header for function prototypes + * xfrm/sa: Include own public header for function prototypes + * xfrm/selector: Include own public header for function prototypes + * xfrm/template: Include own public header for function prototypes + * pktloc: Add missing function prototypes + * ematch: Add missing function prototypes + * build: Add -Wmissing-prototypes to CPPFLAGS + + [ Jeroen Roovers ] + * build: distribute in.h in6.h libc-compat.h + + [ Thomas Haller ] + * lib: fix comment for nl_recv() about return value for non-blocking read + * lib: check for integer-overflow in nlmsg_reserve() + * build: cleanup top-level Makefile.am + * build: merge include/Makefile.am into top-level makefile + * build: merge lib/Makefile.am into top-level makefile + * build: merge man/Makefile.am into top-level makefile + * build: merge python/Makefile.am into top-level makefile + * build: merge tests/Makefile.am into top-level makefile + * build: merge src/lib/Makefile.am into top-level makefile + * build: merge src/Makefile.am into top-level makefile + * build: enable building cli during tests + * build: move compiler warning flags to separate autoconf variable + * all: enable -Wmissing-prototype warning for all components + * build: enable more warnings + + [ Roopa Prabhu ] + * route: neigh: use NDA_MASTER for neigh->n_master if available + + [ Simon Buttgereit ] + * fix build_xfrm_sp_message index condition + * fix xfrmnl_sp_set_sec_ctx length attributes + * little style fixes. + * update sp_attr condition in build_xfrm_sp_message + * add possibity to delete policy without index + * update documentation of xfrmnl_sp_get_sec_ctx + * fix of boolean operators + + [ Thomas Haller ] + * xfrm: allow quering optional arguments from xfrmnl_sp_get_sec_ctx() + * xfrm: NUL terminate the ctx_str buffer in xfrmnl_sa_set_sec_ctx() + * build: ensure build directory for generated sources exist + * build: pass --disable-dependency-tracking to `make distcheck` + * build: fix creating directories for generated sources + * build: style cleanup in doc/Makefile.am + * build: reorder checks in configure.ac + * build: add tools/build_release.sh script + * include: don't include kernel headers in public libnl3 headers + * include: restore linux header includes in public headers + * libnl-3.3.0-rc1 release + + [ Alexey Brodkin ] + * lib: escape usage of strerror_l() if it doesn't exist in libc + + [ Thomas Haller ] + * all: don't use math.h or link with libm.so + * libnl-3.3.0 release + * tools: fix building doc in build_release.sh + + [ Markus Trapp ] + * route/link: add accessor API for IPv6 flags + + [ Santhosh Kumar ] + * Provide accessors for actions (rtnl_act). + * Do not increment refcount in rtnl_*_get_action APIs. + + [ Thomas Haller ] + * route: fix symbol versioning + + [ David Ahern ] + * route: Add support for netconf + * nl-monitor: All user to specify line format + * nl-monitor: Add support for netconf caches + * route: Add support for MPLS to netconf + * Update fib_rules.h to latest kernel + * rule: Add support for l3mdev in FIB rules + + [ Thomas Haller ] + * rule: change API for setting/getting l3mdev rule property + + [ Tobias Klauser ] + * addr: add AF_VSOCK to translation table + + [ Thomas Haller ] + * build: don't build cli libraries by default + * build: allow building cli without dynamic librarires support + + [ Tobias Klauser ] + * genl: drop usage of GENL_ID_GENERATE + + [ Rasmus Villemoes ] + * lib/cache_mngr.c: avoid memleak if realloc fails + * lib/cache_mgr.c: remove pointless goto + * lib/data.c: avoid memleak if realloc fails + * lib/route/cls/u32.c: remove pointless nl_data_append calls + * lib/route/cls/u32.c: avoid overflowing an unsigned char + * lib/route/cls/u32.c: let the compiler do pointer arithmetic + * lib/route/cls/u32.c: remove bogus comment + * lib/route/qdisc/netem.c: avoid memory leak if realloc fails + + [ Thomas Haller ] + * lib/route/cls/u32.c: use UCHAR_MAX define instead of numeric 255 + * lib/route/qdisc/netem.c/trivial: fix whitespace and indentation in netem_msg_fill_raw() + * lib/route/qdisc/netem.c/trivial: don't use braces for one-line blocks + + [ Rasmus Villemoes ] + * lib/xfrm/ae.c: fix memcpy(dst, dst) bug + * lib/genl/family.c: fix if (x) y; else y; + + [ Thomas Haller ] + * all: avoid compiler warnings -Wimplicit-fallthrough + * lib/route: add /usr/lib64/tc/ search path for netem dist file + + [ David Ahern ] + * Update rtnetlink.h from kernel tree + * Import mpls header from kernel tree + + [ Thomas Haller ] + * build: add include/linux-private/linux/mpls.h to Makefile.am + + [ David Ahern ] + * addr: Add implementations for mpls_ntop and mpls_pton + * addr: Add support for AF_MPLS + * route: Add support for MPLS address family + * route: Add support for ttl propagation in MPLS routes + * Add support for label stack in nl-route commands + * Import lwtunnel encap files from kernel + * route: Add support for lwtunnel encapsulations + * route: Add support for MPLS encap + + [ Thomas Haller ] + * build: add new include/netlink-private/route/*.h files to Makefile.am + + [ Amit Khatri ] + * Potential memory leak becaue of wrong variable check. + + [ Tobias Klauser ] + * cli: include sys/select.h for select(2) + + [ Thomas Haller ] + * libnl-3.4.0-rc1 release + + [ David Ahern ] + * netconf: Put nc reference in msg_parser + + [ Jeroen Roovers ] + * build: add missing headers for issue #152 + + [ Thomas Haller ] + * libnl-3.4.0 release + * nl: add "const" specifier for nla_policy argument of parse functions [ Roopa Prabhu ] + * route: link: add family to dump messages + * route: neigh: print family in neigh dumps + + [ Sebastian Bixl ] + * route/vlan: fix memory corruption in rtnl_link_vlan_set_egress_map + + [ Thomas Haller ] + * route/vlan: fix cloning vlan link in vlan_clone() + * route/vlan: grow buffer exponentially in rtnl_link_vlan_set_egress_map() + * route/vlan: add capability to indicate heap overflow fix in rtnl_link_vlan_set_egress_map() + * route: fix handling old_nh in rtnl_route_parse() and avoid leak + + [ Jef Oliver ] + * Change rtnl_link_af_ops.ao_override_rtm behavior + + [ Chris Grahn ] + * tests: fix bug in test-create-bridge.c + + [ Steffen Vogel ] + * route: add separate function to set netem qdisc delay distribution + + [ Thomas Haller ] + * all: declare all variables at the beginning of scope (-Wdeclaration-after-statement) + * route: add rtnl_netem_set_delay_distribution_data() to linker script + * route: mark data argument for rtnl_netem_set_delay_distribution_data() as const + * route: fix memleak in rtnl_netem_set_delay_distribution_data() + * route: free previous data in rtnl_netem_set_delay_distribution_data() + * travis: enable more warnings during build + + [ Marcos Paulo de Souza ] + * tests: Add test to {de}activate loopback interface + * lib/veth.c: Disassociate link name of peer name + + [ d0u9 ] + * Coding style format + * Add new function for setting ifindex and parent of a classifier cache. + + [ Thomas Haller ] + * route: rename rtnl_cls_cache_set_tcm_params() and fix symbol versioning + + [ d0u9 ] + * Fix for cgroup filter addition problem. + + [ Thomas Haller ] + * lib: merge implementations of nl_attr_end() and nl_attr_keep_empty() + + [ Wang Jian ] + * link: add Geneve support. + + [ Thomas Haller ] + * lib/rtnl: rename public define RTNL_GENEVE_ID_MAX + + [ Roopa Prabhu ] + * lib: route: rule: add rule_groups to cache ops + + [ Jonas Johansson ] + * route/vrf: initalize clone destination with NULL in vrf_clone() + + [ David Ahern ] + * Update fib_rules.h to latest kernel + * rule: Add support for protocol and port ranges + + [ Lukáš Karas ] + * add demo program for listen conntrack events + * nf-ct-add typo + + [ Thomas Haller ] + * build: sort entries in Makefile.am and .gitignore by name + * build: indent libnl-route-3.sym with tabs + + [ Tobias Jungel ] + * neigh: set correct AF for NDA_DST + * neigh: support bridge entries for vxlan interfaces + + [ Tuetuopay ] + * cache: make "result" output argument for nl_cache_mngr_add() optional + + [ Volodymyr Bendiuga ] + * include: copy entire pkt_cls.h from linux + * route:cls: add matchall classifier + + [ Thomas Haller ] + * route/mall: fix deep cloning mall + + [ Tuetuopay ] + * route/link: fix sequence number handling in rtnl_link_change() + + [ Thomas Haller ] + * route/link: assert in rtnl_link_change() that the sequence number is set as expected + * nl-msg: explicitly initialize nlmsg_seq and nlmsg_pid field in nlmsg_alloc_simple() + + [ d0u9 ] + * route/class: add new api rtnl_class_get_by_parent() + + [ Tobias Jungel ] + * neigh: correct symbol exposed + + [ Matthieu Baerts ] + * nl: fix function name in debug msg + + [ Tobias Jungel ] + * neigh: cache updates as well query AF_BRIDGE neigh + * whitespace cleanup + * nl-neigh-list: free allocated items + * neigh: add get/set functions for NEIGH_ATTR_MASTER + * neigh_dump_line: dump master as well + + [ d0u9 ] + * Add support for cloning cgroup filter object. + + [ Tuetuopay ] + * route/link/vxlan: Fix IPv4 set_local resetting ce_mask + + [ Tobias Jungel ] + * neigh: update neighbour.h and add missing flags + + [ Thomas Winter ] + * ipgre: Fix wrong array size initialization + * ipvti: Fix wrong array size initialization + * if_tunnel: Update IFLA defines up to FWMARK + + [ Thomas Haller ] + * include/linux: update copy of kernel headers + + [ Volodymyr Bendiuga ] + * include: import linux header pkt_sched.h + * route:qdisc: add MQPRIO Qdisc + + [ Thomas Haller ] + * build: cleanup Makefile.am + * lib/tc: ensure correct error code in rtnl_tc_msg_build() + * lib/qdisc: style fixes in "lib/route/qdisc/mqprio.c" + * lib/qdisc: avoid BUG() in "lib/route/qdisc/mqprio.c" + * build: sort entries in libnl-route-3.sym + * lib/tc: fix uninitalized err variable in rtnl_tc_msg_build() + + [ Volodymyr Bendiuga ] + * route:tc: allow to set chain index for tc objects + + [ Thomas Haller ] + * route/tc: return error code from rtnl_tc_get_chain() + + [ Volodymyr Bendiuga ] + * include: import tc_vlan.h + * route:act: add vlan action + + [ Thomas Haller ] + * route/act: style fixes in "lib/route/act/vlan.c" + * route/act: return error code from act-vlan getters + + [ Ilya Pronin ] + * route/cls: fix potential memory leak + + [ Patrick Havelange ] + * nla_ok: fix overrun in attribute iteration. + + [ Wang Jian ] + * link: macvlan fixes + + [ Thomas Haller ] + * route/macvlan: style fixes in "lib/route/link/macvlan.c" + + [ Tobias Jungel ] + * route/link: expose IFLA_INFO_SLAVE_KIND + + [ Thomas Haller ] + * route/link: avoid dangling pointer in rtnl_link_set_slave_type() + + [ Byeonggon Lee ] + * tests: use nl_send_auto() instead of deprecated nl_send_auto_complete() in test-genl.c + + [ Thomas Haller ] + * doc: fix typos in example in documentation + * attr: mark nested attributes as NLA_F_NESTED + + [ xinbao ] + * Add CTA_LABELS and CTA_LABELS_MASK to ctattr_type according to the new kernel + + [ Thomas Haller ] + * route: fix strncpy() warning from coverity about unterminated string + * link/sriov: fix memleak in rtnl_link_sriov_clone() + * utils: add internal helper macros for cleanup + * lib/genl: avoid VLA in cmd_msg_parser() + * travis: enable -Wvla compiler warning in tests + * travis: build tests with NL_MORE_ASSERTS enabled + * xfrm: fix memory corruption (dangling pointer) when when setting xfrmnl_sa + * route/inet6: fix strncpy() in inet6_dump_details() + * route/tc: ensure not string truncation in rtnl_tc_set_kind() + * genl: reject invalid group names in genl_family_add_grp() + + [ Yegor Yefremov ] + * Add SPDX identifiers + + [ Thomas Haller ] + * lib/genl: fix allocating buffer of too small size in cmd_msg_parser() + + [ Michael Forney ] + * dbg: Use __func__ instead of __PRETTY_FUNCTION__ + * all: Avoid pointer arithmetic on `void *` + * lib: Don't return expression in function returning void + * lib: Don't omit second operand to `?` operator + * all: Use __typeof__ instead of typeof + * route: Remove stray `;` at top-level + * Sync linux headers to 4.19.66 + + [ Thomas Haller ] + * idiag: workaround and add comment about idiagnl_send_simple() only handling 8 bit flags + * lib: accept %NULL arguments for nl_addr_cmp() + * lib: fix error code from nfnl_exp_build_message() + + [ Eyal Birger ] + * doc/route: fix example code comments + * xfrmi: introduce XFRM interfaces support + + [ Thomas Haller ] + * xfrmi: return error code from getters for XFRM links + * route/trivial: sort entries in "libnl-route-3.sym" asciibetically + + [ d0u9 ] + * Add 64bit rate/ceil support for htb class + + [ Thomas Haller ] + * route/qdisc: adjust API for 64 bit rate/ceil support for htb class + * libnl-3.5.0 release + + -- Tamer Ahmed Thu, 02 Jan 2020 10:25:18 -0800 + +libnl3 (3.2.27-2) unstable; urgency=low + + * Add upstream fix for CVE-2017-0553 (Closes: #859948) + + -- Heiko Stuebner Mon, 10 Apr 2017 11:48:23 +0200 + +libnl3 (3.2.27-1) unstable; urgency=low + + * New upstream release + Including fixes for unusable sockets after a failed portid + generation (Closes: #808213) + + -- Heiko Stuebner Sun, 24 Jan 2016 23:54:47 +0100 + +libnl3 (3.2.26-1) unstable; urgency=low + + * New upstream release + * Provide Multiarch:same dev packages + * Add new libnl-xfrm library handling packet transformations + * Update standards to 3.9.6 + + -- Heiko Stuebner Mon, 13 Jul 2015 14:16:22 +0200 + +libnl3 (3.2.24-2) unstable; urgency=low + + * Backport two upstream fixes to prevent issues with older kernels: + - dfd0a80ec845 (route: don't enforce minlen in inet6_parse_protinfo() + (IFLA_PROTINFO) and inet_parse_af() (IFLA_AF_SPEC) + - 5206c050504f (route/addr: only sent IFA_FLAGS when needed to workaround + picky older kernels) + + -- Heiko Stuebner Fri, 18 Apr 2014 17:19:37 +0200 + +libnl3 (3.2.24-1) unstable; urgency=low + + * New upstream release + * Add new libnl-idiag library handling inetdiag requests + + -- Heiko Stuebner Sun, 16 Feb 2014 14:23:26 +0100 + +libnl3 (3.2.21-1) unstable; urgency=low + + * New upstream release (Closes: #707081) + Including CAN support (Closes: #698954) + * Add symbols files (Closes: #654758) + * Provide static libraries (Closes: #693939, #693940) + * Update standards to 3.9.4 + * Removed doc package. Libnl3 documentation is released + separately now. + + -- Heiko Stuebner Tue, 21 May 2013 11:39:13 +0200 + +libnl3 (3.2.7-4) unstable; urgency=low + + * Add watch file (Closes: #679473) + * Use dh-autoreconf to update the build system (Closes: 679474) + + -- Heiko Stuebner Sat, 30 Jun 2012 15:54:25 +0200 + +libnl3 (3.2.7-3) unstable; urgency=low + + * Fix FTBFS due to failing gen-tags.sh (Closes: #674322) + * Convert to Multi-Arch (Closes: #676611) + * Update standards to 3.9.3 - no changes + * Switch to dpkg-source format 3.0 (quilt) + + -- Heiko Stuebner Mon, 18 Jun 2012 21:19:30 +0200 + +libnl3 (3.2.7-2) unstable; urgency=low + + * Force doxygen dot-threads to 1 to circumvent segfaults on armel + * Add missing build-dependency on ghostscript + + -- Heiko Stuebner Mon, 05 Mar 2012 23:29:10 +0100 + +libnl3 (3.2.7-1) unstable; urgency=low + + * New upstream release + * Build-depend on source-highlight (Closes: #657254) + + -- Heiko Stuebner Mon, 13 Feb 2012 18:59:30 +0100 + +libnl3 (3.2.3-2) unstable; urgency=low + + * Upload to unstable + * Split split udeb to be in line with regular packages + * Move libnl and libnl-genl to /lib for iw and wpa_supplicant. + + -- Heiko Stuebner Mon, 19 Dec 2011 20:43:21 +0100 + +libnl3 (3.2.3-1) experimental; urgency=low + + * Upload to experimental to not break debian-installer + * Split library and dev packages for the individual libraries + * Add utils package + + [Mathieu Trudel-Lapierre ] + * New upstream release (Closes: #648819) + * debian/patches/0001-fix-headers.patch, + debian/patches/0002-link-sub-libs.patch, + debian/patches/0003-fix-out-of-tree-build.patch: dropped. + * debian/patches/0004-more-out-of-tree-build-fixes.patch: new patch; adjust + Makefiles some more to properly deal with the out-of-tree build when + generating headers and documentation. + * debian/control: + - rename packages to follow upstream soname. + - add python-pygments, xmlstarlet, texlive-latex-base and asciidoc to + Build-Depends. + * debian/rules: update due to upstream soname changes. + * debian/*.install: rename and update due to upstream soname changes. + * debian/libnl-3-200.install: netlink config files should be installed to + /etc/libnl, not /etc/libnl3. + * debian/libnl-3-doc.install, + debian/libnl-3-doc.doc-base: update to take into account new paths. + + -- Heiko Stuebner Tue, 06 Nov 2011 21:23:12 +0200 + +libnl3 (3.0-2) unstable; urgency=low + + * Acknowledge NMU + * Install config-files to /etc/libnl3 (Closes: #632790) + + -- Heiko Stuebner Mon, 26 Sep 2011 20:27:45 +0200 + +libnl3 (3.0-1.1) unstable; urgency=low + + * Non-maintainer upload with agreement from Heiko Stuebner + * Add libnl3-udeb package with seperate build for + debian-installer (Closes: #635962). + + -- Gaudenz Steinlin Fri, 29 Jul 2011 23:25:48 +0200 + +libnl3 (3.0-1) unstable; urgency=low + + * New upstream release (Closes: #626098) + see README.Debian for version explanation. + * Update standards to 3.9.2 + + -- Heiko Stuebner Sat, 21 May 2011 19:25:13 +0200 + +libnl2 (2.0-1) unstable; urgency=low + + * New upstream release (Closes: #603765) + * Fix compilation with binutils-gold or ld --no-add-needed + (Closes: #615745) + * Update standards + * Update build dependencies - tetex-live is not necessary + anymore (Closes: #616260) + + -- Heiko Stuebner Sun, 06 Mar 2011 18:20:47 +0100 + +libnl2 (1.99+git20091216-2) unstable; urgency=low + + * add README.source describing the patches in use. + * remove libnl*-provides - libnl2 should stay sepparate + from libnl1 for now + + -- Heiko Stuebner Wed, 10 Mar 2010 18:03:35 +0100 + +libnl2 (1.99+git20091216-1) unstable; urgency=low + + * New upstream snapshot + * New source name to enable installing libnl and libnl2 side by side + * Set myself as new maintainer for libnl2 according to agreement + with Michael Biebl + * Add debug package + * README.Debian warns of possible breakage in this snapshot + * Add Patch 0001 which fixes some errors in the build system + * Add Patch 0002 which adds libnl-?? libs to linker statement + until I can resolve this with upstream + + -- Heiko Stuebner Mon, 15 Feb 2010 21:50:35 +0100 + +libnl (1.1-5) unstable; urgency=low + + * Add symbols file for libnl1. + + -- Michael Biebl Wed, 25 Feb 2009 00:26:05 +0100 + +libnl (1.1-4) unstable; urgency=low + + * debian/control + - Add ${misc:Depends} to all binary packages. + - Bump Build-Depends on debhelper to (>= 7). + * debian/compat + - Bump debhelper compat level to 7. + * debian/rules + - Include debhelper.mk before other files as recommended by the cdbs + documentation. + + -- Michael Biebl Wed, 18 Feb 2009 13:26:53 +0100 + +libnl (1.1-3) unstable; urgency=low + + * debian/control + - Bump Standards-Version to 3.8.0. + * Switch to quilt for patch management. + * Add README.source which refers to the quilt documentation. + * debian/patches/limits.patch + - Add missing include to limits.h. This is required when compiling against + glibc 2.8. Thanks to Kees Cook for the patch. Closes: #501485 + + -- Michael Biebl Wed, 08 Oct 2008 21:34:34 +0200 + +libnl (1.1-2) unstable; urgency=low + + * debian/libnl-doc.doc-base + - Register the API documentation with doc-base. + * debian/control + - Add Suggests: doc-base to libnl-doc. + + -- Michael Biebl Wed, 05 Mar 2008 00:42:54 +0100 + +libnl (1.1-1) unstable; urgency=low + + * New stable upstream release. + * debian/patches/01-ip_mg_alg_internal_only.patch + - Removed, merged upstream. + * debian/control + - Rename binary package libnl1-pre8 to libnl1. + - [libnl1] Add Conflicts/Replaces: libnl1-pre8. + - [libnl-dev] Change Depends to libnl1. + * Rename debian/libnl1-pre8.install to debian/libnl1.install + * debian/copyright + - Minor updates and additions. + + -- Michael Biebl Thu, 10 Jan 2008 16:58:12 +0100 + +libnl (1.0~pre8-1) unstable; urgency=low + + * New upstream release. Closes: #456175 + * debian/control + - Bump Standards-Version to 3.7.3. No further changes required. + - The Vcs-* fields are now officially supported, so remove the XS- prefix. + - Rename binary package libnl1-pre6 to libnl1-pre8. + - [libnl1-pre8] Add Conflicts/Replaces: libnl1-pre6. The two versions are + not coinstallable. + - [libnl-dev] Change Depends to libnl1-pre8. + * Rename debian/libnl1-pre6.install to debian/libnl1-pre8.install. + * debian/patches/10-amd64-linux-types.patch + - Removed, merged upstream. + * debian/patches/01-ip_mg_alg_internal_only.patch + - Pull a fix from upstream. The header linux/ip_mp_alg.h is no longer part + of the linux kernel headers (i.e. linux-libc-dev) so remove it from + netlink/netlink.h. + + -- Michael Biebl Thu, 20 Dec 2007 07:45:03 +0100 + +libnl (1.0~pre6-6) unstable; urgency=low + + * debian/control + - Use the new "Homepage:" field to specify the upstream URL. + - Replace deprecated ${Source-Version} substvar with ${binary:Version}. + - Change Build-Depends: gs-gpl | gs-esp to Build-Depends: ghostscript. + + -- Michael Biebl Mon, 22 Oct 2007 07:15:29 +0200 + +libnl (1.0~pre6-5) unstable; urgency=low + + * debian/control + - Add XS-Vcs-* fields. + - Replace Build-Depends: tetex-bin with texlive-latex-base. teTeX is now + gone, superseded by texlive. + - Add Build-Depends: graphviz, gs-gpl | gs-esp. + The "dot" program is needed for generating the diagram image and "gs" + for the ps to png conversion. + + -- Michael Biebl Sun, 15 Apr 2007 15:45:48 +0200 + +libnl (1.0~pre6-4) unstable; urgency=medium + + * Autobuilders do not distinguish between build-arch and build-indep, they + simply run build. So we have to move doxygen and tetex-bin from + Build-Depends-Indep to Build-Depends. Closes: #408719 + * Urgency medium, as it fixes a FTBFS bug. + + -- Michael Biebl Fri, 12 Jan 2007 11:23:52 +0100 + +libnl (1.0~pre6-3) unstable; urgency=low + + * Build and package the API documentation. Closes: #406497 + * debian/control + - Add Build-Depends-Indep on doxygen and tetex-bin (dvips). + - Add new package libnl-doc. + - Add a "Suggests: libnl-doc" to libnl-dev. + * debian/rules + - Call "make gendoc" to build the API documentation. + * debian/libnl-doc.install + - Added. List the files that should be installed. + + -- Michael Biebl Fri, 12 Jan 2007 10:30:40 +0100 + +libnl (1.0~pre6-2) unstable; urgency=low + + * Update maintainer email address to biebl@debian.org. + + -- Michael Biebl Thu, 19 Oct 2006 20:16:09 +0200 + +libnl (1.0~pre6-1) unstable; urgency=low + + * New upstream release. + * Removed 20-autoconf-dirs.patch, merged upstream. + * Updated debian/copyright, libnl is now licensed under the LGPL 2.1. + * Updated debian/watch. + + -- Michael Biebl Fri, 18 Aug 2006 00:40:34 +0200 + +libnl (1.0~pre6~svn30-1) unstable; urgency=low + + * Updated to svn revision 30. + * Bumped Standards-Version to 3.7.2, no further changes required. + * Now that dak officially supports ~ in the version number, let's make use + of it. + * Some install directories were not set correctly, 20-autoconf-dirs.patch + fixes that. + + -- Michael Biebl Thu, 10 Aug 2006 19:51:42 +0200 + +libnl (0.99+1.0.svn21-4) unstable; urgency=low + + * Do not create bogus /usr/lib/pkg-config directory. Closes: #364601 + + -- Michael Biebl Mon, 24 Apr 2006 15:40:23 +0200 + +libnl (0.99+1.0.svn21-3) unstable; urgency=low + + * Include simple-patchsys.mk in debian/rules. + * Merged debian/patches/10-amd64-linux-types.patch from Ubuntu which fixes + the FTBFS error on AMD64. Closes: #358887 + Thanks to Scott James Remnant for this patch. + + -- Michael Biebl Sat, 1 Apr 2006 04:52:13 +0200 + +libnl (0.99+1.0.svn21-2) unstable; urgency=low + + * Initial upload to unstable. + * Renamed libnl1 to libnl1-pre6 to match the currently used so-name. + Otherwise dependent packages like NM will break on upgrades of libnl. + + -- Michael Biebl Tue, 7 Mar 2006 21:22:09 +0100 + +libnl (0.99+1.0.svn21-1) experimental; urgency=low + + * Initial release. Closes: #286847 + + -- Michael Biebl Tue, 21 Feb 2006 18:36:35 +0100 diff --git a/src/libnl3/debian/compat b/src/libnl3/debian/compat new file mode 100644 index 000000000000..ec635144f600 --- /dev/null +++ b/src/libnl3/debian/compat @@ -0,0 +1 @@ +9 diff --git a/src/libnl3/debian/control b/src/libnl3/debian/control new file mode 100644 index 000000000000..ba5062607bc1 --- /dev/null +++ b/src/libnl3/debian/control @@ -0,0 +1,245 @@ +Source: libnl3 +Section: net +Priority: optional +Maintainer: Heiko Stuebner +Build-Depends: debhelper (>= 9), dh-exec (>= 0.3), cdbs (>= 0.4.93~), bison, flex, + automake, autoconf, dh-autoreconf, linux-libc-dev (>= 3.2.41), pkg-config +Standards-Version: 3.9.6 +Homepage: http://www.infradead.org/~tgr/libnl/ +#Vcs-Git: https://github.com/thom311/libnl/ +#Vcs-Browser: https://github.com/thom311/libnl/ + +Package: libnl-3-200 +Architecture: linux-any +Section: libs +Pre-Depends: ${misc:Pre-Depends} +Depends: ${misc:Depends}, ${shlibs:Depends} +Multi-Arch: same +Description: library for dealing with netlink sockets + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + +Package: libnl-cli-3-200 +Architecture: linux-any +Section: libs +Pre-Depends: ${misc:Pre-Depends} +Depends: libnl-3-200 (= ${binary:Version}), libnl-genl-3-200 (= ${binary:Version}), libnl-nf-3-200 (= ${binary:Version}), libnl-route-3-200 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} +Multi-Arch: same +Description: library for dealing with netlink sockets - cli helpers + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + Library for cli helpers in libnl-utils. + +Package: libnl-utils +Architecture: linux-any +Section: libs +Depends: libnl-cli-3-200 (= ${binary:Version}), libnl-idiag-3-200 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} +Description: Utilities for dealing with netlink sockets + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + These utilities help dealing with netlink sockets. + +Package: libnl-genl-3-200 +Architecture: linux-any +Section: libs +Pre-Depends: ${misc:Pre-Depends} +Depends: libnl-3-200 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} +Multi-Arch: same +Description: library for dealing with netlink sockets - generic netlink + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + API to the generic netlink protocol, an extended version of the netlink + protocol. + +Package: libnl-idiag-3-200 +Architecture: linux-any +Section: libs +Pre-Depends: ${misc:Pre-Depends} +Depends: libnl-3-200 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} +Multi-Arch: same +Description: library for dealing with netlink sockets - inetdiag interface + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + API to the inetdiag netlink protocol, handling inetdiag requests + +Package: libnl-nf-3-200 +Architecture: linux-any +Section: libs +Pre-Depends: ${misc:Pre-Depends} +Depends: libnl-3-200 (= ${binary:Version}), libnl-route-3-200 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} +Multi-Arch: same +Description: library for dealing with netlink sockets - netfilter interface + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + API to netlink based netfilter configuration and monitoring interfaces. + +Package: libnl-route-3-200 +Architecture: linux-any +Section: libs +Pre-Depends: ${misc:Pre-Depends} +Depends: libnl-3-200 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} +Multi-Arch: same +Description: library for dealing with netlink sockets - route interface + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + API to the configuration interfaces of the NETLINK_ROUTE family. + +Package: libnl-xfrm-3-200 +Architecture: linux-any +Section: libs +Pre-Depends: ${misc:Pre-Depends} +Depends: libnl-3-200 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} +Multi-Arch: same +Description: library for dealing with netlink sockets - package transformations + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + API to netlink based package transformations (such as encrypting + their payloads). + +Package: libnl-3-dev +Architecture: linux-any +Section: libdevel +Depends: libnl-3-200 (= ${binary:Version}), ${misc:Depends} +Conflicts: libnl-dev, libnl2-dev +Breaks: libnl3-dev +Replaces: libnl3-dev +Multi-Arch: same +Description: development library and headers for libnl-3 + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + This package contains the headers needed by all libraries and the files + that are needed to build applications using libnl3. + +Package: libnl-cli-3-dev +Architecture: linux-any +Section: libdevel +Depends: libnl-3-dev (= ${binary:Version}), libnl-genl-3-dev (= ${binary:Version}), libnl-nf-3-dev (= ${binary:Version}), libnl-route-3-dev (= ${binary:Version}), libnl-cli-3-200 (= ${binary:Version}), ${misc:Depends} +Multi-Arch: same +Description: development library and headers for libnl-cli-3 + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + This package contains the files that are needed to build applications using + libnl-cli-3. + +Package: libnl-genl-3-dev +Architecture: linux-any +Section: libdevel +Depends: libnl-3-dev (= ${binary:Version}), libnl-genl-3-200 (= ${binary:Version}), ${misc:Depends} +Multi-Arch: same +Description: development library and headers for libnl-genl-3 + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + This package contains the files that are needed to build applications using + libnl-genl-3. + +Package: libnl-idiag-3-dev +Architecture: linux-any +Section: libdevel +Depends: libnl-3-dev (= ${binary:Version}), libnl-idiag-3-200 (= ${binary:Version}), ${misc:Depends} +Multi-Arch: same +Description: development library and headers for libnl-genl-3 + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + This package contains the files that are needed to build applications using + libnl-idiag-3. + +Package: libnl-nf-3-dev +Architecture: linux-any +Section: libdevel +Depends: libnl-3-dev (= ${binary:Version}), libnl-route-3-dev (= ${binary:Version}), libnl-nf-3-200 (= ${binary:Version}), ${misc:Depends} +Multi-Arch: same +Description: development library and headers for libnl-nf-3 + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + This package contains the files that are needed to build applications using + libnl-nf-3. + +Package: libnl-route-3-dev +Architecture: linux-any +Section: libdevel +Depends: libnl-3-dev (= ${binary:Version}), libnl-route-3-200 (= ${binary:Version}), ${misc:Depends} +Multi-Arch: same +Description: development library and headers for libnl-route-3 + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + This package contains the files that are needed to build applications using + libnl-route-3. + +Package: libnl-xfrm-3-dev +Architecture: linux-any +Section: libdevel +Depends: libnl-3-dev (= ${binary:Version}), libnl-xfrm-3-200 (= ${binary:Version}), ${misc:Depends} +Multi-Arch: same +Description: development library and headers for libnl-xfrm-3 + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + This package contains the files that are needed to build applications using + libnl-xfrm-3. + +Package: libnl-3-200-dbg +Architecture: linux-any +Section: debug +Depends: libnl-3-200 (= ${binary:Version}), ${misc:Depends} +Priority: extra +Description: debug symbols for libnl3 + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + This package contains unstripped shared libraries. It is provided primarily + to provide a backtrace with names in a debugger, this makes it somewhat easier + to interpret core dumps. The libraries are installed in /usr/lib/debug and + are automatically used by gdb. + +Package: libnl-3-200-udeb +Architecture: linux-any +XC-Package-Type: udeb +Section: debian-installer +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: library for dealing with netlink sockets + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + This package is a udeb. It's only useful inside of debian-installer. + +Package: libnl-genl-3-200-udeb +Architecture: linux-any +XC-Package-Type: udeb +Section: debian-installer +Depends: libnl-3-200-udeb (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} +Description: library for dealing with netlink sockets - generic netlink + This is a library for applications dealing with netlink sockets. + The library provides an interface for raw netlink messaging and various + netlink family specific interfaces. + . + This package is a udeb. It's only useful inside of debian-installer. diff --git a/src/libnl3/debian/copyright b/src/libnl3/debian/copyright new file mode 100644 index 000000000000..07457363bf67 --- /dev/null +++ b/src/libnl3/debian/copyright @@ -0,0 +1,160 @@ +This package was debianized by Tamer Ahmed on +Tue, 31 Decn 2019 12:00:46 +0000. +The packaging is based on Heiko Stuebner's original packaging +of libnl1. + +It was downloaded from https://github.com/thom311/libnl/releases + +Upstream Author: + Thomas Graf + + +Copyright: + +lib/route/addr.c +include/netlink/route/addr.h + + Copyright (c) Thomas Graf + Baruch Even + + +lib/route/cls/u32.c +lib/route/cls/fw.c +lib/route/sch/htb.c +include/netlink/route/cls/fw.h +include/netlink/route/sch/htb.h + + Copyright (c) Thomas Graf + Copyright (c) Petr Gotthard + Copyright (c) Siemens AG Oesterreich + + + +lib/netfilter/log_msg.c +lib/netfilter/ct.c +include/netlink/netfilter/log_msg.h +include/netlink/netfilter/log.h +lib/netfilter/log_obj.c + + Copyright (c) Thomas Graf + Copyright (c) Philip Craig + Copyright (c) Patrick McHardy + Copyright (c) Secure Computing Corporation + + + +include/netlink/netfilter/queue_msg.h +lib/netfilter/queue_msg_obj.c +lib/netfilter/queue_msg.c +lib/netfilter/queue.c +lib/netfilter/netfilter.c +lib/netfilter/queue_obj.c +include/netlink/netfilter/netfilter.h +include/netlink/netfilter/queue.h +src/nf-queue.c + + Copyright (c) Patrick McHardy + + + +include/netlink/xfrm/selector.h +include/netlink/xfrm/sa.h +include/netlink/xfrm/ae.h +include/netlink/xfrm/sp.h +include/netlink/xfrm/template.h +include/netlink/xfrm/lifetime.h +lib/xfrm/sa.c +lib/xfrm/template.c +lib/xfrm/ae.c +lib/xfrm/sp.c +lib/xfrm/selector.c +lib/xfrm/lifetime.c + + Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + + +All other *.c and *.h files not mentioned above are copyright of: + + Copyright (c) 2003-2006 Thomas Graf + + +License: + +src/nl-addr-add.c +src/nl-addr-list.c +src/nl-cls-add.c +src/cls/utils.c +src/cls/cgroup.c +src/cls/utils.h +src/cls/basic.c +src/nl-addr-delete.c: + + This library 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 version 2 of the License. + + 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. + +On Debian GNU/Linux systems, the complete text of the GNU General +Public License can be found in /usr/share/common-licenses/GPL-2 + + +include/netlink/xfrm/selector.h +include/netlink/xfrm/sa.h +include/netlink/xfrm/ae.h +include/netlink/xfrm/sp.h +include/netlink/xfrm/template.h +include/netlink/xfrm/lifetime.h +lib/xfrm/sa.c +lib/xfrm/template.c +lib/xfrm/ae.c +lib/xfrm/sp.c +lib/xfrm/selector.c +lib/xfrm/lifetime.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + + Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +All other *.c and *.h files not mentioned above: + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation version 2.1 of the License. + + 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. + +On Debian GNU/Linux systems, the complete text of the GNU Lesser General +Public License can be found in /usr/share/common-licenses/LGPL-2.1 + diff --git a/src/libnl3/debian/gbp.conf b/src/libnl3/debian/gbp.conf new file mode 100644 index 000000000000..a504bacc7748 --- /dev/null +++ b/src/libnl3/debian/gbp.conf @@ -0,0 +1,16 @@ +# Configuration file for git-buildpackage and friends + +[DEFAULT] +# the default build command: +#builder = debuild -i -I +# the default clean command: +#cleaner = debuild clean +# the default branch for upstream sources: +upstream-branch = upstream-dist +# the default branch for the debian patch: +#debian-branch = master +# the default tag formats used: +#upstream-tag = upstream/%(version)s +#debian-tag = debian/%(version)s +# use pristine-tar: +pristine-tar = true diff --git a/src/libnl3/debian/libnl-3-200-udeb.install b/src/libnl3/debian/libnl-3-200-udeb.install new file mode 100644 index 000000000000..4b3a77ce011d --- /dev/null +++ b/src/libnl3/debian/libnl-3-200-udeb.install @@ -0,0 +1 @@ +usr/lib/*/libnl-3.so.* lib diff --git a/src/libnl3/debian/libnl-3-200.install b/src/libnl3/debian/libnl-3-200.install new file mode 100755 index 000000000000..0a6aa3850b2c --- /dev/null +++ b/src/libnl3/debian/libnl-3-200.install @@ -0,0 +1,3 @@ +#!/usr/bin/dh-exec +debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/libnl-3*.so.* lib/${DEB_HOST_MULTIARCH}/ +debian/tmp/etc/libnl/* etc/libnl-3 diff --git a/src/libnl3/debian/libnl-3-200.symbols b/src/libnl3/debian/libnl-3-200.symbols new file mode 100644 index 000000000000..119e0554920f --- /dev/null +++ b/src/libnl3/debian/libnl-3-200.symbols @@ -0,0 +1,661 @@ +libnl-3.so.200 libnl-3-200 #MINVER# + __flags2str@Base 3.5.0-1 + __flags2str@libnl_3 3.5.0-1 + __list_str2type@Base 3.5.0-1 + __list_str2type@libnl_3 3.5.0-1 + __list_type2str@Base 3.5.0-1 + __list_type2str@libnl_3 3.5.0-1 + __nl_cache_mngt_require@Base 3.5.0-1 + __nl_cache_mngt_require@libnl_3 3.5.0-1 + __nl_cache_ops_lookup@Base 3.5.0-1 + __nl_read_num_str_file@Base 3.5.0-1 + __nl_read_num_str_file@libnl_3 3.5.0-1 + __str2flags@Base 3.5.0-1 + __str2flags@libnl_3 3.5.0-1 + __str2type@Base 3.5.0-1 + __str2type@libnl_3 3.5.0-1 + __trans_list_add@Base 3.5.0-1 + __trans_list_add@libnl_3 3.5.0-1 + __trans_list_clear@Base 3.5.0-1 + __trans_list_clear@libnl_3 3.5.0-1 + __type2str@Base 3.5.0-1 + __type2str@libnl_3 3.5.0-1 + _nl_socket_generate_local_port_no_release@Base 3.5.0-1 + _nl_socket_is_local_port_unspecified@Base 3.5.0-1 + _nl_socket_set_local_port_no_release@Base 3.5.0-1 + _nl_socket_used_ports_release_all@Base 3.5.0-1 + _nl_socket_used_ports_set@Base 3.5.0-1 + dump_from_ops@Base 3.5.0-1 + libnl_3@libnl_3 3.5.0-1 + libnl_3_2_26@libnl_3_2_26 3.5.0-1 + libnl_3_2_27@libnl_3_2_27 3.5.0-1 + libnl_3_2_28@libnl_3_2_28 3.5.0-1 + libnl_3_2_29@libnl_3_2_29 3.5.0-1 + libnl_3_5@libnl_3_5 3.5.0-1 + nl_addr2str@Base 3.5.0-1 + nl_addr2str@libnl_3 3.5.0-1 + nl_addr_alloc@Base 3.5.0-1 + nl_addr_alloc@libnl_3 3.5.0-1 + nl_addr_alloc_attr@Base 3.5.0-1 + nl_addr_alloc_attr@libnl_3 3.5.0-1 + nl_addr_build@Base 3.5.0-1 + nl_addr_build@libnl_3 3.5.0-1 + nl_addr_clone@Base 3.5.0-1 + nl_addr_clone@libnl_3 3.5.0-1 + nl_addr_cmp@Base 3.5.0-1 + nl_addr_cmp@libnl_3 3.5.0-1 + nl_addr_cmp_prefix@Base 3.5.0-1 + nl_addr_cmp_prefix@libnl_3 3.5.0-1 + nl_addr_fill_sockaddr@Base 3.5.0-1 + nl_addr_fill_sockaddr@libnl_3 3.5.0-1 + nl_addr_get@Base 3.5.0-1 + nl_addr_get@libnl_3 3.5.0-1 + nl_addr_get_binary_addr@Base 3.5.0-1 + nl_addr_get_binary_addr@libnl_3 3.5.0-1 + nl_addr_get_family@Base 3.5.0-1 + nl_addr_get_family@libnl_3 3.5.0-1 + nl_addr_get_len@Base 3.5.0-1 + nl_addr_get_len@libnl_3 3.5.0-1 + nl_addr_get_prefixlen@Base 3.5.0-1 + nl_addr_get_prefixlen@libnl_3 3.5.0-1 + nl_addr_guess_family@Base 3.5.0-1 + nl_addr_guess_family@libnl_3 3.5.0-1 + nl_addr_info@Base 3.5.0-1 + nl_addr_info@libnl_3 3.5.0-1 + nl_addr_iszero@Base 3.5.0-1 + nl_addr_iszero@libnl_3 3.5.0-1 + nl_addr_parse@Base 3.5.0-1 + nl_addr_parse@libnl_3 3.5.0-1 + nl_addr_put@Base 3.5.0-1 + nl_addr_put@libnl_3 3.5.0-1 + nl_addr_resolve@Base 3.5.0-1 + nl_addr_resolve@libnl_3 3.5.0-1 + nl_addr_set_binary_addr@Base 3.5.0-1 + nl_addr_set_binary_addr@libnl_3 3.5.0-1 + nl_addr_set_family@Base 3.5.0-1 + nl_addr_set_family@libnl_3 3.5.0-1 + nl_addr_set_prefixlen@Base 3.5.0-1 + nl_addr_set_prefixlen@libnl_3 3.5.0-1 + nl_addr_shared@Base 3.5.0-1 + nl_addr_shared@libnl_3 3.5.0-1 + nl_addr_valid@Base 3.5.0-1 + nl_addr_valid@libnl_3 3.5.0-1 + nl_af2str@Base 3.5.0-1 + nl_af2str@libnl_3 3.5.0-1 + nl_auto_complete@Base 3.5.0-1 + nl_auto_complete@libnl_3 3.5.0-1 + nl_cache_add@Base 3.5.0-1 + nl_cache_add@libnl_3 3.5.0-1 + nl_cache_alloc@Base 3.5.0-1 + nl_cache_alloc@libnl_3 3.5.0-1 + nl_cache_alloc_and_fill@Base 3.5.0-1 + nl_cache_alloc_and_fill@libnl_3 3.5.0-1 + nl_cache_alloc_name@Base 3.5.0-1 + nl_cache_alloc_name@libnl_3 3.5.0-1 + nl_cache_clear@Base 3.5.0-1 + nl_cache_clear@libnl_3 3.5.0-1 + nl_cache_clone@Base 3.5.0-1 + nl_cache_clone@libnl_3 3.5.0-1 + nl_cache_dump@Base 3.5.0-1 + nl_cache_dump@libnl_3 3.5.0-1 + nl_cache_dump_filter@Base 3.5.0-1 + nl_cache_dump_filter@libnl_3 3.5.0-1 + nl_cache_find@Base 3.5.0-1 + nl_cache_find@libnl_3 3.5.0-1 + nl_cache_foreach@Base 3.5.0-1 + nl_cache_foreach@libnl_3 3.5.0-1 + nl_cache_foreach_filter@Base 3.5.0-1 + nl_cache_foreach_filter@libnl_3 3.5.0-1 + nl_cache_free@Base 3.5.0-1 + nl_cache_free@libnl_3 3.5.0-1 + nl_cache_get@Base 3.5.0-1 + nl_cache_get@libnl_3 3.5.0-1 + nl_cache_get_first@Base 3.5.0-1 + nl_cache_get_first@libnl_3 3.5.0-1 + nl_cache_get_last@Base 3.5.0-1 + nl_cache_get_last@libnl_3 3.5.0-1 + nl_cache_get_next@Base 3.5.0-1 + nl_cache_get_next@libnl_3 3.5.0-1 + nl_cache_get_ops@Base 3.5.0-1 + nl_cache_get_ops@libnl_3 3.5.0-1 + nl_cache_get_prev@Base 3.5.0-1 + nl_cache_get_prev@libnl_3 3.5.0-1 + nl_cache_include@Base 3.5.0-1 + nl_cache_include@libnl_3 3.5.0-1 + nl_cache_include_v2@libnl_3_2_29 3.5.0-1 + nl_cache_is_empty@Base 3.5.0-1 + nl_cache_is_empty@libnl_3 3.5.0-1 + nl_cache_mark_all@Base 3.5.0-1 + nl_cache_mark_all@libnl_3 3.5.0-1 + nl_cache_mngr_add@Base 3.5.0-1 + nl_cache_mngr_add@libnl_3 3.5.0-1 + nl_cache_mngr_add_cache@Base 3.5.0-1 + nl_cache_mngr_add_cache@libnl_3 3.5.0-1 + nl_cache_mngr_add_cache_v2@libnl_3_2_29 3.5.0-1 + nl_cache_mngr_alloc@Base 3.5.0-1 + nl_cache_mngr_alloc@libnl_3 3.5.0-1 + nl_cache_mngr_data_ready@Base 3.5.0-1 + nl_cache_mngr_data_ready@libnl_3 3.5.0-1 + nl_cache_mngr_free@Base 3.5.0-1 + nl_cache_mngr_free@libnl_3 3.5.0-1 + nl_cache_mngr_get_fd@Base 3.5.0-1 + nl_cache_mngr_get_fd@libnl_3 3.5.0-1 + nl_cache_mngr_info@Base 3.5.0-1 + nl_cache_mngr_info@libnl_3 3.5.0-1 + nl_cache_mngr_poll@Base 3.5.0-1 + nl_cache_mngr_poll@libnl_3 3.5.0-1 + nl_cache_mngt_provide@Base 3.5.0-1 + nl_cache_mngt_provide@libnl_3 3.5.0-1 + nl_cache_mngt_register@Base 3.5.0-1 + nl_cache_mngt_register@libnl_3 3.5.0-1 + nl_cache_mngt_require@Base 3.5.0-1 + nl_cache_mngt_require@libnl_3 3.5.0-1 + nl_cache_mngt_require_safe@Base 3.5.0-1 + nl_cache_mngt_require_safe@libnl_3 3.5.0-1 + nl_cache_mngt_unprovide@Base 3.5.0-1 + nl_cache_mngt_unprovide@libnl_3 3.5.0-1 + nl_cache_mngt_unregister@Base 3.5.0-1 + nl_cache_mngt_unregister@libnl_3 3.5.0-1 + nl_cache_move@Base 3.5.0-1 + nl_cache_move@libnl_3 3.5.0-1 + nl_cache_nitems@Base 3.5.0-1 + nl_cache_nitems@libnl_3 3.5.0-1 + nl_cache_nitems_filter@Base 3.5.0-1 + nl_cache_nitems_filter@libnl_3 3.5.0-1 + nl_cache_ops_associate@Base 3.5.0-1 + nl_cache_ops_associate@libnl_3 3.5.0-1 + nl_cache_ops_associate_safe@Base 3.5.0-1 + nl_cache_ops_associate_safe@libnl_3 3.5.0-1 + nl_cache_ops_foreach@Base 3.5.0-1 + nl_cache_ops_foreach@libnl_3 3.5.0-1 + nl_cache_ops_get@Base 3.5.0-1 + nl_cache_ops_get@libnl_3 3.5.0-1 + nl_cache_ops_lookup@Base 3.5.0-1 + nl_cache_ops_lookup@libnl_3 3.5.0-1 + nl_cache_ops_lookup_safe@Base 3.5.0-1 + nl_cache_ops_lookup_safe@libnl_3 3.5.0-1 + nl_cache_ops_put@Base 3.5.0-1 + nl_cache_ops_put@libnl_3 3.5.0-1 + nl_cache_ops_set_flags@Base 3.5.0-1 + nl_cache_ops_set_flags@libnl_3 3.5.0-1 + nl_cache_parse@Base 3.5.0-1 + nl_cache_parse@libnl_3 3.5.0-1 + nl_cache_parse_and_add@Base 3.5.0-1 + nl_cache_parse_and_add@libnl_3 3.5.0-1 + nl_cache_pickup@Base 3.5.0-1 + nl_cache_pickup@libnl_3 3.5.0-1 + nl_cache_pickup_checkdup@Base 3.5.0-1 + nl_cache_pickup_checkdup@libnl_3 3.5.0-1 + nl_cache_put@Base 3.5.0-1 + nl_cache_put@libnl_3 3.5.0-1 + nl_cache_refill@Base 3.5.0-1 + nl_cache_refill@libnl_3 3.5.0-1 + nl_cache_remove@Base 3.5.0-1 + nl_cache_remove@libnl_3 3.5.0-1 + nl_cache_resync@Base 3.5.0-1 + nl_cache_resync@libnl_3 3.5.0-1 + nl_cache_search@Base 3.5.0-1 + nl_cache_search@libnl_3 3.5.0-1 + nl_cache_set_arg1@Base 3.5.0-1 + nl_cache_set_arg1@libnl_3 3.5.0-1 + nl_cache_set_arg2@Base 3.5.0-1 + nl_cache_set_arg2@libnl_3 3.5.0-1 + nl_cache_set_flags@Base 3.5.0-1 + nl_cache_set_flags@libnl_3 3.5.0-1 + nl_cache_subset@Base 3.5.0-1 + nl_cache_subset@libnl_3 3.5.0-1 + nl_cancel_down_bits@Base 3.5.0-1 + nl_cancel_down_bits@libnl_3 3.5.0-1 + nl_cancel_down_bytes@Base 3.5.0-1 + nl_cancel_down_bytes@libnl_3 3.5.0-1 + nl_cancel_down_us@Base 3.5.0-1 + nl_cancel_down_us@libnl_3 3.5.0-1 + nl_cb_active_type@Base 3.5.0-1 + nl_cb_active_type@libnl_3 3.5.0-1 + nl_cb_alloc@Base 3.5.0-1 + nl_cb_alloc@libnl_3 3.5.0-1 + nl_cb_clone@Base 3.5.0-1 + nl_cb_clone@libnl_3 3.5.0-1 + nl_cb_err@Base 3.5.0-1 + nl_cb_err@libnl_3 3.5.0-1 + nl_cb_get@Base 3.5.0-1 + nl_cb_get@libnl_3 3.5.0-1 + nl_cb_overwrite_recv@Base 3.5.0-1 + nl_cb_overwrite_recv@libnl_3 3.5.0-1 + nl_cb_overwrite_recvmsgs@Base 3.5.0-1 + nl_cb_overwrite_recvmsgs@libnl_3 3.5.0-1 + nl_cb_overwrite_send@Base 3.5.0-1 + nl_cb_overwrite_send@libnl_3 3.5.0-1 + nl_cb_put@Base 3.5.0-1 + nl_cb_put@libnl_3 3.5.0-1 + nl_cb_set@Base 3.5.0-1 + nl_cb_set@libnl_3 3.5.0-1 + nl_cb_set_all@Base 3.5.0-1 + nl_cb_set_all@libnl_3 3.5.0-1 + nl_close@Base 3.5.0-1 + nl_close@libnl_3 3.5.0-1 + nl_complete_msg@Base 3.5.0-1 + nl_complete_msg@libnl_3 3.5.0-1 + nl_connect@Base 3.5.0-1 + nl_connect@libnl_3 3.5.0-1 + nl_data_alloc@Base 3.5.0-1 + nl_data_alloc@libnl_3 3.5.0-1 + nl_data_alloc_attr@Base 3.5.0-1 + nl_data_alloc_attr@libnl_3 3.5.0-1 + nl_data_append@Base 3.5.0-1 + nl_data_append@libnl_3 3.5.0-1 + nl_data_clone@Base 3.5.0-1 + nl_data_clone@libnl_3 3.5.0-1 + nl_data_cmp@Base 3.5.0-1 + nl_data_cmp@libnl_3 3.5.0-1 + nl_data_free@Base 3.5.0-1 + nl_data_free@libnl_3 3.5.0-1 + nl_data_get@Base 3.5.0-1 + nl_data_get@libnl_3 3.5.0-1 + nl_data_get_size@Base 3.5.0-1 + nl_data_get_size@libnl_3 3.5.0-1 + nl_debug@Base 3.5.0-1 + nl_debug@libnl_3 3.5.0-1 + nl_debug_dp@Base 3.5.0-1 + nl_debug_dp@libnl_3 3.5.0-1 + nl_dump@Base 3.5.0-1 + nl_dump@libnl_3 3.5.0-1 + nl_dump_line@Base 3.5.0-1 + nl_dump_line@libnl_3 3.5.0-1 + nl_ether_proto2str@Base 3.5.0-1 + nl_ether_proto2str@libnl_3 3.5.0-1 + nl_get_psched_hz@Base 3.5.0-1 + nl_get_psched_hz@libnl_3 3.5.0-1 + nl_get_user_hz@Base 3.5.0-1 + nl_get_user_hz@libnl_3 3.5.0-1 + nl_geterror@Base 3.5.0-1 + nl_geterror@libnl_3 3.5.0-1 + nl_has_capability@Base 3.5.0-1 + nl_has_capability@libnl_3 3.5.0-1 + nl_hash@Base 3.5.0-1 + nl_hash@libnl_3 3.5.0-1 + nl_hash_any@Base 3.5.0-1 + nl_hash_any@libnl_3 3.5.0-1 + nl_hash_table_add@Base 3.5.0-1 + nl_hash_table_add@libnl_3 3.5.0-1 + nl_hash_table_alloc@Base 3.5.0-1 + nl_hash_table_alloc@libnl_3 3.5.0-1 + nl_hash_table_del@Base 3.5.0-1 + nl_hash_table_del@libnl_3 3.5.0-1 + nl_hash_table_free@Base 3.5.0-1 + nl_hash_table_free@libnl_3 3.5.0-1 + nl_hash_table_lookup@Base 3.5.0-1 + nl_hash_table_lookup@libnl_3 3.5.0-1 + nl_ip_proto2str@Base 3.5.0-1 + nl_ip_proto2str@libnl_3 3.5.0-1 + nl_join_groups@Base 3.5.0-1 + nl_join_groups@libnl_3 3.5.0-1 + nl_llproto2str@Base 3.5.0-1 + nl_llproto2str@libnl_3 3.5.0-1 + nl_msec2str@Base 3.5.0-1 + nl_msec2str@libnl_3 3.5.0-1 + nl_msg_dump@Base 3.5.0-1 + nl_msg_dump@libnl_3 3.5.0-1 + nl_msg_parse@Base 3.5.0-1 + nl_msg_parse@libnl_3 3.5.0-1 + nl_msgtype_lookup@Base 3.5.0-1 + nl_msgtype_lookup@libnl_3 3.5.0-1 + nl_new_line@Base 3.5.0-1 + nl_new_line@libnl_3 3.5.0-1 + nl_nlfamily2str@Base 3.5.0-1 + nl_nlfamily2str@libnl_3 3.5.0-1 + nl_nlmsg_flags2str@Base 3.5.0-1 + nl_nlmsg_flags2str@libnl_3 3.5.0-1 + nl_nlmsgtype2str@Base 3.5.0-1 + nl_nlmsgtype2str@libnl_3 3.5.0-1 + nl_object_alloc@Base 3.5.0-1 + nl_object_alloc@libnl_3 3.5.0-1 + nl_object_alloc_name@Base 3.5.0-1 + nl_object_alloc_name@libnl_3 3.5.0-1 + nl_object_attr_list@Base 3.5.0-1 + nl_object_attr_list@libnl_3 3.5.0-1 + nl_object_attrs2str@Base 3.5.0-1 + nl_object_attrs2str@libnl_3 3.5.0-1 + nl_object_clone@Base 3.5.0-1 + nl_object_clone@libnl_3 3.5.0-1 + nl_object_diff64@libnl_3_2_28 3.5.0-1 + nl_object_diff@Base 3.5.0-1 + nl_object_diff@libnl_3 3.5.0-1 + nl_object_dump@Base 3.5.0-1 + nl_object_dump@libnl_3 3.5.0-1 + nl_object_dump_buf@Base 3.5.0-1 + nl_object_dump_buf@libnl_3 3.5.0-1 + nl_object_free@Base 3.5.0-1 + nl_object_free@libnl_3 3.5.0-1 + nl_object_get@Base 3.5.0-1 + nl_object_get@libnl_3 3.5.0-1 + nl_object_get_cache@Base 3.5.0-1 + nl_object_get_cache@libnl_3 3.5.0-1 + nl_object_get_id_attrs@Base 3.5.0-1 + nl_object_get_id_attrs@libnl_3 3.5.0-1 + nl_object_get_msgtype@Base 3.5.0-1 + nl_object_get_msgtype@libnl_3 3.5.0-1 + nl_object_get_ops@Base 3.5.0-1 + nl_object_get_ops@libnl_3 3.5.0-1 + nl_object_get_refcnt@Base 3.5.0-1 + nl_object_get_refcnt@libnl_3 3.5.0-1 + nl_object_get_type@Base 3.5.0-1 + nl_object_get_type@libnl_3 3.5.0-1 + nl_object_identical@Base 3.5.0-1 + nl_object_identical@libnl_3 3.5.0-1 + nl_object_is_marked@Base 3.5.0-1 + nl_object_is_marked@libnl_3 3.5.0-1 + nl_object_keygen@Base 3.5.0-1 + nl_object_keygen@libnl_3 3.5.0-1 + nl_object_mark@Base 3.5.0-1 + nl_object_mark@libnl_3 3.5.0-1 + nl_object_match_filter@Base 3.5.0-1 + nl_object_match_filter@libnl_3 3.5.0-1 + nl_object_put@Base 3.5.0-1 + nl_object_put@libnl_3 3.5.0-1 + nl_object_shared@Base 3.5.0-1 + nl_object_shared@libnl_3 3.5.0-1 + nl_object_unmark@Base 3.5.0-1 + nl_object_unmark@libnl_3 3.5.0-1 + nl_object_update@Base 3.5.0-1 + nl_object_update@libnl_3 3.5.0-1 + nl_perror@Base 3.5.0-1 + nl_perror@libnl_3 3.5.0-1 + nl_pickup@Base 3.5.0-1 + nl_pickup@libnl_3 3.5.0-1 + nl_pickup_keep_syserr@Base 3.5.0-1 + nl_pickup_keep_syserr@libnl_3 3.5.0-1 + nl_prob2int@Base 3.5.0-1 + nl_prob2int@libnl_3 3.5.0-1 + nl_rate2str@Base 3.5.0-1 + nl_rate2str@libnl_3 3.5.0-1 + nl_recv@Base 3.5.0-1 + nl_recv@libnl_3 3.5.0-1 + nl_recvmsgs@Base 3.5.0-1 + nl_recvmsgs@libnl_3 3.5.0-1 + nl_recvmsgs_default@Base 3.5.0-1 + nl_recvmsgs_default@libnl_3 3.5.0-1 + nl_recvmsgs_report@Base 3.5.0-1 + nl_recvmsgs_report@libnl_3 3.5.0-1 + nl_send@Base 3.5.0-1 + nl_send@libnl_3 3.5.0-1 + nl_send_auto@Base 3.5.0-1 + nl_send_auto@libnl_3 3.5.0-1 + nl_send_auto_complete@Base 3.5.0-1 + nl_send_auto_complete@libnl_3 3.5.0-1 + nl_send_iovec@Base 3.5.0-1 + nl_send_iovec@libnl_3 3.5.0-1 + nl_send_simple@Base 3.5.0-1 + nl_send_simple@libnl_3 3.5.0-1 + nl_send_sync@Base 3.5.0-1 + nl_send_sync@libnl_3 3.5.0-1 + nl_sendmsg@Base 3.5.0-1 + nl_sendmsg@libnl_3 3.5.0-1 + nl_sendto@Base 3.5.0-1 + nl_sendto@libnl_3 3.5.0-1 + nl_size2int@Base 3.5.0-1 + nl_size2int@libnl_3 3.5.0-1 + nl_size2str@Base 3.5.0-1 + nl_size2str@libnl_3 3.5.0-1 + nl_socket_add_membership@Base 3.5.0-1 + nl_socket_add_membership@libnl_3 3.5.0-1 + nl_socket_add_memberships@Base 3.5.0-1 + nl_socket_add_memberships@libnl_3 3.5.0-1 + nl_socket_alloc@Base 3.5.0-1 + nl_socket_alloc@libnl_3 3.5.0-1 + nl_socket_alloc_cb@Base 3.5.0-1 + nl_socket_alloc_cb@libnl_3 3.5.0-1 + nl_socket_disable_auto_ack@Base 3.5.0-1 + nl_socket_disable_auto_ack@libnl_3 3.5.0-1 + nl_socket_disable_msg_peek@Base 3.5.0-1 + nl_socket_disable_msg_peek@libnl_3 3.5.0-1 + nl_socket_disable_seq_check@Base 3.5.0-1 + nl_socket_disable_seq_check@libnl_3 3.5.0-1 + nl_socket_drop_membership@Base 3.5.0-1 + nl_socket_drop_membership@libnl_3 3.5.0-1 + nl_socket_drop_memberships@Base 3.5.0-1 + nl_socket_drop_memberships@libnl_3 3.5.0-1 + nl_socket_enable_auto_ack@Base 3.5.0-1 + nl_socket_enable_auto_ack@libnl_3 3.5.0-1 + nl_socket_enable_msg_peek@Base 3.5.0-1 + nl_socket_enable_msg_peek@libnl_3 3.5.0-1 + nl_socket_free@Base 3.5.0-1 + nl_socket_free@libnl_3 3.5.0-1 + nl_socket_get_cb@Base 3.5.0-1 + nl_socket_get_cb@libnl_3 3.5.0-1 + nl_socket_get_fd@Base 3.5.0-1 + nl_socket_get_fd@libnl_3 3.5.0-1 + nl_socket_get_local_port@Base 3.5.0-1 + nl_socket_get_local_port@libnl_3 3.5.0-1 + nl_socket_get_msg_buf_size@Base 3.5.0-1 + nl_socket_get_msg_buf_size@libnl_3 3.5.0-1 + nl_socket_get_peer_groups@Base 3.5.0-1 + nl_socket_get_peer_groups@libnl_3 3.5.0-1 + nl_socket_get_peer_port@Base 3.5.0-1 + nl_socket_get_peer_port@libnl_3 3.5.0-1 + nl_socket_modify_cb@Base 3.5.0-1 + nl_socket_modify_cb@libnl_3 3.5.0-1 + nl_socket_modify_err_cb@Base 3.5.0-1 + nl_socket_modify_err_cb@libnl_3 3.5.0-1 + nl_socket_recv_pktinfo@Base 3.5.0-1 + nl_socket_recv_pktinfo@libnl_3 3.5.0-1 + nl_socket_set_buffer_size@Base 3.5.0-1 + nl_socket_set_buffer_size@libnl_3 3.5.0-1 + nl_socket_set_cb@Base 3.5.0-1 + nl_socket_set_cb@libnl_3 3.5.0-1 + nl_socket_set_fd@Base 3.5.0-1 + nl_socket_set_fd@libnl_3_2_26 3.5.0-1 + nl_socket_set_local_port@Base 3.5.0-1 + nl_socket_set_local_port@libnl_3 3.5.0-1 + nl_socket_set_msg_buf_size@Base 3.5.0-1 + nl_socket_set_msg_buf_size@libnl_3 3.5.0-1 + nl_socket_set_nonblocking@Base 3.5.0-1 + nl_socket_set_nonblocking@libnl_3 3.5.0-1 + nl_socket_set_passcred@Base 3.5.0-1 + nl_socket_set_passcred@libnl_3 3.5.0-1 + nl_socket_set_peer_groups@Base 3.5.0-1 + nl_socket_set_peer_groups@libnl_3 3.5.0-1 + nl_socket_set_peer_port@Base 3.5.0-1 + nl_socket_set_peer_port@libnl_3 3.5.0-1 + nl_socket_use_seq@Base 3.5.0-1 + nl_socket_use_seq@libnl_3 3.5.0-1 + nl_str2af@Base 3.5.0-1 + nl_str2af@libnl_3 3.5.0-1 + nl_str2ether_proto@Base 3.5.0-1 + nl_str2ether_proto@libnl_3 3.5.0-1 + nl_str2ip_proto@Base 3.5.0-1 + nl_str2ip_proto@libnl_3 3.5.0-1 + nl_str2llproto@Base 3.5.0-1 + nl_str2llproto@libnl_3 3.5.0-1 + nl_str2msec@Base 3.5.0-1 + nl_str2msec@libnl_3 3.5.0-1 + nl_str2nlfamily@Base 3.5.0-1 + nl_str2nlfamily@libnl_3 3.5.0-1 + nl_str2nlmsgtype@Base 3.5.0-1 + nl_str2nlmsgtype@libnl_3 3.5.0-1 + nl_strerror_l@libnl_3_2_29 3.5.0-1 + nl_syserr2nlerr@Base 3.5.0-1 + nl_syserr2nlerr@libnl_3 3.5.0-1 + nl_ticks2us@Base 3.5.0-1 + nl_ticks2us@libnl_3 3.5.0-1 + nl_us2ticks@Base 3.5.0-1 + nl_us2ticks@libnl_3 3.5.0-1 + nl_ver_maj@Base 3.5.0-1 + nl_ver_maj@libnl_3 3.5.0-1 + nl_ver_mic@Base 3.5.0-1 + nl_ver_mic@libnl_3 3.5.0-1 + nl_ver_min@Base 3.5.0-1 + nl_ver_min@libnl_3 3.5.0-1 + nl_ver_num@Base 3.5.0-1 + nl_ver_num@libnl_3 3.5.0-1 + nl_wait_for_ack@Base 3.5.0-1 + nl_wait_for_ack@libnl_3 3.5.0-1 + nla_attr_size@Base 3.5.0-1 + nla_attr_size@libnl_3 3.5.0-1 + nla_data@Base 3.5.0-1 + nla_data@libnl_3 3.5.0-1 + nla_find@Base 3.5.0-1 + nla_find@libnl_3 3.5.0-1 + nla_get_flag@Base 3.5.0-1 + nla_get_flag@libnl_3 3.5.0-1 + nla_get_msecs@Base 3.5.0-1 + nla_get_msecs@libnl_3 3.5.0-1 + nla_get_s16@Base 3.5.0-1 + nla_get_s16@libnl_3_2_27 3.5.0-1 + nla_get_s32@Base 3.5.0-1 + nla_get_s32@libnl_3_2_27 3.5.0-1 + nla_get_s64@Base 3.5.0-1 + nla_get_s64@libnl_3_2_27 3.5.0-1 + nla_get_s8@Base 3.5.0-1 + nla_get_s8@libnl_3_2_27 3.5.0-1 + nla_get_string@Base 3.5.0-1 + nla_get_string@libnl_3 3.5.0-1 + nla_get_u16@Base 3.5.0-1 + nla_get_u16@libnl_3 3.5.0-1 + nla_get_u32@Base 3.5.0-1 + nla_get_u32@libnl_3 3.5.0-1 + nla_get_u64@Base 3.5.0-1 + nla_get_u64@libnl_3 3.5.0-1 + nla_get_u8@Base 3.5.0-1 + nla_get_u8@libnl_3 3.5.0-1 + nla_is_nested@Base 3.5.0-1 + nla_is_nested@libnl_3 3.5.0-1 + nla_len@Base 3.5.0-1 + nla_len@libnl_3 3.5.0-1 + nla_memcmp@Base 3.5.0-1 + nla_memcmp@libnl_3 3.5.0-1 + nla_memcpy@Base 3.5.0-1 + nla_memcpy@libnl_3 3.5.0-1 + nla_nest_cancel@Base 3.5.0-1 + nla_nest_cancel@libnl_3 3.5.0-1 + nla_nest_end@Base 3.5.0-1 + nla_nest_end@libnl_3 3.5.0-1 + nla_nest_end_keep_empty@libnl_3_5 3.5.0-1 + nla_nest_start@Base 3.5.0-1 + nla_nest_start@libnl_3 3.5.0-1 + nla_next@Base 3.5.0-1 + nla_next@libnl_3 3.5.0-1 + nla_ok@Base 3.5.0-1 + nla_ok@libnl_3 3.5.0-1 + nla_padlen@Base 3.5.0-1 + nla_padlen@libnl_3 3.5.0-1 + nla_parse@Base 3.5.0-1 + nla_parse@libnl_3 3.5.0-1 + nla_parse_nested@Base 3.5.0-1 + nla_parse_nested@libnl_3 3.5.0-1 + nla_put@Base 3.5.0-1 + nla_put@libnl_3 3.5.0-1 + nla_put_addr@Base 3.5.0-1 + nla_put_addr@libnl_3 3.5.0-1 + nla_put_data@Base 3.5.0-1 + nla_put_data@libnl_3 3.5.0-1 + nla_put_flag@Base 3.5.0-1 + nla_put_flag@libnl_3 3.5.0-1 + nla_put_msecs@Base 3.5.0-1 + nla_put_msecs@libnl_3 3.5.0-1 + nla_put_nested@Base 3.5.0-1 + nla_put_nested@libnl_3 3.5.0-1 + nla_put_s16@Base 3.5.0-1 + nla_put_s16@libnl_3_2_27 3.5.0-1 + nla_put_s32@Base 3.5.0-1 + nla_put_s32@libnl_3_2_27 3.5.0-1 + nla_put_s64@Base 3.5.0-1 + nla_put_s64@libnl_3_2_27 3.5.0-1 + nla_put_s8@Base 3.5.0-1 + nla_put_s8@libnl_3_2_27 3.5.0-1 + nla_put_string@Base 3.5.0-1 + nla_put_string@libnl_3 3.5.0-1 + nla_put_u16@Base 3.5.0-1 + nla_put_u16@libnl_3 3.5.0-1 + nla_put_u32@Base 3.5.0-1 + nla_put_u32@libnl_3 3.5.0-1 + nla_put_u64@Base 3.5.0-1 + nla_put_u64@libnl_3 3.5.0-1 + nla_put_u8@Base 3.5.0-1 + nla_put_u8@libnl_3 3.5.0-1 + nla_reserve@Base 3.5.0-1 + nla_reserve@libnl_3 3.5.0-1 + nla_strcmp@Base 3.5.0-1 + nla_strcmp@libnl_3 3.5.0-1 + nla_strdup@Base 3.5.0-1 + nla_strdup@libnl_3 3.5.0-1 + nla_strlcpy@Base 3.5.0-1 + nla_strlcpy@libnl_3 3.5.0-1 + nla_total_size@Base 3.5.0-1 + nla_total_size@libnl_3 3.5.0-1 + nla_type@Base 3.5.0-1 + nla_type@libnl_3 3.5.0-1 + nla_validate@Base 3.5.0-1 + nla_validate@libnl_3 3.5.0-1 + nlmsg_alloc@Base 3.5.0-1 + nlmsg_alloc@libnl_3 3.5.0-1 + nlmsg_alloc_simple@Base 3.5.0-1 + nlmsg_alloc_simple@libnl_3 3.5.0-1 + nlmsg_alloc_size@Base 3.5.0-1 + nlmsg_alloc_size@libnl_3 3.5.0-1 + nlmsg_append@Base 3.5.0-1 + nlmsg_append@libnl_3 3.5.0-1 + nlmsg_attrdata@Base 3.5.0-1 + nlmsg_attrdata@libnl_3 3.5.0-1 + nlmsg_attrlen@Base 3.5.0-1 + nlmsg_attrlen@libnl_3 3.5.0-1 + nlmsg_convert@Base 3.5.0-1 + nlmsg_convert@libnl_3 3.5.0-1 + nlmsg_data@Base 3.5.0-1 + nlmsg_data@libnl_3 3.5.0-1 + nlmsg_datalen@Base 3.5.0-1 + nlmsg_datalen@libnl_3 3.5.0-1 + nlmsg_expand@Base 3.5.0-1 + nlmsg_expand@libnl_3 3.5.0-1 + nlmsg_find_attr@Base 3.5.0-1 + nlmsg_find_attr@libnl_3 3.5.0-1 + nlmsg_free@Base 3.5.0-1 + nlmsg_free@libnl_3 3.5.0-1 + nlmsg_get@Base 3.5.0-1 + nlmsg_get@libnl_3 3.5.0-1 + nlmsg_get_creds@Base 3.5.0-1 + nlmsg_get_creds@libnl_3 3.5.0-1 + nlmsg_get_dst@Base 3.5.0-1 + nlmsg_get_dst@libnl_3 3.5.0-1 + nlmsg_get_max_size@Base 3.5.0-1 + nlmsg_get_max_size@libnl_3 3.5.0-1 + nlmsg_get_proto@Base 3.5.0-1 + nlmsg_get_proto@libnl_3 3.5.0-1 + nlmsg_get_src@Base 3.5.0-1 + nlmsg_get_src@libnl_3 3.5.0-1 + nlmsg_hdr@Base 3.5.0-1 + nlmsg_hdr@libnl_3 3.5.0-1 + nlmsg_inherit@Base 3.5.0-1 + nlmsg_inherit@libnl_3 3.5.0-1 + nlmsg_next@Base 3.5.0-1 + nlmsg_next@libnl_3 3.5.0-1 + nlmsg_ok@Base 3.5.0-1 + nlmsg_ok@libnl_3 3.5.0-1 + nlmsg_padlen@Base 3.5.0-1 + nlmsg_padlen@libnl_3 3.5.0-1 + nlmsg_parse@Base 3.5.0-1 + nlmsg_parse@libnl_3 3.5.0-1 + nlmsg_put@Base 3.5.0-1 + nlmsg_put@libnl_3 3.5.0-1 + nlmsg_reserve@Base 3.5.0-1 + nlmsg_reserve@libnl_3 3.5.0-1 + nlmsg_set_creds@Base 3.5.0-1 + nlmsg_set_creds@libnl_3 3.5.0-1 + nlmsg_set_default_size@Base 3.5.0-1 + nlmsg_set_default_size@libnl_3 3.5.0-1 + nlmsg_set_dst@Base 3.5.0-1 + nlmsg_set_dst@libnl_3 3.5.0-1 + nlmsg_set_proto@Base 3.5.0-1 + nlmsg_set_proto@libnl_3 3.5.0-1 + nlmsg_set_src@Base 3.5.0-1 + nlmsg_set_src@libnl_3 3.5.0-1 + nlmsg_size@Base 3.5.0-1 + nlmsg_size@libnl_3 3.5.0-1 + nlmsg_tail@Base 3.5.0-1 + nlmsg_tail@libnl_3 3.5.0-1 + nlmsg_total_size@Base 3.5.0-1 + nlmsg_total_size@libnl_3 3.5.0-1 + nlmsg_valid_hdr@Base 3.5.0-1 + nlmsg_valid_hdr@libnl_3 3.5.0-1 + nlmsg_validate@Base 3.5.0-1 + nlmsg_validate@libnl_3 3.5.0-1 diff --git a/src/libnl3/debian/libnl-3-dev.install b/src/libnl3/debian/libnl-3-dev.install new file mode 100755 index 000000000000..3715b8b22bbd --- /dev/null +++ b/src/libnl3/debian/libnl-3-dev.install @@ -0,0 +1,5 @@ +#!/usr/bin/dh-exec +debian/tmp/usr/include/* +debian/tmp/usr/lib/*/pkgconfig/libnl-3* +debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/libnl-3.so lib/${DEB_HOST_MULTIARCH}/ +debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/libnl-3.a lib/${DEB_HOST_MULTIARCH}/ diff --git a/src/libnl3/debian/libnl-cli-3-200.install b/src/libnl3/debian/libnl-cli-3-200.install new file mode 100755 index 000000000000..6735ec9d14b1 --- /dev/null +++ b/src/libnl3/debian/libnl-cli-3-200.install @@ -0,0 +1,4 @@ +#!/usr/bin/dh-exec +debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/libnl-cli-3*.so.* +debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/libnl/cli/cls/*.so usr/lib/${DEB_HOST_MULTIARCH}/libnl-3/cli/cls +debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/libnl/cli/qdisc/*.so usr/lib/${DEB_HOST_MULTIARCH}/libnl-3/cli/qdisc diff --git a/src/libnl3/debian/libnl-cli-3-200.symbols b/src/libnl3/debian/libnl-cli-3-200.symbols new file mode 100644 index 000000000000..2d21c139623c --- /dev/null +++ b/src/libnl3/debian/libnl-cli-3-200.symbols @@ -0,0 +1,226 @@ +basic.so libnl-cli-3-200 #MINVER# +bfifo.so libnl-cli-3-200 #MINVER# +blackhole.so libnl-cli-3-200 #MINVER# +cgroup.so libnl-cli-3-200 #MINVER# +fq_codel.so libnl-cli-3-200 #MINVER# +hfsc.so libnl-cli-3-200 #MINVER# +htb.so libnl-cli-3-200 #MINVER# +ingress.so libnl-cli-3-200 #MINVER# +libnl-cli-3.so.200 libnl-cli-3-200 #MINVER# + libnl_3@libnl_3 3.5.0-1 + libnl_3_2_28@libnl_3_2_28 3.5.0-1 + nl_cli_addr_alloc@Base 3.5.0-1 + nl_cli_addr_alloc@libnl_3 3.5.0-1 + nl_cli_addr_parse@Base 3.5.0-1 + nl_cli_addr_parse@libnl_3 3.5.0-1 + nl_cli_addr_parse_broadcast@Base 3.5.0-1 + nl_cli_addr_parse_broadcast@libnl_3 3.5.0-1 + nl_cli_addr_parse_dev@Base 3.5.0-1 + nl_cli_addr_parse_dev@libnl_3 3.5.0-1 + nl_cli_addr_parse_family@Base 3.5.0-1 + nl_cli_addr_parse_family@libnl_3 3.5.0-1 + nl_cli_addr_parse_label@Base 3.5.0-1 + nl_cli_addr_parse_label@libnl_3 3.5.0-1 + nl_cli_addr_parse_local@Base 3.5.0-1 + nl_cli_addr_parse_local@libnl_3 3.5.0-1 + nl_cli_addr_parse_peer@Base 3.5.0-1 + nl_cli_addr_parse_peer@libnl_3 3.5.0-1 + nl_cli_addr_parse_preferred@Base 3.5.0-1 + nl_cli_addr_parse_preferred@libnl_3 3.5.0-1 + nl_cli_addr_parse_scope@Base 3.5.0-1 + nl_cli_addr_parse_scope@libnl_3 3.5.0-1 + nl_cli_addr_parse_valid@Base 3.5.0-1 + nl_cli_addr_parse_valid@libnl_3 3.5.0-1 + nl_cli_alloc_cache@Base 3.5.0-1 + nl_cli_alloc_cache@libnl_3 3.5.0-1 + nl_cli_alloc_cache_flags@libnl_3_2_28 3.5.0-1 + nl_cli_alloc_socket@Base 3.5.0-1 + nl_cli_alloc_socket@libnl_3 3.5.0-1 + nl_cli_class_alloc@Base 3.5.0-1 + nl_cli_class_alloc@libnl_3 3.5.0-1 + nl_cli_class_alloc_cache@Base 3.5.0-1 + nl_cli_class_alloc_cache@libnl_3 3.5.0-1 + nl_cli_cls_alloc@Base 3.5.0-1 + nl_cli_cls_alloc@libnl_3 3.5.0-1 + nl_cli_cls_alloc_cache@Base 3.5.0-1 + nl_cli_cls_alloc_cache@libnl_3 3.5.0-1 + nl_cli_cls_parse_ematch@Base 3.5.0-1 + nl_cli_cls_parse_ematch@libnl_3 3.5.0-1 + nl_cli_cls_parse_proto@Base 3.5.0-1 + nl_cli_cls_parse_proto@libnl_3 3.5.0-1 + nl_cli_confirm@Base 3.5.0-1 + nl_cli_confirm@libnl_3 3.5.0-1 + nl_cli_connect@Base 3.5.0-1 + nl_cli_connect@libnl_3 3.5.0-1 + nl_cli_ct_alloc@Base 3.5.0-1 + nl_cli_ct_alloc@libnl_3 3.5.0-1 + nl_cli_ct_alloc_cache@Base 3.5.0-1 + nl_cli_ct_alloc_cache@libnl_3 3.5.0-1 + nl_cli_ct_parse_dst@Base 3.5.0-1 + nl_cli_ct_parse_dst@libnl_3 3.5.0-1 + nl_cli_ct_parse_dst_port@Base 3.5.0-1 + nl_cli_ct_parse_dst_port@libnl_3 3.5.0-1 + nl_cli_ct_parse_family@Base 3.5.0-1 + nl_cli_ct_parse_family@libnl_3 3.5.0-1 + nl_cli_ct_parse_id@Base 3.5.0-1 + nl_cli_ct_parse_id@libnl_3 3.5.0-1 + nl_cli_ct_parse_mark@Base 3.5.0-1 + nl_cli_ct_parse_mark@libnl_3 3.5.0-1 + nl_cli_ct_parse_protocol@Base 3.5.0-1 + nl_cli_ct_parse_protocol@libnl_3 3.5.0-1 + nl_cli_ct_parse_src@Base 3.5.0-1 + nl_cli_ct_parse_src@libnl_3 3.5.0-1 + nl_cli_ct_parse_src_port@Base 3.5.0-1 + nl_cli_ct_parse_src_port@libnl_3 3.5.0-1 + nl_cli_ct_parse_status@Base 3.5.0-1 + nl_cli_ct_parse_status@libnl_3 3.5.0-1 + nl_cli_ct_parse_tcp_state@Base 3.5.0-1 + nl_cli_ct_parse_tcp_state@libnl_3 3.5.0-1 + nl_cli_ct_parse_timeout@Base 3.5.0-1 + nl_cli_ct_parse_timeout@libnl_3 3.5.0-1 + nl_cli_ct_parse_use@Base 3.5.0-1 + nl_cli_ct_parse_use@libnl_3 3.5.0-1 + nl_cli_ct_parse_zone@Base 3.5.0-1 + nl_cli_ct_parse_zone@libnl_3 3.5.0-1 + nl_cli_exp_alloc@Base 3.5.0-1 + nl_cli_exp_alloc@libnl_3 3.5.0-1 + nl_cli_exp_alloc_cache@Base 3.5.0-1 + nl_cli_exp_alloc_cache@libnl_3 3.5.0-1 + nl_cli_exp_parse_class@Base 3.5.0-1 + nl_cli_exp_parse_class@libnl_3 3.5.0-1 + nl_cli_exp_parse_dst@Base 3.5.0-1 + nl_cli_exp_parse_dst@libnl_3 3.5.0-1 + nl_cli_exp_parse_dst_port@Base 3.5.0-1 + nl_cli_exp_parse_dst_port@libnl_3 3.5.0-1 + nl_cli_exp_parse_family@Base 3.5.0-1 + nl_cli_exp_parse_family@libnl_3 3.5.0-1 + nl_cli_exp_parse_flags@Base 3.5.0-1 + nl_cli_exp_parse_flags@libnl_3 3.5.0-1 + nl_cli_exp_parse_fn@Base 3.5.0-1 + nl_cli_exp_parse_fn@libnl_3 3.5.0-1 + nl_cli_exp_parse_helper_name@Base 3.5.0-1 + nl_cli_exp_parse_helper_name@libnl_3 3.5.0-1 + nl_cli_exp_parse_icmp_code@Base 3.5.0-1 + nl_cli_exp_parse_icmp_code@libnl_3 3.5.0-1 + nl_cli_exp_parse_icmp_id@Base 3.5.0-1 + nl_cli_exp_parse_icmp_id@libnl_3 3.5.0-1 + nl_cli_exp_parse_icmp_type@Base 3.5.0-1 + nl_cli_exp_parse_icmp_type@libnl_3 3.5.0-1 + nl_cli_exp_parse_id@Base 3.5.0-1 + nl_cli_exp_parse_id@libnl_3 3.5.0-1 + nl_cli_exp_parse_l4protonum@Base 3.5.0-1 + nl_cli_exp_parse_l4protonum@libnl_3 3.5.0-1 + nl_cli_exp_parse_nat_dir@Base 3.5.0-1 + nl_cli_exp_parse_nat_dir@libnl_3 3.5.0-1 + nl_cli_exp_parse_src@Base 3.5.0-1 + nl_cli_exp_parse_src@libnl_3 3.5.0-1 + nl_cli_exp_parse_src_port@Base 3.5.0-1 + nl_cli_exp_parse_src_port@libnl_3 3.5.0-1 + nl_cli_exp_parse_timeout@Base 3.5.0-1 + nl_cli_exp_parse_timeout@libnl_3 3.5.0-1 + nl_cli_exp_parse_zone@Base 3.5.0-1 + nl_cli_exp_parse_zone@libnl_3 3.5.0-1 + nl_cli_fatal@Base 3.5.0-1 + nl_cli_fatal@libnl_3 3.5.0-1 + nl_cli_link_alloc@Base 3.5.0-1 + nl_cli_link_alloc@libnl_3 3.5.0-1 + nl_cli_link_alloc_cache@Base 3.5.0-1 + nl_cli_link_alloc_cache@libnl_3 3.5.0-1 + nl_cli_link_alloc_cache_family@Base 3.5.0-1 + nl_cli_link_alloc_cache_family@libnl_3 3.5.0-1 + nl_cli_link_alloc_cache_family_flags@libnl_3_2_28 3.5.0-1 + nl_cli_link_alloc_cache_flags@libnl_3_2_28 3.5.0-1 + nl_cli_link_parse_family@Base 3.5.0-1 + nl_cli_link_parse_family@libnl_3 3.5.0-1 + nl_cli_link_parse_ifalias@Base 3.5.0-1 + nl_cli_link_parse_ifalias@libnl_3 3.5.0-1 + nl_cli_link_parse_ifindex@Base 3.5.0-1 + nl_cli_link_parse_ifindex@libnl_3 3.5.0-1 + nl_cli_link_parse_mtu@Base 3.5.0-1 + nl_cli_link_parse_mtu@libnl_3 3.5.0-1 + nl_cli_link_parse_name@Base 3.5.0-1 + nl_cli_link_parse_name@libnl_3 3.5.0-1 + nl_cli_link_parse_txqlen@Base 3.5.0-1 + nl_cli_link_parse_txqlen@libnl_3 3.5.0-1 + nl_cli_link_parse_weight@Base 3.5.0-1 + nl_cli_link_parse_weight@libnl_3 3.5.0-1 + nl_cli_load_module@Base 3.5.0-1 + nl_cli_load_module@libnl_3 3.5.0-1 + nl_cli_neigh_alloc@Base 3.5.0-1 + nl_cli_neigh_alloc@libnl_3 3.5.0-1 + nl_cli_neigh_parse_dev@Base 3.5.0-1 + nl_cli_neigh_parse_dev@libnl_3 3.5.0-1 + nl_cli_neigh_parse_dst@Base 3.5.0-1 + nl_cli_neigh_parse_dst@libnl_3 3.5.0-1 + nl_cli_neigh_parse_family@Base 3.5.0-1 + nl_cli_neigh_parse_family@libnl_3 3.5.0-1 + nl_cli_neigh_parse_lladdr@Base 3.5.0-1 + nl_cli_neigh_parse_lladdr@libnl_3 3.5.0-1 + nl_cli_neigh_parse_state@Base 3.5.0-1 + nl_cli_neigh_parse_state@libnl_3 3.5.0-1 + nl_cli_parse_dumptype@Base 3.5.0-1 + nl_cli_parse_dumptype@libnl_3 3.5.0-1 + nl_cli_parse_u32@Base 3.5.0-1 + nl_cli_parse_u32@libnl_3 3.5.0-1 + nl_cli_print_version@Base 3.5.0-1 + nl_cli_print_version@libnl_3 3.5.0-1 + nl_cli_qdisc_alloc@Base 3.5.0-1 + nl_cli_qdisc_alloc@libnl_3 3.5.0-1 + nl_cli_route_alloc@Base 3.5.0-1 + nl_cli_route_alloc@libnl_3 3.5.0-1 + nl_cli_route_alloc_cache@Base 3.5.0-1 + nl_cli_route_alloc_cache@libnl_3 3.5.0-1 + nl_cli_route_parse_dst@Base 3.5.0-1 + nl_cli_route_parse_dst@libnl_3 3.5.0-1 + nl_cli_route_parse_family@Base 3.5.0-1 + nl_cli_route_parse_family@libnl_3 3.5.0-1 + nl_cli_route_parse_iif@Base 3.5.0-1 + nl_cli_route_parse_iif@libnl_3 3.5.0-1 + nl_cli_route_parse_metric@Base 3.5.0-1 + nl_cli_route_parse_metric@libnl_3 3.5.0-1 + nl_cli_route_parse_nexthop@Base 3.5.0-1 + nl_cli_route_parse_nexthop@libnl_3 3.5.0-1 + nl_cli_route_parse_pref_src@Base 3.5.0-1 + nl_cli_route_parse_pref_src@libnl_3 3.5.0-1 + nl_cli_route_parse_prio@Base 3.5.0-1 + nl_cli_route_parse_prio@libnl_3 3.5.0-1 + nl_cli_route_parse_protocol@Base 3.5.0-1 + nl_cli_route_parse_protocol@libnl_3 3.5.0-1 + nl_cli_route_parse_scope@Base 3.5.0-1 + nl_cli_route_parse_scope@libnl_3 3.5.0-1 + nl_cli_route_parse_src@Base 3.5.0-1 + nl_cli_route_parse_src@libnl_3 3.5.0-1 + nl_cli_route_parse_table@Base 3.5.0-1 + nl_cli_route_parse_table@libnl_3 3.5.0-1 + nl_cli_route_parse_type@Base 3.5.0-1 + nl_cli_route_parse_type@libnl_3 3.5.0-1 + nl_cli_rule_alloc@Base 3.5.0-1 + nl_cli_rule_alloc@libnl_3 3.5.0-1 + nl_cli_rule_alloc_cache@Base 3.5.0-1 + nl_cli_rule_alloc_cache@libnl_3 3.5.0-1 + nl_cli_rule_parse_family@Base 3.5.0-1 + nl_cli_rule_parse_family@libnl_3 3.5.0-1 + nl_cli_tc_lookup@Base 3.5.0-1 + nl_cli_tc_lookup@libnl_3 3.5.0-1 + nl_cli_tc_parse_dev@Base 3.5.0-1 + nl_cli_tc_parse_dev@libnl_3 3.5.0-1 + nl_cli_tc_parse_handle@Base 3.5.0-1 + nl_cli_tc_parse_handle@libnl_3 3.5.0-1 + nl_cli_tc_parse_kind@Base 3.5.0-1 + nl_cli_tc_parse_kind@libnl_3 3.5.0-1 + nl_cli_tc_parse_linktype@Base 3.5.0-1 + nl_cli_tc_parse_linktype@libnl_3 3.5.0-1 + nl_cli_tc_parse_mpu@Base 3.5.0-1 + nl_cli_tc_parse_mpu@libnl_3 3.5.0-1 + nl_cli_tc_parse_mtu@Base 3.5.0-1 + nl_cli_tc_parse_mtu@libnl_3 3.5.0-1 + nl_cli_tc_parse_overhead@Base 3.5.0-1 + nl_cli_tc_parse_overhead@libnl_3 3.5.0-1 + nl_cli_tc_parse_parent@Base 3.5.0-1 + nl_cli_tc_parse_parent@libnl_3 3.5.0-1 + nl_cli_tc_register@Base 3.5.0-1 + nl_cli_tc_register@libnl_3 3.5.0-1 + nl_cli_tc_unregister@Base 3.5.0-1 + nl_cli_tc_unregister@libnl_3 3.5.0-1 +pfifo.so libnl-cli-3-200 #MINVER# +plug.so libnl-cli-3-200 #MINVER# diff --git a/src/libnl3/debian/libnl-cli-3-dev.install b/src/libnl3/debian/libnl-cli-3-dev.install new file mode 100644 index 000000000000..66aa3b3d9457 --- /dev/null +++ b/src/libnl3/debian/libnl-cli-3-dev.install @@ -0,0 +1,3 @@ +debian/tmp/usr/lib/*/pkgconfig/libnl-cli-3* +debian/tmp/usr/lib/*/libnl-cli-3*.so +debian/tmp/usr/lib/*/libnl-cli-3*.a diff --git a/src/libnl3/debian/libnl-genl-3-200-udeb.install b/src/libnl3/debian/libnl-genl-3-200-udeb.install new file mode 100755 index 000000000000..cb5597bf74da --- /dev/null +++ b/src/libnl3/debian/libnl-genl-3-200-udeb.install @@ -0,0 +1,2 @@ +#!/usr/bin/dh-exec +usr/lib/${DEB_HOST_MULTIARCH}/libnl-genl-3.so.* lib/${DEB_HOST_MULTIARCH}/ diff --git a/src/libnl3/debian/libnl-genl-3-200.install b/src/libnl3/debian/libnl-genl-3-200.install new file mode 100755 index 000000000000..d9d6fae40b21 --- /dev/null +++ b/src/libnl3/debian/libnl-genl-3-200.install @@ -0,0 +1,2 @@ +#!/usr/bin/dh-exec +debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/libnl-genl-3*.so.* lib/${DEB_HOST_MULTIARCH}/ diff --git a/src/libnl3/debian/libnl-genl-3-200.symbols b/src/libnl3/debian/libnl-genl-3-200.symbols new file mode 100644 index 000000000000..0eb2e3be4460 --- /dev/null +++ b/src/libnl3/debian/libnl-genl-3-200.symbols @@ -0,0 +1,88 @@ +libnl-genl-3.so.200 libnl-genl-3-200 #MINVER# + genl_connect@Base 3.5.0-1 + genl_connect@libnl_3 3.5.0-1 + genl_ctrl_alloc_cache@Base 3.5.0-1 + genl_ctrl_alloc_cache@libnl_3 3.5.0-1 + genl_ctrl_resolve@Base 3.5.0-1 + genl_ctrl_resolve@libnl_3 3.5.0-1 + genl_ctrl_resolve_grp@Base 3.5.0-1 + genl_ctrl_resolve_grp@libnl_3 3.5.0-1 + genl_ctrl_search@Base 3.5.0-1 + genl_ctrl_search@libnl_3 3.5.0-1 + genl_ctrl_search_by_name@Base 3.5.0-1 + genl_ctrl_search_by_name@libnl_3 3.5.0-1 + genl_family_add_grp@Base 3.5.0-1 + genl_family_add_grp@libnl_3 3.5.0-1 + genl_family_add_op@Base 3.5.0-1 + genl_family_add_op@libnl_3 3.5.0-1 + genl_family_alloc@Base 3.5.0-1 + genl_family_alloc@libnl_3 3.5.0-1 + genl_family_get_hdrsize@Base 3.5.0-1 + genl_family_get_hdrsize@libnl_3 3.5.0-1 + genl_family_get_id@Base 3.5.0-1 + genl_family_get_id@libnl_3 3.5.0-1 + genl_family_get_maxattr@Base 3.5.0-1 + genl_family_get_maxattr@libnl_3 3.5.0-1 + genl_family_get_name@Base 3.5.0-1 + genl_family_get_name@libnl_3 3.5.0-1 + genl_family_get_version@Base 3.5.0-1 + genl_family_get_version@libnl_3 3.5.0-1 + genl_family_ops@Base 3.5.0-1 + genl_family_ops@libnl_3 3.5.0-1 + genl_family_put@Base 3.5.0-1 + genl_family_put@libnl_3 3.5.0-1 + genl_family_set_hdrsize@Base 3.5.0-1 + genl_family_set_hdrsize@libnl_3 3.5.0-1 + genl_family_set_id@Base 3.5.0-1 + genl_family_set_id@libnl_3 3.5.0-1 + genl_family_set_maxattr@Base 3.5.0-1 + genl_family_set_maxattr@libnl_3 3.5.0-1 + genl_family_set_name@Base 3.5.0-1 + genl_family_set_name@libnl_3 3.5.0-1 + genl_family_set_version@Base 3.5.0-1 + genl_family_set_version@libnl_3 3.5.0-1 + genl_handle_msg@Base 3.5.0-1 + genl_handle_msg@libnl_3 3.5.0-1 + genl_mngt_resolve@Base 3.5.0-1 + genl_mngt_resolve@libnl_3 3.5.0-1 + genl_op2name@Base 3.5.0-1 + genl_op2name@libnl_3 3.5.0-1 + genl_ops_resolve@Base 3.5.0-1 + genl_ops_resolve@libnl_3 3.5.0-1 + genl_register@Base 3.5.0-1 + genl_register@libnl_3 3.5.0-1 + genl_register_family@Base 3.5.0-1 + genl_register_family@libnl_3 3.5.0-1 + genl_resolve_id@Base 3.5.0-1 + genl_resolve_id@libnl_3 3.5.0-1 + genl_send_simple@Base 3.5.0-1 + genl_send_simple@libnl_3 3.5.0-1 + genl_unregister@Base 3.5.0-1 + genl_unregister@libnl_3 3.5.0-1 + genl_unregister_family@Base 3.5.0-1 + genl_unregister_family@libnl_3 3.5.0-1 + genlmsg_attrdata@Base 3.5.0-1 + genlmsg_attrdata@libnl_3 3.5.0-1 + genlmsg_attrlen@Base 3.5.0-1 + genlmsg_attrlen@libnl_3 3.5.0-1 + genlmsg_data@Base 3.5.0-1 + genlmsg_data@libnl_3 3.5.0-1 + genlmsg_hdr@Base 3.5.0-1 + genlmsg_hdr@libnl_3 3.5.0-1 + genlmsg_len@Base 3.5.0-1 + genlmsg_len@libnl_3 3.5.0-1 + genlmsg_parse@Base 3.5.0-1 + genlmsg_parse@libnl_3 3.5.0-1 + genlmsg_put@Base 3.5.0-1 + genlmsg_put@libnl_3 3.5.0-1 + genlmsg_user_data@Base 3.5.0-1 + genlmsg_user_data@libnl_3 3.5.0-1 + genlmsg_user_datalen@Base 3.5.0-1 + genlmsg_user_datalen@libnl_3 3.5.0-1 + genlmsg_user_hdr@Base 3.5.0-1 + genlmsg_user_hdr@libnl_3 3.5.0-1 + genlmsg_valid_hdr@Base 3.5.0-1 + genlmsg_valid_hdr@libnl_3 3.5.0-1 + genlmsg_validate@Base 3.5.0-1 + genlmsg_validate@libnl_3 3.5.0-1 + libnl_3@libnl_3 3.5.0-1 diff --git a/src/libnl3/debian/libnl-genl-3-dev.install b/src/libnl3/debian/libnl-genl-3-dev.install new file mode 100755 index 000000000000..cbc6b51ef474 --- /dev/null +++ b/src/libnl3/debian/libnl-genl-3-dev.install @@ -0,0 +1,4 @@ +#!/usr/bin/dh-exec +debian/tmp/usr/lib/*/pkgconfig/libnl-genl-3* +debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/libnl-genl-3*.so lib/${DEB_HOST_MULTIARCH}/ +debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/libnl-genl-3*.a lib/${DEB_HOST_MULTIARCH}/ diff --git a/src/libnl3/debian/libnl-idiag-3-200.install b/src/libnl3/debian/libnl-idiag-3-200.install new file mode 100644 index 000000000000..f6d6b8064e5f --- /dev/null +++ b/src/libnl3/debian/libnl-idiag-3-200.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/*/libnl-idiag-3*.so.* diff --git a/src/libnl3/debian/libnl-idiag-3-200.symbols b/src/libnl3/debian/libnl-idiag-3-200.symbols new file mode 100644 index 000000000000..13cf27c7c8ac --- /dev/null +++ b/src/libnl3/debian/libnl-idiag-3-200.symbols @@ -0,0 +1,206 @@ +libnl-idiag-3.so.200 libnl-idiag-3-200 #MINVER# + idiagnl_attrs2str@Base 3.5.0-1 + idiagnl_attrs2str@libnl_3 3.5.0-1 + idiagnl_connect@Base 3.5.0-1 + idiagnl_connect@libnl_3 3.5.0-1 + idiagnl_exts2str@Base 3.5.0-1 + idiagnl_exts2str@libnl_3 3.5.0-1 + idiagnl_meminfo_alloc@Base 3.5.0-1 + idiagnl_meminfo_alloc@libnl_3 3.5.0-1 + idiagnl_meminfo_get@Base 3.5.0-1 + idiagnl_meminfo_get@libnl_3 3.5.0-1 + idiagnl_meminfo_get_fmem@Base 3.5.0-1 + idiagnl_meminfo_get_fmem@libnl_3 3.5.0-1 + idiagnl_meminfo_get_rmem@Base 3.5.0-1 + idiagnl_meminfo_get_rmem@libnl_3 3.5.0-1 + idiagnl_meminfo_get_tmem@Base 3.5.0-1 + idiagnl_meminfo_get_tmem@libnl_3 3.5.0-1 + idiagnl_meminfo_get_wmem@Base 3.5.0-1 + idiagnl_meminfo_get_wmem@libnl_3 3.5.0-1 + idiagnl_meminfo_obj_ops@Base 3.5.0-1 + idiagnl_meminfo_obj_ops@libnl_3 3.5.0-1 + idiagnl_meminfo_put@Base 3.5.0-1 + idiagnl_meminfo_put@libnl_3 3.5.0-1 + idiagnl_meminfo_set_fmem@Base 3.5.0-1 + idiagnl_meminfo_set_fmem@libnl_3 3.5.0-1 + idiagnl_meminfo_set_rmem@Base 3.5.0-1 + idiagnl_meminfo_set_rmem@libnl_3 3.5.0-1 + idiagnl_meminfo_set_tmem@Base 3.5.0-1 + idiagnl_meminfo_set_tmem@libnl_3 3.5.0-1 + idiagnl_meminfo_set_wmem@Base 3.5.0-1 + idiagnl_meminfo_set_wmem@libnl_3 3.5.0-1 + idiagnl_msg_alloc@Base 3.5.0-1 + idiagnl_msg_alloc@libnl_3 3.5.0-1 + idiagnl_msg_alloc_cache@Base 3.5.0-1 + idiagnl_msg_alloc_cache@libnl_3 3.5.0-1 + idiagnl_msg_get@Base 3.5.0-1 + idiagnl_msg_get@libnl_3 3.5.0-1 + idiagnl_msg_get_cong@Base 3.5.0-1 + idiagnl_msg_get_cong@libnl_3 3.5.0-1 + idiagnl_msg_get_dport@Base 3.5.0-1 + idiagnl_msg_get_dport@libnl_3 3.5.0-1 + idiagnl_msg_get_dst@Base 3.5.0-1 + idiagnl_msg_get_dst@libnl_3 3.5.0-1 + idiagnl_msg_get_expires@Base 3.5.0-1 + idiagnl_msg_get_expires@libnl_3 3.5.0-1 + idiagnl_msg_get_family@Base 3.5.0-1 + idiagnl_msg_get_family@libnl_3 3.5.0-1 + idiagnl_msg_get_ifindex@Base 3.5.0-1 + idiagnl_msg_get_ifindex@libnl_3 3.5.0-1 + idiagnl_msg_get_inode@Base 3.5.0-1 + idiagnl_msg_get_inode@libnl_3 3.5.0-1 + idiagnl_msg_get_meminfo@Base 3.5.0-1 + idiagnl_msg_get_meminfo@libnl_3 3.5.0-1 + idiagnl_msg_get_retrans@Base 3.5.0-1 + idiagnl_msg_get_retrans@libnl_3 3.5.0-1 + idiagnl_msg_get_rqueue@Base 3.5.0-1 + idiagnl_msg_get_rqueue@libnl_3 3.5.0-1 + idiagnl_msg_get_shutdown@Base 3.5.0-1 + idiagnl_msg_get_shutdown@libnl_3 3.5.0-1 + idiagnl_msg_get_sport@Base 3.5.0-1 + idiagnl_msg_get_sport@libnl_3 3.5.0-1 + idiagnl_msg_get_src@Base 3.5.0-1 + idiagnl_msg_get_src@libnl_3 3.5.0-1 + idiagnl_msg_get_state@Base 3.5.0-1 + idiagnl_msg_get_state@libnl_3 3.5.0-1 + idiagnl_msg_get_tclass@Base 3.5.0-1 + idiagnl_msg_get_tclass@libnl_3 3.5.0-1 + idiagnl_msg_get_tcpinfo@Base 3.5.0-1 + idiagnl_msg_get_tcpinfo@libnl_3 3.5.0-1 + idiagnl_msg_get_timer@Base 3.5.0-1 + idiagnl_msg_get_timer@libnl_3 3.5.0-1 + idiagnl_msg_get_tos@Base 3.5.0-1 + idiagnl_msg_get_tos@libnl_3 3.5.0-1 + idiagnl_msg_get_uid@Base 3.5.0-1 + idiagnl_msg_get_uid@libnl_3 3.5.0-1 + idiagnl_msg_get_vegasinfo@Base 3.5.0-1 + idiagnl_msg_get_vegasinfo@libnl_3 3.5.0-1 + idiagnl_msg_get_wqueue@Base 3.5.0-1 + idiagnl_msg_get_wqueue@libnl_3 3.5.0-1 + idiagnl_msg_obj_ops@Base 3.5.0-1 + idiagnl_msg_obj_ops@libnl_3 3.5.0-1 + idiagnl_msg_parse@Base 3.5.0-1 + idiagnl_msg_parse@libnl_3 3.5.0-1 + idiagnl_msg_put@Base 3.5.0-1 + idiagnl_msg_put@libnl_3 3.5.0-1 + idiagnl_msg_set_cong@Base 3.5.0-1 + idiagnl_msg_set_cong@libnl_3 3.5.0-1 + idiagnl_msg_set_dport@Base 3.5.0-1 + idiagnl_msg_set_dport@libnl_3 3.5.0-1 + idiagnl_msg_set_dst@Base 3.5.0-1 + idiagnl_msg_set_dst@libnl_3 3.5.0-1 + idiagnl_msg_set_expires@Base 3.5.0-1 + idiagnl_msg_set_expires@libnl_3 3.5.0-1 + idiagnl_msg_set_family@Base 3.5.0-1 + idiagnl_msg_set_family@libnl_3 3.5.0-1 + idiagnl_msg_set_ifindex@Base 3.5.0-1 + idiagnl_msg_set_ifindex@libnl_3 3.5.0-1 + idiagnl_msg_set_inode@Base 3.5.0-1 + idiagnl_msg_set_inode@libnl_3 3.5.0-1 + idiagnl_msg_set_meminfo@Base 3.5.0-1 + idiagnl_msg_set_meminfo@libnl_3 3.5.0-1 + idiagnl_msg_set_retrans@Base 3.5.0-1 + idiagnl_msg_set_retrans@libnl_3 3.5.0-1 + idiagnl_msg_set_rqueue@Base 3.5.0-1 + idiagnl_msg_set_rqueue@libnl_3 3.5.0-1 + idiagnl_msg_set_shutdown@Base 3.5.0-1 + idiagnl_msg_set_shutdown@libnl_3 3.5.0-1 + idiagnl_msg_set_sport@Base 3.5.0-1 + idiagnl_msg_set_sport@libnl_3 3.5.0-1 + idiagnl_msg_set_src@Base 3.5.0-1 + idiagnl_msg_set_src@libnl_3 3.5.0-1 + idiagnl_msg_set_state@Base 3.5.0-1 + idiagnl_msg_set_state@libnl_3 3.5.0-1 + idiagnl_msg_set_tclass@Base 3.5.0-1 + idiagnl_msg_set_tclass@libnl_3 3.5.0-1 + idiagnl_msg_set_tcpinfo@Base 3.5.0-1 + idiagnl_msg_set_tcpinfo@libnl_3 3.5.0-1 + idiagnl_msg_set_timer@Base 3.5.0-1 + idiagnl_msg_set_timer@libnl_3 3.5.0-1 + idiagnl_msg_set_tos@Base 3.5.0-1 + idiagnl_msg_set_tos@libnl_3 3.5.0-1 + idiagnl_msg_set_uid@Base 3.5.0-1 + idiagnl_msg_set_uid@libnl_3 3.5.0-1 + idiagnl_msg_set_vegasinfo@Base 3.5.0-1 + idiagnl_msg_set_vegasinfo@libnl_3 3.5.0-1 + idiagnl_msg_set_wqueue@Base 3.5.0-1 + idiagnl_msg_set_wqueue@libnl_3 3.5.0-1 + idiagnl_req_alloc@Base 3.5.0-1 + idiagnl_req_alloc@libnl_3 3.5.0-1 + idiagnl_req_get@Base 3.5.0-1 + idiagnl_req_get@libnl_3 3.5.0-1 + idiagnl_req_get_dbs@Base 3.5.0-1 + idiagnl_req_get_dbs@libnl_3 3.5.0-1 + idiagnl_req_get_dst@Base 3.5.0-1 + idiagnl_req_get_dst@libnl_3 3.5.0-1 + idiagnl_req_get_ext@Base 3.5.0-1 + idiagnl_req_get_ext@libnl_3 3.5.0-1 + idiagnl_req_get_family@Base 3.5.0-1 + idiagnl_req_get_family@libnl_3 3.5.0-1 + idiagnl_req_get_ifindex@Base 3.5.0-1 + idiagnl_req_get_ifindex@libnl_3 3.5.0-1 + idiagnl_req_get_src@Base 3.5.0-1 + idiagnl_req_get_src@libnl_3 3.5.0-1 + idiagnl_req_get_states@Base 3.5.0-1 + idiagnl_req_get_states@libnl_3 3.5.0-1 + idiagnl_req_obj_ops@Base 3.5.0-1 + idiagnl_req_obj_ops@libnl_3 3.5.0-1 + idiagnl_req_parse@Base 3.5.0-1 + idiagnl_req_parse@libnl_3 3.5.0-1 + idiagnl_req_put@Base 3.5.0-1 + idiagnl_req_put@libnl_3 3.5.0-1 + idiagnl_req_set_dbs@Base 3.5.0-1 + idiagnl_req_set_dbs@libnl_3 3.5.0-1 + idiagnl_req_set_dst@Base 3.5.0-1 + idiagnl_req_set_dst@libnl_3 3.5.0-1 + idiagnl_req_set_ext@Base 3.5.0-1 + idiagnl_req_set_ext@libnl_3 3.5.0-1 + idiagnl_req_set_family@Base 3.5.0-1 + idiagnl_req_set_family@libnl_3 3.5.0-1 + idiagnl_req_set_ifindex@Base 3.5.0-1 + idiagnl_req_set_ifindex@libnl_3 3.5.0-1 + idiagnl_req_set_src@Base 3.5.0-1 + idiagnl_req_set_src@libnl_3 3.5.0-1 + idiagnl_req_set_states@Base 3.5.0-1 + idiagnl_req_set_states@libnl_3 3.5.0-1 + idiagnl_send_simple@Base 3.5.0-1 + idiagnl_send_simple@libnl_3 3.5.0-1 + idiagnl_shutdown2str@Base 3.5.0-1 + idiagnl_shutdown2str@libnl_3 3.5.0-1 + idiagnl_state2str@Base 3.5.0-1 + idiagnl_state2str@libnl_3 3.5.0-1 + idiagnl_str2state@Base 3.5.0-1 + idiagnl_str2state@libnl_3 3.5.0-1 + idiagnl_str2timer@Base 3.5.0-1 + idiagnl_str2timer@libnl_3 3.5.0-1 + idiagnl_tcpopts2str@Base 3.5.0-1 + idiagnl_tcpopts2str@libnl_3 3.5.0-1 + idiagnl_tcpstate2str@Base 3.5.0-1 + idiagnl_tcpstate2str@libnl_3 3.5.0-1 + idiagnl_timer2str@Base 3.5.0-1 + idiagnl_timer2str@libnl_3 3.5.0-1 + idiagnl_vegasinfo_alloc@Base 3.5.0-1 + idiagnl_vegasinfo_alloc@libnl_3 3.5.0-1 + idiagnl_vegasinfo_get@Base 3.5.0-1 + idiagnl_vegasinfo_get@libnl_3 3.5.0-1 + idiagnl_vegasinfo_get_enabled@Base 3.5.0-1 + idiagnl_vegasinfo_get_enabled@libnl_3 3.5.0-1 + idiagnl_vegasinfo_get_minrtt@Base 3.5.0-1 + idiagnl_vegasinfo_get_minrtt@libnl_3 3.5.0-1 + idiagnl_vegasinfo_get_rtt@Base 3.5.0-1 + idiagnl_vegasinfo_get_rtt@libnl_3 3.5.0-1 + idiagnl_vegasinfo_get_rttcnt@Base 3.5.0-1 + idiagnl_vegasinfo_get_rttcnt@libnl_3 3.5.0-1 + idiagnl_vegasinfo_obj_ops@Base 3.5.0-1 + idiagnl_vegasinfo_obj_ops@libnl_3 3.5.0-1 + idiagnl_vegasinfo_put@Base 3.5.0-1 + idiagnl_vegasinfo_put@libnl_3 3.5.0-1 + idiagnl_vegasinfo_set_enabled@Base 3.5.0-1 + idiagnl_vegasinfo_set_enabled@libnl_3 3.5.0-1 + idiagnl_vegasinfo_set_minrtt@Base 3.5.0-1 + idiagnl_vegasinfo_set_minrtt@libnl_3 3.5.0-1 + idiagnl_vegasinfo_set_rtt@Base 3.5.0-1 + idiagnl_vegasinfo_set_rtt@libnl_3 3.5.0-1 + idiagnl_vegasinfo_set_rttcnt@Base 3.5.0-1 + idiagnl_vegasinfo_set_rttcnt@libnl_3 3.5.0-1 + libnl_3@libnl_3 3.5.0-1 diff --git a/src/libnl3/debian/libnl-idiag-3-dev.install b/src/libnl3/debian/libnl-idiag-3-dev.install new file mode 100644 index 000000000000..6f19a6e83d61 --- /dev/null +++ b/src/libnl3/debian/libnl-idiag-3-dev.install @@ -0,0 +1,3 @@ +debian/tmp/usr/lib/*/pkgconfig/libnl-idiag-3* +debian/tmp/usr/lib/*/libnl-idiag-3*.so +debian/tmp/usr/lib/*/libnl-idiag-3*.a diff --git a/src/libnl3/debian/libnl-nf-3-200.install b/src/libnl3/debian/libnl-nf-3-200.install new file mode 100644 index 000000000000..6d65611ed34e --- /dev/null +++ b/src/libnl3/debian/libnl-nf-3-200.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/*/libnl-nf-3*.so.* diff --git a/src/libnl3/debian/libnl-nf-3-200.symbols b/src/libnl3/debian/libnl-nf-3-200.symbols new file mode 100644 index 000000000000..2ce4d2ad0ffc --- /dev/null +++ b/src/libnl3/debian/libnl-nf-3-200.symbols @@ -0,0 +1,620 @@ +libnl-nf-3.so.200 libnl-nf-3-200 #MINVER# + ct_obj_ops@Base 3.5.0-1 + ct_obj_ops@libnl_3 3.5.0-1 + exp_obj_ops@Base 3.5.0-1 + exp_obj_ops@libnl_3 3.5.0-1 + libnl_3@libnl_3 3.5.0-1 + log_msg_obj_ops@Base 3.5.0-1 + log_msg_obj_ops@libnl_3 3.5.0-1 + log_obj_ops@Base 3.5.0-1 + log_obj_ops@libnl_3 3.5.0-1 + nfnl_connect@Base 3.5.0-1 + nfnl_connect@libnl_3 3.5.0-1 + nfnl_ct_add@Base 3.5.0-1 + nfnl_ct_add@libnl_3 3.5.0-1 + nfnl_ct_alloc@Base 3.5.0-1 + nfnl_ct_alloc@libnl_3 3.5.0-1 + nfnl_ct_alloc_cache@Base 3.5.0-1 + nfnl_ct_alloc_cache@libnl_3 3.5.0-1 + nfnl_ct_build_add_request@Base 3.5.0-1 + nfnl_ct_build_add_request@libnl_3 3.5.0-1 + nfnl_ct_build_delete_request@Base 3.5.0-1 + nfnl_ct_build_delete_request@libnl_3 3.5.0-1 + nfnl_ct_build_query_request@Base 3.5.0-1 + nfnl_ct_build_query_request@libnl_3 3.5.0-1 + nfnl_ct_del@Base 3.5.0-1 + nfnl_ct_del@libnl_3 3.5.0-1 + nfnl_ct_dump_request@Base 3.5.0-1 + nfnl_ct_dump_request@libnl_3 3.5.0-1 + nfnl_ct_get@Base 3.5.0-1 + nfnl_ct_get@libnl_3 3.5.0-1 + nfnl_ct_get_bytes@Base 3.5.0-1 + nfnl_ct_get_bytes@libnl_3 3.5.0-1 + nfnl_ct_get_dst@Base 3.5.0-1 + nfnl_ct_get_dst@libnl_3 3.5.0-1 + nfnl_ct_get_dst_port@Base 3.5.0-1 + nfnl_ct_get_dst_port@libnl_3 3.5.0-1 + nfnl_ct_get_family@Base 3.5.0-1 + nfnl_ct_get_family@libnl_3 3.5.0-1 + nfnl_ct_get_icmp_code@Base 3.5.0-1 + nfnl_ct_get_icmp_code@libnl_3 3.5.0-1 + nfnl_ct_get_icmp_id@Base 3.5.0-1 + nfnl_ct_get_icmp_id@libnl_3 3.5.0-1 + nfnl_ct_get_icmp_type@Base 3.5.0-1 + nfnl_ct_get_icmp_type@libnl_3 3.5.0-1 + nfnl_ct_get_id@Base 3.5.0-1 + nfnl_ct_get_id@libnl_3 3.5.0-1 + nfnl_ct_get_mark@Base 3.5.0-1 + nfnl_ct_get_mark@libnl_3 3.5.0-1 + nfnl_ct_get_packets@Base 3.5.0-1 + nfnl_ct_get_packets@libnl_3 3.5.0-1 + nfnl_ct_get_proto@Base 3.5.0-1 + nfnl_ct_get_proto@libnl_3 3.5.0-1 + nfnl_ct_get_src@Base 3.5.0-1 + nfnl_ct_get_src@libnl_3 3.5.0-1 + nfnl_ct_get_src_port@Base 3.5.0-1 + nfnl_ct_get_src_port@libnl_3 3.5.0-1 + nfnl_ct_get_status@Base 3.5.0-1 + nfnl_ct_get_status@libnl_3 3.5.0-1 + nfnl_ct_get_tcp_state@Base 3.5.0-1 + nfnl_ct_get_tcp_state@libnl_3 3.5.0-1 + nfnl_ct_get_timeout@Base 3.5.0-1 + nfnl_ct_get_timeout@libnl_3 3.5.0-1 + nfnl_ct_get_timestamp@Base 3.5.0-1 + nfnl_ct_get_timestamp@libnl_3 3.5.0-1 + nfnl_ct_get_use@Base 3.5.0-1 + nfnl_ct_get_use@libnl_3 3.5.0-1 + nfnl_ct_get_zone@Base 3.5.0-1 + nfnl_ct_get_zone@libnl_3 3.5.0-1 + nfnl_ct_put@Base 3.5.0-1 + nfnl_ct_put@libnl_3 3.5.0-1 + nfnl_ct_query@Base 3.5.0-1 + nfnl_ct_query@libnl_3 3.5.0-1 + nfnl_ct_set_bytes@Base 3.5.0-1 + nfnl_ct_set_bytes@libnl_3 3.5.0-1 + nfnl_ct_set_dst@Base 3.5.0-1 + nfnl_ct_set_dst@libnl_3 3.5.0-1 + nfnl_ct_set_dst_port@Base 3.5.0-1 + nfnl_ct_set_dst_port@libnl_3 3.5.0-1 + nfnl_ct_set_family@Base 3.5.0-1 + nfnl_ct_set_family@libnl_3 3.5.0-1 + nfnl_ct_set_icmp_code@Base 3.5.0-1 + nfnl_ct_set_icmp_code@libnl_3 3.5.0-1 + nfnl_ct_set_icmp_id@Base 3.5.0-1 + nfnl_ct_set_icmp_id@libnl_3 3.5.0-1 + nfnl_ct_set_icmp_type@Base 3.5.0-1 + nfnl_ct_set_icmp_type@libnl_3 3.5.0-1 + nfnl_ct_set_id@Base 3.5.0-1 + nfnl_ct_set_id@libnl_3 3.5.0-1 + nfnl_ct_set_mark@Base 3.5.0-1 + nfnl_ct_set_mark@libnl_3 3.5.0-1 + nfnl_ct_set_packets@Base 3.5.0-1 + nfnl_ct_set_packets@libnl_3 3.5.0-1 + nfnl_ct_set_proto@Base 3.5.0-1 + nfnl_ct_set_proto@libnl_3 3.5.0-1 + nfnl_ct_set_src@Base 3.5.0-1 + nfnl_ct_set_src@libnl_3 3.5.0-1 + nfnl_ct_set_src_port@Base 3.5.0-1 + nfnl_ct_set_src_port@libnl_3 3.5.0-1 + nfnl_ct_set_status@Base 3.5.0-1 + nfnl_ct_set_status@libnl_3 3.5.0-1 + nfnl_ct_set_tcp_state@Base 3.5.0-1 + nfnl_ct_set_tcp_state@libnl_3 3.5.0-1 + nfnl_ct_set_timeout@Base 3.5.0-1 + nfnl_ct_set_timeout@libnl_3 3.5.0-1 + nfnl_ct_set_timestamp@Base 3.5.0-1 + nfnl_ct_set_timestamp@libnl_3 3.5.0-1 + nfnl_ct_set_use@Base 3.5.0-1 + nfnl_ct_set_use@libnl_3 3.5.0-1 + nfnl_ct_set_zone@Base 3.5.0-1 + nfnl_ct_set_zone@libnl_3 3.5.0-1 + nfnl_ct_status2str@Base 3.5.0-1 + nfnl_ct_status2str@libnl_3 3.5.0-1 + nfnl_ct_str2status@Base 3.5.0-1 + nfnl_ct_str2status@libnl_3 3.5.0-1 + nfnl_ct_str2tcp_state@Base 3.5.0-1 + nfnl_ct_str2tcp_state@libnl_3 3.5.0-1 + nfnl_ct_tcp_state2str@Base 3.5.0-1 + nfnl_ct_tcp_state2str@libnl_3 3.5.0-1 + nfnl_ct_test_bytes@Base 3.5.0-1 + nfnl_ct_test_bytes@libnl_3 3.5.0-1 + nfnl_ct_test_dst_port@Base 3.5.0-1 + nfnl_ct_test_dst_port@libnl_3 3.5.0-1 + nfnl_ct_test_icmp_code@Base 3.5.0-1 + nfnl_ct_test_icmp_code@libnl_3 3.5.0-1 + nfnl_ct_test_icmp_id@Base 3.5.0-1 + nfnl_ct_test_icmp_id@libnl_3 3.5.0-1 + nfnl_ct_test_icmp_type@Base 3.5.0-1 + nfnl_ct_test_icmp_type@libnl_3 3.5.0-1 + nfnl_ct_test_id@Base 3.5.0-1 + nfnl_ct_test_id@libnl_3 3.5.0-1 + nfnl_ct_test_mark@Base 3.5.0-1 + nfnl_ct_test_mark@libnl_3 3.5.0-1 + nfnl_ct_test_packets@Base 3.5.0-1 + nfnl_ct_test_packets@libnl_3 3.5.0-1 + nfnl_ct_test_proto@Base 3.5.0-1 + nfnl_ct_test_proto@libnl_3 3.5.0-1 + nfnl_ct_test_src_port@Base 3.5.0-1 + nfnl_ct_test_src_port@libnl_3 3.5.0-1 + nfnl_ct_test_status@Base 3.5.0-1 + nfnl_ct_test_status@libnl_3 3.5.0-1 + nfnl_ct_test_tcp_state@Base 3.5.0-1 + nfnl_ct_test_tcp_state@libnl_3 3.5.0-1 + nfnl_ct_test_timeout@Base 3.5.0-1 + nfnl_ct_test_timeout@libnl_3 3.5.0-1 + nfnl_ct_test_timestamp@Base 3.5.0-1 + nfnl_ct_test_timestamp@libnl_3 3.5.0-1 + nfnl_ct_test_use@Base 3.5.0-1 + nfnl_ct_test_use@libnl_3 3.5.0-1 + nfnl_ct_test_zone@Base 3.5.0-1 + nfnl_ct_test_zone@libnl_3 3.5.0-1 + nfnl_ct_unset_status@Base 3.5.0-1 + nfnl_ct_unset_status@libnl_3 3.5.0-1 + nfnl_exp_add@Base 3.5.0-1 + nfnl_exp_add@libnl_3 3.5.0-1 + nfnl_exp_alloc@Base 3.5.0-1 + nfnl_exp_alloc@libnl_3 3.5.0-1 + nfnl_exp_alloc_cache@Base 3.5.0-1 + nfnl_exp_alloc_cache@libnl_3 3.5.0-1 + nfnl_exp_build_add_request@Base 3.5.0-1 + nfnl_exp_build_add_request@libnl_3 3.5.0-1 + nfnl_exp_build_delete_request@Base 3.5.0-1 + nfnl_exp_build_delete_request@libnl_3 3.5.0-1 + nfnl_exp_build_query_request@Base 3.5.0-1 + nfnl_exp_build_query_request@libnl_3 3.5.0-1 + nfnl_exp_del@Base 3.5.0-1 + nfnl_exp_del@libnl_3 3.5.0-1 + nfnl_exp_dump_request@Base 3.5.0-1 + nfnl_exp_dump_request@libnl_3 3.5.0-1 + nfnl_exp_flags2str@Base 3.5.0-1 + nfnl_exp_flags2str@libnl_3 3.5.0-1 + nfnl_exp_get@Base 3.5.0-1 + nfnl_exp_get@libnl_3 3.5.0-1 + nfnl_exp_get_class@Base 3.5.0-1 + nfnl_exp_get_class@libnl_3 3.5.0-1 + nfnl_exp_get_dst@Base 3.5.0-1 + nfnl_exp_get_dst@libnl_3 3.5.0-1 + nfnl_exp_get_dst_port@Base 3.5.0-1 + nfnl_exp_get_dst_port@libnl_3 3.5.0-1 + nfnl_exp_get_family@Base 3.5.0-1 + nfnl_exp_get_family@libnl_3 3.5.0-1 + nfnl_exp_get_flags@Base 3.5.0-1 + nfnl_exp_get_flags@libnl_3 3.5.0-1 + nfnl_exp_get_fn@Base 3.5.0-1 + nfnl_exp_get_fn@libnl_3 3.5.0-1 + nfnl_exp_get_helper_name@Base 3.5.0-1 + nfnl_exp_get_helper_name@libnl_3 3.5.0-1 + nfnl_exp_get_icmp_code@Base 3.5.0-1 + nfnl_exp_get_icmp_code@libnl_3 3.5.0-1 + nfnl_exp_get_icmp_id@Base 3.5.0-1 + nfnl_exp_get_icmp_id@libnl_3 3.5.0-1 + nfnl_exp_get_icmp_type@Base 3.5.0-1 + nfnl_exp_get_icmp_type@libnl_3 3.5.0-1 + nfnl_exp_get_id@Base 3.5.0-1 + nfnl_exp_get_id@libnl_3 3.5.0-1 + nfnl_exp_get_l4protonum@Base 3.5.0-1 + nfnl_exp_get_l4protonum@libnl_3 3.5.0-1 + nfnl_exp_get_nat_dir@Base 3.5.0-1 + nfnl_exp_get_nat_dir@libnl_3 3.5.0-1 + nfnl_exp_get_src@Base 3.5.0-1 + nfnl_exp_get_src@libnl_3 3.5.0-1 + nfnl_exp_get_src_port@Base 3.5.0-1 + nfnl_exp_get_src_port@libnl_3 3.5.0-1 + nfnl_exp_get_timeout@Base 3.5.0-1 + nfnl_exp_get_timeout@libnl_3 3.5.0-1 + nfnl_exp_get_zone@Base 3.5.0-1 + nfnl_exp_get_zone@libnl_3 3.5.0-1 + nfnl_exp_put@Base 3.5.0-1 + nfnl_exp_put@libnl_3 3.5.0-1 + nfnl_exp_query@Base 3.5.0-1 + nfnl_exp_query@libnl_3 3.5.0-1 + nfnl_exp_set_class@Base 3.5.0-1 + nfnl_exp_set_class@libnl_3 3.5.0-1 + nfnl_exp_set_dst@Base 3.5.0-1 + nfnl_exp_set_dst@libnl_3 3.5.0-1 + nfnl_exp_set_family@Base 3.5.0-1 + nfnl_exp_set_family@libnl_3 3.5.0-1 + nfnl_exp_set_flags@Base 3.5.0-1 + nfnl_exp_set_flags@libnl_3 3.5.0-1 + nfnl_exp_set_fn@Base 3.5.0-1 + nfnl_exp_set_fn@libnl_3 3.5.0-1 + nfnl_exp_set_helper_name@Base 3.5.0-1 + nfnl_exp_set_helper_name@libnl_3 3.5.0-1 + nfnl_exp_set_icmp@Base 3.5.0-1 + nfnl_exp_set_icmp@libnl_3 3.5.0-1 + nfnl_exp_set_id@Base 3.5.0-1 + nfnl_exp_set_id@libnl_3 3.5.0-1 + nfnl_exp_set_l4protonum@Base 3.5.0-1 + nfnl_exp_set_l4protonum@libnl_3 3.5.0-1 + nfnl_exp_set_nat_dir@Base 3.5.0-1 + nfnl_exp_set_nat_dir@libnl_3 3.5.0-1 + nfnl_exp_set_ports@Base 3.5.0-1 + nfnl_exp_set_ports@libnl_3 3.5.0-1 + nfnl_exp_set_src@Base 3.5.0-1 + nfnl_exp_set_src@libnl_3 3.5.0-1 + nfnl_exp_set_timeout@Base 3.5.0-1 + nfnl_exp_set_timeout@libnl_3 3.5.0-1 + nfnl_exp_set_zone@Base 3.5.0-1 + nfnl_exp_set_zone@libnl_3 3.5.0-1 + nfnl_exp_str2flags@Base 3.5.0-1 + nfnl_exp_str2flags@libnl_3 3.5.0-1 + nfnl_exp_test_class@Base 3.5.0-1 + nfnl_exp_test_class@libnl_3 3.5.0-1 + nfnl_exp_test_dst@Base 3.5.0-1 + nfnl_exp_test_dst@libnl_3 3.5.0-1 + nfnl_exp_test_flags@Base 3.5.0-1 + nfnl_exp_test_flags@libnl_3 3.5.0-1 + nfnl_exp_test_fn@Base 3.5.0-1 + nfnl_exp_test_fn@libnl_3 3.5.0-1 + nfnl_exp_test_helper_name@Base 3.5.0-1 + nfnl_exp_test_helper_name@libnl_3 3.5.0-1 + nfnl_exp_test_icmp@Base 3.5.0-1 + nfnl_exp_test_icmp@libnl_3 3.5.0-1 + nfnl_exp_test_id@Base 3.5.0-1 + nfnl_exp_test_id@libnl_3 3.5.0-1 + nfnl_exp_test_l4protonum@Base 3.5.0-1 + nfnl_exp_test_l4protonum@libnl_3 3.5.0-1 + nfnl_exp_test_nat_dir@Base 3.5.0-1 + nfnl_exp_test_nat_dir@libnl_3 3.5.0-1 + nfnl_exp_test_ports@Base 3.5.0-1 + nfnl_exp_test_ports@libnl_3 3.5.0-1 + nfnl_exp_test_src@Base 3.5.0-1 + nfnl_exp_test_src@libnl_3 3.5.0-1 + nfnl_exp_test_timeout@Base 3.5.0-1 + nfnl_exp_test_timeout@libnl_3 3.5.0-1 + nfnl_exp_test_zone@Base 3.5.0-1 + nfnl_exp_test_zone@libnl_3 3.5.0-1 + nfnl_exp_unset_flags@Base 3.5.0-1 + nfnl_exp_unset_flags@libnl_3 3.5.0-1 + nfnl_inet_hook2str@Base 3.5.0-1 + nfnl_inet_hook2str@libnl_3 3.5.0-1 + nfnl_log_alloc@Base 3.5.0-1 + nfnl_log_alloc@libnl_3 3.5.0-1 + nfnl_log_build_change_request@Base 3.5.0-1 + nfnl_log_build_change_request@libnl_3 3.5.0-1 + nfnl_log_build_create_request@Base 3.5.0-1 + nfnl_log_build_create_request@libnl_3 3.5.0-1 + nfnl_log_build_delete_request@Base 3.5.0-1 + nfnl_log_build_delete_request@libnl_3 3.5.0-1 + nfnl_log_build_pf_bind@Base 3.5.0-1 + nfnl_log_build_pf_bind@libnl_3 3.5.0-1 + nfnl_log_build_pf_unbind@Base 3.5.0-1 + nfnl_log_build_pf_unbind@libnl_3 3.5.0-1 + nfnl_log_change@Base 3.5.0-1 + nfnl_log_change@libnl_3 3.5.0-1 + nfnl_log_copy_mode2str@Base 3.5.0-1 + nfnl_log_copy_mode2str@libnl_3 3.5.0-1 + nfnl_log_create@Base 3.5.0-1 + nfnl_log_create@libnl_3 3.5.0-1 + nfnl_log_delete@Base 3.5.0-1 + nfnl_log_delete@libnl_3 3.5.0-1 + nfnl_log_flags2str@Base 3.5.0-1 + nfnl_log_flags2str@libnl_3 3.5.0-1 + nfnl_log_get@Base 3.5.0-1 + nfnl_log_get@libnl_3 3.5.0-1 + nfnl_log_get_alloc_size@Base 3.5.0-1 + nfnl_log_get_alloc_size@libnl_3 3.5.0-1 + nfnl_log_get_copy_mode@Base 3.5.0-1 + nfnl_log_get_copy_mode@libnl_3 3.5.0-1 + nfnl_log_get_copy_range@Base 3.5.0-1 + nfnl_log_get_copy_range@libnl_3 3.5.0-1 + nfnl_log_get_flush_timeout@Base 3.5.0-1 + nfnl_log_get_flush_timeout@libnl_3 3.5.0-1 + nfnl_log_get_group@Base 3.5.0-1 + nfnl_log_get_group@libnl_3 3.5.0-1 + nfnl_log_get_queue_threshold@Base 3.5.0-1 + nfnl_log_get_queue_threshold@libnl_3 3.5.0-1 + nfnl_log_msg_alloc@Base 3.5.0-1 + nfnl_log_msg_alloc@libnl_3 3.5.0-1 + nfnl_log_msg_get@Base 3.5.0-1 + nfnl_log_msg_get@libnl_3 3.5.0-1 + nfnl_log_msg_get_family@Base 3.5.0-1 + nfnl_log_msg_get_family@libnl_3 3.5.0-1 + nfnl_log_msg_get_gid@Base 3.5.0-1 + nfnl_log_msg_get_gid@libnl_3 3.5.0-1 + nfnl_log_msg_get_hook@Base 3.5.0-1 + nfnl_log_msg_get_hook@libnl_3 3.5.0-1 + nfnl_log_msg_get_hwaddr@Base 3.5.0-1 + nfnl_log_msg_get_hwaddr@libnl_3 3.5.0-1 + nfnl_log_msg_get_hwproto@Base 3.5.0-1 + nfnl_log_msg_get_hwproto@libnl_3 3.5.0-1 + nfnl_log_msg_get_indev@Base 3.5.0-1 + nfnl_log_msg_get_indev@libnl_3 3.5.0-1 + nfnl_log_msg_get_mark@Base 3.5.0-1 + nfnl_log_msg_get_mark@libnl_3 3.5.0-1 + nfnl_log_msg_get_outdev@Base 3.5.0-1 + nfnl_log_msg_get_outdev@libnl_3 3.5.0-1 + nfnl_log_msg_get_payload@Base 3.5.0-1 + nfnl_log_msg_get_payload@libnl_3 3.5.0-1 + nfnl_log_msg_get_physindev@Base 3.5.0-1 + nfnl_log_msg_get_physindev@libnl_3 3.5.0-1 + nfnl_log_msg_get_physoutdev@Base 3.5.0-1 + nfnl_log_msg_get_physoutdev@libnl_3 3.5.0-1 + nfnl_log_msg_get_prefix@Base 3.5.0-1 + nfnl_log_msg_get_prefix@libnl_3 3.5.0-1 + nfnl_log_msg_get_seq@Base 3.5.0-1 + nfnl_log_msg_get_seq@libnl_3 3.5.0-1 + nfnl_log_msg_get_seq_global@Base 3.5.0-1 + nfnl_log_msg_get_seq_global@libnl_3 3.5.0-1 + nfnl_log_msg_get_timestamp@Base 3.5.0-1 + nfnl_log_msg_get_timestamp@libnl_3 3.5.0-1 + nfnl_log_msg_get_uid@Base 3.5.0-1 + nfnl_log_msg_get_uid@libnl_3 3.5.0-1 + nfnl_log_msg_put@Base 3.5.0-1 + nfnl_log_msg_put@libnl_3 3.5.0-1 + nfnl_log_msg_set_family@Base 3.5.0-1 + nfnl_log_msg_set_family@libnl_3 3.5.0-1 + nfnl_log_msg_set_gid@Base 3.5.0-1 + nfnl_log_msg_set_gid@libnl_3 3.5.0-1 + nfnl_log_msg_set_hook@Base 3.5.0-1 + nfnl_log_msg_set_hook@libnl_3 3.5.0-1 + nfnl_log_msg_set_hwaddr@Base 3.5.0-1 + nfnl_log_msg_set_hwaddr@libnl_3 3.5.0-1 + nfnl_log_msg_set_hwproto@Base 3.5.0-1 + nfnl_log_msg_set_hwproto@libnl_3 3.5.0-1 + nfnl_log_msg_set_indev@Base 3.5.0-1 + nfnl_log_msg_set_indev@libnl_3 3.5.0-1 + nfnl_log_msg_set_mark@Base 3.5.0-1 + nfnl_log_msg_set_mark@libnl_3 3.5.0-1 + nfnl_log_msg_set_outdev@Base 3.5.0-1 + nfnl_log_msg_set_outdev@libnl_3 3.5.0-1 + nfnl_log_msg_set_payload@Base 3.5.0-1 + nfnl_log_msg_set_payload@libnl_3 3.5.0-1 + nfnl_log_msg_set_physindev@Base 3.5.0-1 + nfnl_log_msg_set_physindev@libnl_3 3.5.0-1 + nfnl_log_msg_set_physoutdev@Base 3.5.0-1 + nfnl_log_msg_set_physoutdev@libnl_3 3.5.0-1 + nfnl_log_msg_set_prefix@Base 3.5.0-1 + nfnl_log_msg_set_prefix@libnl_3 3.5.0-1 + nfnl_log_msg_set_seq@Base 3.5.0-1 + nfnl_log_msg_set_seq@libnl_3 3.5.0-1 + nfnl_log_msg_set_seq_global@Base 3.5.0-1 + nfnl_log_msg_set_seq_global@libnl_3 3.5.0-1 + nfnl_log_msg_set_timestamp@Base 3.5.0-1 + nfnl_log_msg_set_timestamp@libnl_3 3.5.0-1 + nfnl_log_msg_set_uid@Base 3.5.0-1 + nfnl_log_msg_set_uid@libnl_3 3.5.0-1 + nfnl_log_msg_test_gid@Base 3.5.0-1 + nfnl_log_msg_test_gid@libnl_3 3.5.0-1 + nfnl_log_msg_test_hook@Base 3.5.0-1 + nfnl_log_msg_test_hook@libnl_3 3.5.0-1 + nfnl_log_msg_test_hwproto@Base 3.5.0-1 + nfnl_log_msg_test_hwproto@libnl_3 3.5.0-1 + nfnl_log_msg_test_mark@Base 3.5.0-1 + nfnl_log_msg_test_mark@libnl_3 3.5.0-1 + nfnl_log_msg_test_seq@Base 3.5.0-1 + nfnl_log_msg_test_seq@libnl_3 3.5.0-1 + nfnl_log_msg_test_seq_global@Base 3.5.0-1 + nfnl_log_msg_test_seq_global@libnl_3 3.5.0-1 + nfnl_log_msg_test_uid@Base 3.5.0-1 + nfnl_log_msg_test_uid@libnl_3 3.5.0-1 + nfnl_log_pf_bind@Base 3.5.0-1 + nfnl_log_pf_bind@libnl_3 3.5.0-1 + nfnl_log_pf_unbind@Base 3.5.0-1 + nfnl_log_pf_unbind@libnl_3 3.5.0-1 + nfnl_log_put@Base 3.5.0-1 + nfnl_log_put@libnl_3 3.5.0-1 + nfnl_log_set_alloc_size@Base 3.5.0-1 + nfnl_log_set_alloc_size@libnl_3 3.5.0-1 + nfnl_log_set_copy_mode@Base 3.5.0-1 + nfnl_log_set_copy_mode@libnl_3 3.5.0-1 + nfnl_log_set_copy_range@Base 3.5.0-1 + nfnl_log_set_copy_range@libnl_3 3.5.0-1 + nfnl_log_set_flags@Base 3.5.0-1 + nfnl_log_set_flags@libnl_3 3.5.0-1 + nfnl_log_set_flush_timeout@Base 3.5.0-1 + nfnl_log_set_flush_timeout@libnl_3 3.5.0-1 + nfnl_log_set_group@Base 3.5.0-1 + nfnl_log_set_group@libnl_3 3.5.0-1 + nfnl_log_set_queue_threshold@Base 3.5.0-1 + nfnl_log_set_queue_threshold@libnl_3 3.5.0-1 + nfnl_log_str2copy_mode@Base 3.5.0-1 + nfnl_log_str2copy_mode@libnl_3 3.5.0-1 + nfnl_log_str2flags@Base 3.5.0-1 + nfnl_log_str2flags@libnl_3 3.5.0-1 + nfnl_log_test_alloc_size@Base 3.5.0-1 + nfnl_log_test_alloc_size@libnl_3 3.5.0-1 + nfnl_log_test_copy_mode@Base 3.5.0-1 + nfnl_log_test_copy_mode@libnl_3 3.5.0-1 + nfnl_log_test_copy_range@Base 3.5.0-1 + nfnl_log_test_copy_range@libnl_3 3.5.0-1 + nfnl_log_test_flush_timeout@Base 3.5.0-1 + nfnl_log_test_flush_timeout@libnl_3 3.5.0-1 + nfnl_log_test_group@Base 3.5.0-1 + nfnl_log_test_group@libnl_3 3.5.0-1 + nfnl_log_test_queue_threshold@Base 3.5.0-1 + nfnl_log_test_queue_threshold@libnl_3 3.5.0-1 + nfnl_log_unset_flags@Base 3.5.0-1 + nfnl_log_unset_flags@libnl_3 3.5.0-1 + nfnl_queue_alloc@Base 3.5.0-1 + nfnl_queue_alloc@libnl_3 3.5.0-1 + nfnl_queue_build_change_request@Base 3.5.0-1 + nfnl_queue_build_change_request@libnl_3 3.5.0-1 + nfnl_queue_build_create_request@Base 3.5.0-1 + nfnl_queue_build_create_request@libnl_3 3.5.0-1 + nfnl_queue_build_delete_request@Base 3.5.0-1 + nfnl_queue_build_delete_request@libnl_3 3.5.0-1 + nfnl_queue_build_pf_bind@Base 3.5.0-1 + nfnl_queue_build_pf_bind@libnl_3 3.5.0-1 + nfnl_queue_build_pf_unbind@Base 3.5.0-1 + nfnl_queue_build_pf_unbind@libnl_3 3.5.0-1 + nfnl_queue_change@Base 3.5.0-1 + nfnl_queue_change@libnl_3 3.5.0-1 + nfnl_queue_copy_mode2str@Base 3.5.0-1 + nfnl_queue_copy_mode2str@libnl_3 3.5.0-1 + nfnl_queue_create@Base 3.5.0-1 + nfnl_queue_create@libnl_3 3.5.0-1 + nfnl_queue_delete@Base 3.5.0-1 + nfnl_queue_delete@libnl_3 3.5.0-1 + nfnl_queue_get@Base 3.5.0-1 + nfnl_queue_get@libnl_3 3.5.0-1 + nfnl_queue_get_copy_mode@Base 3.5.0-1 + nfnl_queue_get_copy_mode@libnl_3 3.5.0-1 + nfnl_queue_get_copy_range@Base 3.5.0-1 + nfnl_queue_get_copy_range@libnl_3 3.5.0-1 + nfnl_queue_get_group@Base 3.5.0-1 + nfnl_queue_get_group@libnl_3 3.5.0-1 + nfnl_queue_get_maxlen@Base 3.5.0-1 + nfnl_queue_get_maxlen@libnl_3 3.5.0-1 + nfnl_queue_msg_alloc@Base 3.5.0-1 + nfnl_queue_msg_alloc@libnl_3 3.5.0-1 + nfnl_queue_msg_build_verdict@Base 3.5.0-1 + nfnl_queue_msg_build_verdict@libnl_3 3.5.0-1 + nfnl_queue_msg_build_verdict_batch@Base 3.5.0-1 + nfnl_queue_msg_build_verdict_batch@libnl_3 3.5.0-1 + nfnl_queue_msg_get@Base 3.5.0-1 + nfnl_queue_msg_get@libnl_3 3.5.0-1 + nfnl_queue_msg_get_family@Base 3.5.0-1 + nfnl_queue_msg_get_family@libnl_3 3.5.0-1 + nfnl_queue_msg_get_group@Base 3.5.0-1 + nfnl_queue_msg_get_group@libnl_3 3.5.0-1 + nfnl_queue_msg_get_hook@Base 3.5.0-1 + nfnl_queue_msg_get_hook@libnl_3 3.5.0-1 + nfnl_queue_msg_get_hwaddr@Base 3.5.0-1 + nfnl_queue_msg_get_hwaddr@libnl_3 3.5.0-1 + nfnl_queue_msg_get_hwproto@Base 3.5.0-1 + nfnl_queue_msg_get_hwproto@libnl_3 3.5.0-1 + nfnl_queue_msg_get_indev@Base 3.5.0-1 + nfnl_queue_msg_get_indev@libnl_3 3.5.0-1 + nfnl_queue_msg_get_mark@Base 3.5.0-1 + nfnl_queue_msg_get_mark@libnl_3 3.5.0-1 + nfnl_queue_msg_get_outdev@Base 3.5.0-1 + nfnl_queue_msg_get_outdev@libnl_3 3.5.0-1 + nfnl_queue_msg_get_packetid@Base 3.5.0-1 + nfnl_queue_msg_get_packetid@libnl_3 3.5.0-1 + nfnl_queue_msg_get_payload@Base 3.5.0-1 + nfnl_queue_msg_get_payload@libnl_3 3.5.0-1 + nfnl_queue_msg_get_physindev@Base 3.5.0-1 + nfnl_queue_msg_get_physindev@libnl_3 3.5.0-1 + nfnl_queue_msg_get_physoutdev@Base 3.5.0-1 + nfnl_queue_msg_get_physoutdev@libnl_3 3.5.0-1 + nfnl_queue_msg_get_timestamp@Base 3.5.0-1 + nfnl_queue_msg_get_timestamp@libnl_3 3.5.0-1 + nfnl_queue_msg_get_verdict@Base 3.5.0-1 + nfnl_queue_msg_get_verdict@libnl_3 3.5.0-1 + nfnl_queue_msg_put@Base 3.5.0-1 + nfnl_queue_msg_put@libnl_3 3.5.0-1 + nfnl_queue_msg_send_verdict@Base 3.5.0-1 + nfnl_queue_msg_send_verdict@libnl_3 3.5.0-1 + nfnl_queue_msg_send_verdict_batch@Base 3.5.0-1 + nfnl_queue_msg_send_verdict_batch@libnl_3 3.5.0-1 + nfnl_queue_msg_send_verdict_payload@Base 3.5.0-1 + nfnl_queue_msg_send_verdict_payload@libnl_3 3.5.0-1 + nfnl_queue_msg_set_family@Base 3.5.0-1 + nfnl_queue_msg_set_family@libnl_3 3.5.0-1 + nfnl_queue_msg_set_group@Base 3.5.0-1 + nfnl_queue_msg_set_group@libnl_3 3.5.0-1 + nfnl_queue_msg_set_hook@Base 3.5.0-1 + nfnl_queue_msg_set_hook@libnl_3 3.5.0-1 + nfnl_queue_msg_set_hwaddr@Base 3.5.0-1 + nfnl_queue_msg_set_hwaddr@libnl_3 3.5.0-1 + nfnl_queue_msg_set_hwproto@Base 3.5.0-1 + nfnl_queue_msg_set_hwproto@libnl_3 3.5.0-1 + nfnl_queue_msg_set_indev@Base 3.5.0-1 + nfnl_queue_msg_set_indev@libnl_3 3.5.0-1 + nfnl_queue_msg_set_mark@Base 3.5.0-1 + nfnl_queue_msg_set_mark@libnl_3 3.5.0-1 + nfnl_queue_msg_set_outdev@Base 3.5.0-1 + nfnl_queue_msg_set_outdev@libnl_3 3.5.0-1 + nfnl_queue_msg_set_packetid@Base 3.5.0-1 + nfnl_queue_msg_set_packetid@libnl_3 3.5.0-1 + nfnl_queue_msg_set_payload@Base 3.5.0-1 + nfnl_queue_msg_set_payload@libnl_3 3.5.0-1 + nfnl_queue_msg_set_physindev@Base 3.5.0-1 + nfnl_queue_msg_set_physindev@libnl_3 3.5.0-1 + nfnl_queue_msg_set_physoutdev@Base 3.5.0-1 + nfnl_queue_msg_set_physoutdev@libnl_3 3.5.0-1 + nfnl_queue_msg_set_timestamp@Base 3.5.0-1 + nfnl_queue_msg_set_timestamp@libnl_3 3.5.0-1 + nfnl_queue_msg_set_verdict@Base 3.5.0-1 + nfnl_queue_msg_set_verdict@libnl_3 3.5.0-1 + nfnl_queue_msg_test_family@Base 3.5.0-1 + nfnl_queue_msg_test_family@libnl_3 3.5.0-1 + nfnl_queue_msg_test_group@Base 3.5.0-1 + nfnl_queue_msg_test_group@libnl_3 3.5.0-1 + nfnl_queue_msg_test_hook@Base 3.5.0-1 + nfnl_queue_msg_test_hook@libnl_3 3.5.0-1 + nfnl_queue_msg_test_hwaddr@Base 3.5.0-1 + nfnl_queue_msg_test_hwaddr@libnl_3 3.5.0-1 + nfnl_queue_msg_test_hwproto@Base 3.5.0-1 + nfnl_queue_msg_test_hwproto@libnl_3 3.5.0-1 + nfnl_queue_msg_test_indev@Base 3.5.0-1 + nfnl_queue_msg_test_indev@libnl_3 3.5.0-1 + nfnl_queue_msg_test_mark@Base 3.5.0-1 + nfnl_queue_msg_test_mark@libnl_3 3.5.0-1 + nfnl_queue_msg_test_outdev@Base 3.5.0-1 + nfnl_queue_msg_test_outdev@libnl_3 3.5.0-1 + nfnl_queue_msg_test_packetid@Base 3.5.0-1 + nfnl_queue_msg_test_packetid@libnl_3 3.5.0-1 + nfnl_queue_msg_test_payload@Base 3.5.0-1 + nfnl_queue_msg_test_payload@libnl_3 3.5.0-1 + nfnl_queue_msg_test_physindev@Base 3.5.0-1 + nfnl_queue_msg_test_physindev@libnl_3 3.5.0-1 + nfnl_queue_msg_test_physoutdev@Base 3.5.0-1 + nfnl_queue_msg_test_physoutdev@libnl_3 3.5.0-1 + nfnl_queue_msg_test_timestamp@Base 3.5.0-1 + nfnl_queue_msg_test_timestamp@libnl_3 3.5.0-1 + nfnl_queue_msg_test_verdict@Base 3.5.0-1 + nfnl_queue_msg_test_verdict@libnl_3 3.5.0-1 + nfnl_queue_pf_bind@Base 3.5.0-1 + nfnl_queue_pf_bind@libnl_3 3.5.0-1 + nfnl_queue_pf_unbind@Base 3.5.0-1 + nfnl_queue_pf_unbind@libnl_3 3.5.0-1 + nfnl_queue_put@Base 3.5.0-1 + nfnl_queue_put@libnl_3 3.5.0-1 + nfnl_queue_set_copy_mode@Base 3.5.0-1 + nfnl_queue_set_copy_mode@libnl_3 3.5.0-1 + nfnl_queue_set_copy_range@Base 3.5.0-1 + nfnl_queue_set_copy_range@libnl_3 3.5.0-1 + nfnl_queue_set_group@Base 3.5.0-1 + nfnl_queue_set_group@libnl_3 3.5.0-1 + nfnl_queue_set_maxlen@Base 3.5.0-1 + nfnl_queue_set_maxlen@libnl_3 3.5.0-1 + nfnl_queue_socket_alloc@Base 3.5.0-1 + nfnl_queue_socket_alloc@libnl_3 3.5.0-1 + nfnl_queue_str2copy_mode@Base 3.5.0-1 + nfnl_queue_str2copy_mode@libnl_3 3.5.0-1 + nfnl_queue_test_copy_mode@Base 3.5.0-1 + nfnl_queue_test_copy_mode@libnl_3 3.5.0-1 + nfnl_queue_test_copy_range@Base 3.5.0-1 + nfnl_queue_test_copy_range@libnl_3 3.5.0-1 + nfnl_queue_test_group@Base 3.5.0-1 + nfnl_queue_test_group@libnl_3 3.5.0-1 + nfnl_queue_test_maxlen@Base 3.5.0-1 + nfnl_queue_test_maxlen@libnl_3 3.5.0-1 + nfnl_send_simple@Base 3.5.0-1 + nfnl_send_simple@libnl_3 3.5.0-1 + nfnl_str2inet_hook@Base 3.5.0-1 + nfnl_str2inet_hook@libnl_3 3.5.0-1 + nfnl_str2verdict@Base 3.5.0-1 + nfnl_str2verdict@libnl_3 3.5.0-1 + nfnl_verdict2str@Base 3.5.0-1 + nfnl_verdict2str@libnl_3 3.5.0-1 + nfnlmsg_alloc_simple@Base 3.5.0-1 + nfnlmsg_alloc_simple@libnl_3 3.5.0-1 + nfnlmsg_ct_group@Base 3.5.0-1 + nfnlmsg_ct_group@libnl_3 3.5.0-1 + nfnlmsg_ct_parse@Base 3.5.0-1 + nfnlmsg_ct_parse@libnl_3 3.5.0-1 + nfnlmsg_exp_group@Base 3.5.0-1 + nfnlmsg_exp_group@libnl_3 3.5.0-1 + nfnlmsg_exp_parse@Base 3.5.0-1 + nfnlmsg_exp_parse@libnl_3 3.5.0-1 + nfnlmsg_family@Base 3.5.0-1 + nfnlmsg_family@libnl_3 3.5.0-1 + nfnlmsg_log_msg_parse@Base 3.5.0-1 + nfnlmsg_log_msg_parse@libnl_3 3.5.0-1 + nfnlmsg_put@Base 3.5.0-1 + nfnlmsg_put@libnl_3 3.5.0-1 + nfnlmsg_queue_msg_parse@Base 3.5.0-1 + nfnlmsg_queue_msg_parse@libnl_3 3.5.0-1 + nfnlmsg_res_id@Base 3.5.0-1 + nfnlmsg_res_id@libnl_3 3.5.0-1 + nfnlmsg_subsys@Base 3.5.0-1 + nfnlmsg_subsys@libnl_3 3.5.0-1 + nfnlmsg_subtype@Base 3.5.0-1 + nfnlmsg_subtype@libnl_3 3.5.0-1 + queue_msg_obj_ops@Base 3.5.0-1 + queue_msg_obj_ops@libnl_3 3.5.0-1 + queue_obj_ops@Base 3.5.0-1 + queue_obj_ops@libnl_3 3.5.0-1 diff --git a/src/libnl3/debian/libnl-nf-3-dev.install b/src/libnl3/debian/libnl-nf-3-dev.install new file mode 100644 index 000000000000..d1307c751b84 --- /dev/null +++ b/src/libnl3/debian/libnl-nf-3-dev.install @@ -0,0 +1,3 @@ +debian/tmp/usr/lib/*/pkgconfig/libnl-nf-3* +debian/tmp/usr/lib/*/libnl-nf-3*.so +debian/tmp/usr/lib/*/libnl-nf-3*.a diff --git a/src/libnl3/debian/libnl-route-3-200.install b/src/libnl3/debian/libnl-route-3-200.install new file mode 100644 index 000000000000..44c7ec8cdfad --- /dev/null +++ b/src/libnl3/debian/libnl-route-3-200.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/*/libnl-route-3*.so.* diff --git a/src/libnl3/debian/libnl-route-3-200.symbols b/src/libnl3/debian/libnl-route-3-200.symbols new file mode 100644 index 000000000000..e11157ba4e88 --- /dev/null +++ b/src/libnl3/debian/libnl-route-3-200.symbols @@ -0,0 +1,2051 @@ +libnl-route-3.so.200 libnl-route-3-200 #MINVER# + ematch__create_buffer@Base 3.5.0-1 + ematch__delete_buffer@Base 3.5.0-1 + ematch__flush_buffer@Base 3.5.0-1 + ematch__scan_buffer@Base 3.5.0-1 + ematch__scan_bytes@Base 3.5.0-1 + ematch__scan_string@Base 3.5.0-1 + ematch__switch_to_buffer@Base 3.5.0-1 + ematch_alloc@Base 3.5.0-1 + ematch_free@Base 3.5.0-1 + ematch_get_column@Base 3.5.0-1 + ematch_get_debug@Base 3.5.0-1 + ematch_get_extra@Base 3.5.0-1 + ematch_get_in@Base 3.5.0-1 + ematch_get_leng@Base 3.5.0-1 + ematch_get_lineno@Base 3.5.0-1 + ematch_get_lval@Base 3.5.0-1 + ematch_get_out@Base 3.5.0-1 + ematch_get_text@Base 3.5.0-1 + ematch_lex@Base 3.5.0-1 + ematch_lex_destroy@Base 3.5.0-1 + ematch_lex_init@Base 3.5.0-1 + ematch_lex_init_extra@Base 3.5.0-1 + ematch_parse@Base 3.5.0-1 + ematch_pop_buffer_state@Base 3.5.0-1 + ematch_push_buffer_state@Base 3.5.0-1 + ematch_realloc@Base 3.5.0-1 + ematch_restart@Base 3.5.0-1 + ematch_set_column@Base 3.5.0-1 + ematch_set_debug@Base 3.5.0-1 + ematch_set_extra@Base 3.5.0-1 + ematch_set_in@Base 3.5.0-1 + ematch_set_lineno@Base 3.5.0-1 + ematch_set_lval@Base 3.5.0-1 + ematch_set_out@Base 3.5.0-1 + flnl_lookup@Base 3.5.0-1 + flnl_lookup@libnl_3 3.5.0-1 + flnl_lookup_build_request@Base 3.5.0-1 + flnl_lookup_build_request@libnl_3 3.5.0-1 + flnl_request_alloc@Base 3.5.0-1 + flnl_request_alloc@libnl_3 3.5.0-1 + flnl_request_get_addr@Base 3.5.0-1 + flnl_request_get_addr@libnl_3 3.5.0-1 + flnl_request_get_fwmark@Base 3.5.0-1 + flnl_request_get_fwmark@libnl_3 3.5.0-1 + flnl_request_get_scope@Base 3.5.0-1 + flnl_request_get_scope@libnl_3 3.5.0-1 + flnl_request_get_table@Base 3.5.0-1 + flnl_request_get_table@libnl_3 3.5.0-1 + flnl_request_get_tos@Base 3.5.0-1 + flnl_request_get_tos@libnl_3 3.5.0-1 + flnl_request_set_addr@Base 3.5.0-1 + flnl_request_set_addr@libnl_3 3.5.0-1 + flnl_request_set_fwmark@Base 3.5.0-1 + flnl_request_set_fwmark@libnl_3 3.5.0-1 + flnl_request_set_scope@Base 3.5.0-1 + flnl_request_set_scope@libnl_3 3.5.0-1 + flnl_request_set_table@Base 3.5.0-1 + flnl_request_set_table@libnl_3 3.5.0-1 + flnl_request_set_tos@Base 3.5.0-1 + flnl_request_set_tos@libnl_3 3.5.0-1 + flnl_result_alloc@Base 3.5.0-1 + flnl_result_alloc@libnl_3 3.5.0-1 + flnl_result_alloc_cache@Base 3.5.0-1 + flnl_result_alloc_cache@libnl_3 3.5.0-1 + flnl_result_get_error@Base 3.5.0-1 + flnl_result_get_error@libnl_3 3.5.0-1 + flnl_result_get_nexthop_sel@Base 3.5.0-1 + flnl_result_get_nexthop_sel@libnl_3 3.5.0-1 + flnl_result_get_prefixlen@Base 3.5.0-1 + flnl_result_get_prefixlen@libnl_3 3.5.0-1 + flnl_result_get_scope@Base 3.5.0-1 + flnl_result_get_scope@libnl_3 3.5.0-1 + flnl_result_get_table_id@Base 3.5.0-1 + flnl_result_get_table_id@libnl_3 3.5.0-1 + flnl_result_get_type@Base 3.5.0-1 + flnl_result_get_type@libnl_3 3.5.0-1 + flnl_result_put@Base 3.5.0-1 + flnl_result_put@libnl_3 3.5.0-1 + libnl_3@libnl_3 3.5.0-1 + libnl_3_2_26@libnl_3_2_26 3.5.0-1 + libnl_3_2_27@libnl_3_2_27 3.5.0-1 + libnl_3_2_28@libnl_3_2_28 3.5.0-1 + libnl_3_2_29@libnl_3_2_29 3.5.0-1 + libnl_3_4@libnl_3_4 3.5.0-1 + libnl_3_5@libnl_3_5 3.5.0-1 + nl_ovl_strategy2str@Base 3.5.0-1 + nl_ovl_strategy2str@libnl_3 3.5.0-1 + nl_police2str@Base 3.5.0-1 + nl_police2str@libnl_3 3.5.0-1 + nl_rtgen_request@Base 3.5.0-1 + nl_rtgen_request@libnl_3 3.5.0-1 + nl_rtntype2str@Base 3.5.0-1 + nl_rtntype2str@libnl_3 3.5.0-1 + nl_str2ovl_strategy@Base 3.5.0-1 + nl_str2ovl_strategy@libnl_3 3.5.0-1 + nl_str2police@Base 3.5.0-1 + nl_str2police@libnl_3 3.5.0-1 + nl_str2rtntype@Base 3.5.0-1 + nl_str2rtntype@libnl_3 3.5.0-1 + pktloc__create_buffer@Base 3.5.0-1 + pktloc__delete_buffer@Base 3.5.0-1 + pktloc__flush_buffer@Base 3.5.0-1 + pktloc__scan_buffer@Base 3.5.0-1 + pktloc__scan_bytes@Base 3.5.0-1 + pktloc__scan_string@Base 3.5.0-1 + pktloc__switch_to_buffer@Base 3.5.0-1 + pktloc_alloc@Base 3.5.0-1 + pktloc_free@Base 3.5.0-1 + pktloc_get_column@Base 3.5.0-1 + pktloc_get_debug@Base 3.5.0-1 + pktloc_get_extra@Base 3.5.0-1 + pktloc_get_in@Base 3.5.0-1 + pktloc_get_leng@Base 3.5.0-1 + pktloc_get_lineno@Base 3.5.0-1 + pktloc_get_lloc@Base 3.5.0-1 + pktloc_get_lval@Base 3.5.0-1 + pktloc_get_out@Base 3.5.0-1 + pktloc_get_text@Base 3.5.0-1 + pktloc_lex@Base 3.5.0-1 + pktloc_lex_destroy@Base 3.5.0-1 + pktloc_lex_init@Base 3.5.0-1 + pktloc_lex_init_extra@Base 3.5.0-1 + pktloc_parse@Base 3.5.0-1 + pktloc_pop_buffer_state@Base 3.5.0-1 + pktloc_push_buffer_state@Base 3.5.0-1 + pktloc_realloc@Base 3.5.0-1 + pktloc_restart@Base 3.5.0-1 + pktloc_set_column@Base 3.5.0-1 + pktloc_set_debug@Base 3.5.0-1 + pktloc_set_extra@Base 3.5.0-1 + pktloc_set_in@Base 3.5.0-1 + pktloc_set_lineno@Base 3.5.0-1 + pktloc_set_lloc@Base 3.5.0-1 + + pktloc_set_lval@Base 3.5.0-1 + pktloc_set_out@Base 3.5.0-1 + route_obj_ops@Base 3.5.0-1 + route_obj_ops@libnl_3 3.5.0-1 + rtln_link_policy@Base 3.5.0-1 + rtln_link_policy@libnl_3 3.5.0-1 + rtnl_act_add@Base 3.5.0-1 + rtnl_act_add@libnl_3 3.5.0-1 + rtnl_act_alloc@Base 3.5.0-1 + rtnl_act_alloc@libnl_3 3.5.0-1 + rtnl_act_append@Base 3.5.0-1 + rtnl_act_append@libnl_3 3.5.0-1 + rtnl_act_build_add_request@Base 3.5.0-1 + rtnl_act_build_add_request@libnl_3 3.5.0-1 + rtnl_act_build_change_request@Base 3.5.0-1 + rtnl_act_build_change_request@libnl_3 3.5.0-1 + rtnl_act_build_delete_request@Base 3.5.0-1 + rtnl_act_build_delete_request@libnl_3 3.5.0-1 + rtnl_act_change@Base 3.5.0-1 + rtnl_act_change@libnl_3 3.5.0-1 + rtnl_act_delete@Base 3.5.0-1 + rtnl_act_delete@libnl_3 3.5.0-1 + rtnl_act_fill@Base 3.5.0-1 + rtnl_act_fill@libnl_3 3.5.0-1 + rtnl_act_get@Base 3.5.0-1 + rtnl_act_get@libnl_3 3.5.0-1 + rtnl_act_next@libnl_3_4 3.5.0-1 + rtnl_act_parse@Base 3.5.0-1 + rtnl_act_parse@libnl_3 3.5.0-1 + rtnl_act_put@Base 3.5.0-1 + rtnl_act_put@libnl_3 3.5.0-1 + rtnl_act_put_all@Base 3.5.0-1 + rtnl_act_put_all@libnl_3 3.5.0-1 + rtnl_act_remove@Base 3.5.0-1 + rtnl_act_remove@libnl_3 3.5.0-1 + rtnl_addr_add@Base 3.5.0-1 + rtnl_addr_add@libnl_3 3.5.0-1 + rtnl_addr_alloc@Base 3.5.0-1 + rtnl_addr_alloc@libnl_3 3.5.0-1 + rtnl_addr_alloc_cache@Base 3.5.0-1 + rtnl_addr_alloc_cache@libnl_3 3.5.0-1 + rtnl_addr_build_add_request@Base 3.5.0-1 + rtnl_addr_build_add_request@libnl_3 3.5.0-1 + rtnl_addr_build_delete_request@Base 3.5.0-1 + rtnl_addr_build_delete_request@libnl_3 3.5.0-1 + rtnl_addr_delete@Base 3.5.0-1 + rtnl_addr_delete@libnl_3 3.5.0-1 + rtnl_addr_flags2str@Base 3.5.0-1 + rtnl_addr_flags2str@libnl_3 3.5.0-1 + rtnl_addr_get@Base 3.5.0-1 + rtnl_addr_get@libnl_3 3.5.0-1 + rtnl_addr_get_anycast@Base 3.5.0-1 + rtnl_addr_get_anycast@libnl_3 3.5.0-1 + rtnl_addr_get_broadcast@Base 3.5.0-1 + rtnl_addr_get_broadcast@libnl_3 3.5.0-1 + rtnl_addr_get_create_time@Base 3.5.0-1 + rtnl_addr_get_create_time@libnl_3 3.5.0-1 + rtnl_addr_get_family@Base 3.5.0-1 + rtnl_addr_get_family@libnl_3 3.5.0-1 + rtnl_addr_get_flags@Base 3.5.0-1 + rtnl_addr_get_flags@libnl_3 3.5.0-1 + rtnl_addr_get_ifindex@Base 3.5.0-1 + rtnl_addr_get_ifindex@libnl_3 3.5.0-1 + rtnl_addr_get_label@Base 3.5.0-1 + rtnl_addr_get_label@libnl_3 3.5.0-1 + rtnl_addr_get_last_update_time@Base 3.5.0-1 + rtnl_addr_get_last_update_time@libnl_3 3.5.0-1 + rtnl_addr_get_link@Base 3.5.0-1 + rtnl_addr_get_link@libnl_3 3.5.0-1 + rtnl_addr_get_local@Base 3.5.0-1 + rtnl_addr_get_local@libnl_3 3.5.0-1 + rtnl_addr_get_multicast@Base 3.5.0-1 + rtnl_addr_get_multicast@libnl_3 3.5.0-1 + rtnl_addr_get_peer@Base 3.5.0-1 + rtnl_addr_get_peer@libnl_3 3.5.0-1 + rtnl_addr_get_preferred_lifetime@Base 3.5.0-1 + rtnl_addr_get_preferred_lifetime@libnl_3 3.5.0-1 + rtnl_addr_get_prefixlen@Base 3.5.0-1 + rtnl_addr_get_prefixlen@libnl_3 3.5.0-1 + rtnl_addr_get_scope@Base 3.5.0-1 + rtnl_addr_get_scope@libnl_3 3.5.0-1 + rtnl_addr_get_valid_lifetime@Base 3.5.0-1 + rtnl_addr_get_valid_lifetime@libnl_3 3.5.0-1 + rtnl_addr_put@Base 3.5.0-1 + rtnl_addr_put@libnl_3 3.5.0-1 + rtnl_addr_set_anycast@Base 3.5.0-1 + rtnl_addr_set_anycast@libnl_3 3.5.0-1 + rtnl_addr_set_broadcast@Base 3.5.0-1 + rtnl_addr_set_broadcast@libnl_3 3.5.0-1 + rtnl_addr_set_family@Base 3.5.0-1 + rtnl_addr_set_family@libnl_3 3.5.0-1 + rtnl_addr_set_flags@Base 3.5.0-1 + rtnl_addr_set_flags@libnl_3 3.5.0-1 + rtnl_addr_set_ifindex@Base 3.5.0-1 + rtnl_addr_set_ifindex@libnl_3 3.5.0-1 + rtnl_addr_set_label@Base 3.5.0-1 + rtnl_addr_set_label@libnl_3 3.5.0-1 + rtnl_addr_set_link@Base 3.5.0-1 + rtnl_addr_set_link@libnl_3 3.5.0-1 + rtnl_addr_set_local@Base 3.5.0-1 + rtnl_addr_set_local@libnl_3 3.5.0-1 + rtnl_addr_set_multicast@Base 3.5.0-1 + rtnl_addr_set_multicast@libnl_3 3.5.0-1 + rtnl_addr_set_peer@Base 3.5.0-1 + rtnl_addr_set_peer@libnl_3 3.5.0-1 + rtnl_addr_set_preferred_lifetime@Base 3.5.0-1 + rtnl_addr_set_preferred_lifetime@libnl_3 3.5.0-1 + rtnl_addr_set_prefixlen@Base 3.5.0-1 + rtnl_addr_set_prefixlen@libnl_3 3.5.0-1 + rtnl_addr_set_scope@Base 3.5.0-1 + rtnl_addr_set_scope@libnl_3 3.5.0-1 + rtnl_addr_set_valid_lifetime@Base 3.5.0-1 + rtnl_addr_set_valid_lifetime@libnl_3 3.5.0-1 + rtnl_addr_str2flags@Base 3.5.0-1 + rtnl_addr_str2flags@libnl_3 3.5.0-1 + rtnl_addr_unset_flags@Base 3.5.0-1 + rtnl_addr_unset_flags@libnl_3 3.5.0-1 + rtnl_basic_add_action@Base 3.5.0-1 + rtnl_basic_add_action@libnl_3 3.5.0-1 + rtnl_basic_del_action@Base 3.5.0-1 + rtnl_basic_del_action@libnl_3 3.5.0-1 + rtnl_basic_get_action@libnl_3_4 3.5.0-1 + rtnl_basic_get_ematch@Base 3.5.0-1 + rtnl_basic_get_ematch@libnl_3 3.5.0-1 + rtnl_basic_get_target@Base 3.5.0-1 + rtnl_basic_get_target@libnl_3 3.5.0-1 + rtnl_basic_set_ematch@Base 3.5.0-1 + rtnl_basic_set_ematch@libnl_3 3.5.0-1 + rtnl_basic_set_target@Base 3.5.0-1 + rtnl_basic_set_target@libnl_3 3.5.0-1 + rtnl_cgroup_get_ematch@Base 3.5.0-1 + rtnl_cgroup_get_ematch@libnl_3 3.5.0-1 + rtnl_cgroup_set_ematch@Base 3.5.0-1 + rtnl_cgroup_set_ematch@libnl_3 3.5.0-1 + rtnl_class_add@Base 3.5.0-1 + rtnl_class_add@libnl_3 3.5.0-1 + rtnl_class_alloc@Base 3.5.0-1 + rtnl_class_alloc@libnl_3 3.5.0-1 + rtnl_class_alloc_cache@Base 3.5.0-1 + rtnl_class_alloc_cache@libnl_3 3.5.0-1 + rtnl_class_build_add_request@Base 3.5.0-1 + rtnl_class_build_add_request@libnl_3 3.5.0-1 + rtnl_class_build_delete_request@Base 3.5.0-1 + rtnl_class_build_delete_request@libnl_3 3.5.0-1 + rtnl_class_delete@Base 3.5.0-1 + rtnl_class_delete@libnl_3 3.5.0-1 + rtnl_class_dsmark_get_bitmask@Base 3.5.0-1 + rtnl_class_dsmark_get_bitmask@libnl_3 3.5.0-1 + rtnl_class_dsmark_get_value@Base 3.5.0-1 + rtnl_class_dsmark_get_value@libnl_3 3.5.0-1 + rtnl_class_dsmark_set_bitmask@Base 3.5.0-1 + rtnl_class_dsmark_set_bitmask@libnl_3 3.5.0-1 + rtnl_class_dsmark_set_value@Base 3.5.0-1 + rtnl_class_dsmark_set_value@libnl_3 3.5.0-1 + rtnl_class_foreach_child@Base 3.5.0-1 + rtnl_class_foreach_child@libnl_3 3.5.0-1 + rtnl_class_foreach_cls@Base 3.5.0-1 + rtnl_class_foreach_cls@libnl_3 3.5.0-1 + rtnl_class_get@Base 3.5.0-1 + rtnl_class_get@libnl_3 3.5.0-1 + rtnl_class_get_by_parent@libnl_3_5 3.5.0-1 + rtnl_class_hfsc_get_fsc@Base 3.5.0-1 + rtnl_class_hfsc_get_fsc@libnl_3 3.5.0-1 + rtnl_class_hfsc_get_rsc@Base 3.5.0-1 + rtnl_class_hfsc_get_rsc@libnl_3 3.5.0-1 + rtnl_class_hfsc_get_usc@Base 3.5.0-1 + rtnl_class_hfsc_get_usc@libnl_3 3.5.0-1 + rtnl_class_hfsc_set_fsc@Base 3.5.0-1 + rtnl_class_hfsc_set_fsc@libnl_3 3.5.0-1 + rtnl_class_hfsc_set_rsc@Base 3.5.0-1 + rtnl_class_hfsc_set_rsc@libnl_3 3.5.0-1 + rtnl_class_hfsc_set_usc@Base 3.5.0-1 + rtnl_class_hfsc_set_usc@libnl_3 3.5.0-1 + rtnl_class_leaf_qdisc@Base 3.5.0-1 + rtnl_class_leaf_qdisc@libnl_3 3.5.0-1 + rtnl_class_put@Base 3.5.0-1 + rtnl_class_put@libnl_3 3.5.0-1 + rtnl_classid_generate@Base 3.5.0-1 + rtnl_classid_generate@libnl_3 3.5.0-1 + rtnl_cls_add@Base 3.5.0-1 + rtnl_cls_add@libnl_3 3.5.0-1 + rtnl_cls_alloc@Base 3.5.0-1 + rtnl_cls_alloc@libnl_3 3.5.0-1 + rtnl_cls_alloc_cache@Base 3.5.0-1 + rtnl_cls_alloc_cache@libnl_3 3.5.0-1 + rtnl_cls_build_add_request@Base 3.5.0-1 + rtnl_cls_build_add_request@libnl_3 3.5.0-1 + rtnl_cls_build_change_request@Base 3.5.0-1 + rtnl_cls_build_change_request@libnl_3 3.5.0-1 + rtnl_cls_build_delete_request@Base 3.5.0-1 + rtnl_cls_build_delete_request@libnl_3 3.5.0-1 + rtnl_cls_cache_set_tc_params@libnl_3_5 3.5.0-1 + rtnl_cls_change@Base 3.5.0-1 + rtnl_cls_change@libnl_3 3.5.0-1 + rtnl_cls_delete@Base 3.5.0-1 + rtnl_cls_delete@libnl_3 3.5.0-1 + rtnl_cls_get_prio@Base 3.5.0-1 + rtnl_cls_get_prio@libnl_3 3.5.0-1 + rtnl_cls_get_protocol@Base 3.5.0-1 + rtnl_cls_get_protocol@libnl_3 3.5.0-1 + rtnl_cls_put@Base 3.5.0-1 + rtnl_cls_put@libnl_3 3.5.0-1 + rtnl_cls_set_prio@Base 3.5.0-1 + rtnl_cls_set_prio@libnl_3 3.5.0-1 + rtnl_cls_set_protocol@Base 3.5.0-1 + rtnl_cls_set_protocol@libnl_3 3.5.0-1 + rtnl_ematch_add_child@Base 3.5.0-1 + rtnl_ematch_add_child@libnl_3 3.5.0-1 + rtnl_ematch_alloc@Base 3.5.0-1 + rtnl_ematch_alloc@libnl_3 3.5.0-1 + rtnl_ematch_cmp_get@Base 3.5.0-1 + rtnl_ematch_cmp_get@libnl_3 3.5.0-1 + rtnl_ematch_cmp_set@Base 3.5.0-1 + rtnl_ematch_cmp_set@libnl_3 3.5.0-1 + rtnl_ematch_data@Base 3.5.0-1 + rtnl_ematch_data@libnl_3 3.5.0-1 + rtnl_ematch_fill_attr@Base 3.5.0-1 + rtnl_ematch_fill_attr@libnl_3 3.5.0-1 + rtnl_ematch_free@Base 3.5.0-1 + rtnl_ematch_free@libnl_3 3.5.0-1 + rtnl_ematch_get_flags@Base 3.5.0-1 + rtnl_ematch_get_flags@libnl_3 3.5.0-1 + rtnl_ematch_lookup_ops@Base 3.5.0-1 + rtnl_ematch_lookup_ops@libnl_3 3.5.0-1 + rtnl_ematch_lookup_ops_by_name@Base 3.5.0-1 + rtnl_ematch_lookup_ops_by_name@libnl_3 3.5.0-1 + rtnl_ematch_meta_set_lvalue@Base 3.5.0-1 + rtnl_ematch_meta_set_lvalue@libnl_3 3.5.0-1 + rtnl_ematch_meta_set_operand@Base 3.5.0-1 + rtnl_ematch_meta_set_operand@libnl_3 3.5.0-1 + rtnl_ematch_meta_set_rvalue@Base 3.5.0-1 + rtnl_ematch_meta_set_rvalue@libnl_3 3.5.0-1 + rtnl_ematch_nbyte_get_layer@Base 3.5.0-1 + rtnl_ematch_nbyte_get_layer@libnl_3 3.5.0-1 + rtnl_ematch_nbyte_get_len@Base 3.5.0-1 + rtnl_ematch_nbyte_get_len@libnl_3 3.5.0-1 + rtnl_ematch_nbyte_get_offset@Base 3.5.0-1 + rtnl_ematch_nbyte_get_offset@libnl_3 3.5.0-1 + rtnl_ematch_nbyte_get_pattern@Base 3.5.0-1 + rtnl_ematch_nbyte_get_pattern@libnl_3 3.5.0-1 + rtnl_ematch_nbyte_set_offset@Base 3.5.0-1 + rtnl_ematch_nbyte_set_offset@libnl_3 3.5.0-1 + rtnl_ematch_nbyte_set_pattern@Base 3.5.0-1 + rtnl_ematch_nbyte_set_pattern@libnl_3 3.5.0-1 + rtnl_ematch_offset2txt@Base 3.5.0-1 + rtnl_ematch_offset2txt@libnl_3 3.5.0-1 + rtnl_ematch_opnd2txt@Base 3.5.0-1 + rtnl_ematch_opnd2txt@libnl_3 3.5.0-1 + rtnl_ematch_parse_attr@Base 3.5.0-1 + rtnl_ematch_parse_attr@libnl_3 3.5.0-1 + rtnl_ematch_parse_expr@Base 3.5.0-1 + rtnl_ematch_parse_expr@libnl_3 3.5.0-1 + rtnl_ematch_register@Base 3.5.0-1 + rtnl_ematch_register@libnl_3 3.5.0-1 + rtnl_ematch_set_flags@Base 3.5.0-1 + rtnl_ematch_set_flags@libnl_3 3.5.0-1 + rtnl_ematch_set_kind@Base 3.5.0-1 + rtnl_ematch_set_kind@libnl_3 3.5.0-1 + rtnl_ematch_set_name@Base 3.5.0-1 + rtnl_ematch_set_name@libnl_3 3.5.0-1 + rtnl_ematch_set_ops@Base 3.5.0-1 + rtnl_ematch_set_ops@libnl_3 3.5.0-1 + rtnl_ematch_text_get_algo@Base 3.5.0-1 + rtnl_ematch_text_get_algo@libnl_3 3.5.0-1 + rtnl_ematch_text_get_from_layer@Base 3.5.0-1 + rtnl_ematch_text_get_from_layer@libnl_3 3.5.0-1 + rtnl_ematch_text_get_from_offset@Base 3.5.0-1 + rtnl_ematch_text_get_from_offset@libnl_3 3.5.0-1 + rtnl_ematch_text_get_len@Base 3.5.0-1 + rtnl_ematch_text_get_len@libnl_3 3.5.0-1 + rtnl_ematch_text_get_pattern@Base 3.5.0-1 + rtnl_ematch_text_get_pattern@libnl_3 3.5.0-1 + rtnl_ematch_text_get_to_layer@Base 3.5.0-1 + rtnl_ematch_text_get_to_layer@libnl_3 3.5.0-1 + rtnl_ematch_text_get_to_offset@Base 3.5.0-1 + rtnl_ematch_text_get_to_offset@libnl_3 3.5.0-1 + rtnl_ematch_text_set_algo@Base 3.5.0-1 + rtnl_ematch_text_set_algo@libnl_3 3.5.0-1 + rtnl_ematch_text_set_from@Base 3.5.0-1 + rtnl_ematch_text_set_from@libnl_3 3.5.0-1 + rtnl_ematch_text_set_pattern@Base 3.5.0-1 + rtnl_ematch_text_set_pattern@libnl_3 3.5.0-1 + rtnl_ematch_text_set_to@Base 3.5.0-1 + rtnl_ematch_text_set_to@libnl_3 3.5.0-1 + rtnl_ematch_tree_add@Base 3.5.0-1 + rtnl_ematch_tree_add@libnl_3 3.5.0-1 + rtnl_ematch_tree_alloc@Base 3.5.0-1 + rtnl_ematch_tree_alloc@libnl_3 3.5.0-1 + rtnl_ematch_tree_clone@libnl_3_5 3.5.0-1 + rtnl_ematch_tree_dump@Base 3.5.0-1 + rtnl_ematch_tree_dump@libnl_3 3.5.0-1 + rtnl_ematch_tree_free@Base 3.5.0-1 + rtnl_ematch_tree_free@libnl_3 3.5.0-1 + rtnl_ematch_unlink@Base 3.5.0-1 + rtnl_ematch_unlink@libnl_3 3.5.0-1 + rtnl_ematch_unset_flags@Base 3.5.0-1 + rtnl_ematch_unset_flags@libnl_3 3.5.0-1 + rtnl_fw_set_classid@Base 3.5.0-1 + rtnl_fw_set_classid@libnl_3 3.5.0-1 + rtnl_fw_set_mask@Base 3.5.0-1 + rtnl_fw_set_mask@libnl_3 3.5.0-1 + rtnl_gact_get_action@libnl_3_2_29 3.5.0-1 + rtnl_gact_set_action@libnl_3_2_29 3.5.0-1 + rtnl_htb_get_cbuffer@Base 3.5.0-1 + rtnl_htb_get_cbuffer@libnl_3 3.5.0-1 + rtnl_htb_get_ceil64@libnl_3_5 3.5.0-1 + rtnl_htb_get_ceil@Base 3.5.0-1 + rtnl_htb_get_ceil@libnl_3 3.5.0-1 + rtnl_htb_get_defcls@Base 3.5.0-1 + rtnl_htb_get_defcls@libnl_3 3.5.0-1 + rtnl_htb_get_level@Base 3.5.0-1 + rtnl_htb_get_level@libnl_3 3.5.0-1 + rtnl_htb_get_prio@Base 3.5.0-1 + rtnl_htb_get_prio@libnl_3 3.5.0-1 + rtnl_htb_get_quantum@Base 3.5.0-1 + rtnl_htb_get_quantum@libnl_3 3.5.0-1 + rtnl_htb_get_rate2quantum@Base 3.5.0-1 + rtnl_htb_get_rate2quantum@libnl_3 3.5.0-1 + rtnl_htb_get_rate64@libnl_3_5 3.5.0-1 + rtnl_htb_get_rate@Base 3.5.0-1 + rtnl_htb_get_rate@libnl_3 3.5.0-1 + rtnl_htb_get_rbuffer@Base 3.5.0-1 + rtnl_htb_get_rbuffer@libnl_3 3.5.0-1 + rtnl_htb_set_cbuffer@Base 3.5.0-1 + rtnl_htb_set_cbuffer@libnl_3 3.5.0-1 + rtnl_htb_set_ceil64@libnl_3_5 3.5.0-1 + rtnl_htb_set_ceil@Base 3.5.0-1 + rtnl_htb_set_ceil@libnl_3 3.5.0-1 + rtnl_htb_set_defcls@Base 3.5.0-1 + rtnl_htb_set_defcls@libnl_3 3.5.0-1 + rtnl_htb_set_level@Base 3.5.0-1 + rtnl_htb_set_level@libnl_3 3.5.0-1 + rtnl_htb_set_prio@Base 3.5.0-1 + rtnl_htb_set_prio@libnl_3 3.5.0-1 + rtnl_htb_set_quantum@Base 3.5.0-1 + rtnl_htb_set_quantum@libnl_3 3.5.0-1 + rtnl_htb_set_rate2quantum@Base 3.5.0-1 + rtnl_htb_set_rate2quantum@libnl_3 3.5.0-1 + rtnl_htb_set_rate64@libnl_3_5 3.5.0-1 + rtnl_htb_set_rate@Base 3.5.0-1 + rtnl_htb_set_rate@libnl_3 3.5.0-1 + rtnl_htb_set_rbuffer@Base 3.5.0-1 + rtnl_htb_set_rbuffer@libnl_3 3.5.0-1 + rtnl_link_add@Base 3.5.0-1 + rtnl_link_add@libnl_3 3.5.0-1 + rtnl_link_af_alloc@Base 3.5.0-1 + rtnl_link_af_alloc@libnl_3 3.5.0-1 + rtnl_link_af_data@Base 3.5.0-1 + rtnl_link_af_data@libnl_3 3.5.0-1 + rtnl_link_af_data_compare@Base 3.5.0-1 + rtnl_link_af_data_compare@libnl_3 3.5.0-1 + rtnl_link_af_ops_lookup@Base 3.5.0-1 + rtnl_link_af_ops_lookup@libnl_3 3.5.0-1 + rtnl_link_af_ops_put@Base 3.5.0-1 + rtnl_link_af_ops_put@libnl_3 3.5.0-1 + rtnl_link_af_register@Base 3.5.0-1 + rtnl_link_af_register@libnl_3 3.5.0-1 + rtnl_link_af_unregister@Base 3.5.0-1 + rtnl_link_af_unregister@libnl_3 3.5.0-1 + rtnl_link_alloc@Base 3.5.0-1 + rtnl_link_alloc@libnl_3 3.5.0-1 + rtnl_link_alloc_cache@Base 3.5.0-1 + rtnl_link_alloc_cache@libnl_3 3.5.0-1 + rtnl_link_alloc_cache_flags@libnl_3_2_28 3.5.0-1 + rtnl_link_bond_add@Base 3.5.0-1 + rtnl_link_bond_add@libnl_3 3.5.0-1 + rtnl_link_bond_alloc@Base 3.5.0-1 + rtnl_link_bond_alloc@libnl_3 3.5.0-1 + rtnl_link_bond_enslave@Base 3.5.0-1 + rtnl_link_bond_enslave@libnl_3 3.5.0-1 + rtnl_link_bond_enslave_ifindex@Base 3.5.0-1 + rtnl_link_bond_enslave_ifindex@libnl_3 3.5.0-1 + rtnl_link_bond_release@Base 3.5.0-1 + rtnl_link_bond_release@libnl_3 3.5.0-1 + rtnl_link_bond_release_ifindex@Base 3.5.0-1 + rtnl_link_bond_release_ifindex@libnl_3 3.5.0-1 + rtnl_link_bridge_add@Base 3.5.0-1 + rtnl_link_bridge_add@libnl_3 3.5.0-1 + rtnl_link_bridge_alloc@Base 3.5.0-1 + rtnl_link_bridge_alloc@libnl_3 3.5.0-1 + rtnl_link_bridge_flags2str@Base 3.5.0-1 + rtnl_link_bridge_flags2str@libnl_3 3.5.0-1 + rtnl_link_bridge_get_cost@Base 3.5.0-1 + rtnl_link_bridge_get_cost@libnl_3 3.5.0-1 + rtnl_link_bridge_get_flags@Base 3.5.0-1 + rtnl_link_bridge_get_flags@libnl_3 3.5.0-1 + rtnl_link_bridge_get_hwmode@libnl_3_2_29 3.5.0-1 + rtnl_link_bridge_get_port_state@Base 3.5.0-1 + rtnl_link_bridge_get_port_state@libnl_3 3.5.0-1 + rtnl_link_bridge_get_port_vlan@libnl_3_2_28 3.5.0-1 + rtnl_link_bridge_get_priority@Base 3.5.0-1 + rtnl_link_bridge_get_priority@libnl_3 3.5.0-1 + rtnl_link_bridge_has_ext_info@Base 3.5.0-1 + rtnl_link_bridge_has_ext_info@libnl_3 3.5.0-1 + rtnl_link_bridge_has_vlan@libnl_3_2_28 3.5.0-1 + rtnl_link_bridge_hwmode2str@libnl_3_2_29 3.5.0-1 + rtnl_link_bridge_portstate2str@libnl_3_2_29 3.5.0-1 + rtnl_link_bridge_pvid@libnl_3_2_28 3.5.0-1 + rtnl_link_bridge_set_cost@Base 3.5.0-1 + rtnl_link_bridge_set_cost@libnl_3 3.5.0-1 + rtnl_link_bridge_set_flags@Base 3.5.0-1 + rtnl_link_bridge_set_flags@libnl_3 3.5.0-1 + rtnl_link_bridge_set_hwmode@libnl_3_2_29 3.5.0-1 + rtnl_link_bridge_set_port_state@Base 3.5.0-1 + rtnl_link_bridge_set_port_state@libnl_3 3.5.0-1 + rtnl_link_bridge_set_priority@Base 3.5.0-1 + rtnl_link_bridge_set_priority@libnl_3 3.5.0-1 + rtnl_link_bridge_set_self@libnl_3_2_29 3.5.0-1 + rtnl_link_bridge_str2flags@Base 3.5.0-1 + rtnl_link_bridge_str2flags@libnl_3 3.5.0-1 + rtnl_link_bridge_str2hwmode@libnl_3_2_29 3.5.0-1 + rtnl_link_bridge_str2portstate@libnl_3_2_29 3.5.0-1 + rtnl_link_bridge_unset_flags@Base 3.5.0-1 + rtnl_link_bridge_unset_flags@libnl_3 3.5.0-1 + rtnl_link_build_add_request@Base 3.5.0-1 + rtnl_link_build_add_request@libnl_3 3.5.0-1 + rtnl_link_build_change_request@Base 3.5.0-1 + rtnl_link_build_change_request@libnl_3 3.5.0-1 + rtnl_link_build_delete_request@Base 3.5.0-1 + rtnl_link_build_delete_request@libnl_3 3.5.0-1 + rtnl_link_build_get_request@Base 3.5.0-1 + rtnl_link_build_get_request@libnl_3 3.5.0-1 + rtnl_link_can_berr@Base 3.5.0-1 + rtnl_link_can_berr@libnl_3 3.5.0-1 + rtnl_link_can_berr_rx@Base 3.5.0-1 + rtnl_link_can_berr_rx@libnl_3 3.5.0-1 + rtnl_link_can_berr_tx@Base 3.5.0-1 + rtnl_link_can_berr_tx@libnl_3 3.5.0-1 + rtnl_link_can_ctrlmode2str@Base 3.5.0-1 + rtnl_link_can_ctrlmode2str@libnl_3 3.5.0-1 + rtnl_link_can_freq@Base 3.5.0-1 + rtnl_link_can_freq@libnl_3 3.5.0-1 + rtnl_link_can_get_bitrate@Base 3.5.0-1 + rtnl_link_can_get_bitrate@libnl_3 3.5.0-1 + rtnl_link_can_get_bittiming@Base 3.5.0-1 + rtnl_link_can_get_bittiming@libnl_3 3.5.0-1 + rtnl_link_can_get_bt_const@Base 3.5.0-1 + rtnl_link_can_get_bt_const@libnl_3 3.5.0-1 + rtnl_link_can_get_ctrlmode@Base 3.5.0-1 + rtnl_link_can_get_ctrlmode@libnl_3 3.5.0-1 + rtnl_link_can_get_restart_ms@Base 3.5.0-1 + rtnl_link_can_get_restart_ms@libnl_3 3.5.0-1 + rtnl_link_can_get_sample_point@Base 3.5.0-1 + rtnl_link_can_get_sample_point@libnl_3 3.5.0-1 + rtnl_link_can_restart@Base 3.5.0-1 + rtnl_link_can_restart@libnl_3 3.5.0-1 + rtnl_link_can_set_bitrate@Base 3.5.0-1 + rtnl_link_can_set_bitrate@libnl_3 3.5.0-1 + rtnl_link_can_set_bittiming@Base 3.5.0-1 + rtnl_link_can_set_bittiming@libnl_3 3.5.0-1 + rtnl_link_can_set_ctrlmode@Base 3.5.0-1 + rtnl_link_can_set_ctrlmode@libnl_3 3.5.0-1 + rtnl_link_can_set_restart_ms@Base 3.5.0-1 + rtnl_link_can_set_restart_ms@libnl_3 3.5.0-1 + rtnl_link_can_set_sample_point@Base 3.5.0-1 + rtnl_link_can_set_sample_point@libnl_3 3.5.0-1 + rtnl_link_can_state@Base 3.5.0-1 + rtnl_link_can_state@libnl_3 3.5.0-1 + rtnl_link_can_str2ctrlmode@Base 3.5.0-1 + rtnl_link_can_str2ctrlmode@libnl_3 3.5.0-1 + rtnl_link_can_unset_ctrlmode@Base 3.5.0-1 + rtnl_link_can_unset_ctrlmode@libnl_3 3.5.0-1 + rtnl_link_carrier2str@Base 3.5.0-1 + rtnl_link_carrier2str@libnl_3 3.5.0-1 + rtnl_link_change@Base 3.5.0-1 + rtnl_link_change@libnl_3 3.5.0-1 + rtnl_link_delete@Base 3.5.0-1 + rtnl_link_delete@libnl_3 3.5.0-1 + rtnl_link_enslave@Base 3.5.0-1 + rtnl_link_enslave@libnl_3 3.5.0-1 + rtnl_link_enslave_ifindex@Base 3.5.0-1 + rtnl_link_enslave_ifindex@libnl_3 3.5.0-1 + rtnl_link_fill_info@Base 3.5.0-1 + rtnl_link_fill_info@libnl_3 3.5.0-1 + rtnl_link_flags2str@Base 3.5.0-1 + rtnl_link_flags2str@libnl_3 3.5.0-1 + rtnl_link_geneve_alloc@libnl_3_5 3.5.0-1 + rtnl_link_geneve_get_flags@libnl_3_5 3.5.0-1 + rtnl_link_geneve_get_id@libnl_3_5 3.5.0-1 + rtnl_link_geneve_get_label@libnl_3_5 3.5.0-1 + rtnl_link_geneve_get_port@libnl_3_5 3.5.0-1 + rtnl_link_geneve_get_remote@libnl_3_5 3.5.0-1 + rtnl_link_geneve_get_tos@libnl_3_5 3.5.0-1 + rtnl_link_geneve_get_ttl@libnl_3_5 3.5.0-1 + rtnl_link_geneve_get_udp_csum@libnl_3_5 3.5.0-1 + rtnl_link_geneve_get_udp_zero_csum6_rx@libnl_3_5 3.5.0-1 + rtnl_link_geneve_get_udp_zero_csum6_tx@libnl_3_5 3.5.0-1 + rtnl_link_geneve_set_flags@libnl_3_5 3.5.0-1 + rtnl_link_geneve_set_id@libnl_3_5 3.5.0-1 + rtnl_link_geneve_set_label@libnl_3_5 3.5.0-1 + rtnl_link_geneve_set_port@libnl_3_5 3.5.0-1 + rtnl_link_geneve_set_remote@libnl_3_5 3.5.0-1 + rtnl_link_geneve_set_tos@libnl_3_5 3.5.0-1 + rtnl_link_geneve_set_ttl@libnl_3_5 3.5.0-1 + rtnl_link_geneve_set_udp_csum@libnl_3_5 3.5.0-1 + rtnl_link_geneve_set_udp_zero_csum6_rx@libnl_3_5 3.5.0-1 + rtnl_link_geneve_set_udp_zero_csum6_tx@libnl_3_5 3.5.0-1 + rtnl_link_get@Base 3.5.0-1 + rtnl_link_get@libnl_3 3.5.0-1 + rtnl_link_get_addr@Base 3.5.0-1 + rtnl_link_get_addr@libnl_3 3.5.0-1 + rtnl_link_get_arptype@Base 3.5.0-1 + rtnl_link_get_arptype@libnl_3 3.5.0-1 + rtnl_link_get_broadcast@Base 3.5.0-1 + rtnl_link_get_broadcast@libnl_3 3.5.0-1 + rtnl_link_get_by_name@Base 3.5.0-1 + rtnl_link_get_by_name@libnl_3 3.5.0-1 + rtnl_link_get_carrier@Base 3.5.0-1 + rtnl_link_get_carrier@libnl_3 3.5.0-1 + rtnl_link_get_carrier_changes@libnl_3_2_29 3.5.0-1 + rtnl_link_get_family@Base 3.5.0-1 + rtnl_link_get_family@libnl_3 3.5.0-1 + rtnl_link_get_flags@Base 3.5.0-1 + rtnl_link_get_flags@libnl_3 3.5.0-1 + rtnl_link_get_group@Base 3.5.0-1 + rtnl_link_get_group@libnl_3 3.5.0-1 + rtnl_link_get_gso_max_segs@libnl_3_2_29 3.5.0-1 + rtnl_link_get_gso_max_size@libnl_3_2_29 3.5.0-1 + rtnl_link_get_ifalias@Base 3.5.0-1 + rtnl_link_get_ifalias@libnl_3 3.5.0-1 + rtnl_link_get_ifindex@Base 3.5.0-1 + rtnl_link_get_ifindex@libnl_3 3.5.0-1 + rtnl_link_get_info_type@Base 3.5.0-1 + rtnl_link_get_info_type@libnl_3 3.5.0-1 + rtnl_link_get_kernel@Base 3.5.0-1 + rtnl_link_get_kernel@libnl_3 3.5.0-1 + rtnl_link_get_link@Base 3.5.0-1 + rtnl_link_get_link@libnl_3 3.5.0-1 + rtnl_link_get_link_netnsid@Base 3.5.0-1 + rtnl_link_get_link_netnsid@libnl_3_2_27 3.5.0-1 + rtnl_link_get_linkmode@Base 3.5.0-1 + rtnl_link_get_linkmode@libnl_3 3.5.0-1 + rtnl_link_get_master@Base 3.5.0-1 + rtnl_link_get_master@libnl_3 3.5.0-1 + rtnl_link_get_mtu@Base 3.5.0-1 + rtnl_link_get_mtu@libnl_3 3.5.0-1 + rtnl_link_get_name@Base 3.5.0-1 + rtnl_link_get_name@libnl_3 3.5.0-1 + rtnl_link_get_ns_fd@Base 3.5.0-1 + rtnl_link_get_ns_fd@libnl_3 3.5.0-1 + rtnl_link_get_ns_pid@Base 3.5.0-1 + rtnl_link_get_ns_pid@libnl_3 3.5.0-1 + rtnl_link_get_num_rx_queues@Base 3.5.0-1 + rtnl_link_get_num_rx_queues@libnl_3 3.5.0-1 + rtnl_link_get_num_tx_queues@Base 3.5.0-1 + rtnl_link_get_num_tx_queues@libnl_3 3.5.0-1 + rtnl_link_get_num_vf@Base 3.5.0-1 + rtnl_link_get_num_vf@libnl_3 3.5.0-1 + rtnl_link_get_operstate@Base 3.5.0-1 + rtnl_link_get_operstate@libnl_3 3.5.0-1 + rtnl_link_get_phys_port_id@Base 3.5.0-1 + rtnl_link_get_phys_port_id@libnl_3 3.5.0-1 + rtnl_link_get_phys_port_name@libnl_3_2_29 3.5.0-1 + rtnl_link_get_phys_switch_id@libnl_3_2_29 3.5.0-1 + rtnl_link_get_pmtudisc@Base 3.5.0-1 + rtnl_link_get_pmtudisc@libnl_3 3.5.0-1 + rtnl_link_get_promiscuity@Base 3.5.0-1 + rtnl_link_get_promiscuity@libnl_3 3.5.0-1 + rtnl_link_get_qdisc@Base 3.5.0-1 + rtnl_link_get_qdisc@libnl_3 3.5.0-1 + rtnl_link_get_slave_type@libnl_3_5 3.5.0-1 + rtnl_link_get_stat@Base 3.5.0-1 + rtnl_link_get_stat@libnl_3 3.5.0-1 + rtnl_link_get_txqlen@Base 3.5.0-1 + rtnl_link_get_txqlen@libnl_3 3.5.0-1 + rtnl_link_get_type@Base 3.5.0-1 + rtnl_link_get_type@libnl_3 3.5.0-1 + rtnl_link_get_weight@Base 3.5.0-1 + rtnl_link_get_weight@libnl_3 3.5.0-1 + rtnl_link_has_vf_list@libnl_3_2_29 3.5.0-1 + rtnl_link_i2name@Base 3.5.0-1 + rtnl_link_i2name@libnl_3 3.5.0-1 + rtnl_link_inet6_addrgenmode2str@Base 3.5.0-1 + rtnl_link_inet6_addrgenmode2str@libnl_3 3.5.0-1 + rtnl_link_inet6_flags2str@libnl_3_4 3.5.0-1 + rtnl_link_inet6_get_addr_gen_mode@Base 3.5.0-1 + rtnl_link_inet6_get_addr_gen_mode@libnl_3 3.5.0-1 + rtnl_link_inet6_get_flags@libnl_3_4 3.5.0-1 + rtnl_link_inet6_get_token@Base 3.5.0-1 + rtnl_link_inet6_get_token@libnl_3 3.5.0-1 + rtnl_link_inet6_set_addr_gen_mode@Base 3.5.0-1 + rtnl_link_inet6_set_addr_gen_mode@libnl_3 3.5.0-1 + rtnl_link_inet6_set_flags@libnl_3_4 3.5.0-1 + rtnl_link_inet6_set_token@Base 3.5.0-1 + rtnl_link_inet6_set_token@libnl_3 3.5.0-1 + rtnl_link_inet6_str2addrgenmode@Base 3.5.0-1 + rtnl_link_inet6_str2addrgenmode@libnl_3 3.5.0-1 + rtnl_link_inet6_str2flags@libnl_3_4 3.5.0-1 + rtnl_link_inet_devconf2str@Base 3.5.0-1 + rtnl_link_inet_devconf2str@libnl_3 3.5.0-1 + rtnl_link_inet_get_conf@Base 3.5.0-1 + rtnl_link_inet_get_conf@libnl_3 3.5.0-1 + rtnl_link_inet_set_conf@Base 3.5.0-1 + rtnl_link_inet_set_conf@libnl_3 3.5.0-1 + rtnl_link_inet_str2devconf@Base 3.5.0-1 + rtnl_link_inet_str2devconf@libnl_3 3.5.0-1 + rtnl_link_info_ops_lookup@Base 3.5.0-1 + rtnl_link_info_ops_lookup@libnl_3 3.5.0-1 + rtnl_link_info_ops_put@Base 3.5.0-1 + rtnl_link_info_ops_put@libnl_3 3.5.0-1 + rtnl_link_info_parse@Base 3.5.0-1 + rtnl_link_info_parse@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_add@Base 3.5.0-1 + rtnl_link_ip6_tnl_add@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_alloc@Base 3.5.0-1 + rtnl_link_ip6_tnl_alloc@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_get_encaplimit@Base 3.5.0-1 + rtnl_link_ip6_tnl_get_encaplimit@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_get_flags@Base 3.5.0-1 + rtnl_link_ip6_tnl_get_flags@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_get_flowinfo@Base 3.5.0-1 + rtnl_link_ip6_tnl_get_flowinfo@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_get_link@Base 3.5.0-1 + rtnl_link_ip6_tnl_get_link@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_get_local@Base 3.5.0-1 + rtnl_link_ip6_tnl_get_local@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_get_proto@Base 3.5.0-1 + rtnl_link_ip6_tnl_get_proto@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_get_remote@Base 3.5.0-1 + rtnl_link_ip6_tnl_get_remote@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_get_tos@Base 3.5.0-1 + rtnl_link_ip6_tnl_get_tos@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_get_ttl@Base 3.5.0-1 + rtnl_link_ip6_tnl_get_ttl@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_set_encaplimit@Base 3.5.0-1 + rtnl_link_ip6_tnl_set_encaplimit@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_set_flags@Base 3.5.0-1 + rtnl_link_ip6_tnl_set_flags@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_set_flowinfo@Base 3.5.0-1 + rtnl_link_ip6_tnl_set_flowinfo@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_set_link@Base 3.5.0-1 + rtnl_link_ip6_tnl_set_link@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_set_local@Base 3.5.0-1 + rtnl_link_ip6_tnl_set_local@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_set_proto@Base 3.5.0-1 + rtnl_link_ip6_tnl_set_proto@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_set_remote@Base 3.5.0-1 + rtnl_link_ip6_tnl_set_remote@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_set_tos@Base 3.5.0-1 + rtnl_link_ip6_tnl_set_tos@libnl_3 3.5.0-1 + rtnl_link_ip6_tnl_set_ttl@Base 3.5.0-1 + rtnl_link_ip6_tnl_set_ttl@libnl_3 3.5.0-1 + rtnl_link_ipgre_add@Base 3.5.0-1 + rtnl_link_ipgre_add@libnl_3 3.5.0-1 + rtnl_link_ipgre_alloc@Base 3.5.0-1 + rtnl_link_ipgre_alloc@libnl_3 3.5.0-1 + rtnl_link_ipgre_get_iflags@Base 3.5.0-1 + rtnl_link_ipgre_get_iflags@libnl_3 3.5.0-1 + rtnl_link_ipgre_get_ikey@Base 3.5.0-1 + rtnl_link_ipgre_get_ikey@libnl_3 3.5.0-1 + rtnl_link_ipgre_get_link@Base 3.5.0-1 + rtnl_link_ipgre_get_link@libnl_3 3.5.0-1 + rtnl_link_ipgre_get_local@Base 3.5.0-1 + rtnl_link_ipgre_get_local@libnl_3 3.5.0-1 + rtnl_link_ipgre_get_oflags@Base 3.5.0-1 + rtnl_link_ipgre_get_oflags@libnl_3 3.5.0-1 + rtnl_link_ipgre_get_okey@Base 3.5.0-1 + rtnl_link_ipgre_get_okey@libnl_3 3.5.0-1 + rtnl_link_ipgre_get_pmtudisc@libnl_3_2_29 3.5.0-1 + rtnl_link_ipgre_get_remote@Base 3.5.0-1 + rtnl_link_ipgre_get_remote@libnl_3 3.5.0-1 + rtnl_link_ipgre_get_tos@Base 3.5.0-1 + rtnl_link_ipgre_get_tos@libnl_3 3.5.0-1 + rtnl_link_ipgre_get_ttl@Base 3.5.0-1 + rtnl_link_ipgre_get_ttl@libnl_3 3.5.0-1 + rtnl_link_ipgre_set_iflags@Base 3.5.0-1 + rtnl_link_ipgre_set_iflags@libnl_3 3.5.0-1 + rtnl_link_ipgre_set_ikey@Base 3.5.0-1 + rtnl_link_ipgre_set_ikey@libnl_3 3.5.0-1 + rtnl_link_ipgre_set_link@Base 3.5.0-1 + rtnl_link_ipgre_set_link@libnl_3 3.5.0-1 + rtnl_link_ipgre_set_local@Base 3.5.0-1 + rtnl_link_ipgre_set_local@libnl_3 3.5.0-1 + rtnl_link_ipgre_set_oflags@Base 3.5.0-1 + rtnl_link_ipgre_set_oflags@libnl_3 3.5.0-1 + rtnl_link_ipgre_set_okey@Base 3.5.0-1 + rtnl_link_ipgre_set_okey@libnl_3 3.5.0-1 + rtnl_link_ipgre_set_pmtudisc@Base 3.5.0-1 + rtnl_link_ipgre_set_pmtudisc@libnl_3 3.5.0-1 + rtnl_link_ipgre_set_remote@Base 3.5.0-1 + rtnl_link_ipgre_set_remote@libnl_3 3.5.0-1 + rtnl_link_ipgre_set_tos@Base 3.5.0-1 + rtnl_link_ipgre_set_tos@libnl_3 3.5.0-1 + rtnl_link_ipgre_set_ttl@Base 3.5.0-1 + rtnl_link_ipgre_set_ttl@libnl_3 3.5.0-1 + rtnl_link_ipgretap_add@libnl_3_2_28 3.5.0-1 + rtnl_link_ipgretap_alloc@libnl_3_2_28 3.5.0-1 + rtnl_link_ipip_add@Base 3.5.0-1 + rtnl_link_ipip_add@libnl_3 3.5.0-1 + rtnl_link_ipip_alloc@Base 3.5.0-1 + rtnl_link_ipip_alloc@libnl_3 3.5.0-1 + rtnl_link_ipip_get_link@Base 3.5.0-1 + rtnl_link_ipip_get_link@libnl_3 3.5.0-1 + rtnl_link_ipip_get_local@Base 3.5.0-1 + rtnl_link_ipip_get_local@libnl_3 3.5.0-1 + rtnl_link_ipip_get_pmtudisc@Base 3.5.0-1 + rtnl_link_ipip_get_pmtudisc@libnl_3 3.5.0-1 + rtnl_link_ipip_get_remote@Base 3.5.0-1 + rtnl_link_ipip_get_remote@libnl_3 3.5.0-1 + rtnl_link_ipip_get_tos@Base 3.5.0-1 + rtnl_link_ipip_get_tos@libnl_3 3.5.0-1 + rtnl_link_ipip_get_ttl@Base 3.5.0-1 + rtnl_link_ipip_get_ttl@libnl_3 3.5.0-1 + rtnl_link_ipip_set_link@Base 3.5.0-1 + rtnl_link_ipip_set_link@libnl_3 3.5.0-1 + rtnl_link_ipip_set_local@Base 3.5.0-1 + rtnl_link_ipip_set_local@libnl_3 3.5.0-1 + rtnl_link_ipip_set_pmtudisc@Base 3.5.0-1 + rtnl_link_ipip_set_pmtudisc@libnl_3 3.5.0-1 + rtnl_link_ipip_set_remote@Base 3.5.0-1 + rtnl_link_ipip_set_remote@libnl_3 3.5.0-1 + rtnl_link_ipip_set_tos@Base 3.5.0-1 + rtnl_link_ipip_set_tos@libnl_3 3.5.0-1 + rtnl_link_ipip_set_ttl@Base 3.5.0-1 + rtnl_link_ipip_set_ttl@libnl_3 3.5.0-1 + rtnl_link_ipvlan_alloc@Base 3.5.0-1 + rtnl_link_ipvlan_alloc@libnl_3_2_27 3.5.0-1 + rtnl_link_ipvlan_get_mode@Base 3.5.0-1 + rtnl_link_ipvlan_get_mode@libnl_3_2_27 3.5.0-1 + rtnl_link_ipvlan_mode2str@Base 3.5.0-1 + rtnl_link_ipvlan_mode2str@libnl_3_2_27 3.5.0-1 + rtnl_link_ipvlan_set_mode@Base 3.5.0-1 + rtnl_link_ipvlan_set_mode@libnl_3_2_27 3.5.0-1 + rtnl_link_ipvlan_str2mode@Base 3.5.0-1 + rtnl_link_ipvlan_str2mode@libnl_3_2_27 3.5.0-1 + rtnl_link_ipvti_add@Base 3.5.0-1 + rtnl_link_ipvti_add@libnl_3 3.5.0-1 + rtnl_link_ipvti_alloc@Base 3.5.0-1 + rtnl_link_ipvti_alloc@libnl_3 3.5.0-1 + rtnl_link_ipvti_get_ikey@Base 3.5.0-1 + rtnl_link_ipvti_get_ikey@libnl_3 3.5.0-1 + rtnl_link_ipvti_get_link@Base 3.5.0-1 + rtnl_link_ipvti_get_link@libnl_3 3.5.0-1 + rtnl_link_ipvti_get_local@Base 3.5.0-1 + rtnl_link_ipvti_get_local@libnl_3 3.5.0-1 + rtnl_link_ipvti_get_okey@Base 3.5.0-1 + rtnl_link_ipvti_get_okey@libnl_3 3.5.0-1 + rtnl_link_ipvti_get_remote@Base 3.5.0-1 + rtnl_link_ipvti_get_remote@libnl_3 3.5.0-1 + rtnl_link_ipvti_set_ikey@Base 3.5.0-1 + rtnl_link_ipvti_set_ikey@libnl_3 3.5.0-1 + rtnl_link_ipvti_set_link@Base 3.5.0-1 + rtnl_link_ipvti_set_link@libnl_3 3.5.0-1 + rtnl_link_ipvti_set_local@Base 3.5.0-1 + rtnl_link_ipvti_set_local@libnl_3 3.5.0-1 + rtnl_link_ipvti_set_okey@Base 3.5.0-1 + rtnl_link_ipvti_set_okey@libnl_3 3.5.0-1 + rtnl_link_ipvti_set_remote@Base 3.5.0-1 + rtnl_link_ipvti_set_remote@libnl_3 3.5.0-1 + rtnl_link_is_bridge@Base 3.5.0-1 + rtnl_link_is_bridge@libnl_3 3.5.0-1 + rtnl_link_is_can@Base 3.5.0-1 + rtnl_link_is_can@libnl_3 3.5.0-1 + rtnl_link_is_geneve@libnl_3_5 3.5.0-1 + rtnl_link_is_ip6_tnl@Base 3.5.0-1 + rtnl_link_is_ip6_tnl@libnl_3 3.5.0-1 + rtnl_link_is_ipgre@Base 3.5.0-1 + rtnl_link_is_ipgre@libnl_3 3.5.0-1 + rtnl_link_is_ipgretap@libnl_3_2_29 3.5.0-1 + rtnl_link_is_ipip@Base 3.5.0-1 + rtnl_link_is_ipip@libnl_3 3.5.0-1 + rtnl_link_is_ipvlan@Base 3.5.0-1 + rtnl_link_is_ipvlan@libnl_3_2_27 3.5.0-1 + rtnl_link_is_ipvti@Base 3.5.0-1 + rtnl_link_is_ipvti@libnl_3 3.5.0-1 + rtnl_link_is_macvlan@Base 3.5.0-1 + rtnl_link_is_macvlan@libnl_3 3.5.0-1 + rtnl_link_is_macvtap@libnl_3_2_28 3.5.0-1 + rtnl_link_is_sit@Base 3.5.0-1 + rtnl_link_is_sit@libnl_3 3.5.0-1 + rtnl_link_is_veth@Base 3.5.0-1 + rtnl_link_is_veth@libnl_3 3.5.0-1 + rtnl_link_is_vlan@Base 3.5.0-1 + rtnl_link_is_vlan@libnl_3 3.5.0-1 + rtnl_link_is_vrf@libnl_3_2_28 3.5.0-1 + rtnl_link_is_vxlan@Base 3.5.0-1 + rtnl_link_is_vxlan@libnl_3 3.5.0-1 + rtnl_link_is_xfrmi@libnl_3_5 3.5.0-1 + rtnl_link_macsec_alloc@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_get_cipher_suite@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_get_encoding_sa@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_get_encrypt@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_get_end_station@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_get_icv_len@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_get_port@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_get_protect@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_get_replay_protect@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_get_scb@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_get_sci@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_get_send_sci@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_get_validation_type@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_get_window@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_set_cipher_suite@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_set_encoding_sa@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_set_encrypt@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_set_end_station@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_set_icv_len@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_set_port@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_set_protect@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_set_replay_protect@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_set_scb@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_set_sci@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_set_send_sci@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_set_validation_type@libnl_3_2_28 3.5.0-1 + rtnl_link_macsec_set_window@libnl_3_2_28 3.5.0-1 + rtnl_link_macvlan_add_macaddr@libnl_3_2_29 3.5.0-1 + rtnl_link_macvlan_alloc@Base 3.5.0-1 + rtnl_link_macvlan_alloc@libnl_3 3.5.0-1 + rtnl_link_macvlan_count_macaddr@libnl_3_2_29 3.5.0-1 + rtnl_link_macvlan_del_macaddr@libnl_3_2_29 3.5.0-1 + rtnl_link_macvlan_flags2str@Base 3.5.0-1 + rtnl_link_macvlan_flags2str@libnl_3 3.5.0-1 + rtnl_link_macvlan_get_flags@Base 3.5.0-1 + rtnl_link_macvlan_get_flags@libnl_3 3.5.0-1 + rtnl_link_macvlan_get_macaddr@libnl_3_2_29 3.5.0-1 + rtnl_link_macvlan_get_macmode@libnl_3_2_29 3.5.0-1 + rtnl_link_macvlan_get_mode@Base 3.5.0-1 + rtnl_link_macvlan_get_mode@libnl_3 3.5.0-1 + rtnl_link_macvlan_macmode2str@libnl_3_2_29 3.5.0-1 + rtnl_link_macvlan_mode2str@Base 3.5.0-1 + rtnl_link_macvlan_mode2str@libnl_3 3.5.0-1 + rtnl_link_macvlan_set_flags@Base 3.5.0-1 + rtnl_link_macvlan_set_flags@libnl_3 3.5.0-1 + rtnl_link_macvlan_set_macmode@libnl_3_2_29 3.5.0-1 + rtnl_link_macvlan_set_mode@Base 3.5.0-1 + rtnl_link_macvlan_set_mode@libnl_3 3.5.0-1 + rtnl_link_macvlan_str2flags@Base 3.5.0-1 + rtnl_link_macvlan_str2flags@libnl_3 3.5.0-1 + rtnl_link_macvlan_str2macmode@libnl_3_2_29 3.5.0-1 + rtnl_link_macvlan_str2mode@Base 3.5.0-1 + rtnl_link_macvlan_str2mode@libnl_3 3.5.0-1 + rtnl_link_macvlan_unset_flags@Base 3.5.0-1 + rtnl_link_macvlan_unset_flags@libnl_3 3.5.0-1 + rtnl_link_macvtap_alloc@libnl_3_2_28 3.5.0-1 + rtnl_link_macvtap_flags2str@libnl_3_2_28 3.5.0-1 + rtnl_link_macvtap_get_flags@libnl_3_2_28 3.5.0-1 + rtnl_link_macvtap_get_mode@libnl_3_2_28 3.5.0-1 + rtnl_link_macvtap_mode2str@libnl_3_2_28 3.5.0-1 + rtnl_link_macvtap_set_flags@libnl_3_2_28 3.5.0-1 + rtnl_link_macvtap_set_mode@libnl_3_2_28 3.5.0-1 + rtnl_link_macvtap_str2flags@libnl_3_2_28 3.5.0-1 + rtnl_link_macvtap_str2mode@libnl_3_2_28 3.5.0-1 + rtnl_link_macvtap_unset_flags@libnl_3_2_28 3.5.0-1 + rtnl_link_mode2str@Base 3.5.0-1 + rtnl_link_mode2str@libnl_3 3.5.0-1 + rtnl_link_name2i@Base 3.5.0-1 + rtnl_link_name2i@libnl_3 3.5.0-1 + rtnl_link_operstate2str@Base 3.5.0-1 + rtnl_link_operstate2str@libnl_3 3.5.0-1 + rtnl_link_ppp_alloc@libnl_3_2_29 3.5.0-1 + rtnl_link_ppp_get_fd@libnl_3_2_29 3.5.0-1 + rtnl_link_ppp_set_fd@libnl_3_2_29 3.5.0-1 + rtnl_link_put@Base 3.5.0-1 + rtnl_link_put@libnl_3 3.5.0-1 + rtnl_link_register_info@Base 3.5.0-1 + rtnl_link_register_info@libnl_3 3.5.0-1 + rtnl_link_release@Base 3.5.0-1 + rtnl_link_release@libnl_3 3.5.0-1 + rtnl_link_release_ifindex@Base 3.5.0-1 + rtnl_link_release_ifindex@libnl_3 3.5.0-1 + rtnl_link_set_addr@Base 3.5.0-1 + rtnl_link_set_addr@libnl_3 3.5.0-1 + rtnl_link_set_arptype@Base 3.5.0-1 + rtnl_link_set_arptype@libnl_3 3.5.0-1 + rtnl_link_set_broadcast@Base 3.5.0-1 + rtnl_link_set_broadcast@libnl_3 3.5.0-1 + rtnl_link_set_carrier@Base 3.5.0-1 + rtnl_link_set_carrier@libnl_3 3.5.0-1 + rtnl_link_set_family@Base 3.5.0-1 + rtnl_link_set_family@libnl_3 3.5.0-1 + rtnl_link_set_flags@Base 3.5.0-1 + rtnl_link_set_flags@libnl_3 3.5.0-1 + rtnl_link_set_group@Base 3.5.0-1 + rtnl_link_set_group@libnl_3 3.5.0-1 + rtnl_link_set_ifalias@Base 3.5.0-1 + rtnl_link_set_ifalias@libnl_3 3.5.0-1 + rtnl_link_set_ifindex@Base 3.5.0-1 + rtnl_link_set_ifindex@libnl_3 3.5.0-1 + rtnl_link_set_info_type@Base 3.5.0-1 + rtnl_link_set_info_type@libnl_3 3.5.0-1 + rtnl_link_set_link@Base 3.5.0-1 + rtnl_link_set_link@libnl_3 3.5.0-1 + rtnl_link_set_link_netnsid@Base 3.5.0-1 + rtnl_link_set_link_netnsid@libnl_3_2_27 3.5.0-1 + rtnl_link_set_linkmode@Base 3.5.0-1 + rtnl_link_set_linkmode@libnl_3 3.5.0-1 + rtnl_link_set_master@Base 3.5.0-1 + rtnl_link_set_master@libnl_3 3.5.0-1 + rtnl_link_set_mtu@Base 3.5.0-1 + rtnl_link_set_mtu@libnl_3 3.5.0-1 + rtnl_link_set_name@Base 3.5.0-1 + rtnl_link_set_name@libnl_3 3.5.0-1 + rtnl_link_set_ns_fd@Base 3.5.0-1 + rtnl_link_set_ns_fd@libnl_3 3.5.0-1 + rtnl_link_set_ns_pid@Base 3.5.0-1 + rtnl_link_set_ns_pid@libnl_3 3.5.0-1 + rtnl_link_set_num_rx_queues@Base 3.5.0-1 + rtnl_link_set_num_rx_queues@libnl_3 3.5.0-1 + rtnl_link_set_num_tx_queues@Base 3.5.0-1 + rtnl_link_set_num_tx_queues@libnl_3 3.5.0-1 + rtnl_link_set_operstate@Base 3.5.0-1 + rtnl_link_set_operstate@libnl_3 3.5.0-1 + rtnl_link_set_promiscuity@Base 3.5.0-1 + rtnl_link_set_promiscuity@libnl_3 3.5.0-1 + rtnl_link_set_qdisc@Base 3.5.0-1 + rtnl_link_set_qdisc@libnl_3 3.5.0-1 + rtnl_link_set_slave_type@libnl_3_5 3.5.0-1 + rtnl_link_set_stat@Base 3.5.0-1 + rtnl_link_set_stat@libnl_3 3.5.0-1 + rtnl_link_set_txqlen@Base 3.5.0-1 + rtnl_link_set_txqlen@libnl_3 3.5.0-1 + rtnl_link_set_type@Base 3.5.0-1 + rtnl_link_set_type@libnl_3 3.5.0-1 + rtnl_link_set_vf_list@libnl_3_2_29 3.5.0-1 + rtnl_link_set_weight@Base 3.5.0-1 + rtnl_link_set_weight@libnl_3 3.5.0-1 + rtnl_link_sit_add@Base 3.5.0-1 + rtnl_link_sit_add@libnl_3 3.5.0-1 + rtnl_link_sit_alloc@Base 3.5.0-1 + rtnl_link_sit_alloc@libnl_3 3.5.0-1 + rtnl_link_sit_get_flags@Base 3.5.0-1 + rtnl_link_sit_get_flags@libnl_3 3.5.0-1 + rtnl_link_sit_get_ip6rd_prefix@libnl_3_2_28 3.5.0-1 + rtnl_link_sit_get_ip6rd_prefixlen@libnl_3_2_28 3.5.0-1 + rtnl_link_sit_get_ip6rd_relay_prefix@libnl_3_2_28 3.5.0-1 + rtnl_link_sit_get_ip6rd_relay_prefixlen@libnl_3_2_28 3.5.0-1 + rtnl_link_sit_get_link@Base 3.5.0-1 + rtnl_link_sit_get_link@libnl_3 3.5.0-1 + rtnl_link_sit_get_local@Base 3.5.0-1 + rtnl_link_sit_get_local@libnl_3 3.5.0-1 + rtnl_link_sit_get_pmtudisc@Base 3.5.0-1 + rtnl_link_sit_get_pmtudisc@libnl_3 3.5.0-1 + rtnl_link_sit_get_proto@Base 3.5.0-1 + rtnl_link_sit_get_proto@libnl_3 3.5.0-1 + rtnl_link_sit_get_remote@Base 3.5.0-1 + rtnl_link_sit_get_remote@libnl_3 3.5.0-1 + rtnl_link_sit_get_tos@Base 3.5.0-1 + rtnl_link_sit_get_tos@libnl_3 3.5.0-1 + rtnl_link_sit_get_ttl@Base 3.5.0-1 + rtnl_link_sit_get_ttl@libnl_3 3.5.0-1 + rtnl_link_sit_set_flags@Base 3.5.0-1 + rtnl_link_sit_set_flags@libnl_3 3.5.0-1 + rtnl_link_sit_set_ip6rd_prefix@libnl_3_2_28 3.5.0-1 + rtnl_link_sit_set_ip6rd_prefixlen@libnl_3_2_28 3.5.0-1 + rtnl_link_sit_set_ip6rd_relay_prefix@libnl_3_2_28 3.5.0-1 + rtnl_link_sit_set_ip6rd_relay_prefixlen@libnl_3_2_28 3.5.0-1 + rtnl_link_sit_set_link@Base 3.5.0-1 + rtnl_link_sit_set_link@libnl_3 3.5.0-1 + rtnl_link_sit_set_local@Base 3.5.0-1 + rtnl_link_sit_set_local@libnl_3 3.5.0-1 + rtnl_link_sit_set_pmtudisc@Base 3.5.0-1 + rtnl_link_sit_set_pmtudisc@libnl_3 3.5.0-1 + rtnl_link_sit_set_proto@Base 3.5.0-1 + rtnl_link_sit_set_proto@libnl_3 3.5.0-1 + rtnl_link_sit_set_remote@Base 3.5.0-1 + rtnl_link_sit_set_remote@libnl_3 3.5.0-1 + rtnl_link_sit_set_tos@Base 3.5.0-1 + rtnl_link_sit_set_tos@libnl_3 3.5.0-1 + rtnl_link_sit_set_ttl@Base 3.5.0-1 + rtnl_link_sit_set_ttl@libnl_3 3.5.0-1 + rtnl_link_stat2str@Base 3.5.0-1 + rtnl_link_stat2str@libnl_3 3.5.0-1 + rtnl_link_str2carrier@Base 3.5.0-1 + rtnl_link_str2carrier@libnl_3 3.5.0-1 + rtnl_link_str2flags@Base 3.5.0-1 + rtnl_link_str2flags@libnl_3 3.5.0-1 + rtnl_link_str2mode@Base 3.5.0-1 + rtnl_link_str2mode@libnl_3 3.5.0-1 + rtnl_link_str2operstate@Base 3.5.0-1 + rtnl_link_str2operstate@libnl_3 3.5.0-1 + rtnl_link_str2stat@Base 3.5.0-1 + rtnl_link_str2stat@libnl_3 3.5.0-1 + rtnl_link_unregister_info@Base 3.5.0-1 + rtnl_link_unregister_info@libnl_3 3.5.0-1 + rtnl_link_unset_flags@Base 3.5.0-1 + rtnl_link_unset_flags@libnl_3 3.5.0-1 + rtnl_link_unset_vf_list@libnl_3_2_29 3.5.0-1 + rtnl_link_veth_add@Base 3.5.0-1 + rtnl_link_veth_add@libnl_3 3.5.0-1 + rtnl_link_veth_alloc@Base 3.5.0-1 + rtnl_link_veth_alloc@libnl_3 3.5.0-1 + rtnl_link_veth_get_peer@Base 3.5.0-1 + rtnl_link_veth_get_peer@libnl_3 3.5.0-1 + rtnl_link_veth_release@Base 3.5.0-1 + rtnl_link_veth_release@libnl_3 3.5.0-1 + rtnl_link_vf_add@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_alloc@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_free@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_get@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_get_addr@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_get_index@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_get_linkstate@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_get_rate@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_get_rss_query_en@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_get_spoofchk@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_get_stat@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_get_trust@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_get_vlans@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_linkstate2str@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_put@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_set_addr@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_set_ib_node_guid@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_set_ib_port_guid@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_set_index@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_set_linkstate@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_set_rate@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_set_rss_query_en@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_set_spoofchk@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_set_trust@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_set_vlans@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_str2guid@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_str2linkstate@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_str2vlanproto@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_vlan_alloc@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_vlan_free@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_vlan_put@libnl_3_2_29 3.5.0-1 + rtnl_link_vf_vlanproto2str@libnl_3_2_29 3.5.0-1 + rtnl_link_vlan_alloc@Base 3.5.0-1 + rtnl_link_vlan_alloc@libnl_3 3.5.0-1 + rtnl_link_vlan_flags2str@Base 3.5.0-1 + rtnl_link_vlan_flags2str@libnl_3 3.5.0-1 + rtnl_link_vlan_get_egress_map@Base 3.5.0-1 + rtnl_link_vlan_get_egress_map@libnl_3 3.5.0-1 + rtnl_link_vlan_get_flags@Base 3.5.0-1 + rtnl_link_vlan_get_flags@libnl_3 3.5.0-1 + rtnl_link_vlan_get_id@Base 3.5.0-1 + rtnl_link_vlan_get_id@libnl_3 3.5.0-1 + rtnl_link_vlan_get_ingress_map@Base 3.5.0-1 + rtnl_link_vlan_get_ingress_map@libnl_3 3.5.0-1 + rtnl_link_vlan_get_protocol@Base 3.5.0-1 + rtnl_link_vlan_get_protocol@libnl_3 3.5.0-1 + rtnl_link_vlan_set_egress_map@Base 3.5.0-1 + rtnl_link_vlan_set_egress_map@libnl_3 3.5.0-1 + rtnl_link_vlan_set_flags@Base 3.5.0-1 + rtnl_link_vlan_set_flags@libnl_3 3.5.0-1 + rtnl_link_vlan_set_id@Base 3.5.0-1 + rtnl_link_vlan_set_id@libnl_3 3.5.0-1 + rtnl_link_vlan_set_ingress_map@Base 3.5.0-1 + rtnl_link_vlan_set_ingress_map@libnl_3 3.5.0-1 + rtnl_link_vlan_set_protocol@Base 3.5.0-1 + rtnl_link_vlan_set_protocol@libnl_3 3.5.0-1 + rtnl_link_vlan_str2flags@Base 3.5.0-1 + rtnl_link_vlan_str2flags@libnl_3 3.5.0-1 + rtnl_link_vlan_unset_flags@Base 3.5.0-1 + rtnl_link_vlan_unset_flags@libnl_3 3.5.0-1 + rtnl_link_vrf_alloc@libnl_3_2_28 3.5.0-1 + rtnl_link_vrf_get_tableid@libnl_3_2_28 3.5.0-1 + rtnl_link_vrf_set_tableid@libnl_3_2_28 3.5.0-1 + rtnl_link_vxlan_alloc@Base 3.5.0-1 + rtnl_link_vxlan_alloc@libnl_3 3.5.0-1 + rtnl_link_vxlan_disable_l2miss@Base 3.5.0-1 + rtnl_link_vxlan_disable_l2miss@libnl_3 3.5.0-1 + rtnl_link_vxlan_disable_l3miss@Base 3.5.0-1 + rtnl_link_vxlan_disable_l3miss@libnl_3 3.5.0-1 + rtnl_link_vxlan_disable_learning@Base 3.5.0-1 + rtnl_link_vxlan_disable_learning@libnl_3 3.5.0-1 + rtnl_link_vxlan_disable_proxy@Base 3.5.0-1 + rtnl_link_vxlan_disable_proxy@libnl_3 3.5.0-1 + rtnl_link_vxlan_disable_rsc@Base 3.5.0-1 + rtnl_link_vxlan_disable_rsc@libnl_3 3.5.0-1 + rtnl_link_vxlan_enable_l2miss@Base 3.5.0-1 + rtnl_link_vxlan_enable_l2miss@libnl_3 3.5.0-1 + rtnl_link_vxlan_enable_l3miss@Base 3.5.0-1 + rtnl_link_vxlan_enable_l3miss@libnl_3 3.5.0-1 + rtnl_link_vxlan_enable_learning@Base 3.5.0-1 + rtnl_link_vxlan_enable_learning@libnl_3 3.5.0-1 + rtnl_link_vxlan_enable_proxy@Base 3.5.0-1 + rtnl_link_vxlan_enable_proxy@libnl_3 3.5.0-1 + rtnl_link_vxlan_enable_rsc@Base 3.5.0-1 + rtnl_link_vxlan_enable_rsc@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_ageing@Base 3.5.0-1 + rtnl_link_vxlan_get_ageing@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_collect_metadata@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_get_flags@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_get_group@Base 3.5.0-1 + rtnl_link_vxlan_get_group@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_id@Base 3.5.0-1 + rtnl_link_vxlan_get_id@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_l2miss@Base 3.5.0-1 + rtnl_link_vxlan_get_l2miss@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_l3miss@Base 3.5.0-1 + rtnl_link_vxlan_get_l3miss@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_label@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_get_learning@Base 3.5.0-1 + rtnl_link_vxlan_get_learning@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_limit@Base 3.5.0-1 + rtnl_link_vxlan_get_limit@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_link@Base 3.5.0-1 + rtnl_link_vxlan_get_link@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_local@Base 3.5.0-1 + rtnl_link_vxlan_get_local@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_port@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_get_port_range@Base 3.5.0-1 + rtnl_link_vxlan_get_port_range@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_proxy@Base 3.5.0-1 + rtnl_link_vxlan_get_proxy@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_remcsum_rx@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_get_remcsum_tx@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_get_rsc@Base 3.5.0-1 + rtnl_link_vxlan_get_rsc@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_tos@Base 3.5.0-1 + rtnl_link_vxlan_get_tos@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_ttl@Base 3.5.0-1 + rtnl_link_vxlan_get_ttl@libnl_3 3.5.0-1 + rtnl_link_vxlan_get_udp_csum@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_get_udp_zero_csum6_rx@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_get_udp_zero_csum6_tx@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_set_ageing@Base 3.5.0-1 + rtnl_link_vxlan_set_ageing@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_collect_metadata@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_set_flags@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_set_group@Base 3.5.0-1 + rtnl_link_vxlan_set_group@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_id@Base 3.5.0-1 + rtnl_link_vxlan_set_id@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_l2miss@Base 3.5.0-1 + rtnl_link_vxlan_set_l2miss@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_l3miss@Base 3.5.0-1 + rtnl_link_vxlan_set_l3miss@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_label@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_set_learning@Base 3.5.0-1 + rtnl_link_vxlan_set_learning@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_limit@Base 3.5.0-1 + rtnl_link_vxlan_set_limit@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_link@Base 3.5.0-1 + rtnl_link_vxlan_set_link@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_local@Base 3.5.0-1 + rtnl_link_vxlan_set_local@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_port@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_set_port_range@Base 3.5.0-1 + rtnl_link_vxlan_set_port_range@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_proxy@Base 3.5.0-1 + rtnl_link_vxlan_set_proxy@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_remcsum_rx@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_set_remcsum_tx@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_set_rsc@Base 3.5.0-1 + rtnl_link_vxlan_set_rsc@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_tos@Base 3.5.0-1 + rtnl_link_vxlan_set_tos@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_ttl@Base 3.5.0-1 + rtnl_link_vxlan_set_ttl@libnl_3 3.5.0-1 + rtnl_link_vxlan_set_udp_csum@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_set_udp_zero_csum6_rx@libnl_3_2_29 3.5.0-1 + rtnl_link_vxlan_set_udp_zero_csum6_tx@libnl_3_2_29 3.5.0-1 + rtnl_link_xfrmi_alloc@libnl_3_5 3.5.0-1 + rtnl_link_xfrmi_get_if_id@libnl_3_5 3.5.0-1 + rtnl_link_xfrmi_get_link@libnl_3_5 3.5.0-1 + rtnl_link_xfrmi_set_if_id@libnl_3_5 3.5.0-1 + rtnl_link_xfrmi_set_link@libnl_3_5 3.5.0-1 + rtnl_mall_append_action@libnl_3_5 3.5.0-1 + rtnl_mall_del_action@libnl_3_5 3.5.0-1 + rtnl_mall_get_classid@libnl_3_5 3.5.0-1 + rtnl_mall_get_first_action@libnl_3_5 3.5.0-1 + rtnl_mall_get_flags@libnl_3_5 3.5.0-1 + rtnl_mall_set_classid@libnl_3_5 3.5.0-1 + rtnl_mall_set_flags@libnl_3_5 3.5.0-1 + rtnl_meta_value_alloc_id@Base 3.5.0-1 + rtnl_meta_value_alloc_id@libnl_3 3.5.0-1 + rtnl_meta_value_alloc_int@Base 3.5.0-1 + rtnl_meta_value_alloc_int@libnl_3 3.5.0-1 + rtnl_meta_value_alloc_var@Base 3.5.0-1 + rtnl_meta_value_alloc_var@libnl_3 3.5.0-1 + rtnl_meta_value_put@Base 3.5.0-1 + rtnl_meta_value_put@libnl_3 3.5.0-1 + rtnl_mirred_get_action@Base 3.5.0-1 + rtnl_mirred_get_action@libnl_3 3.5.0-1 + rtnl_mirred_get_ifindex@Base 3.5.0-1 + rtnl_mirred_get_ifindex@libnl_3 3.5.0-1 + rtnl_mirred_get_policy@Base 3.5.0-1 + rtnl_mirred_get_policy@libnl_3 3.5.0-1 + rtnl_mirred_set_action@Base 3.5.0-1 + rtnl_mirred_set_action@libnl_3 3.5.0-1 + rtnl_mirred_set_ifindex@Base 3.5.0-1 + rtnl_mirred_set_ifindex@libnl_3 3.5.0-1 + rtnl_mirred_set_policy@Base 3.5.0-1 + rtnl_mirred_set_policy@libnl_3 3.5.0-1 + rtnl_neigh_add@Base 3.5.0-1 + rtnl_neigh_add@libnl_3 3.5.0-1 + rtnl_neigh_alloc@Base 3.5.0-1 + rtnl_neigh_alloc@libnl_3 3.5.0-1 + rtnl_neigh_alloc_cache@Base 3.5.0-1 + rtnl_neigh_alloc_cache@libnl_3 3.5.0-1 + rtnl_neigh_alloc_cache_flags@libnl_3_2_28 3.5.0-1 + rtnl_neigh_build_add_request@Base 3.5.0-1 + rtnl_neigh_build_add_request@libnl_3 3.5.0-1 + rtnl_neigh_build_delete_request@Base 3.5.0-1 + rtnl_neigh_build_delete_request@libnl_3 3.5.0-1 + rtnl_neigh_delete@Base 3.5.0-1 + rtnl_neigh_delete@libnl_3 3.5.0-1 + rtnl_neigh_flags2str@Base 3.5.0-1 + rtnl_neigh_flags2str@libnl_3 3.5.0-1 + rtnl_neigh_get@Base 3.5.0-1 + rtnl_neigh_get@libnl_3 3.5.0-1 + rtnl_neigh_get_by_vlan@libnl_3_5 3.5.0-1 + rtnl_neigh_get_dst@Base 3.5.0-1 + rtnl_neigh_get_dst@libnl_3 3.5.0-1 + rtnl_neigh_get_family@Base 3.5.0-1 + rtnl_neigh_get_family@libnl_3 3.5.0-1 + rtnl_neigh_get_flags@Base 3.5.0-1 + rtnl_neigh_get_flags@libnl_3 3.5.0-1 + rtnl_neigh_get_ifindex@Base 3.5.0-1 + rtnl_neigh_get_ifindex@libnl_3 3.5.0-1 + rtnl_neigh_get_lladdr@Base 3.5.0-1 + rtnl_neigh_get_lladdr@libnl_3 3.5.0-1 + rtnl_neigh_get_master@libnl_3_5 3.5.0-1 + rtnl_neigh_get_state@Base 3.5.0-1 + rtnl_neigh_get_state@libnl_3 3.5.0-1 + rtnl_neigh_get_type@Base 3.5.0-1 + rtnl_neigh_get_type@libnl_3 3.5.0-1 + rtnl_neigh_get_vlan@Base 3.5.0-1 + rtnl_neigh_get_vlan@libnl_3_2_26 3.5.0-1 + rtnl_neigh_parse@Base 3.5.0-1 + rtnl_neigh_parse@libnl_3 3.5.0-1 + rtnl_neigh_put@Base 3.5.0-1 + rtnl_neigh_put@libnl_3 3.5.0-1 + rtnl_neigh_set_dst@Base 3.5.0-1 + rtnl_neigh_set_dst@libnl_3 3.5.0-1 + rtnl_neigh_set_family@Base 3.5.0-1 + rtnl_neigh_set_family@libnl_3 3.5.0-1 + rtnl_neigh_set_flags@Base 3.5.0-1 + rtnl_neigh_set_flags@libnl_3 3.5.0-1 + rtnl_neigh_set_ifindex@Base 3.5.0-1 + rtnl_neigh_set_ifindex@libnl_3 3.5.0-1 + rtnl_neigh_set_lladdr@Base 3.5.0-1 + rtnl_neigh_set_lladdr@libnl_3 3.5.0-1 + rtnl_neigh_set_master@libnl_3_5 3.5.0-1 + rtnl_neigh_set_state@Base 3.5.0-1 + rtnl_neigh_set_state@libnl_3 3.5.0-1 + rtnl_neigh_set_type@Base 3.5.0-1 + rtnl_neigh_set_type@libnl_3 3.5.0-1 + rtnl_neigh_set_vlan@Base 3.5.0-1 + rtnl_neigh_set_vlan@libnl_3_2_26 3.5.0-1 + rtnl_neigh_state2str@Base 3.5.0-1 + rtnl_neigh_state2str@libnl_3 3.5.0-1 + rtnl_neigh_str2flag@Base 3.5.0-1 + rtnl_neigh_str2flag@libnl_3 3.5.0-1 + rtnl_neigh_str2state@Base 3.5.0-1 + rtnl_neigh_str2state@libnl_3 3.5.0-1 + rtnl_neigh_unset_flags@Base 3.5.0-1 + rtnl_neigh_unset_flags@libnl_3 3.5.0-1 + rtnl_neigh_unset_state@Base 3.5.0-1 + rtnl_neigh_unset_state@libnl_3 3.5.0-1 + rtnl_neightbl_alloc@Base 3.5.0-1 + rtnl_neightbl_alloc@libnl_3 3.5.0-1 + rtnl_neightbl_alloc_cache@Base 3.5.0-1 + rtnl_neightbl_alloc_cache@libnl_3 3.5.0-1 + rtnl_neightbl_build_change_request@Base 3.5.0-1 + rtnl_neightbl_build_change_request@libnl_3 3.5.0-1 + rtnl_neightbl_change@Base 3.5.0-1 + rtnl_neightbl_change@libnl_3 3.5.0-1 + rtnl_neightbl_get@Base 3.5.0-1 + rtnl_neightbl_get@libnl_3 3.5.0-1 + rtnl_neightbl_put@Base 3.5.0-1 + rtnl_neightbl_put@libnl_3 3.5.0-1 + rtnl_neightbl_set_anycast_delay@Base 3.5.0-1 + rtnl_neightbl_set_anycast_delay@libnl_3 3.5.0-1 + rtnl_neightbl_set_app_probes@Base 3.5.0-1 + rtnl_neightbl_set_app_probes@libnl_3 3.5.0-1 + rtnl_neightbl_set_base_reachable_time@Base 3.5.0-1 + rtnl_neightbl_set_base_reachable_time@libnl_3 3.5.0-1 + rtnl_neightbl_set_delay_probe_time@Base 3.5.0-1 + rtnl_neightbl_set_delay_probe_time@libnl_3 3.5.0-1 + rtnl_neightbl_set_dev@Base 3.5.0-1 + rtnl_neightbl_set_dev@libnl_3 3.5.0-1 + rtnl_neightbl_set_family@Base 3.5.0-1 + rtnl_neightbl_set_family@libnl_3 3.5.0-1 + rtnl_neightbl_set_gc_interval@Base 3.5.0-1 + rtnl_neightbl_set_gc_interval@libnl_3 3.5.0-1 + rtnl_neightbl_set_gc_stale_time@Base 3.5.0-1 + rtnl_neightbl_set_gc_stale_time@libnl_3 3.5.0-1 + rtnl_neightbl_set_gc_tresh1@Base 3.5.0-1 + rtnl_neightbl_set_gc_tresh1@libnl_3 3.5.0-1 + rtnl_neightbl_set_gc_tresh2@Base 3.5.0-1 + rtnl_neightbl_set_gc_tresh2@libnl_3 3.5.0-1 + rtnl_neightbl_set_gc_tresh3@Base 3.5.0-1 + rtnl_neightbl_set_gc_tresh3@libnl_3 3.5.0-1 + rtnl_neightbl_set_locktime@Base 3.5.0-1 + rtnl_neightbl_set_locktime@libnl_3 3.5.0-1 + rtnl_neightbl_set_mcast_probes@Base 3.5.0-1 + rtnl_neightbl_set_mcast_probes@libnl_3 3.5.0-1 + rtnl_neightbl_set_name@Base 3.5.0-1 + rtnl_neightbl_set_name@libnl_3 3.5.0-1 + rtnl_neightbl_set_proxy_delay@Base 3.5.0-1 + rtnl_neightbl_set_proxy_delay@libnl_3 3.5.0-1 + rtnl_neightbl_set_proxy_queue_len@Base 3.5.0-1 + rtnl_neightbl_set_proxy_queue_len@libnl_3 3.5.0-1 + rtnl_neightbl_set_queue_len@Base 3.5.0-1 + rtnl_neightbl_set_queue_len@libnl_3 3.5.0-1 + rtnl_neightbl_set_retrans_time@Base 3.5.0-1 + rtnl_neightbl_set_retrans_time@libnl_3 3.5.0-1 + rtnl_neightbl_set_ucast_probes@Base 3.5.0-1 + rtnl_neightbl_set_ucast_probes@libnl_3 3.5.0-1 + rtnl_netconf_get_all@libnl_3_4 3.5.0-1 + rtnl_netconf_get_by_idx@libnl_3_4 3.5.0-1 + rtnl_netconf_get_default@libnl_3_4 3.5.0-1 + rtnl_netconf_get_family@libnl_3_4 3.5.0-1 + rtnl_netconf_get_forwarding@libnl_3_4 3.5.0-1 + rtnl_netconf_get_ifindex@libnl_3_4 3.5.0-1 + rtnl_netconf_get_input@libnl_3_4 3.5.0-1 + rtnl_netconf_get_mc_forwarding@libnl_3_4 3.5.0-1 + rtnl_netconf_get_rp_filter@libnl_3_4 3.5.0-1 + rtnl_netconf_put@libnl_3_4 3.5.0-1 + rtnl_netem_get_corruption_correlation@Base 3.5.0-1 + rtnl_netem_get_corruption_correlation@libnl_3 3.5.0-1 + rtnl_netem_get_corruption_probability@Base 3.5.0-1 + rtnl_netem_get_corruption_probability@libnl_3 3.5.0-1 + rtnl_netem_get_delay@Base 3.5.0-1 + rtnl_netem_get_delay@libnl_3 3.5.0-1 + rtnl_netem_get_delay_correlation@Base 3.5.0-1 + rtnl_netem_get_delay_correlation@libnl_3 3.5.0-1 + rtnl_netem_get_delay_distribution@Base 3.5.0-1 + rtnl_netem_get_delay_distribution@libnl_3 3.5.0-1 + rtnl_netem_get_delay_distribution_size@Base 3.5.0-1 + rtnl_netem_get_delay_distribution_size@libnl_3 3.5.0-1 + rtnl_netem_get_duplicate@Base 3.5.0-1 + rtnl_netem_get_duplicate@libnl_3 3.5.0-1 + rtnl_netem_get_duplicate_correlation@Base 3.5.0-1 + rtnl_netem_get_duplicate_correlation@libnl_3 3.5.0-1 + rtnl_netem_get_gap@Base 3.5.0-1 + rtnl_netem_get_gap@libnl_3 3.5.0-1 + rtnl_netem_get_jitter@Base 3.5.0-1 + rtnl_netem_get_jitter@libnl_3 3.5.0-1 + rtnl_netem_get_limit@Base 3.5.0-1 + rtnl_netem_get_limit@libnl_3 3.5.0-1 + rtnl_netem_get_loss@Base 3.5.0-1 + rtnl_netem_get_loss@libnl_3 3.5.0-1 + rtnl_netem_get_loss_correlation@Base 3.5.0-1 + rtnl_netem_get_loss_correlation@libnl_3 3.5.0-1 + rtnl_netem_get_reorder_correlation@Base 3.5.0-1 + rtnl_netem_get_reorder_correlation@libnl_3 3.5.0-1 + rtnl_netem_get_reorder_probability@Base 3.5.0-1 + rtnl_netem_get_reorder_probability@libnl_3 3.5.0-1 + rtnl_netem_set_corruption_correlation@Base 3.5.0-1 + rtnl_netem_set_corruption_correlation@libnl_3 3.5.0-1 + rtnl_netem_set_corruption_probability@Base 3.5.0-1 + rtnl_netem_set_corruption_probability@libnl_3 3.5.0-1 + rtnl_netem_set_delay@Base 3.5.0-1 + rtnl_netem_set_delay@libnl_3 3.5.0-1 + rtnl_netem_set_delay_correlation@Base 3.5.0-1 + rtnl_netem_set_delay_correlation@libnl_3 3.5.0-1 + rtnl_netem_set_delay_distribution@Base 3.5.0-1 + rtnl_netem_set_delay_distribution@libnl_3 3.5.0-1 + rtnl_netem_set_delay_distribution_data@libnl_3_5 3.5.0-1 + rtnl_netem_set_duplicate@Base 3.5.0-1 + rtnl_netem_set_duplicate@libnl_3 3.5.0-1 + rtnl_netem_set_duplicate_correlation@Base 3.5.0-1 + rtnl_netem_set_duplicate_correlation@libnl_3 3.5.0-1 + rtnl_netem_set_gap@Base 3.5.0-1 + rtnl_netem_set_gap@libnl_3 3.5.0-1 + rtnl_netem_set_jitter@Base 3.5.0-1 + rtnl_netem_set_jitter@libnl_3 3.5.0-1 + rtnl_netem_set_limit@Base 3.5.0-1 + rtnl_netem_set_limit@libnl_3 3.5.0-1 + rtnl_netem_set_loss@Base 3.5.0-1 + rtnl_netem_set_loss@libnl_3 3.5.0-1 + rtnl_netem_set_loss_correlation@Base 3.5.0-1 + rtnl_netem_set_loss_correlation@libnl_3 3.5.0-1 + rtnl_netem_set_reorder_correlation@Base 3.5.0-1 + rtnl_netem_set_reorder_correlation@libnl_3 3.5.0-1 + rtnl_netem_set_reorder_probability@Base 3.5.0-1 + rtnl_netem_set_reorder_probability@libnl_3 3.5.0-1 + rtnl_pktloc_add@Base 3.5.0-1 + rtnl_pktloc_add@libnl_3 3.5.0-1 + rtnl_pktloc_alloc@Base 3.5.0-1 + rtnl_pktloc_alloc@libnl_3 3.5.0-1 + rtnl_pktloc_foreach@Base 3.5.0-1 + rtnl_pktloc_foreach@libnl_3 3.5.0-1 + rtnl_pktloc_lookup@Base 3.5.0-1 + rtnl_pktloc_lookup@libnl_3 3.5.0-1 + rtnl_pktloc_put@Base 3.5.0-1 + rtnl_pktloc_put@libnl_3 3.5.0-1 + rtnl_prio2str@Base 3.5.0-1 + rtnl_prio2str@libnl_3 3.5.0-1 + rtnl_qdisc_add@Base 3.5.0-1 + rtnl_qdisc_add@libnl_3 3.5.0-1 + rtnl_qdisc_alloc@Base 3.5.0-1 + rtnl_qdisc_alloc@libnl_3 3.5.0-1 + rtnl_qdisc_alloc_cache@Base 3.5.0-1 + rtnl_qdisc_alloc_cache@libnl_3 3.5.0-1 + rtnl_qdisc_build_add_request@Base 3.5.0-1 + rtnl_qdisc_build_add_request@libnl_3 3.5.0-1 + rtnl_qdisc_build_change_request@Base 3.5.0-1 + rtnl_qdisc_build_change_request@libnl_3 3.5.0-1 + rtnl_qdisc_build_delete_request@Base 3.5.0-1 + rtnl_qdisc_build_delete_request@libnl_3 3.5.0-1 + rtnl_qdisc_build_update_request@Base 3.5.0-1 + rtnl_qdisc_build_update_request@libnl_3 3.5.0-1 + rtnl_qdisc_change@Base 3.5.0-1 + rtnl_qdisc_change@libnl_3 3.5.0-1 + rtnl_qdisc_delete@Base 3.5.0-1 + rtnl_qdisc_delete@libnl_3 3.5.0-1 + rtnl_qdisc_dsmark_get_default_index@Base 3.5.0-1 + rtnl_qdisc_dsmark_get_default_index@libnl_3 3.5.0-1 + rtnl_qdisc_dsmark_get_indices@Base 3.5.0-1 + rtnl_qdisc_dsmark_get_indices@libnl_3 3.5.0-1 + rtnl_qdisc_dsmark_get_set_tc_index@Base 3.5.0-1 + rtnl_qdisc_dsmark_get_set_tc_index@libnl_3 3.5.0-1 + rtnl_qdisc_dsmark_set_default_index@Base 3.5.0-1 + rtnl_qdisc_dsmark_set_default_index@libnl_3 3.5.0-1 + rtnl_qdisc_dsmark_set_indices@Base 3.5.0-1 + rtnl_qdisc_dsmark_set_indices@libnl_3 3.5.0-1 + rtnl_qdisc_dsmark_set_set_tc_index@Base 3.5.0-1 + rtnl_qdisc_dsmark_set_set_tc_index@libnl_3 3.5.0-1 + rtnl_qdisc_fifo_get_limit@Base 3.5.0-1 + rtnl_qdisc_fifo_get_limit@libnl_3 3.5.0-1 + rtnl_qdisc_fifo_set_limit@Base 3.5.0-1 + rtnl_qdisc_fifo_set_limit@libnl_3 3.5.0-1 + rtnl_qdisc_foreach_child@Base 3.5.0-1 + rtnl_qdisc_foreach_child@libnl_3 3.5.0-1 + rtnl_qdisc_foreach_cls@Base 3.5.0-1 + rtnl_qdisc_foreach_cls@libnl_3 3.5.0-1 + rtnl_qdisc_fq_codel_get_ecn@Base 3.5.0-1 + rtnl_qdisc_fq_codel_get_ecn@libnl_3 3.5.0-1 + rtnl_qdisc_fq_codel_get_flows@Base 3.5.0-1 + rtnl_qdisc_fq_codel_get_flows@libnl_3 3.5.0-1 + rtnl_qdisc_fq_codel_get_interval@Base 3.5.0-1 + rtnl_qdisc_fq_codel_get_interval@libnl_3 3.5.0-1 + rtnl_qdisc_fq_codel_get_limit@Base 3.5.0-1 + rtnl_qdisc_fq_codel_get_limit@libnl_3 3.5.0-1 + rtnl_qdisc_fq_codel_get_quantum@Base 3.5.0-1 + rtnl_qdisc_fq_codel_get_quantum@libnl_3 3.5.0-1 + rtnl_qdisc_fq_codel_get_target@Base 3.5.0-1 + rtnl_qdisc_fq_codel_get_target@libnl_3 3.5.0-1 + rtnl_qdisc_fq_codel_set_ecn@Base 3.5.0-1 + rtnl_qdisc_fq_codel_set_ecn@libnl_3 3.5.0-1 + rtnl_qdisc_fq_codel_set_flows@Base 3.5.0-1 + rtnl_qdisc_fq_codel_set_flows@libnl_3 3.5.0-1 + rtnl_qdisc_fq_codel_set_interval@Base 3.5.0-1 + rtnl_qdisc_fq_codel_set_interval@libnl_3 3.5.0-1 + rtnl_qdisc_fq_codel_set_limit@Base 3.5.0-1 + rtnl_qdisc_fq_codel_set_limit@libnl_3 3.5.0-1 + rtnl_qdisc_fq_codel_set_quantum@Base 3.5.0-1 + rtnl_qdisc_fq_codel_set_quantum@libnl_3 3.5.0-1 + rtnl_qdisc_fq_codel_set_target@Base 3.5.0-1 + rtnl_qdisc_fq_codel_set_target@libnl_3 3.5.0-1 + rtnl_qdisc_get@Base 3.5.0-1 + rtnl_qdisc_get@libnl_3 3.5.0-1 + rtnl_qdisc_get_by_parent@Base 3.5.0-1 + rtnl_qdisc_get_by_parent@libnl_3 3.5.0-1 + rtnl_qdisc_hfsc_get_defcls@Base 3.5.0-1 + rtnl_qdisc_hfsc_get_defcls@libnl_3 3.5.0-1 + rtnl_qdisc_hfsc_set_defcls@Base 3.5.0-1 + rtnl_qdisc_hfsc_set_defcls@libnl_3 3.5.0-1 + rtnl_qdisc_mqprio_get_hw_offload@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_get_max_rate@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_get_min_rate@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_get_mode@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_get_num_tc@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_get_priomap@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_get_queue@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_get_shaper@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_hw_offload@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_set_max_rate@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_set_min_rate@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_set_mode@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_set_num_tc@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_set_priomap@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_set_queue@libnl_3_5 3.5.0-1 + rtnl_qdisc_mqprio_set_shaper@libnl_3_5 3.5.0-1 + rtnl_qdisc_plug_buffer@Base 3.5.0-1 + rtnl_qdisc_plug_buffer@libnl_3 3.5.0-1 + rtnl_qdisc_plug_release_indefinite@Base 3.5.0-1 + rtnl_qdisc_plug_release_indefinite@libnl_3 3.5.0-1 + rtnl_qdisc_plug_release_one@Base 3.5.0-1 + rtnl_qdisc_plug_release_one@libnl_3 3.5.0-1 + rtnl_qdisc_plug_set_limit@Base 3.5.0-1 + rtnl_qdisc_plug_set_limit@libnl_3 3.5.0-1 + rtnl_qdisc_prio_get_bands@Base 3.5.0-1 + rtnl_qdisc_prio_get_bands@libnl_3 3.5.0-1 + rtnl_qdisc_prio_get_priomap@Base 3.5.0-1 + rtnl_qdisc_prio_get_priomap@libnl_3 3.5.0-1 + rtnl_qdisc_prio_set_bands@Base 3.5.0-1 + rtnl_qdisc_prio_set_bands@libnl_3 3.5.0-1 + rtnl_qdisc_prio_set_priomap@Base 3.5.0-1 + rtnl_qdisc_prio_set_priomap@libnl_3 3.5.0-1 + rtnl_qdisc_put@Base 3.5.0-1 + rtnl_qdisc_put@libnl_3 3.5.0-1 + rtnl_qdisc_tbf_get_limit@Base 3.5.0-1 + rtnl_qdisc_tbf_get_limit@libnl_3 3.5.0-1 + rtnl_qdisc_tbf_get_peakrate@Base 3.5.0-1 + rtnl_qdisc_tbf_get_peakrate@libnl_3 3.5.0-1 + rtnl_qdisc_tbf_get_peakrate_bucket@Base 3.5.0-1 + rtnl_qdisc_tbf_get_peakrate_bucket@libnl_3 3.5.0-1 + rtnl_qdisc_tbf_get_peakrate_cell@Base 3.5.0-1 + rtnl_qdisc_tbf_get_peakrate_cell@libnl_3 3.5.0-1 + rtnl_qdisc_tbf_get_rate@Base 3.5.0-1 + rtnl_qdisc_tbf_get_rate@libnl_3 3.5.0-1 + rtnl_qdisc_tbf_get_rate_bucket@Base 3.5.0-1 + rtnl_qdisc_tbf_get_rate_bucket@libnl_3 3.5.0-1 + rtnl_qdisc_tbf_get_rate_cell@Base 3.5.0-1 + rtnl_qdisc_tbf_get_rate_cell@libnl_3 3.5.0-1 + rtnl_qdisc_tbf_set_limit@Base 3.5.0-1 + rtnl_qdisc_tbf_set_limit@libnl_3 3.5.0-1 + rtnl_qdisc_tbf_set_limit_by_latency@Base 3.5.0-1 + rtnl_qdisc_tbf_set_limit_by_latency@libnl_3 3.5.0-1 + rtnl_qdisc_tbf_set_peakrate@Base 3.5.0-1 + rtnl_qdisc_tbf_set_peakrate@libnl_3 3.5.0-1 + rtnl_qdisc_tbf_set_rate@Base 3.5.0-1 + rtnl_qdisc_tbf_set_rate@libnl_3 3.5.0-1 + rtnl_qdisc_update@Base 3.5.0-1 + rtnl_qdisc_update@libnl_3 3.5.0-1 + rtnl_realms2str@Base 3.5.0-1 + rtnl_realms2str@libnl_3 3.5.0-1 + rtnl_red_get_limit@Base 3.5.0-1 + rtnl_red_get_limit@libnl_3 3.5.0-1 + rtnl_red_set_limit@Base 3.5.0-1 + rtnl_red_set_limit@libnl_3 3.5.0-1 + rtnl_route_add@Base 3.5.0-1 + rtnl_route_add@libnl_3 3.5.0-1 + rtnl_route_add_nexthop@Base 3.5.0-1 + rtnl_route_add_nexthop@libnl_3 3.5.0-1 + rtnl_route_alloc@Base 3.5.0-1 + rtnl_route_alloc@libnl_3 3.5.0-1 + rtnl_route_alloc_cache@Base 3.5.0-1 + rtnl_route_alloc_cache@libnl_3 3.5.0-1 + rtnl_route_build_add_request@Base 3.5.0-1 + rtnl_route_build_add_request@libnl_3 3.5.0-1 + rtnl_route_build_del_request@Base 3.5.0-1 + rtnl_route_build_del_request@libnl_3 3.5.0-1 + rtnl_route_build_msg@Base 3.5.0-1 + rtnl_route_build_msg@libnl_3 3.5.0-1 + rtnl_route_delete@Base 3.5.0-1 + rtnl_route_delete@libnl_3 3.5.0-1 + rtnl_route_foreach_nexthop@Base 3.5.0-1 + rtnl_route_foreach_nexthop@libnl_3 3.5.0-1 + rtnl_route_get@Base 3.5.0-1 + rtnl_route_get@libnl_3 3.5.0-1 + rtnl_route_get_dst@Base 3.5.0-1 + rtnl_route_get_dst@libnl_3 3.5.0-1 + rtnl_route_get_family@Base 3.5.0-1 + rtnl_route_get_family@libnl_3 3.5.0-1 + rtnl_route_get_flags@Base 3.5.0-1 + rtnl_route_get_flags@libnl_3 3.5.0-1 + rtnl_route_get_iif@Base 3.5.0-1 + rtnl_route_get_iif@libnl_3 3.5.0-1 + rtnl_route_get_metric@Base 3.5.0-1 + rtnl_route_get_metric@libnl_3 3.5.0-1 + rtnl_route_get_nexthops@Base 3.5.0-1 + rtnl_route_get_nexthops@libnl_3 3.5.0-1 + rtnl_route_get_nnexthops@Base 3.5.0-1 + rtnl_route_get_nnexthops@libnl_3 3.5.0-1 + rtnl_route_get_pref_src@Base 3.5.0-1 + rtnl_route_get_pref_src@libnl_3 3.5.0-1 + rtnl_route_get_priority@Base 3.5.0-1 + rtnl_route_get_priority@libnl_3 3.5.0-1 + rtnl_route_get_protocol@Base 3.5.0-1 + rtnl_route_get_protocol@libnl_3 3.5.0-1 + rtnl_route_get_scope@Base 3.5.0-1 + rtnl_route_get_scope@libnl_3 3.5.0-1 + rtnl_route_get_src@Base 3.5.0-1 + rtnl_route_get_src@libnl_3 3.5.0-1 + rtnl_route_get_table@Base 3.5.0-1 + rtnl_route_get_table@libnl_3 3.5.0-1 + rtnl_route_get_tos@Base 3.5.0-1 + rtnl_route_get_tos@libnl_3 3.5.0-1 + rtnl_route_get_ttl_propagate@libnl_3_4 3.5.0-1 + rtnl_route_get_type@Base 3.5.0-1 + rtnl_route_get_type@libnl_3 3.5.0-1 + rtnl_route_guess_scope@Base 3.5.0-1 + rtnl_route_guess_scope@libnl_3 3.5.0-1 + rtnl_route_metric2str@Base 3.5.0-1 + rtnl_route_metric2str@libnl_3 3.5.0-1 + rtnl_route_nexthop_n@Base 3.5.0-1 + rtnl_route_nexthop_n@libnl_3 3.5.0-1 + rtnl_route_nh_alloc@Base 3.5.0-1 + rtnl_route_nh_alloc@libnl_3 3.5.0-1 + rtnl_route_nh_clone@Base 3.5.0-1 + rtnl_route_nh_clone@libnl_3 3.5.0-1 + rtnl_route_nh_compare@Base 3.5.0-1 + rtnl_route_nh_compare@libnl_3 3.5.0-1 + rtnl_route_nh_dump@Base 3.5.0-1 + rtnl_route_nh_dump@libnl_3 3.5.0-1 + rtnl_route_nh_encap_mpls@libnl_3_4 3.5.0-1 + rtnl_route_nh_flags2str@Base 3.5.0-1 + rtnl_route_nh_flags2str@libnl_3 3.5.0-1 + rtnl_route_nh_free@Base 3.5.0-1 + rtnl_route_nh_free@libnl_3 3.5.0-1 + rtnl_route_nh_get_flags@Base 3.5.0-1 + rtnl_route_nh_get_flags@libnl_3 3.5.0-1 + rtnl_route_nh_get_gateway@Base 3.5.0-1 + rtnl_route_nh_get_gateway@libnl_3 3.5.0-1 + rtnl_route_nh_get_ifindex@Base 3.5.0-1 + rtnl_route_nh_get_ifindex@libnl_3 3.5.0-1 + rtnl_route_nh_get_newdst@libnl_3_4 3.5.0-1 + rtnl_route_nh_get_realms@Base 3.5.0-1 + rtnl_route_nh_get_realms@libnl_3 3.5.0-1 + rtnl_route_nh_get_via@libnl_3_4 3.5.0-1 + rtnl_route_nh_get_weight@Base 3.5.0-1 + rtnl_route_nh_get_weight@libnl_3 3.5.0-1 + rtnl_route_nh_set_flags@Base 3.5.0-1 + rtnl_route_nh_set_flags@libnl_3 3.5.0-1 + rtnl_route_nh_set_gateway@Base 3.5.0-1 + rtnl_route_nh_set_gateway@libnl_3 3.5.0-1 + rtnl_route_nh_set_ifindex@Base 3.5.0-1 + rtnl_route_nh_set_ifindex@libnl_3 3.5.0-1 + rtnl_route_nh_set_newdst@libnl_3_4 3.5.0-1 + rtnl_route_nh_set_realms@Base 3.5.0-1 + rtnl_route_nh_set_realms@libnl_3 3.5.0-1 + rtnl_route_nh_set_via@libnl_3_4 3.5.0-1 + rtnl_route_nh_set_weight@Base 3.5.0-1 + rtnl_route_nh_set_weight@libnl_3 3.5.0-1 + rtnl_route_nh_str2flags@Base 3.5.0-1 + rtnl_route_nh_str2flags@libnl_3 3.5.0-1 + rtnl_route_nh_unset_flags@Base 3.5.0-1 + rtnl_route_nh_unset_flags@libnl_3 3.5.0-1 + rtnl_route_parse@Base 3.5.0-1 + rtnl_route_parse@libnl_3 3.5.0-1 + rtnl_route_proto2str@Base 3.5.0-1 + rtnl_route_proto2str@libnl_3 3.5.0-1 + rtnl_route_put@Base 3.5.0-1 + rtnl_route_put@libnl_3 3.5.0-1 + rtnl_route_read_protocol_names@Base 3.5.0-1 + rtnl_route_read_protocol_names@libnl_3 3.5.0-1 + rtnl_route_read_table_names@Base 3.5.0-1 + rtnl_route_read_table_names@libnl_3 3.5.0-1 + rtnl_route_remove_nexthop@Base 3.5.0-1 + rtnl_route_remove_nexthop@libnl_3 3.5.0-1 + rtnl_route_set_dst@Base 3.5.0-1 + rtnl_route_set_dst@libnl_3 3.5.0-1 + rtnl_route_set_family@Base 3.5.0-1 + rtnl_route_set_family@libnl_3 3.5.0-1 + rtnl_route_set_flags@Base 3.5.0-1 + rtnl_route_set_flags@libnl_3 3.5.0-1 + rtnl_route_set_iif@Base 3.5.0-1 + rtnl_route_set_iif@libnl_3 3.5.0-1 + rtnl_route_set_metric@Base 3.5.0-1 + rtnl_route_set_metric@libnl_3 3.5.0-1 + rtnl_route_set_pref_src@Base 3.5.0-1 + rtnl_route_set_pref_src@libnl_3 3.5.0-1 + rtnl_route_set_priority@Base 3.5.0-1 + rtnl_route_set_priority@libnl_3 3.5.0-1 + rtnl_route_set_protocol@Base 3.5.0-1 + rtnl_route_set_protocol@libnl_3 3.5.0-1 + rtnl_route_set_scope@Base 3.5.0-1 + rtnl_route_set_scope@libnl_3 3.5.0-1 + rtnl_route_set_src@Base 3.5.0-1 + rtnl_route_set_src@libnl_3 3.5.0-1 + rtnl_route_set_table@Base 3.5.0-1 + rtnl_route_set_table@libnl_3 3.5.0-1 + rtnl_route_set_tos@Base 3.5.0-1 + rtnl_route_set_tos@libnl_3 3.5.0-1 + rtnl_route_set_ttl_propagate@libnl_3_4 3.5.0-1 + rtnl_route_set_type@Base 3.5.0-1 + rtnl_route_set_type@libnl_3 3.5.0-1 + rtnl_route_str2metric@Base 3.5.0-1 + rtnl_route_str2metric@libnl_3 3.5.0-1 + rtnl_route_str2proto@Base 3.5.0-1 + rtnl_route_str2proto@libnl_3 3.5.0-1 + rtnl_route_str2table@Base 3.5.0-1 + rtnl_route_str2table@libnl_3 3.5.0-1 + rtnl_route_table2str@Base 3.5.0-1 + rtnl_route_table2str@libnl_3 3.5.0-1 + rtnl_route_unset_flags@Base 3.5.0-1 + rtnl_route_unset_flags@libnl_3 3.5.0-1 + rtnl_route_unset_metric@Base 3.5.0-1 + rtnl_route_unset_metric@libnl_3 3.5.0-1 + rtnl_rule_add@Base 3.5.0-1 + rtnl_rule_add@libnl_3 3.5.0-1 + rtnl_rule_alloc@Base 3.5.0-1 + rtnl_rule_alloc@libnl_3 3.5.0-1 + rtnl_rule_alloc_cache@Base 3.5.0-1 + rtnl_rule_alloc_cache@libnl_3 3.5.0-1 + rtnl_rule_build_add_request@Base 3.5.0-1 + rtnl_rule_build_add_request@libnl_3 3.5.0-1 + rtnl_rule_build_delete_request@Base 3.5.0-1 + rtnl_rule_build_delete_request@libnl_3 3.5.0-1 + rtnl_rule_delete@Base 3.5.0-1 + rtnl_rule_delete@libnl_3 3.5.0-1 + rtnl_rule_get_action@Base 3.5.0-1 + rtnl_rule_get_action@libnl_3 3.5.0-1 + rtnl_rule_get_dport@libnl_3_5 3.5.0-1 + rtnl_rule_get_dsfield@Base 3.5.0-1 + rtnl_rule_get_dsfield@libnl_3 3.5.0-1 + rtnl_rule_get_dst@Base 3.5.0-1 + rtnl_rule_get_dst@libnl_3 3.5.0-1 + rtnl_rule_get_family@Base 3.5.0-1 + rtnl_rule_get_family@libnl_3 3.5.0-1 + rtnl_rule_get_goto@Base 3.5.0-1 + rtnl_rule_get_goto@libnl_3 3.5.0-1 + rtnl_rule_get_iif@Base 3.5.0-1 + rtnl_rule_get_iif@libnl_3 3.5.0-1 + rtnl_rule_get_ipproto@libnl_3_5 3.5.0-1 + rtnl_rule_get_l3mdev@libnl_3_4 3.5.0-1 + rtnl_rule_get_mark@Base 3.5.0-1 + rtnl_rule_get_mark@libnl_3 3.5.0-1 + rtnl_rule_get_mask@Base 3.5.0-1 + rtnl_rule_get_mask@libnl_3 3.5.0-1 + rtnl_rule_get_oif@Base 3.5.0-1 + rtnl_rule_get_oif@libnl_3 3.5.0-1 + rtnl_rule_get_prio@Base 3.5.0-1 + rtnl_rule_get_prio@libnl_3 3.5.0-1 + rtnl_rule_get_protocol@libnl_3_5 3.5.0-1 + rtnl_rule_get_realms@Base 3.5.0-1 + rtnl_rule_get_realms@libnl_3 3.5.0-1 + rtnl_rule_get_sport@libnl_3_5 3.5.0-1 + rtnl_rule_get_src@Base 3.5.0-1 + rtnl_rule_get_src@libnl_3 3.5.0-1 + rtnl_rule_get_table@Base 3.5.0-1 + rtnl_rule_get_table@libnl_3 3.5.0-1 + rtnl_rule_put@Base 3.5.0-1 + rtnl_rule_put@libnl_3 3.5.0-1 + rtnl_rule_set_action@Base 3.5.0-1 + rtnl_rule_set_action@libnl_3 3.5.0-1 + rtnl_rule_set_dport@libnl_3_5 3.5.0-1 + rtnl_rule_set_dport_range@libnl_3_5 3.5.0-1 + rtnl_rule_set_dsfield@Base 3.5.0-1 + rtnl_rule_set_dsfield@libnl_3 3.5.0-1 + rtnl_rule_set_dst@Base 3.5.0-1 + rtnl_rule_set_dst@libnl_3 3.5.0-1 + rtnl_rule_set_family@Base 3.5.0-1 + rtnl_rule_set_family@libnl_3 3.5.0-1 + rtnl_rule_set_goto@Base 3.5.0-1 + rtnl_rule_set_goto@libnl_3 3.5.0-1 + rtnl_rule_set_iif@Base 3.5.0-1 + rtnl_rule_set_iif@libnl_3 3.5.0-1 + rtnl_rule_set_ipproto@libnl_3_5 3.5.0-1 + rtnl_rule_set_l3mdev@libnl_3_4 3.5.0-1 + rtnl_rule_set_mark@Base 3.5.0-1 + rtnl_rule_set_mark@libnl_3 3.5.0-1 + rtnl_rule_set_mask@Base 3.5.0-1 + rtnl_rule_set_mask@libnl_3 3.5.0-1 + rtnl_rule_set_oif@Base 3.5.0-1 + rtnl_rule_set_oif@libnl_3 3.5.0-1 + rtnl_rule_set_prio@Base 3.5.0-1 + rtnl_rule_set_prio@libnl_3 3.5.0-1 + rtnl_rule_set_protocol@libnl_3_5 3.5.0-1 + rtnl_rule_set_realms@Base 3.5.0-1 + rtnl_rule_set_realms@libnl_3 3.5.0-1 + rtnl_rule_set_sport@libnl_3_5 3.5.0-1 + rtnl_rule_set_sport_range@libnl_3_5 3.5.0-1 + rtnl_rule_set_src@Base 3.5.0-1 + rtnl_rule_set_src@libnl_3 3.5.0-1 + rtnl_rule_set_table@Base 3.5.0-1 + rtnl_rule_set_table@libnl_3 3.5.0-1 + rtnl_scope2str@Base 3.5.0-1 + rtnl_scope2str@libnl_3 3.5.0-1 + rtnl_sfq_get_divisor@Base 3.5.0-1 + rtnl_sfq_get_divisor@libnl_3 3.5.0-1 + rtnl_sfq_get_limit@Base 3.5.0-1 + rtnl_sfq_get_limit@libnl_3 3.5.0-1 + rtnl_sfq_get_perturb@Base 3.5.0-1 + rtnl_sfq_get_perturb@libnl_3 3.5.0-1 + rtnl_sfq_get_quantum@Base 3.5.0-1 + rtnl_sfq_get_quantum@libnl_3 3.5.0-1 + rtnl_sfq_set_limit@Base 3.5.0-1 + rtnl_sfq_set_limit@libnl_3 3.5.0-1 + rtnl_sfq_set_perturb@Base 3.5.0-1 + rtnl_sfq_set_perturb@libnl_3 3.5.0-1 + rtnl_sfq_set_quantum@Base 3.5.0-1 + rtnl_sfq_set_quantum@libnl_3 3.5.0-1 + rtnl_skbedit_get_action@Base 3.5.0-1 + rtnl_skbedit_get_action@libnl_3_2_26 3.5.0-1 + rtnl_skbedit_get_mark@Base 3.5.0-1 + rtnl_skbedit_get_mark@libnl_3_2_26 3.5.0-1 + rtnl_skbedit_get_priority@Base 3.5.0-1 + rtnl_skbedit_get_priority@libnl_3_2_26 3.5.0-1 + rtnl_skbedit_get_queue_mapping@Base 3.5.0-1 + rtnl_skbedit_get_queue_mapping@libnl_3_2_26 3.5.0-1 + rtnl_skbedit_set_action@Base 3.5.0-1 + rtnl_skbedit_set_action@libnl_3_2_26 3.5.0-1 + rtnl_skbedit_set_mark@Base 3.5.0-1 + rtnl_skbedit_set_mark@libnl_3_2_26 3.5.0-1 + rtnl_skbedit_set_priority@Base 3.5.0-1 + rtnl_skbedit_set_priority@libnl_3_2_26 3.5.0-1 + rtnl_skbedit_set_queue_mapping@Base 3.5.0-1 + rtnl_skbedit_set_queue_mapping@libnl_3_2_26 3.5.0-1 + rtnl_str2prio@Base 3.5.0-1 + rtnl_str2prio@libnl_3 3.5.0-1 + rtnl_str2scope@Base 3.5.0-1 + rtnl_str2scope@libnl_3 3.5.0-1 + rtnl_tc_build_rate_table@Base 3.5.0-1 + rtnl_tc_build_rate_table@libnl_3 3.5.0-1 + rtnl_tc_calc_bufsize@Base 3.5.0-1 + rtnl_tc_calc_bufsize@libnl_3 3.5.0-1 + rtnl_tc_calc_cell_log@Base 3.5.0-1 + rtnl_tc_calc_cell_log@libnl_3 3.5.0-1 + rtnl_tc_calc_txtime@Base 3.5.0-1 + rtnl_tc_calc_txtime@libnl_3 3.5.0-1 + rtnl_tc_clone@Base 3.5.0-1 + rtnl_tc_clone@libnl_3 3.5.0-1 + rtnl_tc_compare@Base 3.5.0-1 + rtnl_tc_compare@libnl_3 3.5.0-1 + rtnl_tc_data@Base 3.5.0-1 + rtnl_tc_data@libnl_3 3.5.0-1 + rtnl_tc_data_check@Base 3.5.0-1 + rtnl_tc_data_check@libnl_3 3.5.0-1 + rtnl_tc_data_peek@Base 3.5.0-1 + rtnl_tc_dump_details@Base 3.5.0-1 + rtnl_tc_dump_details@libnl_3 3.5.0-1 + rtnl_tc_dump_line@Base 3.5.0-1 + rtnl_tc_dump_line@libnl_3 3.5.0-1 + rtnl_tc_dump_stats@Base 3.5.0-1 + rtnl_tc_dump_stats@libnl_3 3.5.0-1 + rtnl_tc_free_data@Base 3.5.0-1 + rtnl_tc_free_data@libnl_3 3.5.0-1 + rtnl_tc_get_chain@libnl_3_5 3.5.0-1 + rtnl_tc_get_handle@Base 3.5.0-1 + rtnl_tc_get_handle@libnl_3 3.5.0-1 + rtnl_tc_get_ifindex@Base 3.5.0-1 + rtnl_tc_get_ifindex@libnl_3 3.5.0-1 + rtnl_tc_get_kind@Base 3.5.0-1 + rtnl_tc_get_kind@libnl_3 3.5.0-1 + rtnl_tc_get_link@Base 3.5.0-1 + rtnl_tc_get_link@libnl_3 3.5.0-1 + rtnl_tc_get_linktype@Base 3.5.0-1 + rtnl_tc_get_linktype@libnl_3 3.5.0-1 + rtnl_tc_get_mpu@Base 3.5.0-1 + rtnl_tc_get_mpu@libnl_3 3.5.0-1 + rtnl_tc_get_mtu@Base 3.5.0-1 + rtnl_tc_get_mtu@libnl_3 3.5.0-1 + rtnl_tc_get_ops@Base 3.5.0-1 + rtnl_tc_get_ops@libnl_3 3.5.0-1 + rtnl_tc_get_overhead@Base 3.5.0-1 + rtnl_tc_get_overhead@libnl_3 3.5.0-1 + rtnl_tc_get_parent@Base 3.5.0-1 + rtnl_tc_get_parent@libnl_3 3.5.0-1 + rtnl_tc_get_stat@Base 3.5.0-1 + rtnl_tc_get_stat@libnl_3 3.5.0-1 + rtnl_tc_handle2str@Base 3.5.0-1 + rtnl_tc_handle2str@libnl_3 3.5.0-1 + rtnl_tc_lookup_ops@Base 3.5.0-1 + rtnl_tc_lookup_ops@libnl_3 3.5.0-1 + rtnl_tc_msg_build@Base 3.5.0-1 + rtnl_tc_msg_build@libnl_3 3.5.0-1 + rtnl_tc_msg_parse@Base 3.5.0-1 + rtnl_tc_msg_parse@libnl_3 3.5.0-1 + rtnl_tc_read_classid_file@Base 3.5.0-1 + rtnl_tc_read_classid_file@libnl_3 3.5.0-1 + rtnl_tc_register@Base 3.5.0-1 + rtnl_tc_register@libnl_3 3.5.0-1 + rtnl_tc_set_chain@libnl_3_5 3.5.0-1 + rtnl_tc_set_handle@Base 3.5.0-1 + rtnl_tc_set_handle@libnl_3 3.5.0-1 + rtnl_tc_set_ifindex@Base 3.5.0-1 + rtnl_tc_set_ifindex@libnl_3 3.5.0-1 + rtnl_tc_set_kind@Base 3.5.0-1 + rtnl_tc_set_kind@libnl_3 3.5.0-1 + rtnl_tc_set_link@Base 3.5.0-1 + rtnl_tc_set_link@libnl_3 3.5.0-1 + rtnl_tc_set_linktype@Base 3.5.0-1 + rtnl_tc_set_linktype@libnl_3 3.5.0-1 + rtnl_tc_set_mpu@Base 3.5.0-1 + rtnl_tc_set_mpu@libnl_3 3.5.0-1 + rtnl_tc_set_mtu@Base 3.5.0-1 + rtnl_tc_set_mtu@libnl_3 3.5.0-1 + rtnl_tc_set_overhead@Base 3.5.0-1 + rtnl_tc_set_overhead@libnl_3 3.5.0-1 + rtnl_tc_set_parent@Base 3.5.0-1 + rtnl_tc_set_parent@libnl_3 3.5.0-1 + rtnl_tc_stat2str@Base 3.5.0-1 + rtnl_tc_stat2str@libnl_3_2_26 3.5.0-1 + rtnl_tc_str2handle@Base 3.5.0-1 + rtnl_tc_str2handle@libnl_3 3.5.0-1 + rtnl_tc_str2stat@Base 3.5.0-1 + rtnl_tc_str2stat@libnl_3_2_26 3.5.0-1 + rtnl_tc_type_register@Base 3.5.0-1 + rtnl_tc_type_register@libnl_3 3.5.0-1 + rtnl_tc_type_unregister@Base 3.5.0-1 + rtnl_tc_type_unregister@libnl_3 3.5.0-1 + rtnl_tc_unregister@Base 3.5.0-1 + rtnl_tc_unregister@libnl_3 3.5.0-1 + rtnl_u32_add_action@Base 3.5.0-1 + rtnl_u32_add_action@libnl_3 3.5.0-1 + rtnl_u32_add_key@Base 3.5.0-1 + rtnl_u32_add_key@libnl_3 3.5.0-1 + rtnl_u32_add_key_in6_addr@Base 3.5.0-1 + rtnl_u32_add_key_in6_addr@libnl_3 3.5.0-1 + rtnl_u32_add_key_in_addr@Base 3.5.0-1 + rtnl_u32_add_key_in_addr@libnl_3 3.5.0-1 + rtnl_u32_add_key_uint16@Base 3.5.0-1 + rtnl_u32_add_key_uint16@libnl_3 3.5.0-1 + rtnl_u32_add_key_uint32@Base 3.5.0-1 + rtnl_u32_add_key_uint32@libnl_3 3.5.0-1 + rtnl_u32_add_key_uint8@Base 3.5.0-1 + rtnl_u32_add_key_uint8@libnl_3 3.5.0-1 + rtnl_u32_add_mark@Base 3.5.0-1 + rtnl_u32_add_mark@libnl_3 3.5.0-1 + rtnl_u32_del_action@Base 3.5.0-1 + rtnl_u32_del_action@libnl_3 3.5.0-1 + rtnl_u32_del_mark@Base 3.5.0-1 + rtnl_u32_del_mark@libnl_3 3.5.0-1 + rtnl_u32_get_action@libnl_3_4 3.5.0-1 + rtnl_u32_get_classid@Base 3.5.0-1 + rtnl_u32_get_classid@libnl_3_2_26 3.5.0-1 + rtnl_u32_get_key@Base 3.5.0-1 + rtnl_u32_get_key@libnl_3 3.5.0-1 + rtnl_u32_set_classid@Base 3.5.0-1 + rtnl_u32_set_classid@libnl_3 3.5.0-1 + rtnl_u32_set_cls_terminal@Base 3.5.0-1 + rtnl_u32_set_cls_terminal@libnl_3 3.5.0-1 + rtnl_u32_set_divisor@Base 3.5.0-1 + rtnl_u32_set_divisor@libnl_3 3.5.0-1 + rtnl_u32_set_flags@Base 3.5.0-1 + rtnl_u32_set_flags@libnl_3 3.5.0-1 + rtnl_u32_set_handle@Base 3.5.0-1 + rtnl_u32_set_handle@libnl_3 3.5.0-1 + rtnl_u32_set_hashmask@Base 3.5.0-1 + rtnl_u32_set_hashmask@libnl_3 3.5.0-1 + rtnl_u32_set_hashtable@Base 3.5.0-1 + rtnl_u32_set_hashtable@libnl_3 3.5.0-1 + rtnl_u32_set_link@Base 3.5.0-1 + rtnl_u32_set_link@libnl_3 3.5.0-1 + rtnl_u32_set_selector@libnl_3_2_29 3.5.0-1 + rtnl_vlan_get_action@libnl_3_5 3.5.0-1 + rtnl_vlan_get_mode@libnl_3_5 3.5.0-1 + rtnl_vlan_get_protocol@libnl_3_5 3.5.0-1 + rtnl_vlan_get_vlan_id@libnl_3_5 3.5.0-1 + rtnl_vlan_get_vlan_prio@libnl_3_5 3.5.0-1 + rtnl_vlan_set_action@libnl_3_5 3.5.0-1 + rtnl_vlan_set_mode@libnl_3_5 3.5.0-1 + rtnl_vlan_set_protocol@libnl_3_5 3.5.0-1 + rtnl_vlan_set_vlan_id@libnl_3_5 3.5.0-1 + rtnl_vlan_set_vlan_prio@libnl_3_5 3.5.0-1 + tc_groups@Base 3.5.0-1 + tca_parse@Base 3.5.0-1 + tca_set_kind@Base 3.5.0-1 diff --git a/src/libnl3/debian/libnl-route-3-dev.install b/src/libnl3/debian/libnl-route-3-dev.install new file mode 100644 index 000000000000..37e248c3ed5b --- /dev/null +++ b/src/libnl3/debian/libnl-route-3-dev.install @@ -0,0 +1,3 @@ +debian/tmp/usr/lib/*/pkgconfig/libnl-route-3* +debian/tmp/usr/lib/*/libnl-route-3*.so +debian/tmp/usr/lib/*/libnl-route-3*.a diff --git a/src/libnl3/debian/libnl-utils.install b/src/libnl3/debian/libnl-utils.install new file mode 100644 index 000000000000..8ffdce84e93a --- /dev/null +++ b/src/libnl3/debian/libnl-utils.install @@ -0,0 +1 @@ +debian/tmp/usr/bin/* diff --git a/src/libnl3/debian/libnl-utils.manpages b/src/libnl3/debian/libnl-utils.manpages new file mode 100644 index 000000000000..0b2dcacf5b84 --- /dev/null +++ b/src/libnl3/debian/libnl-utils.manpages @@ -0,0 +1 @@ +debian/tmp/usr/share/man/man8/* diff --git a/src/libnl3/debian/libnl-xfrm-3-200.install b/src/libnl3/debian/libnl-xfrm-3-200.install new file mode 100644 index 000000000000..89b2d4e0c9e0 --- /dev/null +++ b/src/libnl3/debian/libnl-xfrm-3-200.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/*/libnl-xfrm-3*.so.* diff --git a/src/libnl3/debian/libnl-xfrm-3-200.symbols b/src/libnl3/debian/libnl-xfrm-3-200.symbols new file mode 100644 index 000000000000..3704a7aa4384 --- /dev/null +++ b/src/libnl3/debian/libnl-xfrm-3-200.symbols @@ -0,0 +1,484 @@ +libnl-xfrm-3.so.200 libnl-xfrm-3-200 #MINVER# + libnl_3@libnl_3 3.5.0-1 + xfrmnl_ae_alloc@Base 3.5.0-1 + xfrmnl_ae_alloc@libnl_3 3.5.0-1 + xfrmnl_ae_build_get_request@Base 3.5.0-1 + xfrmnl_ae_build_get_request@libnl_3 3.5.0-1 + xfrmnl_ae_flags2str@Base 3.5.0-1 + xfrmnl_ae_flags2str@libnl_3 3.5.0-1 + xfrmnl_ae_get_curlifetime@Base 3.5.0-1 + xfrmnl_ae_get_curlifetime@libnl_3 3.5.0-1 + xfrmnl_ae_get_daddr@Base 3.5.0-1 + xfrmnl_ae_get_daddr@libnl_3 3.5.0-1 + xfrmnl_ae_get_family@Base 3.5.0-1 + xfrmnl_ae_get_family@libnl_3 3.5.0-1 + xfrmnl_ae_get_flags@Base 3.5.0-1 + xfrmnl_ae_get_flags@libnl_3 3.5.0-1 + xfrmnl_ae_get_kernel@Base 3.5.0-1 + xfrmnl_ae_get_kernel@libnl_3 3.5.0-1 + xfrmnl_ae_get_mark@Base 3.5.0-1 + xfrmnl_ae_get_mark@libnl_3 3.5.0-1 + xfrmnl_ae_get_proto@Base 3.5.0-1 + xfrmnl_ae_get_proto@libnl_3 3.5.0-1 + xfrmnl_ae_get_replay_maxage@Base 3.5.0-1 + xfrmnl_ae_get_replay_maxage@libnl_3 3.5.0-1 + xfrmnl_ae_get_replay_maxdiff@Base 3.5.0-1 + xfrmnl_ae_get_replay_maxdiff@libnl_3 3.5.0-1 + xfrmnl_ae_get_replay_state@Base 3.5.0-1 + xfrmnl_ae_get_replay_state@libnl_3 3.5.0-1 + xfrmnl_ae_get_replay_state_esn@Base 3.5.0-1 + xfrmnl_ae_get_replay_state_esn@libnl_3 3.5.0-1 + xfrmnl_ae_get_reqid@Base 3.5.0-1 + xfrmnl_ae_get_reqid@libnl_3 3.5.0-1 + xfrmnl_ae_get_saddr@Base 3.5.0-1 + xfrmnl_ae_get_saddr@libnl_3 3.5.0-1 + xfrmnl_ae_get_spi@Base 3.5.0-1 + xfrmnl_ae_get_spi@libnl_3 3.5.0-1 + xfrmnl_ae_parse@Base 3.5.0-1 + xfrmnl_ae_parse@libnl_3 3.5.0-1 + xfrmnl_ae_put@Base 3.5.0-1 + xfrmnl_ae_put@libnl_3 3.5.0-1 + xfrmnl_ae_set@Base 3.5.0-1 + xfrmnl_ae_set@libnl_3 3.5.0-1 + xfrmnl_ae_set_curlifetime@Base 3.5.0-1 + xfrmnl_ae_set_curlifetime@libnl_3 3.5.0-1 + xfrmnl_ae_set_daddr@Base 3.5.0-1 + xfrmnl_ae_set_daddr@libnl_3 3.5.0-1 + xfrmnl_ae_set_family@Base 3.5.0-1 + xfrmnl_ae_set_family@libnl_3 3.5.0-1 + xfrmnl_ae_set_flags@Base 3.5.0-1 + xfrmnl_ae_set_flags@libnl_3 3.5.0-1 + xfrmnl_ae_set_mark@Base 3.5.0-1 + xfrmnl_ae_set_mark@libnl_3 3.5.0-1 + xfrmnl_ae_set_proto@Base 3.5.0-1 + xfrmnl_ae_set_proto@libnl_3 3.5.0-1 + xfrmnl_ae_set_replay_maxage@Base 3.5.0-1 + xfrmnl_ae_set_replay_maxage@libnl_3 3.5.0-1 + xfrmnl_ae_set_replay_maxdiff@Base 3.5.0-1 + xfrmnl_ae_set_replay_maxdiff@libnl_3 3.5.0-1 + xfrmnl_ae_set_replay_state@Base 3.5.0-1 + xfrmnl_ae_set_replay_state@libnl_3 3.5.0-1 + xfrmnl_ae_set_replay_state_esn@Base 3.5.0-1 + xfrmnl_ae_set_replay_state_esn@libnl_3 3.5.0-1 + xfrmnl_ae_set_reqid@Base 3.5.0-1 + xfrmnl_ae_set_reqid@libnl_3 3.5.0-1 + xfrmnl_ae_set_saddr@Base 3.5.0-1 + xfrmnl_ae_set_saddr@libnl_3 3.5.0-1 + xfrmnl_ae_set_spi@Base 3.5.0-1 + xfrmnl_ae_set_spi@libnl_3 3.5.0-1 + xfrmnl_ae_str2flag@Base 3.5.0-1 + xfrmnl_ae_str2flag@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_alloc@Base 3.5.0-1 + xfrmnl_ltime_cfg_alloc@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_clone@Base 3.5.0-1 + xfrmnl_ltime_cfg_clone@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_cmp@Base 3.5.0-1 + xfrmnl_ltime_cfg_cmp@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_get@Base 3.5.0-1 + xfrmnl_ltime_cfg_get@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_get_hard_addexpires@Base 3.5.0-1 + xfrmnl_ltime_cfg_get_hard_addexpires@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_get_hard_bytelimit@Base 3.5.0-1 + xfrmnl_ltime_cfg_get_hard_bytelimit@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_get_hard_packetlimit@Base 3.5.0-1 + xfrmnl_ltime_cfg_get_hard_packetlimit@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_get_hard_useexpires@Base 3.5.0-1 + xfrmnl_ltime_cfg_get_hard_useexpires@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_get_soft_addexpires@Base 3.5.0-1 + xfrmnl_ltime_cfg_get_soft_addexpires@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_get_soft_bytelimit@Base 3.5.0-1 + xfrmnl_ltime_cfg_get_soft_bytelimit@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_get_soft_packetlimit@Base 3.5.0-1 + xfrmnl_ltime_cfg_get_soft_packetlimit@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_get_soft_useexpires@Base 3.5.0-1 + xfrmnl_ltime_cfg_get_soft_useexpires@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_put@Base 3.5.0-1 + xfrmnl_ltime_cfg_put@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_set_hard_addexpires@Base 3.5.0-1 + xfrmnl_ltime_cfg_set_hard_addexpires@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_set_hard_bytelimit@Base 3.5.0-1 + xfrmnl_ltime_cfg_set_hard_bytelimit@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_set_hard_packetlimit@Base 3.5.0-1 + xfrmnl_ltime_cfg_set_hard_packetlimit@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_set_hard_useexpires@Base 3.5.0-1 + xfrmnl_ltime_cfg_set_hard_useexpires@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_set_soft_addexpires@Base 3.5.0-1 + xfrmnl_ltime_cfg_set_soft_addexpires@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_set_soft_bytelimit@Base 3.5.0-1 + xfrmnl_ltime_cfg_set_soft_bytelimit@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_set_soft_packetlimit@Base 3.5.0-1 + xfrmnl_ltime_cfg_set_soft_packetlimit@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_set_soft_useexpires@Base 3.5.0-1 + xfrmnl_ltime_cfg_set_soft_useexpires@libnl_3 3.5.0-1 + xfrmnl_ltime_cfg_shared@Base 3.5.0-1 + xfrmnl_ltime_cfg_shared@libnl_3 3.5.0-1 + xfrmnl_sa_add@Base 3.5.0-1 + xfrmnl_sa_add@libnl_3 3.5.0-1 + xfrmnl_sa_alloc@Base 3.5.0-1 + xfrmnl_sa_alloc@libnl_3 3.5.0-1 + xfrmnl_sa_alloc_cache@Base 3.5.0-1 + xfrmnl_sa_alloc_cache@libnl_3 3.5.0-1 + xfrmnl_sa_build_add_request@Base 3.5.0-1 + xfrmnl_sa_build_add_request@libnl_3 3.5.0-1 + xfrmnl_sa_build_delete_request@Base 3.5.0-1 + xfrmnl_sa_build_delete_request@libnl_3 3.5.0-1 + xfrmnl_sa_build_get_request@Base 3.5.0-1 + xfrmnl_sa_build_get_request@libnl_3 3.5.0-1 + xfrmnl_sa_build_update_request@Base 3.5.0-1 + xfrmnl_sa_build_update_request@libnl_3 3.5.0-1 + xfrmnl_sa_delete@Base 3.5.0-1 + xfrmnl_sa_delete@libnl_3 3.5.0-1 + xfrmnl_sa_flags2str@Base 3.5.0-1 + xfrmnl_sa_flags2str@libnl_3 3.5.0-1 + xfrmnl_sa_get@Base 3.5.0-1 + xfrmnl_sa_get@libnl_3 3.5.0-1 + xfrmnl_sa_get_aead_params@Base 3.5.0-1 + xfrmnl_sa_get_aead_params@libnl_3 3.5.0-1 + xfrmnl_sa_get_auth_params@Base 3.5.0-1 + xfrmnl_sa_get_auth_params@libnl_3 3.5.0-1 + xfrmnl_sa_get_coaddr@Base 3.5.0-1 + xfrmnl_sa_get_coaddr@libnl_3 3.5.0-1 + xfrmnl_sa_get_comp_params@Base 3.5.0-1 + xfrmnl_sa_get_comp_params@libnl_3 3.5.0-1 + xfrmnl_sa_get_crypto_params@Base 3.5.0-1 + xfrmnl_sa_get_crypto_params@libnl_3 3.5.0-1 + xfrmnl_sa_get_curlifetime@Base 3.5.0-1 + xfrmnl_sa_get_curlifetime@libnl_3 3.5.0-1 + xfrmnl_sa_get_daddr@Base 3.5.0-1 + xfrmnl_sa_get_daddr@libnl_3 3.5.0-1 + xfrmnl_sa_get_encap_tmpl@Base 3.5.0-1 + xfrmnl_sa_get_encap_tmpl@libnl_3 3.5.0-1 + xfrmnl_sa_get_family@Base 3.5.0-1 + xfrmnl_sa_get_family@libnl_3 3.5.0-1 + xfrmnl_sa_get_flags@Base 3.5.0-1 + xfrmnl_sa_get_flags@libnl_3 3.5.0-1 + xfrmnl_sa_get_kernel@Base 3.5.0-1 + xfrmnl_sa_get_kernel@libnl_3 3.5.0-1 + xfrmnl_sa_get_lifetime_cfg@Base 3.5.0-1 + xfrmnl_sa_get_lifetime_cfg@libnl_3 3.5.0-1 + xfrmnl_sa_get_mark@Base 3.5.0-1 + xfrmnl_sa_get_mark@libnl_3 3.5.0-1 + xfrmnl_sa_get_mode@Base 3.5.0-1 + xfrmnl_sa_get_mode@libnl_3 3.5.0-1 + xfrmnl_sa_get_proto@Base 3.5.0-1 + xfrmnl_sa_get_proto@libnl_3 3.5.0-1 + xfrmnl_sa_get_replay_maxage@Base 3.5.0-1 + xfrmnl_sa_get_replay_maxage@libnl_3 3.5.0-1 + xfrmnl_sa_get_replay_maxdiff@Base 3.5.0-1 + xfrmnl_sa_get_replay_maxdiff@libnl_3 3.5.0-1 + xfrmnl_sa_get_replay_state@Base 3.5.0-1 + xfrmnl_sa_get_replay_state@libnl_3 3.5.0-1 + xfrmnl_sa_get_replay_state_esn@Base 3.5.0-1 + xfrmnl_sa_get_replay_state_esn@libnl_3 3.5.0-1 + xfrmnl_sa_get_replay_window@Base 3.5.0-1 + xfrmnl_sa_get_replay_window@libnl_3 3.5.0-1 + xfrmnl_sa_get_reqid@Base 3.5.0-1 + xfrmnl_sa_get_reqid@libnl_3 3.5.0-1 + xfrmnl_sa_get_saddr@Base 3.5.0-1 + xfrmnl_sa_get_saddr@libnl_3 3.5.0-1 + xfrmnl_sa_get_sec_ctx@Base 3.5.0-1 + xfrmnl_sa_get_sec_ctx@libnl_3 3.5.0-1 + xfrmnl_sa_get_sel@Base 3.5.0-1 + xfrmnl_sa_get_sel@libnl_3 3.5.0-1 + xfrmnl_sa_get_seq@Base 3.5.0-1 + xfrmnl_sa_get_seq@libnl_3 3.5.0-1 + xfrmnl_sa_get_spi@Base 3.5.0-1 + xfrmnl_sa_get_spi@libnl_3 3.5.0-1 + xfrmnl_sa_get_stats@Base 3.5.0-1 + xfrmnl_sa_get_stats@libnl_3 3.5.0-1 + xfrmnl_sa_get_tfcpad@Base 3.5.0-1 + xfrmnl_sa_get_tfcpad@libnl_3 3.5.0-1 + xfrmnl_sa_is_expiry_reached@Base 3.5.0-1 + xfrmnl_sa_is_expiry_reached@libnl_3 3.5.0-1 + xfrmnl_sa_is_hardexpiry_reached@Base 3.5.0-1 + xfrmnl_sa_is_hardexpiry_reached@libnl_3 3.5.0-1 + xfrmnl_sa_mode2str@Base 3.5.0-1 + xfrmnl_sa_mode2str@libnl_3 3.5.0-1 + xfrmnl_sa_parse@Base 3.5.0-1 + xfrmnl_sa_parse@libnl_3 3.5.0-1 + xfrmnl_sa_put@Base 3.5.0-1 + xfrmnl_sa_put@libnl_3 3.5.0-1 + xfrmnl_sa_set_aead_params@Base 3.5.0-1 + xfrmnl_sa_set_aead_params@libnl_3 3.5.0-1 + xfrmnl_sa_set_auth_params@Base 3.5.0-1 + xfrmnl_sa_set_auth_params@libnl_3 3.5.0-1 + xfrmnl_sa_set_coaddr@Base 3.5.0-1 + xfrmnl_sa_set_coaddr@libnl_3 3.5.0-1 + xfrmnl_sa_set_comp_params@Base 3.5.0-1 + xfrmnl_sa_set_comp_params@libnl_3 3.5.0-1 + xfrmnl_sa_set_crypto_params@Base 3.5.0-1 + xfrmnl_sa_set_crypto_params@libnl_3 3.5.0-1 + xfrmnl_sa_set_daddr@Base 3.5.0-1 + xfrmnl_sa_set_daddr@libnl_3 3.5.0-1 + xfrmnl_sa_set_encap_tmpl@Base 3.5.0-1 + xfrmnl_sa_set_encap_tmpl@libnl_3 3.5.0-1 + xfrmnl_sa_set_family@Base 3.5.0-1 + xfrmnl_sa_set_family@libnl_3 3.5.0-1 + xfrmnl_sa_set_flags@Base 3.5.0-1 + xfrmnl_sa_set_flags@libnl_3 3.5.0-1 + xfrmnl_sa_set_lifetime_cfg@Base 3.5.0-1 + xfrmnl_sa_set_lifetime_cfg@libnl_3 3.5.0-1 + xfrmnl_sa_set_mark@Base 3.5.0-1 + xfrmnl_sa_set_mark@libnl_3 3.5.0-1 + xfrmnl_sa_set_mode@Base 3.5.0-1 + xfrmnl_sa_set_mode@libnl_3 3.5.0-1 + xfrmnl_sa_set_proto@Base 3.5.0-1 + xfrmnl_sa_set_proto@libnl_3 3.5.0-1 + xfrmnl_sa_set_replay_maxage@Base 3.5.0-1 + xfrmnl_sa_set_replay_maxage@libnl_3 3.5.0-1 + xfrmnl_sa_set_replay_maxdiff@Base 3.5.0-1 + xfrmnl_sa_set_replay_maxdiff@libnl_3 3.5.0-1 + xfrmnl_sa_set_replay_state@Base 3.5.0-1 + xfrmnl_sa_set_replay_state@libnl_3 3.5.0-1 + xfrmnl_sa_set_replay_state_esn@Base 3.5.0-1 + xfrmnl_sa_set_replay_state_esn@libnl_3 3.5.0-1 + xfrmnl_sa_set_replay_window@Base 3.5.0-1 + xfrmnl_sa_set_replay_window@libnl_3 3.5.0-1 + xfrmnl_sa_set_reqid@Base 3.5.0-1 + xfrmnl_sa_set_reqid@libnl_3 3.5.0-1 + xfrmnl_sa_set_saddr@Base 3.5.0-1 + xfrmnl_sa_set_saddr@libnl_3 3.5.0-1 + xfrmnl_sa_set_sec_ctx@Base 3.5.0-1 + xfrmnl_sa_set_sec_ctx@libnl_3 3.5.0-1 + xfrmnl_sa_set_sel@Base 3.5.0-1 + xfrmnl_sa_set_sel@libnl_3 3.5.0-1 + xfrmnl_sa_set_spi@Base 3.5.0-1 + xfrmnl_sa_set_spi@libnl_3 3.5.0-1 + xfrmnl_sa_set_tfcpad@Base 3.5.0-1 + xfrmnl_sa_set_tfcpad@libnl_3 3.5.0-1 + xfrmnl_sa_str2flag@Base 3.5.0-1 + xfrmnl_sa_str2flag@libnl_3 3.5.0-1 + xfrmnl_sa_str2mode@Base 3.5.0-1 + xfrmnl_sa_str2mode@libnl_3 3.5.0-1 + xfrmnl_sa_update@Base 3.5.0-1 + xfrmnl_sa_update@libnl_3 3.5.0-1 + xfrmnl_sel_alloc@Base 3.5.0-1 + xfrmnl_sel_alloc@libnl_3 3.5.0-1 + xfrmnl_sel_clone@Base 3.5.0-1 + xfrmnl_sel_clone@libnl_3 3.5.0-1 + xfrmnl_sel_cmp@Base 3.5.0-1 + xfrmnl_sel_cmp@libnl_3 3.5.0-1 + xfrmnl_sel_dump@Base 3.5.0-1 + xfrmnl_sel_dump@libnl_3 3.5.0-1 + xfrmnl_sel_get@Base 3.5.0-1 + xfrmnl_sel_get@libnl_3 3.5.0-1 + xfrmnl_sel_get_daddr@Base 3.5.0-1 + xfrmnl_sel_get_daddr@libnl_3 3.5.0-1 + xfrmnl_sel_get_dport@Base 3.5.0-1 + xfrmnl_sel_get_dport@libnl_3 3.5.0-1 + xfrmnl_sel_get_dportmask@Base 3.5.0-1 + xfrmnl_sel_get_dportmask@libnl_3 3.5.0-1 + xfrmnl_sel_get_family@Base 3.5.0-1 + xfrmnl_sel_get_family@libnl_3 3.5.0-1 + xfrmnl_sel_get_ifindex@Base 3.5.0-1 + xfrmnl_sel_get_ifindex@libnl_3 3.5.0-1 + xfrmnl_sel_get_prefixlen_d@Base 3.5.0-1 + xfrmnl_sel_get_prefixlen_d@libnl_3 3.5.0-1 + xfrmnl_sel_get_prefixlen_s@Base 3.5.0-1 + xfrmnl_sel_get_prefixlen_s@libnl_3 3.5.0-1 + xfrmnl_sel_get_proto@Base 3.5.0-1 + xfrmnl_sel_get_proto@libnl_3 3.5.0-1 + xfrmnl_sel_get_saddr@Base 3.5.0-1 + xfrmnl_sel_get_saddr@libnl_3 3.5.0-1 + xfrmnl_sel_get_sport@Base 3.5.0-1 + xfrmnl_sel_get_sport@libnl_3 3.5.0-1 + xfrmnl_sel_get_sportmask@Base 3.5.0-1 + xfrmnl_sel_get_sportmask@libnl_3 3.5.0-1 + xfrmnl_sel_get_userid@Base 3.5.0-1 + xfrmnl_sel_get_userid@libnl_3 3.5.0-1 + xfrmnl_sel_put@Base 3.5.0-1 + xfrmnl_sel_put@libnl_3 3.5.0-1 + xfrmnl_sel_set_daddr@Base 3.5.0-1 + xfrmnl_sel_set_daddr@libnl_3 3.5.0-1 + xfrmnl_sel_set_dport@Base 3.5.0-1 + xfrmnl_sel_set_dport@libnl_3 3.5.0-1 + xfrmnl_sel_set_dportmask@Base 3.5.0-1 + xfrmnl_sel_set_dportmask@libnl_3 3.5.0-1 + xfrmnl_sel_set_family@Base 3.5.0-1 + xfrmnl_sel_set_family@libnl_3 3.5.0-1 + xfrmnl_sel_set_ifindex@Base 3.5.0-1 + xfrmnl_sel_set_ifindex@libnl_3 3.5.0-1 + xfrmnl_sel_set_prefixlen_d@Base 3.5.0-1 + xfrmnl_sel_set_prefixlen_d@libnl_3 3.5.0-1 + xfrmnl_sel_set_prefixlen_s@Base 3.5.0-1 + xfrmnl_sel_set_prefixlen_s@libnl_3 3.5.0-1 + xfrmnl_sel_set_proto@Base 3.5.0-1 + xfrmnl_sel_set_proto@libnl_3 3.5.0-1 + xfrmnl_sel_set_saddr@Base 3.5.0-1 + xfrmnl_sel_set_saddr@libnl_3 3.5.0-1 + xfrmnl_sel_set_sport@Base 3.5.0-1 + xfrmnl_sel_set_sport@libnl_3 3.5.0-1 + xfrmnl_sel_set_sportmask@Base 3.5.0-1 + xfrmnl_sel_set_sportmask@libnl_3 3.5.0-1 + xfrmnl_sel_set_userid@Base 3.5.0-1 + xfrmnl_sel_set_userid@libnl_3 3.5.0-1 + xfrmnl_sel_shared@Base 3.5.0-1 + xfrmnl_sel_shared@libnl_3 3.5.0-1 + xfrmnl_sp_action2str@Base 3.5.0-1 + xfrmnl_sp_action2str@libnl_3 3.5.0-1 + xfrmnl_sp_add@Base 3.5.0-1 + xfrmnl_sp_add@libnl_3 3.5.0-1 + xfrmnl_sp_add_usertemplate@Base 3.5.0-1 + xfrmnl_sp_add_usertemplate@libnl_3 3.5.0-1 + xfrmnl_sp_alloc@Base 3.5.0-1 + xfrmnl_sp_alloc@libnl_3 3.5.0-1 + xfrmnl_sp_alloc_cache@Base 3.5.0-1 + xfrmnl_sp_alloc_cache@libnl_3 3.5.0-1 + xfrmnl_sp_build_add_request@Base 3.5.0-1 + xfrmnl_sp_build_add_request@libnl_3 3.5.0-1 + xfrmnl_sp_build_delete_request@Base 3.5.0-1 + xfrmnl_sp_build_delete_request@libnl_3 3.5.0-1 + xfrmnl_sp_build_get_request@Base 3.5.0-1 + xfrmnl_sp_build_get_request@libnl_3 3.5.0-1 + xfrmnl_sp_build_update_request@Base 3.5.0-1 + xfrmnl_sp_build_update_request@libnl_3 3.5.0-1 + xfrmnl_sp_delete@Base 3.5.0-1 + xfrmnl_sp_delete@libnl_3 3.5.0-1 + xfrmnl_sp_dir2str@Base 3.5.0-1 + xfrmnl_sp_dir2str@libnl_3 3.5.0-1 + xfrmnl_sp_flags2str@Base 3.5.0-1 + xfrmnl_sp_flags2str@libnl_3 3.5.0-1 + xfrmnl_sp_foreach_usertemplate@Base 3.5.0-1 + xfrmnl_sp_foreach_usertemplate@libnl_3 3.5.0-1 + xfrmnl_sp_get@Base 3.5.0-1 + xfrmnl_sp_get@libnl_3 3.5.0-1 + xfrmnl_sp_get_action@Base 3.5.0-1 + xfrmnl_sp_get_action@libnl_3 3.5.0-1 + xfrmnl_sp_get_curlifetime@Base 3.5.0-1 + xfrmnl_sp_get_curlifetime@libnl_3 3.5.0-1 + xfrmnl_sp_get_dir@Base 3.5.0-1 + xfrmnl_sp_get_dir@libnl_3 3.5.0-1 + xfrmnl_sp_get_flags@Base 3.5.0-1 + xfrmnl_sp_get_flags@libnl_3 3.5.0-1 + xfrmnl_sp_get_index@Base 3.5.0-1 + xfrmnl_sp_get_index@libnl_3 3.5.0-1 + xfrmnl_sp_get_kernel@Base 3.5.0-1 + xfrmnl_sp_get_kernel@libnl_3 3.5.0-1 + xfrmnl_sp_get_lifetime_cfg@Base 3.5.0-1 + xfrmnl_sp_get_lifetime_cfg@libnl_3 3.5.0-1 + xfrmnl_sp_get_mark@Base 3.5.0-1 + xfrmnl_sp_get_mark@libnl_3 3.5.0-1 + xfrmnl_sp_get_nusertemplates@Base 3.5.0-1 + xfrmnl_sp_get_nusertemplates@libnl_3 3.5.0-1 + xfrmnl_sp_get_priority@Base 3.5.0-1 + xfrmnl_sp_get_priority@libnl_3 3.5.0-1 + xfrmnl_sp_get_sec_ctx@Base 3.5.0-1 + xfrmnl_sp_get_sec_ctx@libnl_3 3.5.0-1 + xfrmnl_sp_get_sel@Base 3.5.0-1 + xfrmnl_sp_get_sel@libnl_3 3.5.0-1 + xfrmnl_sp_get_share@Base 3.5.0-1 + xfrmnl_sp_get_share@libnl_3 3.5.0-1 + xfrmnl_sp_get_userpolicy_type@Base 3.5.0-1 + xfrmnl_sp_get_userpolicy_type@libnl_3 3.5.0-1 + xfrmnl_sp_get_usertemplates@Base 3.5.0-1 + xfrmnl_sp_get_usertemplates@libnl_3 3.5.0-1 + xfrmnl_sp_index2dir@Base 3.5.0-1 + xfrmnl_sp_index2dir@libnl_3 3.5.0-1 + xfrmnl_sp_parse@Base 3.5.0-1 + xfrmnl_sp_parse@libnl_3 3.5.0-1 + xfrmnl_sp_put@Base 3.5.0-1 + xfrmnl_sp_put@libnl_3 3.5.0-1 + xfrmnl_sp_remove_usertemplate@Base 3.5.0-1 + xfrmnl_sp_remove_usertemplate@libnl_3 3.5.0-1 + xfrmnl_sp_set_action@Base 3.5.0-1 + xfrmnl_sp_set_action@libnl_3 3.5.0-1 + xfrmnl_sp_set_dir@Base 3.5.0-1 + xfrmnl_sp_set_dir@libnl_3 3.5.0-1 + xfrmnl_sp_set_flags@Base 3.5.0-1 + xfrmnl_sp_set_flags@libnl_3 3.5.0-1 + xfrmnl_sp_set_index@Base 3.5.0-1 + xfrmnl_sp_set_index@libnl_3 3.5.0-1 + xfrmnl_sp_set_lifetime_cfg@Base 3.5.0-1 + xfrmnl_sp_set_lifetime_cfg@libnl_3 3.5.0-1 + xfrmnl_sp_set_mark@Base 3.5.0-1 + xfrmnl_sp_set_mark@libnl_3 3.5.0-1 + xfrmnl_sp_set_priority@Base 3.5.0-1 + xfrmnl_sp_set_priority@libnl_3 3.5.0-1 + xfrmnl_sp_set_sec_ctx@Base 3.5.0-1 + xfrmnl_sp_set_sec_ctx@libnl_3 3.5.0-1 + xfrmnl_sp_set_sel@Base 3.5.0-1 + xfrmnl_sp_set_sel@libnl_3 3.5.0-1 + xfrmnl_sp_set_share@Base 3.5.0-1 + xfrmnl_sp_set_share@libnl_3 3.5.0-1 + xfrmnl_sp_set_userpolicy_type@Base 3.5.0-1 + xfrmnl_sp_set_userpolicy_type@libnl_3 3.5.0-1 + xfrmnl_sp_share2str@Base 3.5.0-1 + xfrmnl_sp_share2str@libnl_3 3.5.0-1 + xfrmnl_sp_str2action@Base 3.5.0-1 + xfrmnl_sp_str2action@libnl_3 3.5.0-1 + xfrmnl_sp_str2dir@Base 3.5.0-1 + xfrmnl_sp_str2dir@libnl_3 3.5.0-1 + xfrmnl_sp_str2flag@Base 3.5.0-1 + xfrmnl_sp_str2flag@libnl_3 3.5.0-1 + xfrmnl_sp_str2share@Base 3.5.0-1 + xfrmnl_sp_str2share@libnl_3 3.5.0-1 + xfrmnl_sp_str2type@Base 3.5.0-1 + xfrmnl_sp_str2type@libnl_3 3.5.0-1 + xfrmnl_sp_type2str@Base 3.5.0-1 + xfrmnl_sp_type2str@libnl_3 3.5.0-1 + xfrmnl_sp_update@Base 3.5.0-1 + xfrmnl_sp_update@libnl_3 3.5.0-1 + xfrmnl_sp_usertemplate_n@Base 3.5.0-1 + xfrmnl_sp_usertemplate_n@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_alloc@Base 3.5.0-1 + xfrmnl_user_tmpl_alloc@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_clone@Base 3.5.0-1 + xfrmnl_user_tmpl_clone@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_cmp@Base 3.5.0-1 + xfrmnl_user_tmpl_cmp@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_dump@Base 3.5.0-1 + xfrmnl_user_tmpl_dump@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_free@Base 3.5.0-1 + xfrmnl_user_tmpl_free@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_get_aalgos@Base 3.5.0-1 + xfrmnl_user_tmpl_get_aalgos@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_get_calgos@Base 3.5.0-1 + xfrmnl_user_tmpl_get_calgos@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_get_daddr@Base 3.5.0-1 + xfrmnl_user_tmpl_get_daddr@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_get_ealgos@Base 3.5.0-1 + xfrmnl_user_tmpl_get_ealgos@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_get_family@Base 3.5.0-1 + xfrmnl_user_tmpl_get_family@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_get_mode@Base 3.5.0-1 + xfrmnl_user_tmpl_get_mode@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_get_optional@Base 3.5.0-1 + xfrmnl_user_tmpl_get_optional@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_get_proto@Base 3.5.0-1 + xfrmnl_user_tmpl_get_proto@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_get_reqid@Base 3.5.0-1 + xfrmnl_user_tmpl_get_reqid@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_get_saddr@Base 3.5.0-1 + xfrmnl_user_tmpl_get_saddr@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_get_share@Base 3.5.0-1 + xfrmnl_user_tmpl_get_share@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_get_spi@Base 3.5.0-1 + xfrmnl_user_tmpl_get_spi@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_mode2str@Base 3.5.0-1 + xfrmnl_user_tmpl_mode2str@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_set_aalgos@Base 3.5.0-1 + xfrmnl_user_tmpl_set_aalgos@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_set_calgos@Base 3.5.0-1 + xfrmnl_user_tmpl_set_calgos@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_set_daddr@Base 3.5.0-1 + xfrmnl_user_tmpl_set_daddr@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_set_ealgos@Base 3.5.0-1 + xfrmnl_user_tmpl_set_ealgos@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_set_family@Base 3.5.0-1 + xfrmnl_user_tmpl_set_family@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_set_mode@Base 3.5.0-1 + xfrmnl_user_tmpl_set_mode@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_set_optional@Base 3.5.0-1 + xfrmnl_user_tmpl_set_optional@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_set_proto@Base 3.5.0-1 + xfrmnl_user_tmpl_set_proto@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_set_reqid@Base 3.5.0-1 + xfrmnl_user_tmpl_set_reqid@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_set_saddr@Base 3.5.0-1 + xfrmnl_user_tmpl_set_saddr@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_set_share@Base 3.5.0-1 + xfrmnl_user_tmpl_set_share@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_set_spi@Base 3.5.0-1 + xfrmnl_user_tmpl_set_spi@libnl_3 3.5.0-1 + xfrmnl_user_tmpl_str2mode@Base 3.5.0-1 + xfrmnl_user_tmpl_str2mode@libnl_3 3.5.0-1 diff --git a/src/libnl3/debian/libnl-xfrm-3-dev.install b/src/libnl3/debian/libnl-xfrm-3-dev.install new file mode 100644 index 000000000000..f57e152c5aae --- /dev/null +++ b/src/libnl3/debian/libnl-xfrm-3-dev.install @@ -0,0 +1,3 @@ +debian/tmp/usr/lib/*/pkgconfig/libnl-xfrm-3* +debian/tmp/usr/lib/*/libnl-xfrm-3*.so +debian/tmp/usr/lib/*/libnl-xfrm-3*.a diff --git a/src/libnl3/debian/patches/series b/src/libnl3/debian/patches/series new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/libnl3/debian/rules b/src/libnl3/debian/rules new file mode 100755 index 000000000000..bb33dda05a64 --- /dev/null +++ b/src/libnl3/debian/rules @@ -0,0 +1,39 @@ +#!/usr/bin/make -f + +DEB_BUILDDIR = debian/build +DEB_MAKE_FLAVORS = main udeb + +udeb_libnl=libnl-3-200-udeb +udeb_libnl_genl=libnl-genl-3-200-udeb + +TG_BRANCHES := debian/etc-libnl-3,debian/out-of-tree,debian/no-symvers + +-include /usr/share/topgit/tg2quilt.mk + +# to export the patch series use +# debian/rules tg-clean +# debian/rules tg-export + + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/rules/autoreconf.mk +include /usr/share/cdbs/1/class/autotools.mk + +# FIXME: not honoured +#CFLAGS_udeb += $(CFLAGS) -Os +CFLAGS += $(if $(findstring udeb,$(cdbs_make_curflavor)),-Os) + +DEB_DH_STRIP_ARGS := --dbg-package=libnl-3-200-dbg +DEB_DH_MAKESHLIBS_ARGS_libnl-3-200 := --add-udeb=$(udeb_libnl) +DEB_DH_MAKESHLIBS_ARGS_libnl-genl-3-200 := --add-udeb=$(udeb_libnl_genl) + +DEB_MAKE_DESTDIRSKEL = $(CURDIR)/debian/tmp +DEB_MAKE_DESTDIRSKEL_udeb = $(CURDIR)/debian/tmp/udeb + +DEB_DH_INSTALL_ARGS_$(udeb) += --sourcedir=debian/tmp/udeb + +DEB_CONFIGURE_EXTRA_FLAGS += --libdir=\$${prefix}/lib/$(DEB_HOST_MULTIARCH) + +clean:: + # from some unknown reason CDBS does not remove the builddir + rm -rf $(DEB_BUILDDIR) diff --git a/src/libnl3/debian/source/format b/src/libnl3/debian/source/format new file mode 100644 index 000000000000..163aaf8d82b6 --- /dev/null +++ b/src/libnl3/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/src/libnl3/debian/watch b/src/libnl3/debian/watch new file mode 100644 index 000000000000..9939913ca0e0 --- /dev/null +++ b/src/libnl3/debian/watch @@ -0,0 +1,2 @@ +version=3 +https://github.com/thom311/libnl/releases/libnl-(.*)\.tar\.gz From 04b911341016546fcfa39f31742fb28a2b7686a8 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Tue, 7 Jan 2020 16:42:00 +0800 Subject: [PATCH 278/278] [Mellanox]Update the hw-mgmt patch for simx on V.7.0000.2308 (#3957) * [Mellanox/hw-mgmt] Update the hw-mgmt patch for simx on V.7.0000.2308 * removing the extra "[PATCH]" --- .../0001-Make-hw-mgmt-SimX-compatiable.patch | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/platform/mellanox/hw-management/0001-Make-hw-mgmt-SimX-compatiable.patch b/platform/mellanox/hw-management/0001-Make-hw-mgmt-SimX-compatiable.patch index 31a85434fb49..f16c0d02794b 100644 --- a/platform/mellanox/hw-management/0001-Make-hw-mgmt-SimX-compatiable.patch +++ b/platform/mellanox/hw-management/0001-Make-hw-mgmt-SimX-compatiable.patch @@ -1,53 +1,53 @@ -From 051938b7c49cc18aaddd699939353f591554d635 Mon Sep 17 00:00:00 2001 -From: Mykola Faryma -Date: Wed, 3 Apr 2019 14:09:26 +0000 +From c6ee8c86c35f8b1e60bf4df0d7198f349f8552c1 Mon Sep 17 00:00:00 2001 +From: Stephen Sun +Date: Wed, 25 Dec 2019 19:33:17 +0800 Subject: [PATCH] Make hw-mgmt SimX compatiable. -Signed-off-by: Mykola Faryma +Signed-off-by: Stephen Sun --- usr/usr/bin/hw-management.sh | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/usr/usr/bin/hw-management.sh b/usr/usr/bin/hw-management.sh -index fdb3013..68da9bc 100755 +index cff10fe..0511c7c 100755 --- a/usr/usr/bin/hw-management.sh +++ b/usr/usr/bin/hw-management.sh -@@ -646,6 +646,35 @@ do_chip_down() +@@ -737,6 +737,35 @@ do_chip_down() /usr/bin/hw-management-thermal-events.sh change hotplug_asic down %S %p } +handle_simx() +{ -+ local -r onie_platform="$(cat /host/machine.conf | grep onie_platform | cut -d= -f2)" ++ local -r onie_platform="$(cat /host/machine.conf | grep onie_platform | cut -d= -f2)" + -+ local -r syseeprom_cache_path="/var/cache/sonic/decode-syseeprom/syseeprom_cache" -+ local -r syseeprom_hex_path="/usr/share/sonic/device/${onie_platform}/syseeprom.hex" -+ local -r syseeprom_vpd_path="/var/run/hw-management/eeprom/vpd_info" ++ local -r syseeprom_cache_path="/var/cache/sonic/decode-syseeprom/syseeprom_cache" ++ local -r syseeprom_hex_path="/usr/share/sonic/device/${onie_platform}/syseeprom.hex" ++ local -r syseeprom_vpd_path="/var/run/hw-management/eeprom/vpd_info" + -+ case $ACTION in -+ start) -+ /bin/bash -c "/bin/rm -f ${syseeprom_cache_path}" -+ /bin/bash -c "/bin/mkdir -p ${eeprom_path}" -+ /bin/bash -c "/usr/bin/xxd -r -p ${syseeprom_hex_path} ${syseeprom_vpd_path}" -+ ;; -+ stop) -+ /bin/bash -c "/bin/rm -fr ${hw_management_path}" -+ ;; -+ *) -+ echo "Usage: `basename $0` {start|stop}" -+ exit 1 -+ ;; -+ esac ++ case $ACTION in ++ start) ++ /bin/bash -c "/bin/rm -f ${syseeprom_cache_path}" ++ /bin/bash -c "/bin/mkdir -p ${eeprom_path}" ++ /bin/bash -c "/usr/bin/xxd -r -p ${syseeprom_hex_path} ${syseeprom_vpd_path}" ++ ;; ++ stop) ++ /bin/bash -c "/bin/rm -fr ${hw_management_path}" ++ ;; ++ *) ++ echo "Usage: `basename $0` {start|stop}" ++ exit 1 ++ ;; ++ esac +} + +if [[ "$(cat /sys/devices/virtual/dmi/id/chassis_vendor)" = "QEMU" ]]; then -+ handle_simx -+ exit 0 ++ handle_simx ++ exit 0 +fi + case $ACTION in start) - do_start + if [ -d /var/run/hw-management ]; then -- 1.9.1

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 zⅅ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%0AW?1 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�!aAZIt39-bB2bc;J1p7Y_!T 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 Si3xq7R#~=kHl`c Date: Fri, 27 Sep 2019 14:49:44 -0700 Subject: [PATCH 029/278] Regular quit needs to clean the ports two (#3531) --- src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch b/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch index 52a181d4da6f..e62d2df0597e 100644 --- a/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch +++ b/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch @@ -108,11 +108,11 @@ index 9dc85b5..679da49 100644 + teamd_refresh_ports(ctx); + if (ctrl_byte == 'w') + teamd_ports_flush_data(ctx); -+ /* Flush ports to destroy port object */ -+ err = teamd_flush_ports(ctx); -+ if (err) -+ return err; + } ++ ++ err = teamd_flush_ports(ctx); ++ if (err) ++ return err; quit_in_progress = true; continue; case 'r': From fb666d23f11e147beb1a63528b5e34ebac29474e Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Sun, 29 Sep 2019 10:57:08 -0700 Subject: [PATCH 030/278] [FRR]: Use stg instead of patch (#3480) * Use stg instead of patch --- src/sonic-frr/Makefile | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sonic-frr/Makefile b/src/sonic-frr/Makefile index 1e1e198e42d7..e7c13a1f8b6f 100644 --- a/src/sonic-frr/Makefile +++ b/src/sonic-frr/Makefile @@ -4,17 +4,20 @@ SHELL = /bin/bash MAIN_TARGET = $(FRR) DERIVED_TARGET = $(FRR_PYTHONTOOLS) $(FRR_DBG) $(FRR_SNMP) $(FRR_SNMP_DBG) +BRANCH = $(shell date +%Y%m%d\.%H%M%S) $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : # Build the package - pushd ./frr - patch -p1 < ../patch/0001-Add-support-of-bgp-tcp-DSCP-value.patch - patch -p1 < ../patch/0002-Reduce-severity-of-Vty-connected-from-message.patch - patch -p1 < ../patch/0003-ignore-nexthop-attribute-when-NLRI-is-present.patch - patch -p1 < ../patch/0004-Allow-BGP-attr-NEXT_HOP-to-be-0.0.0.0-due-to-allevia.patch - patch -p1 < ../patch/0005-Support-VRF.patch + pushd ./frr + git checkout -b $(BRANCH) origin/frr/7.0 + stg init + stg import -s ../patch/series tools/tarsource.sh -V -e '-sonic' dpkg-buildpackage -rfakeroot -b -us -uc -Ppkg.frr.nortrlib -j$(SONIC_CONFIG_MAKE_JOBS) + stg undo + git clean -xfdf + git checkout frr/7.0 + git branch -D $(BRANCH) popd mv $(DERIVED_TARGET) $* $(DEST)/ From f54792d8a7aac80f15381187a095bb37f289d3cc Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Tue, 1 Oct 2019 09:54:27 +0300 Subject: [PATCH 031/278] [mellanox]Integrate sai-1.15, sdk 4.3.2104 and firmware 2162 to sonic. (#3538) --- platform/mellanox/fw.mk | 4 ++-- platform/mellanox/mlnx-sai.mk | 2 +- platform/mellanox/mlnx-sai/SAI-Implementation | 2 +- platform/mellanox/sdk.mk | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/platform/mellanox/fw.mk b/platform/mellanox/fw.mk index 72a92c1dc57e..6e9a285cc1ce 100644 --- a/platform/mellanox/fw.mk +++ b/platform/mellanox/fw.mk @@ -2,12 +2,12 @@ MLNX_FW_BASE_URL = $(MLNX_SDK_BASE_URL) -MLNX_SPC_FW_VERSION = 13.2000.1886 +MLNX_SPC_FW_VERSION = 13.2000.2162 MLNX_SPC_FW_FILE = fw-SPC-rel-$(subst .,_,$(MLNX_SPC_FW_VERSION))-EVB.mfa $(MLNX_SPC_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC_FW_FILE) SONIC_ONLINE_FILES += $(MLNX_SPC_FW_FILE) -MLNX_SPC2_FW_VERSION = 29.2000.1886 +MLNX_SPC2_FW_VERSION = 29.2000.2162 MLNX_SPC2_FW_FILE = fw-SPC2-rel-$(subst .,_,$(MLNX_SPC2_FW_VERSION))-EVB.mfa $(MLNX_SPC2_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC2_FW_FILE) SONIC_ONLINE_FILES += $(MLNX_SPC2_FW_FILE) diff --git a/platform/mellanox/mlnx-sai.mk b/platform/mellanox/mlnx-sai.mk index fd023ab9c2ed..cd736ba256c4 100644 --- a/platform/mellanox/mlnx-sai.mk +++ b/platform/mellanox/mlnx-sai.mk @@ -1,6 +1,6 @@ # Mellanox SAI -MLNX_SAI_VERSION = SAIRel1.14.2-master +MLNX_SAI_VERSION = SAIRel1.15.0-master export MLNX_SAI_VERSION diff --git a/platform/mellanox/mlnx-sai/SAI-Implementation b/platform/mellanox/mlnx-sai/SAI-Implementation index d446176da71b..350187a41e40 160000 --- a/platform/mellanox/mlnx-sai/SAI-Implementation +++ b/platform/mellanox/mlnx-sai/SAI-Implementation @@ -1 +1 @@ -Subproject commit d446176da71b42bd0d9c5421cae24c6b255c7a5c +Subproject commit 350187a41e408daaf03380401a0a2351b6cb0f9e diff --git a/platform/mellanox/sdk.mk b/platform/mellanox/sdk.mk index ae49cb619228..7a832b2502d1 100644 --- a/platform/mellanox/sdk.mk +++ b/platform/mellanox/sdk.mk @@ -1,5 +1,5 @@ -MLNX_SDK_BASE_URL = https://github.com/Mellanox/SAI-Implementation/raw/acf8ed31fd43e8280b553357c4ac4248f2c2e3aa/sdk -MLNX_SDK_VERSION = 4.3.1886 +MLNX_SDK_BASE_URL = https://github.com/Mellanox/SAI-Implementation/raw/350187a41e408daaf03380401a0a2351b6cb0f9e/sdk +MLNX_SDK_VERSION = 4.3.2104 MLNX_SDK_ISSU_VERSION = 101 MLNX_SDK_DEB_VERSION = $(subst _,.,$(MLNX_SDK_VERSION)) From abc02a702ec28ce7944481313a8efa1e645d829e Mon Sep 17 00:00:00 2001 From: Wenda Ni Date: Tue, 1 Oct 2019 09:52:03 -0700 Subject: [PATCH 032/278] [sairedis]: Advance sairedis reference pointer (#3530) Signed-off-by: Wenda Ni --- src/sonic-sairedis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 6bc64eedf16e..5fc89b569c98 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 6bc64eedf16e0dd377374e3c81ff179f996d459d +Subproject commit 5fc89b569c98ca1be51f0069c59465abd5873b19 From 52e35a0f9528f4a58707430c4219431dc4776cfa Mon Sep 17 00:00:00 2001 From: Stepan Blyshchak <38952541+stepanblyschak@users.noreply.github.com> Date: Wed, 2 Oct 2019 06:48:03 +0300 Subject: [PATCH 033/278] [docker_image_ctl.j2] skip hostname update if is up to date (#3529) Signed-off-by: Stepan Blyschak --- files/build_templates/docker_image_ctl.j2 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 index 718730f813ef..8bf0f2c6d4b0 100644 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -119,7 +119,7 @@ function postStartAction() v3SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" DestIp` v3SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" DestPort` v3MgmtVrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" vrf` - + if [ "${v1SnmpTrapIp}" != "" ] then sed -i "s/v1_trap_dest:.*/v1_trap_dest: ${v1SnmpTrapIp}:${v1SnmpTrapPort}%${v1MgmtVrf}/" "/etc/sonic/snmp.yml" @@ -185,7 +185,10 @@ start() { {%- endif %} preStartAction docker start {{docker_container_name}} - updateHostName "$HOSTNAME" + CURRENT_HOSTNAME="$(docker exec {{docker_container_name}} hostname)" + if [ x"$HOSTNAME" != x"$CURRENT_HOSTNAME" ]; then + updateHostName "$HOSTNAME" + fi postStartAction exit $? fi From 1515e39e71d71d3d4bd222fde4e10e74e6b18661 Mon Sep 17 00:00:00 2001 From: Ying Xie Date: Tue, 1 Oct 2019 21:12:19 -0700 Subject: [PATCH 034/278] [makefile] build Jessie slave unless NOJESSIE is specified (#3546) * [makefile] build Jessie slave unless NOJESSIE is specified * fix if condition --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index c949171a899a..13a3f247fc31 100644 --- a/Makefile +++ b/Makefile @@ -17,4 +17,7 @@ endif clean reset init configure showtag sonic-slave-build sonic-slave-bash : @echo "+++ Making $@ +++" +ifeq ($(NOJESSIE), 0) + make -f Makefile.work $@ +endif BLDENV=stretch make -f Makefile.work $@ From cf0465bf53c6bfe044c35e609e638e356d5babeb Mon Sep 17 00:00:00 2001 From: Wenda Ni Date: Wed, 2 Oct 2019 13:01:16 -0700 Subject: [PATCH 035/278] Adopt per-port buffer and qos profile (#3542) Signed-off-by: Wenda Ni --- files/build_templates/buffers_config.j2 | 22 +- files/build_templates/qos_config.j2 | 7 +- .../tests/sample_output/buffers-dell6100.json | 524 +++++++++++++++++- .../tests/sample_output/qos-dell6100.json | 303 +++++++++- 4 files changed, 843 insertions(+), 13 deletions(-) diff --git a/files/build_templates/buffers_config.j2 b/files/build_templates/buffers_config.j2 index 95830cd01a89..a5212d979fcb 100644 --- a/files/build_templates/buffers_config.j2 +++ b/files/build_templates/buffers_config.j2 @@ -131,9 +131,12 @@ def {{ defs.generate_pg_profils(port_names_active) }} {% else %} "BUFFER_PG": { - "{{ port_names_active }}|0": { +{% for port in PORT_ACTIVE %} + "{{ port }}|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} }, {% endif %} @@ -141,15 +144,22 @@ def {{ defs.generate_queue_buffers(port_names_active) }} {% else %} "BUFFER_QUEUE": { - "{{ port_names_active }}|3-4": { +{% for port in PORT_ACTIVE %} + "{{ port }}|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, - "{{ port_names_active }}|0-2": { +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|0-2": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, - "{{ port_names_active }}|5-6": { +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} } {% endif %} } diff --git a/files/build_templates/qos_config.j2 b/files/build_templates/qos_config.j2 index 8fddf800c023..2a9a5be8d83c 100644 --- a/files/build_templates/qos_config.j2 +++ b/files/build_templates/qos_config.j2 @@ -175,7 +175,8 @@ }, {% endif %} "PORT_QOS_MAP": { - "{{ port_names_active }}": { +{% for port in PORT_ACTIVE %} + "{{ port }}": { {% if 'type' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['type'] in backend_device_types %} "dot1p_to_tc_map" : "[DOT1P_TO_TC_MAP|AZURE]", {% else %} @@ -188,7 +189,9 @@ "pfc_to_pg_map" : "[PFC_PRIORITY_TO_PRIORITY_GROUP_MAP|AZURE]", {% endif %} "pfc_enable" : "3,4" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} }, "WRED_PROFILE": { "AZURE_LOSSLESS" : { diff --git a/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json b/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json index ce157b442614..5cf0472f3f11 100644 --- a/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json +++ b/src/sonic-config-engine/tests/sample_output/buffers-dell6100.json @@ -105,19 +105,535 @@ } }, "BUFFER_PG": { - "Ethernet0,Ethernet1,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet48,Ethernet52,Ethernet53,Ethernet54,Ethernet55,Ethernet56,Ethernet57,Ethernet58|0": { + "Ethernet0|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet1|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet4|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet5|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet6|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet7|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet8|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet9|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet10|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet11|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet12|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet13|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet14|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet15|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet16|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet17|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet20|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet21|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet22|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet23|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet24|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet25|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet26|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet27|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet28|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet29|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet30|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet31|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet32|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet36|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet37|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet38|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet39|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet40|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet41|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet42|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet48|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet52|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet53|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet54|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet55|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet56|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet57|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }, + "Ethernet58|0": { "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" } }, "BUFFER_QUEUE": { - "Ethernet0,Ethernet1,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet48,Ethernet52,Ethernet53,Ethernet54,Ethernet55,Ethernet56,Ethernet57,Ethernet58|3-4": { + "Ethernet0|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet1|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet4|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet5|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet6|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet7|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet8|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet9|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet10|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet11|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet12|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet13|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet14|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet15|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet16|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet17|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet20|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet21|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet22|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet23|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet24|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet25|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet26|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet27|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet28|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet29|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet30|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet31|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet32|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet36|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet37|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet38|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet39|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet40|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet41|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet42|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet48|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet52|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet53|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet54|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet55|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet56|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet57|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "Ethernet58|3-4": { "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" }, - "Ethernet0,Ethernet1,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet48,Ethernet52,Ethernet53,Ethernet54,Ethernet55,Ethernet56,Ethernet57,Ethernet58|0-2": { + "Ethernet0|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet1|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet4|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet5|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet6|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet7|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet8|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet9|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet10|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet11|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet12|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet13|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet14|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet15|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet16|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet17|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet20|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet21|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet22|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet23|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet24|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet25|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet26|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet27|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet28|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet29|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet30|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet31|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet32|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet36|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet37|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet38|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet39|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet40|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet41|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet42|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet48|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet52|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet53|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet54|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet55|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet56|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet57|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet58|0-2": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet0|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet1|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet4|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet5|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet6|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet7|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet8|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet9|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet10|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet11|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet12|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet13|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet14|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet15|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet16|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet17|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet20|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet21|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet22|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet23|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet24|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet25|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet26|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet27|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet28|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet29|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet30|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet31|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet32|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet36|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet37|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet38|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet39|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet40|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet41|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet42|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet48|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet52|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet53|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet54|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet55|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet56|5-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }, + "Ethernet57|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" }, - "Ethernet0,Ethernet1,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet48,Ethernet52,Ethernet53,Ethernet54,Ethernet55,Ethernet56,Ethernet57,Ethernet58|5-6": { + "Ethernet58|5-6": { "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" } } diff --git a/src/sonic-config-engine/tests/sample_output/qos-dell6100.json b/src/sonic-config-engine/tests/sample_output/qos-dell6100.json index 0387e10dc2f2..680ca6232e11 100644 --- a/src/sonic-config-engine/tests/sample_output/qos-dell6100.json +++ b/src/sonic-config-engine/tests/sample_output/qos-dell6100.json @@ -114,7 +114,308 @@ } }, "PORT_QOS_MAP": { - "Ethernet0,Ethernet1,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet48,Ethernet52,Ethernet53,Ethernet54,Ethernet55,Ethernet56,Ethernet57,Ethernet58": { + "Ethernet0": { + "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" + }, + "Ethernet1": { + "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" + }, + "Ethernet4": { + "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" + }, + "Ethernet5": { + "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" + }, + "Ethernet6": { + "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" + }, + "Ethernet7": { + "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" + }, + "Ethernet8": { + "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" + }, + "Ethernet9": { + "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" + }, + "Ethernet10": { + "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" + }, + "Ethernet11": { + "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" + }, + "Ethernet12": { + "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" + }, + "Ethernet13": { + "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" + }, + "Ethernet14": { + "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" + }, + "Ethernet15": { + "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" + }, + "Ethernet16": { + "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" + }, + "Ethernet17": { + "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" + }, + "Ethernet20": { + "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" + }, + "Ethernet21": { + "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" + }, + "Ethernet22": { + "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" + }, + "Ethernet23": { + "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" + }, + "Ethernet24": { + "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" + }, + "Ethernet25": { + "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" + }, + "Ethernet26": { + "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" + }, + "Ethernet27": { + "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" + }, + "Ethernet28": { + "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" + }, + "Ethernet29": { + "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" + }, + "Ethernet30": { + "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" + }, + "Ethernet31": { + "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" + }, + "Ethernet32": { + "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" + }, + "Ethernet36": { + "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" + }, + "Ethernet37": { + "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" + }, + "Ethernet38": { + "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" + }, + "Ethernet39": { + "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" + }, + "Ethernet40": { + "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" + }, + "Ethernet41": { + "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" + }, + "Ethernet42": { + "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" + }, + "Ethernet48": { + "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" + }, + "Ethernet52": { + "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" + }, + "Ethernet53": { + "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" + }, + "Ethernet54": { + "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" + }, + "Ethernet55": { + "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" + }, + "Ethernet56": { + "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" + }, + "Ethernet57": { + "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" + }, + "Ethernet58": { "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]", From d5262a36214dc197c0744d8bf70f2e24f2a1c786 Mon Sep 17 00:00:00 2001 From: Ying Xie Date: Wed, 2 Oct 2019 13:58:34 -0700 Subject: [PATCH 036/278] [first boot] sync file system after moving/copying files (#3550) Signed-off-by: Ying Xie --- files/image_config/platform/rc.local | 2 ++ files/image_config/updategraph/updategraph | 2 ++ 2 files changed, 4 insertions(+) diff --git a/files/image_config/platform/rc.local b/files/image_config/platform/rc.local index 5ea98a8eccd9..190743285644 100755 --- a/files/image_config/platform/rc.local +++ b/files/image_config/platform/rc.local @@ -242,6 +242,8 @@ if [ -f $FIRST_BOOT_FILE ]; then dpkg -i /host/image-$SONIC_VERSION/platform/$platform/*.deb fi + sync + # If the unit booted into SONiC from another NOS's grub, # we now install a grub for SONiC. if [ -n "$onie_platform" ] && [ -n "$migration" ]; then diff --git a/files/image_config/updategraph/updategraph b/files/image_config/updategraph/updategraph index b14f75f8582f..5dc9c24d35ef 100755 --- a/files/image_config/updategraph/updategraph +++ b/files/image_config/updategraph/updategraph @@ -33,6 +33,8 @@ function copy_config_files_and_directories() logger "Missing SONiC configuration ${file_dir} ..." fi done + + sync } function check_system_warm_boot() From cd85e2148b42aeae166fe17b68e54186e356bb5b Mon Sep 17 00:00:00 2001 From: Ying Xie Date: Wed, 2 Oct 2019 13:58:44 -0700 Subject: [PATCH 037/278] [updategraph] enhance update graph handling (#3549) - after reloading minigraph, write latest version string in the DB. - if old config_db.json file exists, use it and migrate to latest version. - only reload minigraph when config_db.json doesn't exist and minigraph exists. Signed-off-by: Ying Xie --- files/image_config/updategraph/updategraph | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/files/image_config/updategraph/updategraph b/files/image_config/updategraph/updategraph index 5dc9c24d35ef..dd8314b01221 100755 --- a/files/image_config/updategraph/updategraph +++ b/files/image_config/updategraph/updategraph @@ -62,13 +62,20 @@ if [ -f /tmp/pending_config_migration ]; then copy_config_files_and_directories $copy_list if [ x"${WARM_BOOT}" == x"true" ]; then echo "Warm reboot detected..." - elif [ "$enabled" = "true" ]; then + elif [ -r /etc/sonic/config_db.json ]; then + echo "Use config_db.json from old system..." + sonic-cfggen -j /etc/sonic/config_db.json --write-to-db + + if [[ -x /usr/bin/db_migrator.py ]]; then + # Migrate the DB to the latest schema version if needed + /usr/bin/db_migrator.py -o migrate + fi + elif [ -r /etc/sonic/minigraph.xml ]; then echo "Use minigraph.xml from old system..." reload_minigraph sonic-cfggen -d --print-data > /etc/sonic/config_db.json else - echo "Use config_db.json from old system..." - sonic-cfggen -j /etc/sonic/config_db.json --write-to-db + echo "Didn't found neither config_db.json nor minigraph.xml ..." fi rm -f /tmp/pending_config_migration sed -i "/enabled=/d" /etc/sonic/updategraph.conf From 8971b899b8c8a8ceff18723534bc79c6fe1e16c0 Mon Sep 17 00:00:00 2001 From: pavel-shirshov Date: Wed, 2 Oct 2019 15:35:11 -0700 Subject: [PATCH 038/278] [libteam]: Keep member ports parts of a team when teamd quits in FR and WR (#3544) --- .../0008-libteam-Add-warm_reboot-mode.patch | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch b/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch index e62d2df0597e..3f428bbec19e 100644 --- a/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch +++ b/src/libteam/patch/0008-libteam-Add-warm_reboot-mode.patch @@ -1,18 +1,19 @@ -From 5d418847bf6fa86f049e18c1b57028c71e40a9c4 Mon Sep 17 00:00:00 2001 +From 113d482704198685fba09cd2597fd93ca9d297c5 Mon Sep 17 00:00:00 2001 From: Pavel Shirshov -Date: Thu, 19 Sep 2019 14:49:17 -0700 +Date: Tue, 1 Oct 2019 09:23:23 -0700 Subject: [PATCH 1/1] [libteam]: Reimplement Warm-Reboot procedure --- libteam/ifinfo.c | 6 +- - teamd/teamd.c | 57 ++++- + teamd/teamd.c | 51 +++- teamd/teamd.h | 6 + teamd/teamd_events.c | 13 ++ + teamd/teamd_per_port.c | 6 + teamd/teamd_runner_lacp.c | 474 +++++++++++++++++++++++++++++++++++--- - 5 files changed, 509 insertions(+), 47 deletions(-) + 6 files changed, 512 insertions(+), 44 deletions(-) diff --git a/libteam/ifinfo.c b/libteam/ifinfo.c -index a15788b..e48193e 100644 +index 46d56a2..b86d34c 100644 --- a/libteam/ifinfo.c +++ b/libteam/ifinfo.c @@ -109,15 +109,13 @@ static void update_hwaddr(struct team_ifinfo *ifinfo, struct rtnl_link *link) @@ -34,7 +35,7 @@ index a15788b..e48193e 100644 } } diff --git a/teamd/teamd.c b/teamd/teamd.c -index 9dc85b5..679da49 100644 +index 9dc85b5..17221a9 100644 --- a/teamd/teamd.c +++ b/teamd/teamd.c @@ -117,7 +117,9 @@ static void print_help(const struct teamd_context *ctx) { @@ -90,7 +91,7 @@ index 9dc85b5..679da49 100644 if (optind < argc) { fprintf(stderr, "Too many arguments\n"); return -1; -@@ -390,12 +410,21 @@ static int teamd_run_loop_run(struct teamd_context *ctx) +@@ -390,9 +410,18 @@ static int teamd_run_loop_run(struct teamd_context *ctx) if (err != -1) { switch(ctrl_byte) { case 'q': @@ -99,9 +100,6 @@ index 9dc85b5..679da49 100644 if (quit_in_progress) return -EBUSY; - teamd_refresh_ports(ctx); -- err = teamd_flush_ports(ctx); -- if (err) -- return err; + if (ctrl_byte == 'w' || ctrl_byte == 'f') { + ctx->keep_ports = true; + ctx->no_quit_destroy = true; @@ -110,12 +108,9 @@ index 9dc85b5..679da49 100644 + teamd_ports_flush_data(ctx); + } + -+ err = teamd_flush_ports(ctx); -+ if (err) -+ return err; - quit_in_progress = true; - continue; - case 'r': + err = teamd_flush_ports(ctx); + if (err) + return err; @@ -434,6 +463,12 @@ void teamd_run_loop_quit(struct teamd_context *ctx, int err) teamd_run_loop_sent_ctrl_byte(ctx, 'q'); } @@ -207,6 +202,23 @@ index 221803e..bd4dcc1 100644 int teamd_event_port_added(struct teamd_context *ctx, struct teamd_port *tdport) { +diff --git a/teamd/teamd_per_port.c b/teamd/teamd_per_port.c +index f98a90d..a87e809 100644 +--- a/teamd/teamd_per_port.c ++++ b/teamd/teamd_per_port.c +@@ -350,6 +350,12 @@ static int teamd_port_remove(struct teamd_context *ctx, + { + int err; + ++ if (ctx->keep_ports) { ++ teamd_log_dbg("%s: Keeping port (found ifindex \"%d\").", ++ tdport->ifname, tdport->ifindex); ++ return 0; ++ } ++ + teamd_log_dbg("%s: Removing port (found ifindex \"%d\").", + tdport->ifname, tdport->ifindex); + err = team_port_remove(ctx->th, tdport->ifindex); diff --git a/teamd/teamd_runner_lacp.c b/teamd/teamd_runner_lacp.c index 4016b15..81be5b7 100644 --- a/teamd/teamd_runner_lacp.c From eeeda28434afb8288d04ff183caf199ead4d26df Mon Sep 17 00:00:00 2001 From: Ying Xie Date: Thu, 3 Oct 2019 17:02:59 -0700 Subject: [PATCH 039/278] [bcm config] enable sram scan (#3558) Per Broadcom's recommendations. Signed-off-by: Ying Xie --- .../Arista-7260CX3-C64/th2-a7260cx3-64-64x100G.config.bcm | 1 - .../th2-a7260cx3-64-112x50G+8x100G.config.bcm | 1 - .../Arista-7260CX3-Q64/th2-a7260cx3-64-64x40G.config.bcm | 1 - .../Delta-ag9064/th2-ag9064-64x100G.config.bcm | 1 - 4 files changed, 4 deletions(-) diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/th2-a7260cx3-64-64x100G.config.bcm b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/th2-a7260cx3-64-64x100G.config.bcm index 500d00de960c..44fb6f7536b4 100644 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/th2-a7260cx3-64-64x100G.config.bcm +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/th2-a7260cx3-64-64x100G.config.bcm @@ -939,7 +939,6 @@ portmap_9=17:100 robust_hash_disable_egress_vlan=1 robust_hash_disable_mpls=1 robust_hash_disable_vlan=1 -sram_scan_enable=0 stable_size=0x5500000 stable_size=0x5500000 tdma_timeout_usec=15000000 diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/th2-a7260cx3-64-112x50G+8x100G.config.bcm b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/th2-a7260cx3-64-112x50G+8x100G.config.bcm index 85be9fced908..3c2a343bf04d 100644 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/th2-a7260cx3-64-112x50G+8x100G.config.bcm +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/th2-a7260cx3-64-112x50G+8x100G.config.bcm @@ -681,7 +681,6 @@ port_init_cl72_hg=1 robust_hash_disable_egress_vlan=1 robust_hash_disable_mpls=1 robust_hash_disable_vlan=1 -sram_scan_enable=0 stable_size=0x5500000 stable_size=0x5500000 tdma_timeout_usec=15000000 diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-Q64/th2-a7260cx3-64-64x40G.config.bcm b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-Q64/th2-a7260cx3-64-64x40G.config.bcm index 0af841fe64fa..f5ac5e37ef7e 100644 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-Q64/th2-a7260cx3-64-64x40G.config.bcm +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-Q64/th2-a7260cx3-64-64x40G.config.bcm @@ -939,7 +939,6 @@ portmap_9=17:40 robust_hash_disable_egress_vlan=1 robust_hash_disable_mpls=1 robust_hash_disable_vlan=1 -sram_scan_enable=0 stable_size=0x5500000 stable_size=0x5500000 tdma_timeout_usec=15000000 diff --git a/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/th2-ag9064-64x100G.config.bcm b/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/th2-ag9064-64x100G.config.bcm index 859196d8e5c8..3914599abf7c 100644 --- a/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/th2-ag9064-64x100G.config.bcm +++ b/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/th2-ag9064-64x100G.config.bcm @@ -797,6 +797,5 @@ phy_an_allow_pll_change_hg=0 robust_hash_disable_egress_vlan=1 robust_hash_disable_mpls=1 robust_hash_disable_vlan=1 -sram_scan_enable=0 stable_size=0x5500000 mmu_lossless=1 From f3cfa8fdff251c699debb49b127d65f7ff545f12 Mon Sep 17 00:00:00 2001 From: zzhiyuan Date: Fri, 4 Oct 2019 10:14:09 -0700 Subject: [PATCH 040/278] Fix buffer configurations for 7170 (#2972) * Fix buffer configurations for 7170 * Adjust buffer configurations for 7170 * Remove ingress lossless profiles for Arista 7170 --- .../Arista-7170-64C/buffers_defaults_t0.j2 | 61 ++++++++++--- .../Arista-7170-64C/buffers_defaults_t1.j2 | 79 ++++++++++++++++ .../Arista-7170-64C/pg_profile_lookup.ini | 17 ++++ .../Arista-7170-Q59S20/buffers_defaults_t0.j2 | 61 ++++++++++--- .../Arista-7170-Q59S20/buffers_defaults_t1.j2 | 91 +++++++++++++++++++ .../Arista-7170-Q59S20/pg_profile_lookup.ini | 17 ++++ 6 files changed, 298 insertions(+), 28 deletions(-) create mode 100644 device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t1.j2 create mode 100644 device/arista/x86_64-arista_7170_64c/Arista-7170-64C/pg_profile_lookup.ini create mode 100644 device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t1.j2 create mode 100644 device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/pg_profile_lookup.ini diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t0.j2 b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t0.j2 index 3442612f70b2..e880e6bc3a9c 100644 --- a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t0.j2 +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t0.j2 @@ -1,4 +1,8 @@ -{%- set default_cable = '5m' %} +{% set default_cable = '5m' %} +{% set ingress_lossless_pool_size = '4194304' %} +{% set ingress_lossy_pool_size = '7340032' %} +{% set egress_lossless_pool_size = '16777152' %} +{% set egress_lossy_pool_size = '7340032' %} {%- macro generate_port_lists(PORT_ALL) %} {# Generate list of ports #} @@ -10,37 +14,66 @@ {%- macro generate_buffer_pool_and_profiles() %} "BUFFER_POOL": { "ingress_lossless_pool": { - "size": "33329088", + "size": "{{ ingress_lossless_pool_size }}", "type": "ingress", "mode": "dynamic", - "xoff": "7827456" + "xoff": "2867200" }, - "egress_lossy_pool": { - "size": "26663272", - "type": "egress", + "ingress_lossy_pool": { + "size": "{{ ingress_lossy_pool_size }}", + "type": "ingress", "mode": "dynamic" }, "egress_lossless_pool": { - "size": "42349632", + "size": "{{ egress_lossless_pool_size }}", + "type": "egress", + "mode": "dynamic" + }, + "egress_lossy_pool": { + "size": "{{ egress_lossy_pool_size }}", "type": "egress", - "mode": "static" + "mode": "dynamic" } }, "BUFFER_PROFILE": { "ingress_lossy_profile": { - "pool":"[BUFFER_POOL|ingress_lossless_pool]", - "size":"0", - "static_th":"44302336" + "pool":"[BUFFER_POOL|ingress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" }, "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"0", - "static_th":"42349632" + "dynamic_th":"7" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", - "size":"1664", - "dynamic_th":"-1" + "size":"4096", + "dynamic_th":"3" + }, + "q_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names) %} + "BUFFER_PG": { + "{{ port_names }}|3-4": { + "profile" : "[BUFFER_PROFILE|ingress_lossless_profile]" } }, {%- endmacro %} + +{%- macro generate_queue_buffers(port_names) %} + "BUFFER_QUEUE": { + "{{ port_names }}|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "{{ port_names }}|0-1": { + "profile" : "[BUFFER_PROFILE|q_lossy_profile]" + } + } +{%- endmacro %} diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t1.j2 b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t1.j2 new file mode 100644 index 000000000000..e115dc9f0a1d --- /dev/null +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/buffers_defaults_t1.j2 @@ -0,0 +1,79 @@ +{% set default_cable = '5m' %} +{% set ingress_lossless_pool_size = '2097152' %} +{% set ingress_lossy_pool_size = '5242880' %} +{% set egress_lossless_pool_size = '16777152' %} +{% set egress_lossy_pool_size = '5242880' %} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {%- for port_idx in range(0,64) %} + {%- 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": "dynamic", + "xoff": "2867200" + }, + "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_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"0", + "dynamic_th":"7" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + }, + "q_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names) %} + "BUFFER_PG": { + "{{ port_names }}|3-4": { + "profile" : "[BUFFER_PROFILE|ingress_lossless_profile]" + } + }, +{%- endmacro %} + +{%- macro generate_queue_buffers(port_names) %} + "BUFFER_QUEUE": { + "{{ port_names }}|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "{{ port_names }}|0-1": { + "profile" : "[BUFFER_PROFILE|q_lossy_profile]" + } + } +{%- endmacro %} diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/pg_profile_lookup.ini b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/pg_profile_lookup.ini new file mode 100644 index 000000000000..78a72d842acd --- /dev/null +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-64C/pg_profile_lookup.ini @@ -0,0 +1,17 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold + 10000 5m 34816 18432 16384 7 + 25000 5m 34816 18432 16384 7 + 40000 5m 34816 18432 16384 7 + 50000 5m 34816 18432 16384 7 + 100000 5m 36864 18432 18432 7 + 10000 40m 36864 18432 18432 7 + 25000 40m 39936 18432 21504 7 + 40000 40m 41984 18432 23552 7 + 50000 40m 41984 18432 23552 7 + 100000 40m 54272 18432 35840 7 + 10000 300m 49152 18432 30720 7 + 25000 300m 71680 18432 53248 7 + 40000 300m 94208 18432 75776 7 + 50000 300m 94208 18432 75776 7 + 100000 300m 184320 18432 165888 7 diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t0.j2 b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t0.j2 index fabdac2df879..1f6e3f5ed35d 100644 --- a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t0.j2 +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t0.j2 @@ -1,4 +1,8 @@ -{%- set default_cable = '5m' %} +{% set default_cable = '5m' %} +{% set ingress_lossless_pool_size = '4194304' %} +{% set ingress_lossy_pool_size = '7340032' %} +{% set egress_lossless_pool_size = '16777152' %} +{% set egress_lossy_pool_size = '7340032' %} {%- macro generate_port_lists(PORT_ALL) %} {# Generate list of ports #} @@ -22,37 +26,66 @@ {%- macro generate_buffer_pool_and_profiles() %} "BUFFER_POOL": { "ingress_lossless_pool": { - "size": "33329088", + "size": "{{ ingress_lossless_pool_size }}", "type": "ingress", "mode": "dynamic", - "xoff": "7827456" + "xoff": "2867200" }, - "egress_lossy_pool": { - "size": "26663272", - "type": "egress", + "ingress_lossy_pool": { + "size": "{{ ingress_lossy_pool_size }}", + "type": "ingress", "mode": "dynamic" }, "egress_lossless_pool": { - "size": "42349632", + "size": "{{ egress_lossless_pool_size }}", + "type": "egress", + "mode": "dynamic" + }, + "egress_lossy_pool": { + "size": "{{ egress_lossy_pool_size }}", "type": "egress", - "mode": "static" + "mode": "dynamic" } }, "BUFFER_PROFILE": { "ingress_lossy_profile": { - "pool":"[BUFFER_POOL|ingress_lossless_pool]", - "size":"0", - "static_th":"44302336" + "pool":"[BUFFER_POOL|ingress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" }, "egress_lossless_profile": { "pool":"[BUFFER_POOL|egress_lossless_pool]", "size":"0", - "static_th":"42349632" + "dynamic_th":"7" }, "egress_lossy_profile": { "pool":"[BUFFER_POOL|egress_lossy_pool]", - "size":"1664", - "dynamic_th":"-1" + "size":"4096", + "dynamic_th":"3" + }, + "q_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names) %} + "BUFFER_PG": { + "{{ port_names }}|3-4": { + "profile" : "[BUFFER_PROFILE|ingress_lossless_profile]" } }, {%- endmacro %} + +{%- macro generate_queue_buffers(port_names) %} + "BUFFER_QUEUE": { + "{{ port_names }}|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "{{ port_names }}|0-1": { + "profile" : "[BUFFER_PROFILE|q_lossy_profile]" + } + } +{%- endmacro %} diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t1.j2 b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t1.j2 new file mode 100644 index 000000000000..7487a1db19ba --- /dev/null +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/buffers_defaults_t1.j2 @@ -0,0 +1,91 @@ +{% set default_cable = '5m' %} +{% set ingress_lossless_pool_size = '2097152' %} +{% set ingress_lossy_pool_size = '5242880' %} +{% set egress_lossless_pool_size = '16777152' %} +{% set egress_lossy_pool_size = '5242880' %} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {%- for port_idx in range(0,20) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %} + {%- endfor %} + {%- for port_idx in range(80,88) %} + {%- if PORT_ALL.append("Ethernet%d" % port_idx) %}{%- endif %} + {%- endfor %} + {%- for port_idx in range(22,32) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %} + {%- endfor %} + {%- for port_idx in range(128,140) %} + {%- if PORT_ALL.append("Ethernet%d" % port_idx) %}{%- endif %} + {%- endfor %} + {%- for port_idx in range(35,64) %} + {%- 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": "dynamic", + "xoff": "2867200" + }, + "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_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"0", + "dynamic_th":"7" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + }, + "q_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"4096", + "dynamic_th":"3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names) %} + "BUFFER_PG": { + "{{ port_names }}|3-4": { + "profile" : "[BUFFER_PROFILE|ingress_lossless_profile]" + } + }, +{%- endmacro %} + +{%- macro generate_queue_buffers(port_names) %} + "BUFFER_QUEUE": { + "{{ port_names }}|3-4": { + "profile" : "[BUFFER_PROFILE|egress_lossless_profile]" + }, + "{{ port_names }}|0-1": { + "profile" : "[BUFFER_PROFILE|q_lossy_profile]" + } + } +{%- endmacro %} diff --git a/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/pg_profile_lookup.ini b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/pg_profile_lookup.ini new file mode 100644 index 000000000000..78a72d842acd --- /dev/null +++ b/device/arista/x86_64-arista_7170_64c/Arista-7170-Q59S20/pg_profile_lookup.ini @@ -0,0 +1,17 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold + 10000 5m 34816 18432 16384 7 + 25000 5m 34816 18432 16384 7 + 40000 5m 34816 18432 16384 7 + 50000 5m 34816 18432 16384 7 + 100000 5m 36864 18432 18432 7 + 10000 40m 36864 18432 18432 7 + 25000 40m 39936 18432 21504 7 + 40000 40m 41984 18432 23552 7 + 50000 40m 41984 18432 23552 7 + 100000 40m 54272 18432 35840 7 + 10000 300m 49152 18432 30720 7 + 25000 300m 71680 18432 53248 7 + 40000 300m 94208 18432 75776 7 + 50000 300m 94208 18432 75776 7 + 100000 300m 184320 18432 165888 7 From 976850fc00d7e007844834e9487631b8302f4238 Mon Sep 17 00:00:00 2001 From: Andriy Moroz Date: Fri, 4 Oct 2019 20:52:58 +0300 Subject: [PATCH 041/278] [submodule update] Add SSD Health tools (#3218) Signed-off-by: Andriy Moroz --- dockers/docker-platform-monitor/Dockerfile.j2 | 1 + .../base_image_files/{sensors => cmd_wrapper} | 2 +- .../base_image_files/smartctl | 10 ---------- .../ssd_tools/SmartCmd | Bin 0 -> 2435104 bytes .../docker-platform-monitor/ssd_tools/iSmart | Bin 0 -> 120064 bytes rules/docker-platform-monitor.mk | 6 ++++-- src/sonic-platform-common | 2 +- 7 files changed, 7 insertions(+), 14 deletions(-) rename dockers/docker-platform-monitor/base_image_files/{sensors => cmd_wrapper} (69%) delete mode 100755 dockers/docker-platform-monitor/base_image_files/smartctl create mode 100755 dockers/docker-platform-monitor/ssd_tools/SmartCmd create mode 100755 dockers/docker-platform-monitor/ssd_tools/iSmart diff --git a/dockers/docker-platform-monitor/Dockerfile.j2 b/dockers/docker-platform-monitor/Dockerfile.j2 index 9a3deebef34a..c2e142727b80 100755 --- a/dockers/docker-platform-monitor/Dockerfile.j2 +++ b/dockers/docker-platform-monitor/Dockerfile.j2 @@ -56,5 +56,6 @@ RUN apt-get purge -y \ COPY ["docker_init.sh", "lm-sensors.sh", "/usr/bin/"] COPY ["docker-pmon.supervisord.conf.j2", "start.sh.j2", "/usr/share/sonic/templates/"] +COPY ["ssd_tools/*", "/usr/bin/"] ENTRYPOINT ["/usr/bin/docker_init.sh"] diff --git a/dockers/docker-platform-monitor/base_image_files/sensors b/dockers/docker-platform-monitor/base_image_files/cmd_wrapper similarity index 69% rename from dockers/docker-platform-monitor/base_image_files/sensors rename to dockers/docker-platform-monitor/base_image_files/cmd_wrapper index 23a12034f071..74e5dd7ab9cb 100755 --- a/dockers/docker-platform-monitor/base_image_files/sensors +++ b/dockers/docker-platform-monitor/base_image_files/cmd_wrapper @@ -7,4 +7,4 @@ if [ -t 1 ] ; then DOCKER_EXEC_FLAGS+="t" fi -docker exec -$DOCKER_EXEC_FLAGS pmon sensors "$@" +docker exec -$DOCKER_EXEC_FLAGS pmon $(basename $0) "$@" diff --git a/dockers/docker-platform-monitor/base_image_files/smartctl b/dockers/docker-platform-monitor/base_image_files/smartctl deleted file mode 100755 index 2bbc5f7a6d74..000000000000 --- a/dockers/docker-platform-monitor/base_image_files/smartctl +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -DOCKER_EXEC_FLAGS="i" - -# Determine whether stdout is on a terminal -if [ -t 1 ] ; then - DOCKER_EXEC_FLAGS+="t" -fi - -docker exec -$DOCKER_EXEC_FLAGS pmon smartctl "$@" diff --git a/dockers/docker-platform-monitor/ssd_tools/SmartCmd b/dockers/docker-platform-monitor/ssd_tools/SmartCmd new file mode 100755 index 0000000000000000000000000000000000000000..dae647e4697e8afd25c5d9521e8762a2f95ad66a GIT binary patch literal 2435104 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