From 6802167ac070ec4d5e21d0585929189752e14c71 Mon Sep 17 00:00:00 2001 From: Maxwill Ma Date: Thu, 4 Jun 2020 14:07:40 +0800 Subject: [PATCH] add new device folder and platform folder for Shamu and Jaws Signed-off-by: Maxwill Ma --- .../AS14-128H/port_config.ini | 129 + .../AS14-128H/sai.profile | 1 + .../custom_led.bin | Bin 0 -> 332 bytes .../default_sku | 1 + .../installer.conf | 2 + .../led_proc_init.soc | 9 + .../linkscan_led_fw.bin | Bin 0 -> 4752 bytes .../minigraph.xml | 1333 +++++++ .../opennsl-postinit.cfg | 3 + .../plugins/cputemputil.py | 43 + .../plugins/eeprom.py | 23 + .../plugins/fanutil.py | 309 ++ .../plugins/fwmgrutil.py | 882 +++++ .../plugins/optictemputil.py | 126 + .../plugins/psuutil.py | 248 ++ .../plugins/sensorutil.py | 383 ++ .../plugins/sfputil.py | 205 ++ .../th3-as14-128h.config.bcm | 631 ++++ .../.installer.conf.swp | Bin 0 -> 12288 bytes .../AS14-40D/port_config.ini | 33 + .../AS14-40D/sai.profile | 1 + .../custom_led.bin | Bin 0 -> 216 bytes .../x86_64-alibaba_as14-40d-cl-r0/default_sku | 1 + .../installer.conf | 3 + .../led_proc_init.soc | 9 + .../linkscan_led_fw.bin | Bin 0 -> 4716 bytes .../minigraph.xml | 854 +++++ .../opennsl-postinit.cfg | 3 + .../plugins/cputemputil.py | 43 + .../plugins/eeprom.py | 23 + .../plugins/fanutil.py | 310 ++ .../plugins/fwmgrutil.py | 882 +++++ .../plugins/optictemputil.py | 126 + .../plugins/optictemputil_lp.py | 126 + .../plugins/optictemputil_rl.py | 133 + .../plugins/psuutil.py | 248 ++ .../plugins/sensorutil.py | 369 ++ .../plugins/sfputil.py | 234 ++ .../td3-as14-40d.config.bcm | 590 ++++ platform/broadcom/platform-modules-cel.mk | 6 + .../sonic-platform-modules-cel/debian/control | 6 + .../debian/platform-modules-jaws.init | 45 + .../debian/platform-modules-jaws.install | 15 + .../debian/platform-modules-jaws.postinst | 15 + .../debian/platform-modules-shamu.init | 51 + .../debian/platform-modules-shamu.install | 20 + .../debian/platform-modules-shamu.postinst | 17 + .../sonic-platform-modules-cel/debian/rules | 10 +- .../jaws/cfg/jaws-modules.conf | 16 + .../jaws/modules/Makefile | 1 + .../jaws/modules/baseboard_cpld.c | 417 +++ .../jaws/modules/dimm-bus.c | 107 + .../jaws/modules/dimm-bus.h | 18 + .../jaws/modules/i2c-imc.c | 556 +++ .../jaws/modules/mc24lc64t.c | 173 + .../jaws/modules/switchboard_fpga.c | 2997 ++++++++++++++++ .../systemd/platform-modules-jaws.service | 14 + .../shamu/cfg/shamu-modules.conf | 15 + .../shamu/modules/Makefile | 1 + .../shamu/modules/baseboard_cpld.c | 409 +++ .../shamu/modules/dimm-bus.c | 107 + .../shamu/modules/dimm-bus.h | 18 + .../shamu/modules/i2c-imc.c | 556 +++ .../shamu/modules/mc24lc64t.c | 173 + .../sonic_platform-1.0-py2-none-any.whl | Bin 0 -> 8941 bytes .../shamu/modules/switchboard_fpga.c | 2431 +++++++++++++ .../shamu/scripts/platform_sensors.py | 173 + .../shamu/scripts/sensors | 11 + .../sonic-platform-modules-cel/shamu/setup.py | 34 + .../shamu/sonic_platform.egg-info/PKG-INFO | 23 + .../shamu/sonic_platform.egg-info/SOURCES.txt | 11 + .../dependency_links.txt | 1 + .../sonic_platform.egg-info/top_level.txt | 1 + .../systemd/platform-modules-shamu.service | 14 + .../tools/bmc_wdt/bmc_wdt.py | 118 + .../tools/bmc_wdt/bmc_wdt.service | 10 + .../tools/bmcutil/bmc-exec | 45 + .../tools/bmcutil/bmcpwd | 1 + .../tools/bmcutil/bmcutil.py | 296 ++ .../tools/fpga_prog/fpga_prog | Bin 0 -> 13768 bytes .../tools/fpga_prog/fpga_prog.c | 282 ++ .../tools/ispvme_12.2/Makefile | 25 + .../tools/ispvme_12.2/hardware.c | 409 +++ .../tools/ispvme_12.2/ispvm | Bin 0 -> 106272 bytes .../tools/ispvme_12.2/ispvm_ui.c | 1043 ++++++ .../tools/ispvme_12.2/ivm_core.c | 3081 +++++++++++++++++ .../tools/ispvme_12.2/origi_ispvm_ui.c | 908 +++++ .../tools/ispvme_12.2/vmopcode.h | 233 ++ .../tools/platformutil.py | 642 ++++ .../tools/power_utils/power | 86 + .../tools/read_optic_temp.py | 189 + .../tools/sync_bmc/bmc_vlan.service | 12 + .../tools/sync_bmc/bmc_vlan.sh | 7 + .../tools/sync_bmc/sync_bmc.py | 203 ++ .../tools/sync_bmc/sync_bmc.service | 10 + .../tools/sync_bmc/sync_bmc.timer | 10 + 96 files changed, 24387 insertions(+), 1 deletion(-) create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/port_config.ini create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/sai.profile create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/custom_led.bin create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/default_sku create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/installer.conf create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/led_proc_init.soc create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/linkscan_led_fw.bin create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/minigraph.xml create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/opennsl-postinit.cfg create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/cputemputil.py create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/eeprom.py create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fanutil.py create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fwmgrutil.py create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/optictemputil.py create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/psuutil.py create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sensorutil.py create mode 100755 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sfputil.py create mode 100644 device/alibaba/x86_64-alibaba_as14-128h-cl-r0/th3-as14-128h.config.bcm create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/.installer.conf.swp create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/port_config.ini create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/sai.profile create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/custom_led.bin create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/default_sku create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/installer.conf create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/led_proc_init.soc create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/linkscan_led_fw.bin create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/minigraph.xml create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/opennsl-postinit.cfg create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/cputemputil.py create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/eeprom.py create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fanutil.py create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fwmgrutil.py create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil.py create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_lp.py create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_rl.py create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/psuutil.py create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sensorutil.py create mode 100755 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sfputil.py create mode 100644 device/alibaba/x86_64-alibaba_as14-40d-cl-r0/td3-as14-40d.config.bcm create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.init create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.install create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.postinst create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.init create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.install create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.postinst create mode 100644 platform/broadcom/sonic-platform-modules-cel/jaws/cfg/jaws-modules.conf create mode 100644 platform/broadcom/sonic-platform-modules-cel/jaws/modules/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-cel/jaws/modules/baseboard_cpld.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.h create mode 100644 platform/broadcom/sonic-platform-modules-cel/jaws/modules/i2c-imc.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/jaws/modules/mc24lc64t.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/jaws/modules/switchboard_fpga.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/jaws/systemd/platform-modules-jaws.service create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/cfg/shamu-modules.conf create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/modules/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/modules/baseboard_cpld.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.h create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/modules/i2c-imc.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/modules/mc24lc64t.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/modules/sonic_platform-1.0-py2-none-any.whl create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/modules/switchboard_fpga.c create mode 100755 platform/broadcom/sonic-platform-modules-cel/shamu/scripts/platform_sensors.py create mode 100755 platform/broadcom/sonic-platform-modules-cel/shamu/scripts/sensors create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/setup.py create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/PKG-INFO create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/SOURCES.txt create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/dependency_links.txt create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/top_level.txt create mode 100644 platform/broadcom/sonic-platform-modules-cel/shamu/systemd/platform-modules-shamu.service create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.py create mode 100755 platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.service create mode 100755 platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmc-exec create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcpwd create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcutil.py create mode 100755 platform/broadcom/sonic-platform-modules-cel/tools/fpga_prog/fpga_prog create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/fpga_prog/fpga_prog.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/hardware.c create mode 100755 platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ispvm create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ispvm_ui.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ivm_core.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/origi_ispvm_ui.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/vmopcode.h create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/platformutil.py create mode 100755 platform/broadcom/sonic-platform-modules-cel/tools/power_utils/power create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/read_optic_temp.py create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.service create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.sh create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.py create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.service create mode 100644 platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.timer diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/port_config.ini b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/port_config.ini new file mode 100644 index 000000000000..224418d2c15a --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/port_config.ini @@ -0,0 +1,129 @@ +# name lanes alias index +Ethernet1 9,10 QSFP1 1 +Ethernet2 11,12 QSFP2 2 +Ethernet3 15,16 QSFP3 3 +Ethernet4 13,14 QSFP4 4 +Ethernet5 77,78 QSFP5 5 +Ethernet6 79,80 QSFP6 6 +Ethernet7 75,76 QSFP7 7 +Ethernet8 73,74 QSFP8 8 +Ethernet9 1,2 QSFP9 9 +Ethernet10 3,4 QSFP10 10 +Ethernet11 7,8 QSFP11 11 +Ethernet12 5,6 QSFP12 12 +Ethernet13 69,70 QSFP13 13 +Ethernet14 71,72 QSFP14 14 +Ethernet15 67,68 QSFP15 15 +Ethernet16 65,66 QSFP16 16 +Ethernet17 41,42 QSFP17 17 +Ethernet18 43,44 QSFP18 18 +Ethernet19 47,48 QSFP19 19 +Ethernet20 45,46 QSFP20 20 +Ethernet21 109,110 QSFP21 21 +Ethernet22 111,112 QSFP22 22 +Ethernet23 107,108 QSFP23 23 +Ethernet24 105,106 QSFP24 24 +Ethernet25 33,34 QSFP25 25 +Ethernet26 35,36 QSFP26 26 +Ethernet27 39,40 QSFP27 27 +Ethernet28 37,38 QSFP28 28 +Ethernet29 101,102 QSFP29 29 +Ethernet30 103,104 QSFP30 30 +Ethernet31 99,100 QSFP31 31 +Ethernet32 97,98 QSFP32 32 +Ethernet33 137,138 QSFP33 33 +Ethernet34 139,140 QSFP34 34 +Ethernet35 143,144 QSFP35 35 +Ethernet36 141,142 QSFP36 36 +Ethernet37 205,206 QSFP37 37 +Ethernet38 207,208 QSFP38 38 +Ethernet39 203,204 QSFP39 39 +Ethernet40 201,202 QSFP40 40 +Ethernet41 129,130 QSFP41 41 +Ethernet42 131,132 QSFP42 42 +Ethernet43 135,136 QSFP43 43 +Ethernet44 133,134 QSFP44 44 +Ethernet45 197,198 QSFP45 45 +Ethernet46 199,200 QSFP46 46 +Ethernet47 195,196 QSFP47 47 +Ethernet48 193,194 QSFP48 48 +Ethernet49 169,170 QSFP49 49 +Ethernet50 171,172 QSFP50 50 +Ethernet51 175,176 QSFP51 51 +Ethernet52 173,174 QSFP52 52 +Ethernet53 237,238 QSFP53 53 +Ethernet54 239,240 QSFP54 54 +Ethernet55 235,236 QSFP55 55 +Ethernet56 233,234 QSFP56 56 +Ethernet57 161,162 QSFP57 57 +Ethernet58 163,164 QSFP58 58 +Ethernet59 167,168 QSFP59 59 +Ethernet60 165,166 QSFP60 60 +Ethernet61 229,230 QSFP61 61 +Ethernet62 231,232 QSFP62 62 +Ethernet63 227,228 QSFP63 63 +Ethernet64 225,226 QSFP64 64 +Ethernet65 25,26 QSFP65 65 +Ethernet66 27,28 QSFP66 66 +Ethernet67 31,32 QSFP67 67 +Ethernet68 29,30 QSFP68 68 +Ethernet69 93,94 QSFP69 69 +Ethernet70 95,96 QSFP70 70 +Ethernet71 91,92 QSFP71 71 +Ethernet72 89,90 QSFP72 72 +Ethernet73 17,18 QSFP73 73 +Ethernet74 19,20 QSFP74 74 +Ethernet75 23,24 QSFP75 75 +Ethernet76 21,22 QSFP76 76 +Ethernet77 85,86 QSFP77 77 +Ethernet78 87,88 QSFP78 78 +Ethernet79 83,84 QSFP79 79 +Ethernet80 81,82 QSFP80 80 +Ethernet81 57,58 QSFP81 81 +Ethernet82 59,60 QSFP82 82 +Ethernet83 63,64 QSFP83 83 +Ethernet84 61,62 QSFP84 84 +Ethernet85 125,126 QSFP85 85 +Ethernet86 127,128 QSFP86 86 +Ethernet87 123,124 QSFP87 87 +Ethernet88 121,122 QSFP88 88 +Ethernet89 49,50 QSFP89 89 +Ethernet90 51,52 QSFP90 90 +Ethernet91 55,56 QSFP91 91 +Ethernet92 53,54 QSFP92 92 +Ethernet93 117,118 QSFP93 93 +Ethernet94 119,120 QSFP94 94 +Ethernet95 115,116 QSFP95 95 +Ethernet96 113,114 QSFP96 96 +Ethernet97 153,154 QSFP97 97 +Ethernet98 155,156 QSFP98 98 +Ethernet99 159,160 QSFP99 99 +Ethernet100 157,158 QSFP100 100 +Ethernet101 221,222 QSFP101 101 +Ethernet102 223,224 QSFP102 102 +Ethernet103 219,220 QSFP103 103 +Ethernet104 217,218 QSFP104 104 +Ethernet105 145,146 QSFP105 105 +Ethernet106 147,148 QSFP106 106 +Ethernet107 151,152 QSFP107 107 +Ethernet108 149,150 QSFP108 108 +Ethernet109 213,214 QSFP109 109 +Ethernet110 215,216 QSFP110 110 +Ethernet111 211,212 QSFP111 111 +Ethernet112 209,210 QSFP112 112 +Ethernet113 185,186 QSFP113 113 +Ethernet114 187,188 QSFP114 114 +Ethernet115 191,192 QSFP115 115 +Ethernet116 189,190 QSFP116 116 +Ethernet117 253,254 QSFP117 117 +Ethernet118 255,256 QSFP118 118 +Ethernet119 251,252 QSFP119 119 +Ethernet120 249,250 QSFP120 120 +Ethernet121 177,178 QSFP121 121 +Ethernet122 179,180 QSFP122 122 +Ethernet123 183,184 QSFP123 123 +Ethernet124 181,182 QSFP124 124 +Ethernet125 245,246 QSFP125 125 +Ethernet126 247,248 QSFP126 126 +Ethernet127 243,244 QSFP127 127 +Ethernet128 241,242 QSFP128 128 diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/sai.profile b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/sai.profile new file mode 100644 index 000000000000..f2db109d7afc --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/platform/th3-as14-128h.config.bcm diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/custom_led.bin b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/custom_led.bin new file mode 100644 index 0000000000000000000000000000000000000000..a7f256cadee83260004df5e76ae6647712a15d2e GIT binary patch literal 332 zcmV-S0ki(_wO>Y7MomUUM)0(QunHUiBY-CZCIKOcM$jZ=0HH>ZB%}bNMgkkcnK^G*e!T%vP4F#Kmn9QMgg5kMh!v) z(NsoRMh!v$(KH+uLIcoZMgS@R&@>#H07Yn2Qvox8E7j2fBEnz*Apv0@BST>VBZFbW zVIU*~Vm~BAVuNDBVn8GWV_zghV}oPDV_+fzWPc(;WP@bEWCO4~ypTqjMxsWmM)1AN zH~;_%3l9we0|x~uD=#e}BPS(^i;s+kKs!^g$R%g@bWV`pV)Yj15qLq|nPOHWPl^Y``n e`~UsX)7RD6+uz-Bb9Z%ldw+dVQ&&}4TVGul3xSFN literal 0 HcmV?d00001 diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/default_sku b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/default_sku new file mode 100644 index 000000000000..30e5af958eb9 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/default_sku @@ -0,0 +1 @@ +AS23-128H t1 \ No newline at end of file diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/installer.conf b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/installer.conf new file mode 100644 index 000000000000..dc3cf67d19e7 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/installer.conf @@ -0,0 +1,2 @@ +CONSOLE_SPEED=9600 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="processor.max_cstate=1 intel_idle.max_cstate=0" diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/led_proc_init.soc b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/led_proc_init.soc new file mode 100644 index 000000000000..28cd4b9bc9f7 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/led_proc_init.soc @@ -0,0 +1,9 @@ +#Enable all ports +#port all en=1 +#sleep 6 +#linkscan 250000; port xe,ce linkscan=on + +#Load LED +#led auto on; led start + + diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/linkscan_led_fw.bin b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/linkscan_led_fw.bin new file mode 100644 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/alibaba/x86_64-alibaba_as14-128h-cl-r0/minigraph.xml b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/minigraph.xml new file mode 100644 index 000000000000..500be59307a0 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/minigraph.xml @@ -0,0 +1,1333 @@ + + + + + + ARISTA01T0 + 10.0.0.33 + sonic + 10.0.0.32 + 1 + 180 + 60 + + + sonic + 10.0.0.0 + ARISTA01T2 + 10.0.0.1 + 1 + 180 + 60 + + + ARISTA02T0 + 10.0.0.35 + sonic + 10.0.0.34 + 1 + 180 + 60 + + + sonic + 10.0.0.2 + ARISTA02T2 + 10.0.0.3 + 1 + 180 + 60 + + + ARISTA03T0 + 10.0.0.37 + sonic + 10.0.0.36 + 1 + 180 + 60 + + + sonic + 10.0.0.4 + ARISTA03T2 + 10.0.0.5 + 1 + 180 + 60 + + + ARISTA04T0 + 10.0.0.39 + sonic + 10.0.0.38 + 1 + 180 + 60 + + + sonic + 10.0.0.6 + ARISTA04T2 + 10.0.0.7 + 1 + 180 + 60 + + + ARISTA05T0 + 10.0.0.41 + sonic + 10.0.0.40 + 1 + 180 + 60 + + + sonic + 10.0.0.8 + ARISTA05T2 + 10.0.0.9 + 1 + 180 + 60 + + + ARISTA06T0 + 10.0.0.43 + sonic + 10.0.0.42 + 1 + 180 + 60 + + + sonic + 10.0.0.10 + ARISTA06T2 + 10.0.0.11 + 1 + 180 + 60 + + + ARISTA07T0 + 10.0.0.45 + sonic + 10.0.0.44 + 1 + 180 + 60 + + + sonic + 10.0.0.12 + ARISTA07T2 + 10.0.0.13 + 1 + 180 + 60 + + + ARISTA08T0 + 10.0.0.47 + sonic + 10.0.0.46 + 1 + 180 + 60 + + + sonic + 10.0.0.14 + ARISTA08T2 + 10.0.0.15 + 1 + 180 + 60 + + + ARISTA09T0 + 10.0.0.49 + sonic + 10.0.0.48 + 1 + 180 + 60 + + + sonic + 10.0.0.16 + ARISTA09T2 + 10.0.0.17 + 1 + 180 + 60 + + + ARISTA10T0 + 10.0.0.51 + sonic + 10.0.0.50 + 1 + 180 + 60 + + + sonic + 10.0.0.18 + ARISTA10T2 + 10.0.0.19 + 1 + 180 + 60 + + + ARISTA11T0 + 10.0.0.53 + sonic + 10.0.0.52 + 1 + 180 + 60 + + + sonic + 10.0.0.20 + ARISTA11T2 + 10.0.0.21 + 1 + 180 + 60 + + + ARISTA12T0 + 10.0.0.55 + sonic + 10.0.0.54 + 1 + 180 + 60 + + + sonic + 10.0.0.22 + ARISTA12T2 + 10.0.0.23 + 1 + 180 + 60 + + + ARISTA13T0 + 10.0.0.57 + sonic + 10.0.0.56 + 1 + 180 + 60 + + + sonic + 10.0.0.24 + ARISTA13T2 + 10.0.0.25 + 1 + 180 + 60 + + + ARISTA14T0 + 10.0.0.59 + sonic + 10.0.0.58 + 1 + 180 + 60 + + + sonic + 10.0.0.26 + ARISTA14T2 + 10.0.0.27 + 1 + 180 + 60 + + + ARISTA15T0 + 10.0.0.61 + sonic + 10.0.0.60 + 1 + 180 + 60 + + + sonic + 10.0.0.28 + ARISTA15T2 + 10.0.0.29 + 1 + 180 + 60 + + + ARISTA16T0 + 10.0.0.63 + sonic + 10.0.0.62 + 1 + 180 + 60 + + + sonic + 10.0.0.30 + ARISTA16T2 + 10.0.0.31 + 1 + 180 + 60 + + + + + 65100 + sonic + + +
10.0.0.33
+ + +
+ +
10.0.0.1
+ + +
+ +
10.0.0.35
+ + +
+ +
10.0.0.3
+ + +
+ +
10.0.0.37
+ + +
+ +
10.0.0.5
+ + +
+ +
10.0.0.39
+ + +
+ +
10.0.0.7
+ + +
+ +
10.0.0.41
+ + +
+ +
10.0.0.9
+ + +
+ +
10.0.0.43
+ + +
+ +
10.0.0.11
+ + +
+ +
10.0.0.45
+ + +
+ +
10.0.0.13
+ + +
+ +
10.0.0.47
+ + +
+ +
10.0.0.15
+ + +
+ +
10.0.0.49
+ + +
+ +
10.0.0.17
+ + +
+ +
10.0.0.51
+ + +
+ +
10.0.0.19
+ + +
+ +
10.0.0.53
+ + +
+ +
10.0.0.21
+ + +
+ +
10.0.0.55
+ + +
+ +
10.0.0.23
+ + +
+ +
10.0.0.57
+ + +
+ +
10.0.0.25
+ + +
+ +
10.0.0.59
+ + +
+ +
10.0.0.27
+ + +
+ +
10.0.0.61
+ + +
+ +
10.0.0.29
+ + +
+ +
10.0.0.63
+ + +
+ +
10.0.0.31
+ + +
+
+ +
+ + 64001 + ARISTA01T0 + + + + 65200 + ARISTA01T2 + + + + 64002 + ARISTA02T0 + + + + 65200 + ARISTA02T2 + + + + 64003 + ARISTA03T0 + + + + 65200 + ARISTA03T2 + + + + 64004 + ARISTA04T0 + + + + 65200 + ARISTA04T2 + + + + 64005 + ARISTA05T0 + + + + 65200 + ARISTA05T2 + + + + 64006 + ARISTA06T0 + + + + 65200 + ARISTA06T2 + + + + 64007 + ARISTA07T0 + + + + 65200 + ARISTA07T2 + + + + 64008 + ARISTA08T0 + + + + 65200 + ARISTA08T2 + + + + 64009 + ARISTA09T0 + + + + 65200 + ARISTA09T2 + + + + 64010 + ARISTA10T0 + + + + 65200 + ARISTA10T2 + + + + 64011 + ARISTA11T0 + + + + 65200 + ARISTA11T2 + + + + 64012 + ARISTA12T0 + + + + 65200 + ARISTA12T2 + + + + 64013 + ARISTA13T0 + + + + 65200 + ARISTA13T2 + + + + 64014 + ARISTA14T0 + + + + 65200 + ARISTA14T2 + + + + 64015 + ARISTA15T0 + + + + 65200 + ARISTA15T2 + + + + 64016 + ARISTA16T0 + + + + 65200 + ARISTA16T2 + + +
+
+ + + + + + HostIP + Loopback0 + + 10.1.0.32/32 + + 10.1.0.32/32 + + + + + + + + sonic + + + + + + QSFP1 + 10.0.0.0/31 + + + + QSFP2 + 10.0.0.2/31 + + + + QSFP3 + 10.0.0.4/31 + + + + QSFP4 + 10.0.0.6/31 + + + + QSFP5 + 10.0.0.8/31 + + + + QSFP6 + 10.0.0.10/31 + + + + QSFP7 + 10.0.0.12/31 + + + + QSFP8 + 10.0.0.14/31 + + + + QSFP9 + 10.0.0.16/31 + + + + QSFP10 + 10.0.0.18/31 + + + + QSFP11 + 10.0.0.20/31 + + + + QSFP12 + 10.0.0.22/31 + + + + QSFP13 + 10.0.0.24/31 + + + + QSFP14 + 10.0.0.26/31 + + + + QSFP15 + 10.0.0.28/31 + + + + QSFP16 + 10.0.0.30/31 + + + + QSFP17 + 10.0.0.32/31 + + + + QSFP18 + 10.0.0.34/31 + + + + QSFP19 + 10.0.0.36/31 + + + + QSFP20 + 10.0.0.38/31 + + + + QSFP21 + 10.0.0.40/31 + + + + QSFP22 + 10.0.0.42/31 + + + + QSFP23 + 10.0.0.44/31 + + + + QSFP24 + 10.0.0.46/31 + + + + QSFP25 + 10.0.0.48/31 + + + + QSFP26 + 10.0.0.50/31 + + + + QSFP27 + 10.0.0.52/31 + + + + QSFP28 + 10.0.0.54/31 + + + + QSFP29 + 10.0.0.56/31 + + + + QSFP30 + 10.0.0.58/31 + + + + QSFP31 + 10.0.0.60/31 + + + + QSFP32 + 10.0.0.62/31 + + + + QSFP33 + 10.0.0.64/31 + + + + QSFP34 + 10.0.0.66/31 + + + + QSFP35 + 10.0.0.68/31 + + + + QSFP36 + 10.0.0.70/31 + + + + QSFP37 + 10.0.0.72/31 + + + + QSFP38 + 10.0.0.74/31 + + + + QSFP39 + 10.0.0.76/31 + + + + QSFP40 + 10.0.0.78/31 + + + + QSFP41 + 10.0.0.80/31 + + + + QSFP42 + 10.0.0.82/31 + + + + QSFP43 + 10.0.0.84/31 + + + + QSFP44 + 10.0.0.86/31 + + + + QSFP45 + 10.0.0.88/31 + + + + QSFP46 + 10.0.0.90/31 + + + + QSFP47 + 10.0.0.92/31 + + + + QSFP48 + 10.0.0.94/31 + + + + QSFP49 + 10.0.0.96/31 + + + + QSFP50 + 10.0.0.98/31 + + + + QSFP51 + 10.0.0.100/31 + + + + QSFP52 + 10.0.0.102/31 + + + + QSFP53 + 10.0.0.104/31 + + + + QSFP54 + 10.0.0.106/31 + + + + QSFP55 + 10.0.0.108/31 + + + + QSFP56 + 10.0.0.110/31 + + + + QSFP57 + 10.0.0.112/31 + + + + QSFP58 + 10.0.0.114/31 + + + + QSFP59 + 10.0.0.116/31 + + + + QSFP60 + 10.0.0.118/31 + + + + QSFP61 + 10.0.0.120/31 + + + + QSFP62 + 10.0.0.122/31 + + + + QSFP63 + 10.0.0.124/31 + + + + QSFP64 + 10.0.0.126/31 + + + + QSFP65 + 10.0.1.0/31 + + + + QSFP66 + 10.0.1.2/31 + + + + QSFP67 + 10.0.1.4/31 + + + + QSFP68 + 10.0.1.6/31 + + + + QSFP69 + 10.0.1.8/31 + + + + QSFP70 + 10.0.1.10/31 + + + + QSFP71 + 10.0.1.12/31 + + + + QSFP72 + 10.0.1.14/31 + + + + QSFP73 + 10.0.1.16/31 + + + + QSFP74 + 10.0.1.18/31 + + + + QSFP75 + 10.0.1.20/31 + + + + QSFP76 + 10.0.1.22/31 + + + + QSFP77 + 10.0.1.24/31 + + + + QSFP78 + 10.0.1.26/31 + + + + QSFP79 + 10.0.1.28/31 + + + + QSFP80 + 10.0.1.30/31 + + + + QSFP81 + 10.0.1.32/31 + + + + QSFP82 + 10.0.1.34/31 + + + + QSFP83 + 10.0.1.36/31 + + + + QSFP84 + 10.0.1.38/31 + + + + QSFP85 + 10.0.1.40/31 + + + + QSFP86 + 10.0.1.42/31 + + + + QSFP87 + 10.0.1.44/31 + + + + QSFP88 + 10.0.1.46/31 + + + + QSFP89 + 10.0.1.48/31 + + + + QSFP90 + 10.0.1.50/31 + + + + QSFP91 + 10.0.1.52/31 + + + + QSFP92 + 10.0.1.54/31 + + + + QSFP93 + 10.0.1.56/31 + + + + QSFP94 + 10.0.1.58/31 + + + + QSFP95 + 10.0.1.60/31 + + + + QSFP96 + 10.0.1.62/31 + + + + QSFP97 + 10.0.1.64/31 + + + + QSFP98 + 10.0.1.66/31 + + + + QSFP99 + 10.0.1.68/31 + + + + QSFP100 + 10.0.1.70/31 + + + + QSFP101 + 10.0.1.72/31 + + + + QSFP102 + 10.0.1.74/31 + + + + QSFP103 + 10.0.1.76/31 + + + + QSFP104 + 10.0.1.78/31 + + + + QSFP105 + 10.0.1.80/31 + + + + QSFP106 + 10.0.1.82/31 + + + + QSFP107 + 10.0.1.84/31 + + + + QSFP108 + 10.0.1.86/31 + + + + QSFP109 + 10.0.1.88/31 + + + + QSFP110 + 10.0.1.90/31 + + + + QSFP111 + 10.0.1.92/31 + + + + QSFP112 + 10.0.1.94/31 + + + + QSFP113 + 10.0.1.96/31 + + + + QSFP114 + 10.0.1.98/31 + + + + QSFP115 + 10.0.1.100/31 + + + + QSFP116 + 10.0.1.102/31 + + + + QSFP117 + 10.0.1.104/31 + + + + QSFP118 + 10.0.1.106/31 + + + + QSFP119 + 10.0.1.108/31 + + + + QSFP120 + 10.0.1.110/31 + + + + QSFP121 + 10.0.1.112/31 + + + + QSFP122 + 10.0.1.114/31 + + + + QSFP123 + 10.0.1.116/31 + + + + QSFP124 + 10.0.1.118/31 + + + + QSFP125 + 10.0.1.120/31 + + + + QSFP126 + 10.0.1.122/31 + + + + QSFP127 + 10.0.1.124/31 + + + + QSFP128 + 10.0.1.126/31 + + + + + + + + + + + + sonic + AS14-128H + + + + + + + sonic + + + DhcpResources + + + + + NtpResources + + 0.debian.pool.ntp.org;1.debian.pool.ntp.org;2.debian.pool.ntp.org;3.debian.pool.ntp.org + + + SyslogResources + + + + + ErspanDestinationIpv4 + + 2.2.2.2 + + + + + + + sonic + AS14-128H +
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/opennsl-postinit.cfg b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/opennsl-postinit.cfg new file mode 100644 index 000000000000..7008c14c0ffc --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/opennsl-postinit.cfg @@ -0,0 +1,3 @@ +linkscan 250000; port xe,ce linkscan=on +sleep 1 +led auto on; led start diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/cputemputil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/cputemputil.py new file mode 100644 index 000000000000..ac2589d044fd --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/cputemputil.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# +# cputemputil.py +# +# Platform-specific CPU temperature Interface for SONiC +# + +__author__ = 'Wirut G.' +__license__ = "GPL" +__version__ = "0.1.0" +__status__ = "Development" + + +import subprocess +import requests + + +class CpuTempUtil(): + """Platform-specific CpuTempUtil class""" + + def __init__(self): + pass + + def get_cpu_temp(self): + + # Get list of temperature of CPU cores. + p = subprocess.Popen(['sensors', '-Au', 'coretemp-isa-0000'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = p.communicate() + raw_data_list = out.splitlines() + temp_string_list = [i for i, s in enumerate( + raw_data_list) if '_input' in s] + tmp_list = [0] + + for temp_string in temp_string_list: + tmp_list.append(float(raw_data_list[temp_string].split(":")[1])) + + return tmp_list + + def get_max_cpu_tmp(self): + # Get maximum temperature from list of temperature of CPU cores. + return max(self.get_cpu_temp()) diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/eeprom.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/eeprom.py new file mode 100644 index 000000000000..46559439061d --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/eeprom.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica PHALANX +# +# 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/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fanutil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fanutil.py new file mode 100644 index 000000000000..7c37088b927e --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fanutil.py @@ -0,0 +1,309 @@ +#!/usr/bin/env python + +__author__ = 'Wirut G.' +__license__ = "GPL" +__version__ = "0.1.2" +__status__ = "Development" + +import requests +import re + + +class FanUtil(): + """Platform-specific FanUtil class""" + + def __init__(self): + + self.fan_fru_url = "http://240.1.1.1:8080/api/sys/fruid/fan" + self.sensor_url = "http://240.1.1.1:8080/api/sys/sensors" + self.fru_data_list = None + self.sensor_data_list = None + + def request_data(self): + # Reqest data from BMC if not exist. + if self.fru_data_list is None or self.sensor_data_list is None: + fru_data_req = requests.get(self.fan_fru_url) + sensor_data_req = requests.get(self.sensor_url) + fru_json = fru_data_req.json() + sensor_json = sensor_data_req.json() + self.fru_data_list = fru_json.get('Information') + self.sensor_data_list = sensor_json.get('Information') + return self.fru_data_list, self.sensor_data_list + + def name_to_index(self, fan_name): + # Get fan index from fan name + match = re.match(r"(FAN)([0-9]+)-(1|2)", fan_name, re.I) + fan_index = None + if match: + i_list = list(match.groups()) + fan_index = int(i_list[1])*2 - (int(i_list[2]) % 2) + return fan_index + + def get_num_fans(self): + """ + Get the number of fans + :return: int num_fans + """ + num_fans = 10 + + return num_fans + + def get_fan_speed(self, fan_name): + """ + Get the current speed of the fan, the unit is "RPM" + :return: int fan_speed + """ + + try: + # Get real fan index + index = self.name_to_index(fan_name) + + # Set key and index. + fan_speed = 0 + position_key = "Front" if index % 2 != 0 else "Rear" + index = int(round(float(index)/2)) + fan_key = "Fan " + str(index) + " " + position_key + + # Request and validate fan information. + self.fru_data_list, self.sensor_data_list = self.request_data() + + # Get fan's speed. + for sensor_data in self.sensor_data_list: + sensor_name = sensor_data.get('name') + if "fan" in str(sensor_name): + fan_data = sensor_data.get(fan_key) + fan_sp_list = map(int, re.findall(r'\d+', fan_data)) + fan_speed = fan_sp_list[0] + + except: + return 0 + + return fan_speed + + def get_fan_low_threshold(self, fan_name): + """ + Get the low speed threshold of the fan. + if the current speed < low speed threshold, + the status of the fan is not ok. + :return: int fan_low_threshold + """ + + try: + # Get real fan index + index = self.name_to_index(fan_name) + + # Set key and index. + fan_low_threshold = 0 + position_key = "Front" if index % 2 != 0 else "Rear" + index = int(round(float(index)/2)) + fan_key = "Fan " + str(index) + " " + position_key + + # Request and validate fan information. + self.fru_data_list, self.sensor_data_list = self.request_data() + + # Get fan's threshold. + for sensor_data in self.sensor_data_list: + sensor_name = sensor_data.get('name') + if "fan" in str(sensor_name): + fan_data = sensor_data.get(fan_key) + fan_sp_list = map(int, re.findall(r'\d+', fan_data)) + fan_low_threshold = fan_sp_list[1] + + except: + return "N/A" + + return fan_low_threshold + + def get_fan_high_threshold(self, fan_name): + """ + Get the hight speed threshold of the fan, + if the current speed > high speed threshold, + the status of the fan is not ok + :return: int fan_high_threshold + """ + + try: + # Get real fan index + index = self.name_to_index(fan_name) + + # Set key and index. + fan_high_threshold = 0 + position_key = "Front" if index % 2 != 0 else "Rear" + index = int(round(float(index)/2)) + fan_key = "Fan " + str(index) + " " + position_key + + # Request and validate fan information. + self.fru_data_list, self.sensor_data_list = self.request_data() + + # Get fan's threshold. + for sensor_data in self.sensor_data_list: + sensor_name = sensor_data.get('name') + if "fan" in str(sensor_name): + fan_data = sensor_data.get(fan_key) + fan_sp_list = map(int, re.findall(r'\d+', fan_data)) + fan_high_threshold = fan_sp_list[2] + + except: + return 0 + + return fan_high_threshold + + def get_fan_pn(self, fan_name): + """ + Get the product name of the fan + :return: str fan_pn + """ + + try: + # Get real fan index + index = self.name_to_index(fan_name) + + # Set key and index. + fan_pn = "N/A" + index = int(round(float(index)/2)) + fan_fru_key = "Fantray" + str(index) + + # Request and validate fan information. + self.fru_data_list, self.sensor_data_list = self.request_data() + + # Get fan's fru. + for fan_fru in self.fru_data_list: + matching_fan = [s for s in fan_fru if fan_fru_key in s] + if matching_fan: + pn = [s for s in fan_fru if "Part" in s] + fan_pn = pn[0].split()[4] + + except: + return "N/A" + + return fan_pn + + def get_fan_sn(self, fan_name): + """ + Get the serial number of the fan + :return: str fan_sn + """ + try: + # Get real fan index + index = self.name_to_index(fan_name) + + # Set key and index. + fan_sn = "N/A" + index = int(round(float(index)/2)) + fan_fru_key = "Fantray" + str(index) + + # Request and validate fan information. + self.fru_data_list, self.sensor_data_list = self.request_data() + + # Get fan's fru. + for fan_fru in self.fru_data_list: + matching_fan = [s for s in fan_fru if fan_fru_key in s] + if matching_fan: + serial = [s for s in fan_fru if "Serial" in s] + fan_sn = serial[0].split()[3] + + except: + return "N/A" + + return fan_sn + + def get_fans_name_list(self): + """ + Get list of fan name. + :return: list fan_names + """ + fan_names = [] + + # Get the number of fans + n_fan = self.get_num_fans() + + # Set fan name and add to the list. + for x in range(1, n_fan + 1): + f_index = int(round(float(x)/2)) + pos = 1 if x % 2 else 2 + fan_name = 'FAN{}_{}'.format(f_index, pos) + fan_names.append(fan_name) + + return fan_names + + def get_all(self): + """ + Get all information of system FANs, returns JSON objects in python 'DICT'. + Number, mandatory, max number of FAN, integer + FAN1_1, FAN1_2, ... mandatory, FAN name, string + Present, mandatory for each FAN, present status, boolean, True for present, False for NOT present, read directly from h/w + Running, conditional, if PRESENT is True, running status of the FAN, True for running, False for stopped, read directly from h/w + Speed, conditional, if PRESENT is True, real FAN speed, float, read directly from h/w + LowThd, conditional, if PRESENT is True, lower bound of FAN speed, float, read from h/w + HighThd, conditional, if PRESENT is True, upper bound of FAN speed, float, read from h/w + PN, conditional, if PRESENT is True, PN of the FAN, string + SN, conditional, if PRESENT is True, SN of the FAN, string) + """ + + self.fru_data_list, self.sensor_data_list = self.request_data() + all_fan_dict = dict() + + # Get the number of fans + n_fan = self.get_num_fans() + all_fan_dict["Number"] = n_fan + + # Set fan FRU data. + fan_fru_dict = dict() + fan_raw_idx = 1 + for fan_fru in self.fru_data_list: + fru_dict = dict() + fan_ps = False + + if len(fan_fru) == 0: + fan_idx = fan_raw_idx + fan_pn = "N/A" + fan_sn = "N/A" + else: + fan_key = fan_fru[0].split() + if str(fan_key[-1]).lower() == "absent": + fan_idx = int(re.findall('\d+', fan_key[0])[0]) + + else: + fan_idx = int(re.findall('\d+', fan_key[-1])[0]) + fan_ps = True + pn = [s for s in fan_fru if "Part" in s] + sn = [s for s in fan_fru if "Serial" in s] + fan_pn = pn[0].split( + ":")[-1].strip() if len(pn) > 0 else 'N/A' + fan_sn = sn[0].split( + ":")[-1].strip() if len(sn) > 0 else 'N/A' + + fru_dict["PN"] = "N/A" if not fan_pn or fan_pn == "" else fan_pn + fru_dict["SN"] = "N/A" if not fan_sn or fan_sn == "" else fan_sn + fru_dict["Present"] = fan_ps + fan_fru_dict[fan_idx] = fru_dict + fan_raw_idx += 1 + + # Set fan sensor data. + for sensor_data in self.sensor_data_list: + sensor_name = sensor_data.get('name') + if "fan" in str(sensor_name): + for x in range(1, n_fan + 1): + fan_dict = dict() + f_index = int(round(float(x)/2)) + pos = 1 if x % 2 else 2 + position_key = "Front" if x % 2 != 0 else "Rear" + fan_key = "Fan " + str(f_index) + " " + position_key + fan_data = sensor_data.get(fan_key) + fan_sp_list = map(int, re.findall(r'\d+', fan_data)) + fan_dict["Present"] = fan_fru_dict[f_index]["Present"] + if fan_dict["Present"] or fan_sp_list[0] > 0: + fan_dict["Present"] = True + fan_dict["Speed"] = fan_sp_list[0] + fan_dict["Running"] = True if fan_dict["Speed"] > 0 else False + fan_dict["LowThd"] = fan_sp_list[1] + fan_dict["HighThd"] = fan_sp_list[2] + fan_dict["PN"] = fan_fru_dict[f_index]["PN"] + fan_dict["SN"] = fan_fru_dict[f_index]["SN"] + fan_dict["AirFlow"] = "FTOB" if "R1240-G0009" in fan_dict["PN"] else "Unknown" + fan_dict["Status"] = True if fan_dict["AirFlow"] != "Unknown" else False + fan_name = 'FAN{}_{}'.format(f_index, pos) + all_fan_dict[fan_name] = fan_dict + break + + return all_fan_dict diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fwmgrutil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fwmgrutil.py new file mode 100644 index 000000000000..619aa7b173f3 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fwmgrutil.py @@ -0,0 +1,882 @@ +# fwmgrutil.py +# +# Platform-specific firmware management interface for SONiC +# + +import subprocess +import requests +import os +import pexpect +import base64 +import time +import json +import logging +import ast +from datetime import datetime + +try: + from sonic_fwmgr.fwgmr_base import FwMgrUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class FwMgrUtil(FwMgrUtilBase): + + """Platform-specific FwMgrUtil class""" + + def __init__(self): + self.platform_name = "AS23128h" + self.onie_config_file = "/host/machine.conf" + self.bmc_info_url = "http://240.1.1.1:8080/api/sys/bmc" + self.bmc_raw_command_url = "http://240.1.1.1:8080/api/sys/raw" + self.fw_upgrade_url = "http://240.1.1.1:8080/api/sys/upgrade" + self.onie_config_file = "/host/machine.conf" + self.fw_upgrade_logger_path = "/var/log/fw_upgrade.log" + self.cpldb_version_path = "/sys/devices/platform/%s.cpldb/getreg" % self.platform_name + self.fpga_version_path = "/sys/devices/platform/%s.switchboard/FPGA/getreg" % self.platform_name + self.switchboard_cpld1_path = "/sys/devices/platform/%s.switchboard/CPLD1/getreg" % self.platform_name + self.switchboard_cpld2_path = "/sys/devices/platform/%s.switchboard/CPLD2/getreg" % self.platform_name + self.switchboard_cpld3_path = "/sys/devices/platform/%s.switchboard/CPLD3/getreg" % self.platform_name + self.switchboard_cpld4_path = "/sys/devices/platform/%s.switchboard/CPLD4/getreg" % self.platform_name + self.bmc_pwd_path = "/usr/local/etc/bmcpwd" + + def __get_register_value(self, path, register): + cmd = "echo {1} > {0}; cat {0}".format(path, register) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err is not '': + return 'None' + else: + return raw_data.strip() + + def __update_fw_upgrade_logger(self, header, message): + if not os.path.isfile(self.fw_upgrade_logger_path): + cmd = "sudo touch %s && sudo chmod +x %s" % ( + self.fw_upgrade_logger_path, self.fw_upgrade_logger_path) + subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + logging.basicConfig(filename=self.fw_upgrade_logger_path, + filemode='a', + format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s', + datefmt='%b %d %H:%M:%S', + level=logging.INFO) + + log_message = "%s : %s" % (header, message) + if header != "last_upgrade_result": + print(log_message) + return logging.info(log_message) + + def get_bmc_pass(self): + if os.path.exists(self.bmc_pwd_path): + with open(self.bmc_pwd_path) as file: + data = file.read() + + key = "bmc" + dec = [] + enc = base64.urlsafe_b64decode(data) + for i in range(len(enc)): + key_c = key[i % len(key)] + dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256) + dec.append(dec_c) + return "".join(dec) + return False + + def get_bmc_version(self): + """Get BMC version from SONiC + :returns: version string + + """ + bmc_version = None + + bmc_version_key = "OpenBMC Version" + bmc_info_req = requests.get(self.bmc_info_url, timeout=60) + if bmc_info_req.status_code == 200: + bmc_info_json = bmc_info_req.json() + bmc_info = bmc_info_json.get('Information') + bmc_version = bmc_info.get(bmc_version_key) + return str(bmc_version) + + def upload_file_bmc(self, fw_path): + scp_command = 'sudo scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -r %s root@240.1.1.1:/home/root/' % os.path.abspath( + fw_path) + child = pexpect.spawn(scp_command) + i = child.expect(["root@240.1.1.1's password:"], timeout=30) + bmc_pwd = self.get_bmc_pass() + if i == 0 and bmc_pwd: + child.sendline(bmc_pwd) + data = child.read() + print(data) + child.close + return os.path.isfile(fw_path) + return False + + def get_cpld_version(self): + """Get CPLD version from SONiC + :returns: dict like {'CPLD_1': version_string, 'CPLD_2': version_string} + """ + + CPLD_B = self.__get_register_value(self.cpldb_version_path, '0xA100') + CPLD_C = self.__get_register_value(self.cpldb_version_path, '0xA1E0') + CPLD_1 = self.__get_register_value(self.switchboard_cpld1_path, '0x00') + CPLD_2 = self.__get_register_value(self.switchboard_cpld2_path, '0x00') + CPLD_3 = self.__get_register_value(self.switchboard_cpld3_path, '0x00') + CPLD_4 = self.__get_register_value(self.switchboard_cpld4_path, '0x00') + + fan_cpld_key = "FanCPLD Version" + fan_cpld = None + bmc_info_req = requests.get(self.bmc_info_url) + if bmc_info_req.status_code == 200: + bmc_info_json = bmc_info_req.json() + bmc_info = bmc_info_json.get('Information') + fan_cpld = bmc_info.get(fan_cpld_key) + + CPLD_B = 'None' if CPLD_B is 'None' else "{}.{}".format( + int(CPLD_B[2], 16), int(CPLD_B[3], 16)) + CPLD_C = 'None' if CPLD_C is 'None' else "{}.{}".format( + int(CPLD_C[2], 16), int(CPLD_C[3], 16)) + CPLD_1 = 'None' if CPLD_1 is 'None' else "{}.{}".format( + int(CPLD_1[2], 16), int(CPLD_1[3], 16)) + CPLD_2 = 'None' if CPLD_2 is 'None' else "{}.{}".format( + int(CPLD_2[2], 16), int(CPLD_2[3], 16)) + CPLD_3 = 'None' if CPLD_3 is 'None' else "{}.{}".format( + int(CPLD_3[2], 16), int(CPLD_3[3], 16)) + CPLD_4 = 'None' if CPLD_4 is 'None' else "{}.{}".format( + int(CPLD_4[2], 16), int(CPLD_4[3], 16)) + FAN_CPLD = 'None' if fan_cpld is None else "{}.{}".format( + int(fan_cpld[0], 16), int(fan_cpld[1], 16)) + + cpld_version_dict = {} + cpld_version_dict.update({'CPLD_B': CPLD_B}) + cpld_version_dict.update({'CPLD_C': CPLD_C}) + cpld_version_dict.update({'CPLD_1': CPLD_1}) + cpld_version_dict.update({'CPLD_2': CPLD_2}) + cpld_version_dict.update({'CPLD_3': CPLD_3}) + cpld_version_dict.update({'CPLD_4': CPLD_4}) + cpld_version_dict.update({'CPLD_FAN': FAN_CPLD}) + + return cpld_version_dict + + def get_bios_version(self): + """Get BIOS version from SONiC + :returns: version string + + """ + bios_version = None + + p = subprocess.Popen( + ["sudo", "dmidecode", "-s", "bios-version"], stdout=subprocess.PIPE) + raw_data = str(p.communicate()[0]) + if raw_data == '': + return str(None) + raw_data_list = raw_data.split("\n") + bios_version = raw_data_list[0] if len( + raw_data_list) == 1 else raw_data_list[-2] + + return str(bios_version) + + def get_onie_version(self): + """Get ONiE version from SONiC + :returns: version string + + """ + onie_verison = None + + onie_version_keys = "onie_version" + onie_config_file = open(self.onie_config_file, "r") + for line in onie_config_file.readlines(): + if onie_version_keys in line: + onie_version_raw = line.split('=') + onie_verison = onie_version_raw[1].strip() + break + onie_config_file.close() + return str(onie_verison) + + def get_pcie_version(self): + """Get PCiE version from SONiC + :returns: version dict { "PCIE_FW_LOADER": "2.5", "PCIE_FW": "D102_08" } + + """ + cmd = "sudo bcmcmd 'pciephy fw version'" + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + + pcie_version = dict() + pcie_version["PCIE_FW_LOADER"] = 'None' + pcie_version["PCIE_FW"] = 'None' + + if err == '': + lines = raw_data.split('\n') + for line in lines: + if 'PCIe FW loader' in line: + pcie_version["PCIE_FW_LOADER"] = line.split(':')[1].strip() + elif 'PCIe FW version' in line: + pcie_version["PCIE_FW"] = line.split(':')[1].strip() + return pcie_version + + def get_fpga_version(self): + """Get FPGA version from SONiC + :returns: version string + + """ + version = self.__get_register_value(self.fpga_version_path, '0x00') + if version is not 'None': + version = "{}.{}".format( + int(version[2:][:4], 16), int(version[2:][4:], 16)) + return str(version) + + def firmware_upgrade(self, fw_type, fw_path, fw_extra=None): + """ + @fw_type MANDATORY, firmware type, should be one of the strings: 'cpld', 'fpga', 'bios', 'bmc' + @fw_path MANDATORY, target firmware file + @fw_extra OPTIONAL, extra information string, + + for fw_type 'cpld' and 'fpga': it can be used to indicate specific cpld, such as 'cpld1', 'cpld2', ... + or 'cpld_fan_come_board', etc. If None, upgrade all CPLD/FPGA firmware. for fw_type 'bios' and 'bmc', + value should be one of 'master' or 'slave' or 'both' + """ + fw_type = fw_type.lower() + bmc_pwd = self.get_bmc_pass() + if not bmc_pwd and fw_type != "fpga": + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=BMC credential not found") + return False + + if fw_type == 'bmc': + self.__update_fw_upgrade_logger( + "bmc_upgrade", "start BMC upgrade") + # Copy BMC image file to BMC + fw_extra_str = str(fw_extra).lower() + last_fw_upgrade = ["BMC", fw_path, fw_extra_str, "FAILED"] + upload_file = self.upload_file_bmc(fw_path) + if not upload_file: + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=unable to upload BMC image to BMC") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + filename_w_ext = os.path.basename(fw_path) + json_data = dict() + json_data["path"] = "root@127.0.0.1:/home/root/%s" % filename_w_ext + json_data["password"] = bmc_pwd + + # Set flash type + current_bmc = self.get_running_bmc() + flash = fw_extra_str if fw_extra_str in [ + "master", "slave", "both"] else "both" + if fw_extra_str == "pingpong": + #flash = "master" if current_bmc == "slave" else "slave" + flash = "slave" + json_data["flash"] = flash + + # Install BMC + if flash == "both": + self.__update_fw_upgrade_logger( + "bmc_upgrade", "install BMC as master mode") + json_data["flash"] = "master" + r = requests.post(self.bmc_info_url, json=json_data) + if r.status_code != 200 or 'success' not in r.json().get('result'): + self.__update_fw_upgrade_logger( + "bmc_upgrade", "fail, message=BMC API report error code %d" % r.status_code) + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + json_data["flash"] = "slave" + + self.__update_fw_upgrade_logger( + "bmc_upgrade", "install BMC as %s mode" % json_data["flash"]) + r = requests.post(self.bmc_info_url, json=json_data) + if r.status_code == 200 and 'success' in r.json().get('result'): + if fw_extra_str == "pingpong": + flash = "master" if current_bmc == "slave" else "slave" + self.__update_fw_upgrade_logger( + "bmc_upgrade", "switch to boot from %s" % flash) + self.set_bmc_boot_flash(flash) + self.__update_fw_upgrade_logger( + "bmc_upgrade", "reboot BMC") + if not self.reboot_bmc(): + return False + else: + self.__update_fw_upgrade_logger( + "bmc_upgrade", "reboot BMC") + reboot_dict = {} + reboot_dict["reboot"] = "yes" + r = requests.post(self.bmc_info_url, json=reboot_dict) + last_fw_upgrade[3] = "DONE" + else: + self.__update_fw_upgrade_logger( + "bmc_upgrade", "fail, message=unable to install BMC image") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + self.__update_fw_upgrade_logger( + "bmc_upgrade", "done") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return True + + elif fw_type == 'fpga': + last_fw_upgrade = ["FPGA", fw_path, None, "FAILED"] + self.__update_fw_upgrade_logger( + "fpga_upgrade", "start FPGA upgrade") + + if not os.path.isfile(fw_path): + self.__update_fw_upgrade_logger( + "fpga_upgrade", "fail, message=FPGA image not found %s" % fw_path) + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + command = 'fpga_prog ' + fw_path + print("Running command : %s" % command) + process = subprocess.Popen( + command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + + rc = process.returncode + if rc != 0: + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=unable to install FPGA") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + self.__update_fw_upgrade_logger("fpga_upgrade", "done") + last_fw_upgrade[3] = "DONE" + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + self.firmware_refresh(["FPGA"], None, None) + return True + + elif 'cpld' in fw_type: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "start CPLD upgrade") + # Check input + fw_extra_str = str(fw_extra).upper() + if ":" in fw_path and ":" in fw_extra_str: + fw_path_list = fw_path.split(":") + fw_extra_str_list = fw_extra_str.split(":") + else: + fw_path_list = [fw_path] + fw_extra_str_list = [fw_extra_str] + + if len(fw_path_list) != len(fw_extra_str_list): + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=invalid input") + return False + + data_list = list(zip(fw_path_list, fw_extra_str_list)) + refresh_img_path = None + cpld_result_list = ["FAILED" for i in range( + 0, len(fw_extra_str_list))] + last_fw_upgrade = ["CPLD", ":".join( + fw_path_list), ":".join(fw_extra_str_list), ":".join(cpld_result_list)] + for i in range(0, len(data_list)): + data = data_list[i] + fw_path = data[0] + fw_extra_str = data[1] + + # Set fw_extra + fw_extra_str = { + "TOP_LC_CPLD": "top_lc", + "BOT_LC_CPLD": "bottom_lc", + "FAN_CPLD": "fan", + "CPU_CPLD": "cpu", + "BASE_CPLD": "base", + "COMBO_CPLD": "combo", + "SW_CPLD1": "switch", + "SW_CPLD2": "switch", + "REFRESH_CPLD": "refresh" + }.get(fw_extra_str, None) + + if fw_extra_str == "refresh": + refresh_img_path = fw_path + del cpld_result_list[i] + del fw_extra_str_list[i] + continue + + if fw_extra_str is None: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=invalid extra information string") + continue + + # Uploading image to BMC + self.__update_fw_upgrade_logger( + "cpld_upgrade", "start %s upgrade" % data[1]) + upload_file = self.upload_file_bmc(fw_path) + if not upload_file: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=unable to upload BMC image to BMC") + continue + + filename_w_ext = os.path.basename(fw_path) + json_data = dict() + json_data["image_path"] = "root@127.0.0.1:/home/root/%s" % filename_w_ext + json_data["password"] = bmc_pwd + json_data["device"] = "cpld" + json_data["reboot"] = "no" + json_data["type"] = fw_extra_str + + # Call BMC api to install cpld image + print("Installing...") + r = requests.post(self.fw_upgrade_url, json=json_data) + if r.status_code != 200 or 'success' not in r.json().get('result'): + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=invalid cpld image") + continue + + cpld_result_list[i] = "DONE" + self.__update_fw_upgrade_logger( + "cpld_upgrade", "%s upgrade done" % data[1]) + last_fw_upgrade[3] = ":".join(cpld_result_list) + self.__update_fw_upgrade_logger( + "cpld_upgrade", "done") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + + # Refresh CPLD + refresh_img_str_list = [] + for fw_extra in fw_extra_str_list: + if "BASE_CPLD" in fw_extra or "FAN_CPLD" in fw_extra: + refresh_img_str_list.append(refresh_img_path) + else: + refresh_img_str_list.append("None") + self.firmware_refresh(None, fw_extra_str_list, + ":".join(refresh_img_str_list)) + + return True + + elif 'bios' in fw_type: + self.__update_fw_upgrade_logger( + "bios_upgrade", "start BIOS upgrade") + last_fw_upgrade = ["BIOS", fw_path, None, "FAILED"] + fw_extra_str = str(fw_extra).lower() + flash = fw_extra_str if fw_extra_str in [ + "master", "slave"] else "master" + + if not os.path.exists(fw_path): + self.__update_fw_upgrade_logger( + "bios_upgrade", "fail, message=image not found") + return False + + scp_command = 'sudo scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -r %s root@240.1.1.1:/home/root/' % os.path.abspath( + fw_path) + child = pexpect.spawn(scp_command) + i = child.expect(["root@240.1.1.1's password:"], timeout=30) + if i != 0: + self.__update_fw_upgrade_logger( + "bios_upgrade", "fail, message=unable to upload image to BMC") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + child.sendline(bmc_pwd) + data = child.read() + print(data) + child.close + + json_data = dict() + json_data["data"] = "/usr/bin/ipmitool -b 1 -t 0x2c raw 0x2e 0xdf 0x57 0x01 0x00 0x01" + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + self.__update_fw_upgrade_logger( + "bios_upgrade", "fail, message=unable to set state") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + filename_w_ext = os.path.basename(fw_path) + json_data = dict() + json_data["image_path"] = "root@127.0.0.1:/home/root/%s" % filename_w_ext + json_data["password"] = bmc_pwd + json_data["device"] = "bios" + json_data["flash"] = flash + json_data["reboot"] = "no" + + print("Installing...") + r = requests.post(self.fw_upgrade_url, json=json_data) + if r.status_code != 200 or 'success' not in r.json().get('result'): + self.__update_fw_upgrade_logger( + "bios_upgrade", "fail, message=unable install bios") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + last_fw_upgrade[3] = "DONE" + self.__update_fw_upgrade_logger( + "bios_upgrade", "done") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + else: + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=invalid firmware type") + return False + + return True + + def get_last_upgrade_result(self): + """ + Get last firmware upgrade information, inlcudes: + 1) FwType: cpld/fpga/bios/bmc(passed by method 'firmware_upgrade'), string + 2) FwPath: path and file name of firmware(passed by method 'firmware_upgrade'), string + 3) FwExtra: designated string, econdings of this string is determined by vendor(passed by method 'firmware_program') + 4) Result: indicates whether the upgrade action is performed and success/failure status if performed. Values should be one of: "DONE"/"FAILED"/"NOT_PERFORMED". + list of object: + [ + { + "FwType": "cpld", + "FwPath": "cpu_cpld.vme" + "FwExtra":"CPU_CPLD" + "Result": "DONE" + }, + { + "FwType": "cpld", + "FwPath": "fan_cpld.vme" + "FwExtra": "FAN_CPLD" + "Result": "FAILED" + } + ] + """ + last_update_list = [] + + if os.path.exists(self.fw_upgrade_logger_path): + with open(self.fw_upgrade_logger_path, 'r') as file: + lines = file.read().splitlines() + + upgrade_txt = [i for i in reversed( + lines) if "last_upgrade_result" in i] + if len(upgrade_txt) > 0: + last_upgrade_txt = upgrade_txt[0].split( + "last_upgrade_result : ") + last_upgrade_list = ast.literal_eval(last_upgrade_txt[1]) + for x in range(0, len(last_upgrade_list[1].split(":"))): + upgrade_dict = {} + upgrade_dict["FwType"] = last_upgrade_list[0].lower() + upgrade_dict["FwPath"] = last_upgrade_list[1].split(":")[x] + upgrade_dict["FwExtra"] = last_upgrade_list[2].split(":")[ + x] if last_upgrade_list[2] else "None" + upgrade_dict["Result"] = last_upgrade_list[3].split(":")[x] + last_update_list.append(upgrade_dict) + + return last_update_list + + def firmware_program(self, fw_type, fw_path, fw_extra=None): + """ + Program FPGA and/or CPLD firmware only, but do not refresh them + + @param fw_type value can be: FPGA, CPLD + @param fw_path a string of firmware file path, seperated by ':', it should + match the sequence of param @fw_type + @param fw_extra a string of firmware subtype, i.e CPU_CPLD, BOARD_CPLD, + FAN_CPLD, LC_CPLD, etc. Subtypes are seperated by ':' + @return True when all required firmware is program succefully, + False otherwise. + + Example: + self.firmware_program("CPLD", "/cpu_cpld.vme:/lc_cpld", \ + "CPU_CPLD:LC_CPLD") + or + self.firmware_program("FPGA", "/fpga.bin") + """ + fw_type = fw_type.lower() + bmc_pwd = self.get_bmc_pass() + if not bmc_pwd and fw_type != "fpga": + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=BMC credential not found") + return False + + if fw_type == 'fpga': + last_fw_upgrade = ["FPGA", fw_path, None, "FAILED"] + self.__update_fw_upgrade_logger( + "fpga_upgrade", "start FPGA upgrade") + + if not os.path.isfile(fw_path): + self.__update_fw_upgrade_logger( + "fpga_upgrade", "fail, message=FPGA image not found %s" % fw_path) + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + command = 'fpga_prog ' + fw_path + print("Running command: %s" % command) + process = subprocess.Popen( + command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + + rc = process.returncode + if rc != 0: + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=Unable to install FPGA") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + self.__update_fw_upgrade_logger("fpga_upgrade", "done") + last_fw_upgrade[3] = "DONE" + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return True + + elif 'cpld' in fw_type: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "start CPLD upgrade") + + # Check input + fw_extra_str = str(fw_extra).upper() + if ":" in fw_path and ":" in fw_extra_str: + fw_path_list = fw_path.split(":") + fw_extra_str_list = fw_extra_str.split(":") + else: + fw_path_list = [fw_path] + fw_extra_str_list = [fw_extra_str] + + if len(fw_path_list) != len(fw_extra_str_list): + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=Invalid input") + return False + + cpld_result_list = [] + data_list = list(zip(fw_path_list, fw_extra_str_list)) + for data in data_list: + fw_path = data[0] + fw_extra_str = data[1] + + # Set fw_extra + fw_extra_str = { + "TOP_LC_CPLD": "top_lc", + "BOT_LC_CPLD": "bottom_lc", + "FAN_CPLD": "fan", + "CPU_CPLD": "cpu", + "BASE_CPLD": "base", + "COMBO_CPLD": "combo", + "SW_CPLD1": "switch", + "SW_CPLD2": "switch" + }.get(fw_extra_str, None) + + self.__update_fw_upgrade_logger( + "cpld_upgrade", "start %s upgrade" % data[1]) + upgrade_result = "FAILED" + for x in range(1, 4): + # Set fw_extra + if x > 1: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=Retry to upgrade %s" % data[1]) + + elif fw_extra_str is None: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=Invalid extra information string %s" % data[1]) + break + elif not os.path.isfile(os.path.abspath(fw_path)): + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=CPLD image not found %s" % fw_path) + break + + # Install cpld image via ispvm tool + print("Installing...") + command = 'ispvm %s' % fw_path + if fw_extra_str in ["top_lc", "bottom_lc"]: + option = 1 if fw_extra_str == "top_lc" else 2 + command = "ispvm -c %d %s" % (option, + os.path.abspath(fw_path)) + print("Running command : %s" % command) + process = subprocess.Popen( + command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + + rc = process.returncode + if rc != 0: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=Unable to install CPLD") + continue + + upgrade_result = "DONE" + self.__update_fw_upgrade_logger("cpld_upgrade", "done") + break + cpld_result_list.append(upgrade_result) + + last_fw_upgrade = ["CPLD", ":".join( + fw_path_list), ":".join(fw_extra_str_list), ":".join(cpld_result_list)] + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return "FAILED" not in cpld_result_list + else: + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=Invalid firmware type") + return False + + return True + + def firmware_refresh(self, fpga_list, cpld_list, fw_extra=None): + """ + Refresh firmware and take extra action when necessary. + @param fpga_list a list of FPGA names + @param cpld_list a list of CPLD names + @return True if refresh succefully and no power cycle action is taken. + + @Note extra action should be: power cycle the whole system(except BMC) when + CPU_CPLD or BOARD_CPLD or FPGA is refreshed. + No operation if the power cycle is not needed. + + Example: + self.firmware_refresh( + ["FPGA"], ["BASE_CPLD", "LC_CPLD"],"/tmp/fw/refresh.vme") + or + self.firmware_refresh(["FPGA"], None, None) + or + self.firmware_refresh(None, ["FAN_CPLD", "LC1_CPLD", "BASE_CPLD"], + "/tmp/fw/fan_refresh.vme:none:/tmp/fw/base_refresh.vme") + """ + + if not fpga_list and not cpld_list: + return False + + if type(cpld_list) is list and ("BASE_CPLD" in cpld_list or "FAN_CPLD" in cpld_list): + refresh_list = fpga_list + \ + cpld_list if type(fpga_list) is list else cpld_list + self.__update_fw_upgrade_logger( + "fw_refresh", "start %s refresh" % ",".join(refresh_list)) + fw_path_list = fw_extra.split(':') + command = "echo " + if len(fw_path_list) != len(cpld_list): + self.__update_fw_upgrade_logger( + "cpld_refresh", "fail, message=Invalid fw_extra") + return False + + for idx in range(0, len(cpld_list)): + fw_path = fw_path_list[idx] + refresh_type = { + "BASE_CPLD": "base", + "FAN_CPLD": "fan" + }.get(cpld_list[idx], None) + + if not refresh_type: + continue + elif not self.upload_file_bmc(fw_path): + self.__update_fw_upgrade_logger( + "cpld_refresh", "fail, message=Unable to upload refresh image to BMC") + return False + else: + filename_w_ext = os.path.basename(fw_path) + + sub_command = "%s /home/root/%s > /tmp/cpld_refresh " % ( + refresh_type, filename_w_ext) + command += sub_command + + json_data = dict() + json_data["data"] = command + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + self.__update_fw_upgrade_logger( + "cpld_refresh", "fail, message=%d Invalid refresh image" % r.status_code) + return False + elif type(cpld_list) is list: + refresh_list = fpga_list + \ + cpld_list if type(fpga_list) is list else cpld_list + self.__update_fw_upgrade_logger( + "fw_refresh", "start %s refresh" % ",".join(refresh_list)) + json_data = dict() + json_data["data"] = "echo cpu_cpld > /tmp/cpld_refresh" + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + self.__update_fw_upgrade_logger( + "cpld_refresh", "fail, message=%d Unable to load new CPLD" % r.status_code) + return False + elif type(fpga_list) is list: + self.__update_fw_upgrade_logger( + "fw_refresh", "start FPGA refresh") + json_data = dict() + json_data["data"] = "echo fpga > /tmp/cpld_refresh" + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + self.__update_fw_upgrade_logger( + "cpld_refresh", "fail, message=%d Unable to load new FPGA" % r.status_code) + return False + else: + self.__update_fw_upgrade_logger( + "fw_refresh", "fail, message=Invalid input") + return False + + self.__update_fw_upgrade_logger("fw_refresh", "done") + return True + + def get_running_bmc(self): + """ + Get booting flash of running BMC. + @return a string, "master" or "slave" + """ + json_data = dict() + json_data["data"] = "/usr/local/bin/boot_info.sh" + r = requests.post(self.bmc_raw_command_url, json=json_data) + try: + boot_info_list = r.json().get('result') + for boot_info_raw in boot_info_list: + boot_info = boot_info_raw.split(":") + if "Current Boot Code Source" in boot_info[0]: + flash = "master" if "master "in boot_info[1].lower( + ) else "slave" + return flash + raise Exception( + "Error: Unable to detect booting flash of running BMC") + except Exception as e: + raise Exception(e) + + def set_bmc_boot_flash(self, flash): + """ + Set booting flash of BMC + @param flash should be "master" or "slave" + """ + if flash.lower() not in ["master", "slave"]: + return False + json_data = dict() + json_data["data"] = "source /usr/local/bin/openbmc-utils.sh;bmc_reboot %s" % flash + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + return False + return True + + def reboot_bmc(self): + """ + Reboot BMC + """ + json_data = dict() + json_data["data"] = "source /usr/local/bin/openbmc-utils.sh;bmc_reboot reboot" + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + return False + return True + + def get_current_bios(self): + """ + # Get booting bios image of current running host OS + # @return a string, "master" or "slave" + """ + json_data = dict() + json_data["data"] = "source /usr/local/bin/openbmc-utils.sh;come_boot_info" + r = requests.post(self.bmc_raw_command_url, json=json_data) + try: + cpu_boot_info_list = r.json().get('result') + for cpu_boot_info_raw in cpu_boot_info_list: + if "COMe CPU boots from BIOS" in cpu_boot_info_raw: + bios_image = "master" if "master "in cpu_boot_info_raw.lower( + ) else "slave" + return bios_image + raise Exception( + "Error: Unable to detect current running bios image") + except Exception as e: + raise Exception(e) diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/optictemputil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/optictemputil.py new file mode 100644 index 000000000000..0e5b6a1c7109 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/optictemputil.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python + +# +# optictemputil.py +# +# Platform-specific Optic module temperature Interface for SONiC +# + +__author__ = 'Pradchaya P.' +__author__ = 'Wirut G.' +__license__ = "GPL" +__version__ = "1.0.0" +__status__ = "Development" + +import os +import sys +import binascii +import subprocess + +class OpticTempUtil(): + """Platform-specific OpticTempUtil class""" + + def __init__(self): + pass + + def read_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes): + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + try: + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + except IOError: + return None + + try: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except: + return None + + return eeprom_raw + + + def twos_comp(self, num, bits): + try: + if ((num & (1 << (bits - 1))) != 0): + num = num - (1 << bits) + return num + except: + return 0 + + + def calc_temperature(self, cal_type, eeprom_data, offset, size): + + msb = int(eeprom_data[offset], 16) + lsb = int(eeprom_data[offset + 1], 16) + + result = (msb << 8) | (lsb & 0xff) + result = self.twos_comp(result, 16) + + if cal_type == 1: + # Internal calibration + result = float(result / 256.0) + retval = '%.4f' %result + + # TODO: Should support external calibration in future. + else: + retval = 0 + + return retval + + ''' TODO: Change busnum to sysfs_sfp_i2c_client_eeprom_path from caller!!! + ''' + def get_optic_temp(self, sysfs_sfp_i2c_client_eeprom_path, port_type): + + EEPROM_ADDR = 0x50 + DOM_ADDR = 0x51 + EEPROM_OFFSET = 0 + DOM_OFFSET = 256 + + SFP_DMT_ADDR = 92 + SFP_DMT_WIDTH = 1 + SFP_TEMP_DATA_ADDR = 96 + SFP_TEMP_DATA_WIDTH = 2 + + QSFP_TEMP_DATA_ADDR = 22 + QSFP_TEMP_DATA_WIDTH = 2 + temperature_raw = None + + + ''' Open file here ''' + try: + sysfsfile_eeprom = open(sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % sysfs_sfp_i2c_client_eeprom_path) + return 0 + + if port_type == 'QSFP': + + # QSFP only have internal calibration mode. + cal_type = 1 + # read temperature raw value + temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(EEPROM_OFFSET+QSFP_TEMP_DATA_ADDR),QSFP_TEMP_DATA_WIDTH) + else: + # read calibration type at bit 5 + cal_type = self.read_eeprom_specific_bytes(sysfsfile_eeprom,EEPROM_OFFSET+SFP_DMT_ADDR,SFP_DMT_WIDTH) + if cal_type is None: + return 0 + else: + cal_type = (int(cal_type[0],16) >> 5 ) & 1 + # read temperature raw value + temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(DOM_OFFSET+SFP_TEMP_DATA_ADDR),SFP_TEMP_DATA_WIDTH) + + try: + sysfsfile_eeprom.close() + except IOError: + print("Error: closing sysfs file %s" % file_path) + return 0 + + #calculate temperature + if temperature_raw is not None: + return self.calc_temperature(cal_type, temperature_raw, 0, 2) + else: + return 0 \ No newline at end of file diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/psuutil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/psuutil.py new file mode 100644 index 000000000000..55c3a41e1f68 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/psuutil.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python + +__author__ = 'Wirut G.' +__license__ = "GPL" +__version__ = "0.1.4" +__status__ = "Development" + +import requests +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): + PsuBase.__init__(self) + self.fru_status_url = "http://240.1.1.1:8080/api/sys/fruid/status" + self.psu_info_url = "http://240.1.1.1:8080/api/sys/fruid/psu" + + self.fru_status_list = None + self.psu_info_list = None + + def request_data(self): + # Reqest data from BMC if not exist. + if self.fru_status_list is None or self.psu_info_list is None: + fru_status_req = requests.get(self.fru_status_url) + psu_info_req = requests.get(self.psu_info_url) + fru_status_json = fru_status_req.json() + psu_info_json = psu_info_req.json() + self.fru_status_list = fru_status_json.get('Information') + self.psu_info_list = psu_info_json.get('Information') + return self.fru_status_list, self.psu_info_list + + def airflow_selector(self, pn): + # Set airflow type + pn = pn.upper() + if "DPS-1100FB" in pn: + airflow = "FTOB" + elif "DPS-1100AB" in pn: + airflow = "BTOF" + elif "FSJ026-A20G" in pn: + airflow = "FTOB" + elif "FSJ038-A20G" in pn: + airflow = "BTOF" + else: + airflow = "Unknown" + return airflow + + 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 + """ + + num_psus = 4 + + return num_psus + + 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 + """ + + # init data + psu_key = "PSU" + str(index) + psu_status_key = "Power Status" + psu_power_status = False + + try: + # Request and validate sensor's information + self.fru_status_list, self.psu_info_list = self.request_data() + + # Get PSU power status. + for fru_status in self.fru_status_list: + is_psu = fru_status.get(psu_key) + psu_status = str(fru_status.get(psu_status_key)).strip() + + if is_psu is not None and psu_status == "OK": + psu_power_status = True + + except: + print("Error: Unable to access PSU power status") + return False + + return psu_power_status + + 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 + """ + + # Init data + psu_key = "PSU" + str(index) + psu_presence_key = "Present" + psu_presence_status = False + + try: + # Request and validate sensor's information. + self.fru_status_list, self.psu_info_list = self.request_data() + + # Get PSU present status. + for fru_status in self.fru_status_list: + is_psu = fru_status.get(psu_key) + psu_status = str(fru_status.get(psu_presence_key)).strip() + + if is_psu is not None and psu_status == "Present": + psu_presence_status = True + + except: + print("Error: Unable to access PSU presence status") + return False + + return psu_presence_status + + def get_psu_sn(self, index): + """ + Get the serial number of the psu, + + :param index: An integer, 1-based index of the PSU. + :return: Serial number + """ + serial_number = "N/A" + psu_key = "PSU" + str(index) + " FRU" + psu_sn_key = "Serial Number" + + try: + # Request and validate sensor's information. + self.fru_status_list, self.psu_info_list = self.request_data() + + # Get PSU fru info. + for psu_fru in self.psu_info_list: + psu_sn = str(psu_fru.get(psu_sn_key)).strip() + if psu_fru.get(psu_key) is not None: + serial_number = psu_sn if psu_sn.strip() != "" else "N/A" + break + + except: + return "N/A" + + return serial_number + + def get_psu_pn(self, index): + """ + Get the product name of the psu + + :param index: An integer, 1-based index of the PSU. + :return: Product name + """ + product_name = "N/A" + psu_key = "PSU" + str(index) + " FRU" + psu_pn_key = "Product Name" + + try: + # Request and validate sensor's information + self.fru_status_list, self.psu_info_list = self.request_data() + + # Get PSU fru info. + for psu_fru in self.psu_info_list: + psu_pn = str(psu_fru.get(psu_pn_key)).strip() + if psu_fru.get(psu_key) is not None: + product_name = psu_pn if psu_pn.strip() != "" else "N/A" + break + + except: + return "N/A" + + return product_name + + def get_all(self): + """ + Number: mandatory, max number of PSU, integer + PSU1, PSU2, ...: mandatory, PSU name, string + Present: mandatory for each PSU, present status, boolean, True for present, False for NOT present + PowerStatus: conditional, if PRESENT is True, power status of PSU,boolean, True for powered, False for NOT powered + PN, conditional, if PRESENT is True, PN of the PSU, string + SN, conditional, if PRESENT is True, SN of the PSU, string + """ + + # Init data + all_psu_dict = dict() + all_psu_dict["Number"] = self.get_num_psus() + psu_sn_key_1 = "Serial Number" + psu_sn_key_2 = "Product Serial" + psu_pn_key = "Product Name" + + # Request and validate sensor's information. + self.fru_status_list, self.psu_info_list = self.request_data() + + # Set PSU FRU data. + psu_info_dict = dict() + for psu_fru in self.psu_info_list: + psu_data = dict() + pn = psu_fru.get(psu_pn_key) + sn = psu_fru.get(psu_sn_key_1) or psu_fru.get(psu_sn_key_2) + psu_data["PN"] = "N/A" if not pn or str( + pn).strip() == "" else str(pn).strip() + psu_data["SN"] = "N/A" if not pn or str( + pn).strip() == "" else str(sn).strip() + + fru_check = [psu_fru[v] for v in psu_fru.keys() if 'FRU Info' in v] + non_fru_check = [v for v in psu_fru.keys() if 'PSU' in v] + + if len(non_fru_check) > 0: + psu_idx = int(re.findall('\d+', non_fru_check[0])[0]) + psu_info_dict[psu_idx] = psu_data + elif len(fru_check) > 0: + psu_idx = int(re.findall('\d+', fru_check[0])[0]) + psu_info_dict[psu_idx] = psu_data + + # Set PSU status. + for fru_status in self.fru_status_list: + psu_status_dict = dict() + find_psu = [v for v in fru_status.keys() if "PSU" in v] + if len(find_psu) > 0: + psu_idx = int(re.findall('\d+', find_psu[0])[0]) + psu_ps_status = True if str(fru_status.get( + "Present")).strip() == "Present" else False + psu_pw_status = True if str(fru_status.get( + "Power Status")).strip() == "OK" else False + psu_pw_type = str(fru_status.get( + "Power Type")).strip() + ac_status = True if str(fru_status.get( + "AC Status")).strip().upper() == "OK" else False + + psu_status_dict["Present"] = psu_ps_status + if psu_ps_status: + psu_status_dict["PowerStatus"] = psu_pw_status + psu_status_dict["PN"] = psu_info_dict[psu_idx]["PN"] + psu_status_dict["SN"] = psu_info_dict[psu_idx]["SN"] + psu_status_dict["InputType"] = psu_pw_type + psu_status_dict["InputStatus"] = True if psu_pw_status and psu_ps_status else False + psu_status_dict["OutputStatus"] = ac_status + psu_status_dict["AirFlow"] = self.airflow_selector( + psu_status_dict["PN"]) + all_psu_dict[find_psu[0]] = psu_status_dict + + return all_psu_dict diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sensorutil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sensorutil.py new file mode 100644 index 000000000000..29f56e8578e6 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sensorutil.py @@ -0,0 +1,383 @@ +#!/usr/bin/env python + +__author__ = 'Wirut G.' +__license__ = "GPL" +__version__ = "0.2.0" +__status__ = "Development" + +import requests + + +class SensorUtil(): + """Platform-specific SensorUtil class""" + + def __init__(self): + self.sensor_url = "http://240.1.1.1:8080/api/sys/sensors" + self.sys_fruid_url = "http://240.1.1.1:8080/api/sys/fruid/sys" + self.sensor_info_list = None + + def request_data(self): + # Reqest data from BMC if not exist. + if self.sensor_info_list is None: + sensor_data_req = requests.get(self.sensor_url) + sensor_json = sensor_data_req.json() + self.sensor_info_list = sensor_json.get('Information') + sys_fruid_req = requests.get(self.sys_fruid_url) + sys_fruid_json = sys_fruid_req.json() + self.sys_fruid_list = sys_fruid_json.get('Information') + return self.sensor_info_list + + def input_type_selector(self, unit): + # Set input type. + return { + "C": "temperature", + "V": "voltage", + "RPM": "RPM", + "A": "amp", + "W": "power" + }.get(unit, unit) + + def input_name_selector(self, sensor_name, input_name): + + self.sensor_name = { + "syscpld-i2c-0-0d": "TEMPERATURE", + "dps1100-i2c-27-58": "PSU1", + "dps1100-i2c-26-58": "PSU2", + "dps1100-i2c-25-58": "PSU3", + "dps1100-i2c-24-58": "PSU4", + "fancpld-i2c-8-0d": "FAN", + "isl68137-i2c-17-60": "ISL68137" + }.get(sensor_name, sensor_name) + + if 'dps1100' in sensor_name: + input_name = { + "fan1": self.sensor_name + "_FAN", + "iin": self.sensor_name + "_CURR_I", + "iout1": self.sensor_name + "_CURR_O", + "pin": self.sensor_name + "_POWER_I", + "pout1": self.sensor_name + "_POWER_O", + "temp1": self.sensor_name + "_TEMP1", + "temp2": self.sensor_name + "_TEMP2", + "vin": self.sensor_name + "_VOL_I", + "vout1": self.sensor_name + "_VOL_O" + }.get(input_name, input_name) + + elif 'isl68137' in sensor_name: + input_name = { + "iin": self.sensor_name + "_CURR_I", + "iout2": self.sensor_name + "_CURR_O", + "pin": self.sensor_name + "_POWER_I", + "pout2": self.sensor_name + "_POWER_O", + "vin": self.sensor_name + "_VOL_I", + "vout2": self.sensor_name + "_VOL_O", + "temp1": self.sensor_name + "_TEMP1" + }.get(input_name, input_name) + + elif 'tmp75' in sensor_name or 'max31730' in sensor_name: + input_name = { + "tmp75-i2c-7-4f": "BASEBOARD_INLET_RIGHT", + "tmp75-i2c-7-4e": "BASEBOARD_INLET_CENTER", + "tmp75-i2c-7-4d": "SWITCH_OUTLET", + "tmp75-i2c-31-48": "PSU_INLET_LEFT", + "tmp75-i2c-31-49": "INLET_TEMP", + "tmp75-i2c-39-48": "FANBOARD_LEFT", + "tmp75-i2c-39-49": "FANBOARD_RIGHT", + "tmp75-i2c-42-48": "LINECARD_TOP_RIGHT", + "tmp75-i2c-42-49": "LINECARD_TOP_LEFT", + "tmp75-i2c-43-48": "LINECARD_BOTTOM_RIGHT", + "tmp75-i2c-43-49": "LINECARD_BOTTOM_LEFT", + "max31730-i2c-7-4c": "SWITCH_REMOTE_" + input_name + }.get(sensor_name, input_name) + self.sensor_name = "TEMPERATURE" + + elif 'fancpld' in sensor_name: + raw_fan_input = input_name.split() + input_name = raw_fan_input[0] + \ + raw_fan_input[1] + "_" + raw_fan_input[2] + + elif 'ir35' in sensor_name or 'ir38' in sensor_name: + sensor_name_raw = sensor_name.split("-") + sensor_name = sensor_name_raw[0] + self.sensor_name = sensor_name.upper() + + return input_name.replace(" ", "_").upper() + + def get_num_sensors(self): + """ + Get the number of sensors + :return: int num_sensors + """ + + num_sensors = 0 + try: + # Request and validate sensor's information + self.sensor_info_list = self.request_data() + + # Get number of sensors. + num_sensors = len(self.sensor_info_list) + except: + print "Error: Unable to access sensor information" + return 0 + + return num_sensors + + def get_sensor_input_num(self, index): + """ + Get the number of the input items of the specified sensor + :return: int input_num + """ + + input_num = 0 + try: + # Request and validate sensor's information. + self.sensor_info_list = self.request_data() + + # Get sensor's input number. + sensor_data = self.sensor_info_list[index-1] + input_num = len(sensor_data.keys())-2 + except: + print "Error: Unable to access sensor information" + return 0 + + return input_num + + def get_sensor_name(self, index): + """ + Get the device name of the specified sensor. + for example "coretemp-isa-0000" + :return: str sensor_name + """ + + sensor_name = "N/A" + try: + # Request and validate sensor's information. + self.sensor_info_list = self.request_data() + + # Get sensor's name. + sensor_data = self.sensor_info_list[index-1] + sensor_name = sensor_data.get('name') + + except: + return "N/A" + + return sensor_name + + def get_sensor_input_name(self, sensor_index, input_index): + """ + Get the input item name of the specified input item of the + specified sensor index, for example "Physical id 0" + :return: str sensor_input_name + """ + + sensor_input_name = "N/A" + try: + # Request and validate sensor's information. + self.sensor_info_list = self.request_data() + sensor_data = self.sensor_info_list[sensor_index-1].copy() + + # Remove none input key. + del sensor_data["name"] + del sensor_data["Adapter"] + + # Get sensor's input name. + sensor_data_key = sensor_data.keys() + sensor_input_name = sensor_data_key[input_index-1] + except: + return "N/A" + + return sensor_input_name + + def get_sensor_input_type(self, sensor_index, input_index): + """ + Get the item type of the specified input item of the specified sensor index, + The return value should among "valtage","temperature" + :return: str sensor_input_type + """ + + sensor_input_type = "N/A" + try: + # Request and validate sensor's information. + self.sensor_info_list = self.request_data() + sensor_data = self.sensor_info_list[sensor_index-1].copy() + + # Remove none input key. + del sensor_data["name"] + del sensor_data["Adapter"] + + # Get sensor's input type name. + sensor_data_key = sensor_data.keys() + sensor_input_raw = sensor_data.get(sensor_data_key[input_index-1]) + sensor_data_str = sensor_input_raw.split() + sensor_input_type = self.input_type_selector(sensor_data_str[1]) + except: + return "N/A" + + return sensor_input_type + + def get_sensor_input_value(self, sensor_index, input_index): + """ + Get the current value of the input item, the unit is "V" or "C" + :return: float sensor_input_value + """ + + sensor_input_value = 0 + try: + # Request and validate sensor's information. + self.sensor_info_list = self.request_data() + sensor_data = self.sensor_info_list[sensor_index-1].copy() + + # Remove none input key. + del sensor_data["name"] + del sensor_data["Adapter"] + + # Get sensor's input value. + sensor_data_key = sensor_data.keys() + sensor_input_raw = sensor_data.get(sensor_data_key[input_index-1]) + sensor_data_str = sensor_input_raw.split() + sensor_input_value = float( + sensor_data_str[0]) if sensor_data_str[0] != "N/A" else 0 + except: + print "Error: Unable to access sensor information" + return 0 + + return sensor_input_value + + def get_sensor_input_low_threshold(self, sensor_index, input_index): + """ + Get the low threshold of the value, + the status of this item is not ok if the current value 1: + sensor_input_low_threshold = l_thres * \ + 1000 if str(unit[0]).lower() == 'k' else l_thres + except: + print "Error: Unable to access sensor information" + return 0 + + return sensor_input_low_threshold + + def get_sensor_input_high_threshold(self, sensor_index, input_index): + """ + Get the high threshold of the value, + the status of this item is not ok if the current value > high_threshold + :return: float sensor_input_high_threshold + """ + + sensor_input_high_threshold = 0 + try: + # Request and validate sensor's information. + self.sensor_info_list = self.request_data() + sensor_data = self.sensor_info_list[sensor_index-1].copy() + + # Remove none input key. + del sensor_data["name"] + del sensor_data["Adapter"] + + # Get sensor's input high threshold. + sensor_data_key = sensor_data.keys() + sensor_input_raw = sensor_data.get(sensor_data_key[input_index-1]) + sensor_data_str = sensor_input_raw.split() + indices = [i for i, s in enumerate( + sensor_data_str) if 'max' in s or 'high' in s] + h_thres = float( + sensor_data_str[indices[0] + 2]) if len(indices) != 0 else 0 + unit = sensor_data_str[indices[0] + + 3] if len(indices) != 0 else None + if unit is not None and len(unit) > 1: + sensor_input_high_threshold = h_thres * \ + 1000 if str(unit[0]).lower() == 'k' else h_thres + + except: + print "Error: Unable to access sensor information" + return 0 + + return sensor_input_high_threshold + + def get_sys_airflow(self): + sys_air_flow = "Unknown" + sys_pn_data = [ + v.split(":") for v in self.sys_fruid_list if "Product Part Number" in v] + + if len(sys_pn_data) == 0: + return sys_air_flow + + sys_pn = sys_pn_data[0][1] + if "R1240-F0001" in sys_pn: + sys_air_flow = "FTOB" + elif"R1240-F0002" in sys_pn: + sys_air_flow = "BTOF" + + return sys_air_flow + + def get_all(self): + + all_sensor_dict = dict() + + # Request sensor's information. + self.sensor_info_list = self.request_data() + for sensor_data in self.sensor_info_list: + sensor_info = sensor_data.copy() + + # Remove none unuse key. + del sensor_info["name"] + del sensor_info["Adapter"] + + # Set sensor data. + sensor_dict = dict() + for k, v in sensor_info.items(): + sensor_i_dict = dict() + sensor_data_str = v.split() + indices_h = [i for i, s in enumerate( + sensor_data_str) if 'max' in s or 'high' in s] + indices_l = [i for i, s in enumerate( + sensor_data_str) if 'min' in s or 'low' in s] + h_thres = float( + sensor_data_str[indices_h[0] + 2]) if len(indices_h) != 0 else 0 + l_thres = float( + sensor_data_str[indices_l[0] + 2]) if len(indices_l) != 0 else 0 + thres_unit = sensor_data_str[-1] + + sensor_i_dict["Type"] = self.input_type_selector( + sensor_data_str[1]) + sensor_i_dict["Value"] = float( + sensor_data_str[0]) if sensor_data_str[0] != "N/A" else 0 + sensor_i_dict["HighThd"] = h_thres * \ + 1000 if str(thres_unit[0]).lower() == 'k' else h_thres + sensor_i_dict["LowThd"] = l_thres * \ + 1000 if str(thres_unit[0]).lower() == 'k' else l_thres + + k = self.input_name_selector(sensor_data.get('name'), k) + sensor_dict[k] = sensor_i_dict + + if all_sensor_dict.get(self.sensor_name) is None: + all_sensor_dict[self.sensor_name] = dict() + + all_sensor_dict[self.sensor_name].update(sensor_dict) + + sensor_dict = dict() + sensor_dict["Sys_AirFlow"] = self.get_sys_airflow() + all_sensor_dict["TEMPERATURE"].update(sensor_dict) + + return all_sensor_dict diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sfputil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sfputil.py new file mode 100755 index 000000000000..2831a75af545 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sfputil.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 128 + QSFP_PORT_START = 1 + QSFP_PORT_END = 128 + + EEPROM_OFFSET = 9 + PORT_INFO_PATH = '/sys/class/phalanx_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 range(self.QSFP_PORT_START, self.QSFP_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.qsfp_ports: + self._port_name = "QSFP" + str(port_num - self.QSFP_PORT_START + 1) + else: + self._port_name = "SFP" + str(port_num) + return self._port_name + + 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 __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.qsfp_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): + return NotImplementedError + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid QSFP port_num + if port_num not in self.qsfp_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.qsfp_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 + """ + return NotImplementedError + + def tx_disable(self, port_num, disable): + """ + @param port_num index of physical port + @param disable, True -- disable port tx signal + False -- enable port tx signal + @return True when operation success, False on failure. + """ + TX_DISABLE_BYTE_OFFSET = 86 + if port_num not in range(self.port_start, self.port_end + 1) or type(disable) != bool: + return False + + # QSFP, set eeprom to disable tx + if port_num in self.qsfp_ports: + presence = self.get_presence(port_num) + if not presence: + return True + + disable = b'\x0f' if disable else b'\x00' + # open eeprom + try: + with open(self.port_to_eeprom_mapping[port_num], mode="wb", buffering=0) as sysfsfile: + sysfsfile.seek(TX_DISABLE_BYTE_OFFSET) + sysfsfile.write(bytearray(disable)) + except IOError: + return False + except: + return False + + # SFP, set tx_disable pin + else: + try: + disable = hex(1) if disable else hex(0) + port_name = self.get_port_name(port_num) + reg_file = open( + "/".join([self.PORT_INFO_PATH, port_name, "sfp_txdisable"]), "w") + reg_file.write(disable) + reg_file.close() + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + return True diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/th3-as14-128h.config.bcm b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/th3-as14-128h.config.bcm new file mode 100644 index 000000000000..354e0f2fad00 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/th3-as14-128h.config.bcm @@ -0,0 +1,631 @@ +pbmp_xport_xe.0=0x0ffff0ffff0ffff0ffff0ffff0ffff0ffff1fffe +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 +port_fec=3 +serdes_tx_taps_ce=pam4:0:140:0:0:0:0 + +init_all_modules=0 +mdio_output_delay=64 + +#BC1 +portmap_5=9:100:2 +portmap_6=11:100:2 +portmap_7=13:100:2 +portmap_8=15:100:2 + +dport_map_port_5=1 +dport_map_port_6=2 +dport_map_port_7=4 +dport_map_port_8=3 + +#BC9 +portmap_44=73:100:2 +portmap_45=75:100:2 +portmap_46=77:100:2 +portmap_47=79:100:2 + +dport_map_port_44=8 +dport_map_port_45=7 +dport_map_port_46=5 +dport_map_port_47=6 + +#BC0 +portmap_1=1:100:2 +portmap_2=3:100:2 +portmap_3=5:100:2 +portmap_4=7:100:2 + +dport_map_port_1=9 +dport_map_port_2=10 +dport_map_port_3=12 +dport_map_port_4=11 + +#BC8 +portmap_40=65:100:2 +portmap_41=67:100:2 +portmap_42=69:100:2 +portmap_43=71:100:2 + +dport_map_port_40=16 +dport_map_port_41=15 +dport_map_port_42=13 +dport_map_port_43=14 + +#BC5 +portmap_24=41:100:2 +portmap_25=43:100:2 +portmap_26=45:100:2 +portmap_27=47:100:2 + +dport_map_port_24=17 +dport_map_port_25=18 +dport_map_port_26=20 +dport_map_port_27=19 + +#BC13 +portmap_64=105:100:2 +portmap_65=107:100:2 +portmap_66=109:100:2 +portmap_67=111:100:2 + +dport_map_port_64=24 +dport_map_port_65=23 +dport_map_port_66=21 +dport_map_port_67=22 + +#BC4 +portmap_20=33:100:2 +portmap_21=35:100:2 +portmap_22=37:100:2 +portmap_23=39:100:2 + +dport_map_port_20=25 +dport_map_port_21=26 +dport_map_port_22=28 +dport_map_port_23=27 + +#BC12 +portmap_60=97:100:2 +portmap_61=99:100:2 +portmap_62=101:100:2 +portmap_63=103:100:2 + +dport_map_port_60=32 +dport_map_port_61=31 +dport_map_port_62=29 +dport_map_port_63=30 + +#BC17 +portmap_84=137:100:2 +portmap_85=139:100:2 +portmap_86=141:100:2 +portmap_87=143:100:2 + +dport_map_port_84=33 +dport_map_port_85=34 +dport_map_port_86=36 +dport_map_port_87=35 + +#BC25 +portmap_124=201:100:2 +portmap_125=203:100:2 +portmap_126=205:100:2 +portmap_127=207:100:2 + +dport_map_port_124=40 +dport_map_port_125=39 +dport_map_port_126=37 +dport_map_port_127=38 + +#BC16 +portmap_80=129:100:2 +portmap_81=131:100:2 +portmap_82=133:100:2 +portmap_83=135:100:2 + +dport_map_port_80=41 +dport_map_port_81=42 +dport_map_port_82=44 +dport_map_port_83=43 + +#BC24 +portmap_120=193:100:2 +portmap_121=195:100:2 +portmap_122=197:100:2 +portmap_123=199:100:2 + +dport_map_port_120=48 +dport_map_port_121=47 +dport_map_port_122=45 +dport_map_port_123=46 + +#BC21 +portmap_104=169:100:2 +portmap_105=171:100:2 +portmap_106=173:100:2 +portmap_107=175:100:2 + +dport_map_port_104=49 +dport_map_port_105=50 +dport_map_port_106=52 +dport_map_port_107=51 + +#BC29 +portmap_144=233:100:2 +portmap_145=235:100:2 +portmap_146=237:100:2 +portmap_147=239:100:2 + +dport_map_port_144=56 +dport_map_port_145=55 +dport_map_port_146=53 +dport_map_port_147=54 + +#BC20 +portmap_100=161:100:2 +portmap_101=163:100:2 +portmap_102=165:100:2 +portmap_103=167:100:2 + +dport_map_port_100=57 +dport_map_port_101=58 +dport_map_port_102=60 +dport_map_port_103=59 + +#BC28 +portmap_140=225:100:2 +portmap_141=227:100:2 +portmap_142=229:100:2 +portmap_143=231:100:2 + +dport_map_port_140=64 +dport_map_port_141=63 +dport_map_port_142=61 +dport_map_port_143=62 + +#BC3 +portmap_13=25:100:2 +portmap_14=27:100:2 +portmap_15=29:100:2 +portmap_16=31:100:2 + +dport_map_port_13=65 +dport_map_port_14=66 +dport_map_port_15=68 +dport_map_port_16=67 + +#BC11 +portmap_52=89:100:2 +portmap_53=91:100:2 +portmap_54=93:100:2 +portmap_55=95:100:2 + +dport_map_port_52=72 +dport_map_port_53=71 +dport_map_port_54=69 +dport_map_port_55=70 + +#BC2 +portmap_9=17:100:2 +portmap_10=19:100:2 +portmap_11=21:100:2 +portmap_12=23:100:2 + +dport_map_port_9=73 +dport_map_port_10=74 +dport_map_port_11=76 +dport_map_port_12=75 + +#BC10 +portmap_48=81:100:2 +portmap_49=83:100:2 +portmap_50=85:100:2 +portmap_51=87:100:2 + +dport_map_port_48=80 +dport_map_port_49=79 +dport_map_port_50=77 +dport_map_port_51=78 + +#BC7 +portmap_32=57:100:2 +portmap_33=59:100:2 +portmap_34=61:100:2 +portmap_35=63:100:2 + +dport_map_port_32=81 +dport_map_port_33=82 +dport_map_port_34=84 +dport_map_port_35=83 + +#BC15 +portmap_72=121:100:2 +portmap_73=123:100:2 +portmap_74=125:100:2 +portmap_75=127:100:2 + +dport_map_port_72=88 +dport_map_port_73=87 +dport_map_port_74=85 +dport_map_port_75=86 + +#BC6 +portmap_28=49:100:2 +portmap_29=51:100:2 +portmap_30=53:100:2 +portmap_31=55:100:2 + +dport_map_port_28=89 +dport_map_port_29=90 +dport_map_port_30=92 +dport_map_port_31=91 + +#BC14 +portmap_68=113:100:2 +portmap_69=115:100:2 +portmap_70=117:100:2 +portmap_71=119:100:2 + +dport_map_port_68=96 +dport_map_port_69=95 +dport_map_port_70=93 +dport_map_port_71=94 + +#BC19 +portmap_92=153:100:2 +portmap_93=155:100:2 +portmap_94=157:100:2 +portmap_95=159:100:2 + +dport_map_port_92=97 +dport_map_port_93=98 +dport_map_port_94=100 +dport_map_port_95=99 + +#BC27 +portmap_132=217:100:2 +portmap_133=219:100:2 +portmap_134=221:100:2 +portmap_135=223:100:2 + +dport_map_port_132=104 +dport_map_port_133=103 +dport_map_port_134=101 +dport_map_port_135=102 + +#BC18 +portmap_88=145:100:2 +portmap_89=147:100:2 +portmap_90=149:100:2 +portmap_91=151:100:2 + +dport_map_port_88=105 +dport_map_port_89=106 +dport_map_port_90=108 +dport_map_port_91=107 + +#BC26 +portmap_128=209:100:2 +portmap_129=211:100:2 +portmap_130=213:100:2 +portmap_131=215:100:2 + +dport_map_port_128=112 +dport_map_port_129=111 +dport_map_port_130=109 +dport_map_port_131=110 + +#BC23 +portmap_112=185:100:2 +portmap_113=187:100:2 +portmap_114=189:100:2 +portmap_115=191:100:2 + +dport_map_port_112=113 +dport_map_port_113=114 +dport_map_port_114=116 +dport_map_port_115=115 + +#BC31 +portmap_152=249:100:2 +portmap_153=251:100:2 +portmap_154=253:100:2 +portmap_155=255:100:2 + +dport_map_port_152=120 +dport_map_port_153=119 +dport_map_port_154=117 +dport_map_port_155=118 + +#BC22 +portmap_108=177:100:2 +portmap_109=179:100:2 +portmap_110=181:100:2 +portmap_111=183:100:2 + +dport_map_port_108=121 +dport_map_port_109=122 +dport_map_port_110=124 +dport_map_port_111=123 + +#BC30 +portmap_148=241:100:2 +portmap_149=243:100:2 +portmap_150=245:100:2 +portmap_151=247:100:2 + +dport_map_port_148=128 +dport_map_port_149=127 +dport_map_port_150=125 +dport_map_port_151=126 + +#BC1 +phy_chain_rx_lane_map_physical{9.0}=0x13026475 +phy_chain_tx_lane_map_physical{9.0}=0x21340756 + +#BC9 +phy_chain_rx_lane_map_physical{73.0}=0x47560213 +phy_chain_tx_lane_map_physical{73.0}=0x76540132 + +#BC0 +phy_chain_rx_lane_map_physical{1.0}=0x20314657 +phy_chain_tx_lane_map_physical{1.0}=0x32014567 + +#BC8 +phy_chain_rx_lane_map_physical{65.0}=0x13025647 +phy_chain_tx_lane_map_physical{65.0}=0x13204675 + +#BC5 +phy_chain_rx_lane_map_physical{41.0}=0x31207564 +phy_chain_tx_lane_map_physical{41.0}=0x23104567 + +#BC13 +phy_chain_rx_lane_map_physical{105.0}=0x63725140 +phy_chain_tx_lane_map_physical{105.0}=0x76541032 + +#BC4 +phy_chain_rx_lane_map_physical{33.0}=0x76452031 +phy_chain_tx_lane_map_physical{33.0}=0x67450123 + +#BC12 +phy_chain_rx_lane_map_physical{97.0}=0x31206574 +phy_chain_tx_lane_map_physical{97.0}=0x31025467 + +#BC17 +phy_chain_rx_lane_map_physical{137.0}=0x13025746 +phy_chain_tx_lane_map_physical{137.0}=0x23410576 + +#BC25 +phy_chain_rx_lane_map_physical{201.0}=0x47560213 +phy_chain_tx_lane_map_physical{201.0}=0x67450231 + +#BC16 +phy_chain_rx_lane_map_physical{129.0}=0x30214657 +phy_chain_tx_lane_map_physical{129.0}=0x13427065 + +#BC24 +phy_chain_rx_lane_map_physical{193.0}=0x13025647 +phy_chain_tx_lane_map_physical{193.0}=0x23104675 + +#BC21 +phy_chain_rx_lane_map_physical{169.0}=0x31206574 +phy_chain_tx_lane_map_physical{169.0}=0x13205476 + +#BC29 +phy_chain_rx_lane_map_physical{233.0}=0x65741302 +phy_chain_tx_lane_map_physical{233.0}=0x57610423 + +#BC20 +phy_chain_rx_lane_map_physical{161.0}=0x74652031 +phy_chain_tx_lane_map_physical{161.0}=0x57640132 + +#BC28 +phy_chain_rx_lane_map_physical{225.0}=0x16072435 +phy_chain_tx_lane_map_physical{225.0}=0x43127065 + +#BC3 laneswap +phy_chain_rx_lane_map_physical{25.0}=0x36271504 +phy_chain_tx_lane_map_physical{25.0}=0x13204576 + +#BC11 +phy_chain_rx_lane_map_physical{89.0}=0x47560213 +phy_chain_tx_lane_map_physical{89.0}=0x76540132 + +#BC2 +phy_chain_rx_lane_map_physical{17.0}=0x43507162 +phy_chain_tx_lane_map_physical{17.0}=0x46570123 + +#BC10 +phy_chain_rx_lane_map_physical{81.0}=0x13025647 +phy_chain_tx_lane_map_physical{81.0}=0x13204675 + +#BC7 +phy_chain_rx_lane_map_physical{57.0}=0x31207564 +phy_chain_tx_lane_map_physical{57.0}=0x23406175 + +#BC15 +phy_chain_rx_lane_map_physical{121.0}=0x13026475 +phy_chain_tx_lane_map_physical{121.0}=0x23507614 + +#BC6 +phy_chain_rx_lane_map_physical{49.0}=0x65742031 +phy_chain_tx_lane_map_physical{49.0}=0x57640231 + +#BC14 +phy_chain_rx_lane_map_physical{113.0}=0x02136574 +phy_chain_tx_lane_map_physical{113.0}=0x12436075 + +#BC19 +phy_chain_rx_lane_map_physical{153.0}=0x40516273 +phy_chain_tx_lane_map_physical{153.0}=0x32045671 + +#BC27 +phy_chain_rx_lane_map_physical{217.0}=0x64570213 +phy_chain_tx_lane_map_physical{217.0}=0x67054123 + +#BC18 +phy_chain_rx_lane_map_physical{145.0}=0x46570213 +phy_chain_tx_lane_map_physical{145.0}=0x57063421 + +#BC26 +phy_chain_rx_lane_map_physical{209.0}=0x13025647 +phy_chain_tx_lane_map_physical{209.0}=0x23104675 + +#BC23 +phy_chain_rx_lane_map_physical{185.0}=0x31207564 +phy_chain_tx_lane_map_physical{185.0}=0x13245076 + +#BC31 +phy_chain_rx_lane_map_physical{249.0}=0x02137564 +phy_chain_tx_lane_map_physical{249.0}=0x32106457 + +#BC22 +phy_chain_rx_lane_map_physical{177.0}=0x64752031 +phy_chain_tx_lane_map_physical{177.0}=0x57640132 + +#BC30 +phy_chain_rx_lane_map_physical{241.0}=0x31204657 +phy_chain_tx_lane_map_physical{241.0}=0x32016457 + +#BC1 +serdes_core_rx_polarity_flip_physical{9}=0x33 +serdes_core_tx_polarity_flip_physical{9}=0x71 + +#BC9 +serdes_core_rx_polarity_flip_physical{73}=0x93 +serdes_core_tx_polarity_flip_physical{73}=0xa9 + +#BC0 +serdes_core_rx_polarity_flip_physical{1}=0xc3 +serdes_core_tx_polarity_flip_physical{1}=0xdf + +#BC8 +serdes_core_rx_polarity_flip_physical{65}=0x39 +serdes_core_tx_polarity_flip_physical{65}=0xbe + +#BC5 +serdes_core_rx_polarity_flip_physical{41}=0x3c +serdes_core_tx_polarity_flip_physical{41}=0x6a + +#BC13 +serdes_core_rx_polarity_flip_physical{105}=0xc6 +serdes_core_tx_polarity_flip_physical{105}=0xaf + +#BC4 +serdes_core_rx_polarity_flip_physical{33}=0x63 +serdes_core_tx_polarity_flip_physical{33}=0x1c + +#BC12 +serdes_core_rx_polarity_flip_physical{97}=0x36 +serdes_core_tx_polarity_flip_physical{97}=0x7f + +#BC17 +serdes_core_rx_polarity_flip_physical{137}=0x3c +serdes_core_tx_polarity_flip_physical{137}=0x71 + +#BC25 +serdes_core_rx_polarity_flip_physical{201}=0x93 +serdes_core_tx_polarity_flip_physical{201}=0x5c + +#BC16 +serdes_core_rx_polarity_flip_physical{129}=0x63 +serdes_core_tx_polarity_flip_physical{129}=0x6f + +#BC24 +serdes_core_rx_polarity_flip_physical{193}=0x39 +serdes_core_tx_polarity_flip_physical{193}=0x1e + +#BC21 +serdes_core_rx_polarity_flip_physical{169}=0x32 +serdes_core_tx_polarity_flip_physical{169}=0xc5 + +#BC29 +serdes_core_rx_polarity_flip_physical{233}=0x9c +serdes_core_tx_polarity_flip_physical{233}=0xca + +#BC20 +serdes_core_rx_polarity_flip_physical{161}=0x63 +serdes_core_tx_polarity_flip_physical{161}=0x87 + +#BC28 +serdes_core_rx_polarity_flip_physical{225}=0x21 +serdes_core_tx_polarity_flip_physical{225}=0xca + +#Polarity BC3 +serdes_core_rx_polarity_flip_physical{25}=0x89 +serdes_core_tx_polarity_flip_physical{25}=0xcb + +#BC11 +serdes_core_rx_polarity_flip_physical{89}=0x93 +serdes_core_tx_polarity_flip_physical{89}=0xb9 + +#BC2 +serdes_core_rx_polarity_flip_physical{17}=0xc2 +serdes_core_tx_polarity_flip_physical{17}=0x8a +#BC10 +serdes_core_rx_polarity_flip_physical{81}=0x39 +serdes_core_tx_polarity_flip_physical{81}=0xbe + +#BC7 +serdes_core_rx_polarity_flip_physical{57}=0x3c +serdes_core_tx_polarity_flip_physical{57}=0x6c + +#BC15 +serdes_core_rx_polarity_flip_physical{121}=0x33 +serdes_core_tx_polarity_flip_physical{121}=0x47 + +#BC6 +serdes_core_rx_polarity_flip_physical{49}=0x93 +serdes_core_tx_polarity_flip_physical{49}=0x82 + +#BC14 +serdes_core_rx_polarity_flip_physical{113}=0x86 +serdes_core_tx_polarity_flip_physical{113}=0x08 + +#BC19 +serdes_core_rx_polarity_flip_physical{153}=0x66 +serdes_core_tx_polarity_flip_physical{153}=0xc6 + +#BC27 +serdes_core_rx_polarity_flip_physical{217}=0xc3 +serdes_core_tx_polarity_flip_physical{217}=0x52 + +#BC18 +serdes_core_rx_polarity_flip_physical{145}=0xc3 +serdes_core_tx_polarity_flip_physical{145}=0xef + +#BC26 +serdes_core_rx_polarity_flip_physical{209}=0x39 +serdes_core_tx_polarity_flip_physical{209}=0x3e + +#BC23 +serdes_core_rx_polarity_flip_physical{185}=0x3c +serdes_core_tx_polarity_flip_physical{185}=0xd5 + +#BC31 +serdes_core_rx_polarity_flip_physical{249}=0xcc +serdes_core_tx_polarity_flip_physical{249}=0xac + +#BC22 +serdes_core_rx_polarity_flip_physical{177}=0xc3 +serdes_core_tx_polarity_flip_physical{177}=0x83 + +#BC30 +serdes_core_rx_polarity_flip_physical{241}=0x33 +serdes_core_tx_polarity_flip_physical{241}=0x2d + +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/alibaba/x86_64-alibaba_as14-40d-cl-r0/.installer.conf.swp b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/.installer.conf.swp new file mode 100644 index 0000000000000000000000000000000000000000..e85feb00996a62b85b6d8c040dae5967353a2e86 GIT binary patch literal 12288 zcmeI&Jx;?g6bEn@W>f?h2xTQrQle6jI-n9zrM9X1fjVJ1jsYXLsp9Z4!9iGIXW$52 zhdbcXAR&e_FrogRl)Tu_vf|$soGf{k9dEOyp%w&S`Dm{KAw^JH@V+bf|Cf#ndm&d%-H+Hkkx zxw8Xrm$t0Ujp1^f9jAl<1Rwwb2tWV=5P$##J_WLAfjpR}mE2=B&xId3A0j~j0uX=z z1Rwwb2tWV=5P$##An*?bSWL)4k&wt-v;Y5J-~aDs{Fu+5%xVY-KmY;|fB*y_009U< z00Izz00fBjmynap^uA9`<9a6QvD7S5qC~<@Goanp;ovyzwP`RK^bTpGebj1p0%~r< tQN1)x6E3t)(z0o-r+mJFXU+GMu@c|sUD60U{je3#em4k?>ibpKB_B)UZ^!@u literal 0 HcmV?d00001 diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/port_config.ini b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/port_config.ini new file mode 100644 index 000000000000..5c6ca5db0a7b --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/port_config.ini @@ -0,0 +1,33 @@ +# name lanes alias index +Ethernet1 1,2,3,4 QSFP1 1 +Ethernet2 5,6,7,8 QSFP2 2 +Ethernet3 9,10,11,12 QSFP3 3 +Ethernet4 13,14,15,16 QSFP4 4 +Ethernet5 17,18,19,20 QSFP5 5 +Ethernet6 21,22,23,24 QSFP6 6 +Ethernet7 25,26,27,28 QSFP7 7 +Ethernet8 29,30,31,32 QSFP8 8 +Ethernet9 33,34,35,36 QSFP9 9 +Ethernet10 37,38,39,40 QSFP10 10 +Ethernet11 41,42,43,44 QSFP11 11 +Ethernet12 45,46,47,48 QSFP12 12 +Ethernet13 49,50,51,52 QSFP13 13 +Ethernet14 53,54,55,56 QSFP14 14 +Ethernet15 57,58,59,60 QSFP15 15 +Ethernet16 61,62,63,64 QSFP16 16 +Ethernet17 65,66,67,68 QSFP17 17 +Ethernet18 69,70,71,72 QSFP18 18 +Ethernet19 73,74,75,76 QSFP19 19 +Ethernet20 77,78,79,80 QSFP20 20 +Ethernet21 81,82,83,84 QSFP21 21 +Ethernet22 85,86,87,88 QSFP22 22 +Ethernet23 89,90,91,92 QSFP23 23 +Ethernet24 93,94,95,96 QSFP24 24 +Ethernet25 97,98,99,100 QSFP25 25 +Ethernet26 101,102,103,104 QSFP26 26 +Ethernet27 105,106,107,108 QSFP27 27 +Ethernet28 109,110,111,112 QSFP28 28 +Ethernet29 113,114,115,116 QSFP29 29 +Ethernet30 117,118,119,120 QSFP30 30 +Ethernet31 121,122,123,124 QSFP31 31 +Ethernet32 125,126,127,128 QSFP32 32 diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/sai.profile b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/sai.profile new file mode 100644 index 000000000000..a4240891e387 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/platform/td3-as14-40d.config.bcm diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/custom_led.bin b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/custom_led.bin new file mode 100644 index 0000000000000000000000000000000000000000..91552022dc6fc83bcf2f7c12ed02c92e808ae12a GIT binary patch literal 216 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 + + + + + ARISTA01T0 + 10.0.0.33 + sonic + 10.0.0.32 + 1 + 180 + 60 + + + sonic + 10.0.0.0 + ARISTA01T2 + 10.0.0.1 + 1 + 180 + 60 + + + ARISTA02T0 + 10.0.0.35 + sonic + 10.0.0.34 + 1 + 180 + 60 + + + sonic + 10.0.0.2 + ARISTA02T2 + 10.0.0.3 + 1 + 180 + 60 + + + ARISTA03T0 + 10.0.0.37 + sonic + 10.0.0.36 + 1 + 180 + 60 + + + sonic + 10.0.0.4 + ARISTA03T2 + 10.0.0.5 + 1 + 180 + 60 + + + ARISTA04T0 + 10.0.0.39 + sonic + 10.0.0.38 + 1 + 180 + 60 + + + sonic + 10.0.0.6 + ARISTA04T2 + 10.0.0.7 + 1 + 180 + 60 + + + ARISTA05T0 + 10.0.0.41 + sonic + 10.0.0.40 + 1 + 180 + 60 + + + sonic + 10.0.0.8 + ARISTA05T2 + 10.0.0.9 + 1 + 180 + 60 + + + ARISTA06T0 + 10.0.0.43 + sonic + 10.0.0.42 + 1 + 180 + 60 + + + sonic + 10.0.0.10 + ARISTA06T2 + 10.0.0.11 + 1 + 180 + 60 + + + ARISTA07T0 + 10.0.0.45 + sonic + 10.0.0.44 + 1 + 180 + 60 + + + sonic + 10.0.0.12 + ARISTA07T2 + 10.0.0.13 + 1 + 180 + 60 + + + ARISTA08T0 + 10.0.0.47 + sonic + 10.0.0.46 + 1 + 180 + 60 + + + sonic + 10.0.0.14 + ARISTA08T2 + 10.0.0.15 + 1 + 180 + 60 + + + ARISTA09T0 + 10.0.0.49 + sonic + 10.0.0.48 + 1 + 180 + 60 + + + sonic + 10.0.0.16 + ARISTA09T2 + 10.0.0.17 + 1 + 180 + 60 + + + ARISTA10T0 + 10.0.0.51 + sonic + 10.0.0.50 + 1 + 180 + 60 + + + sonic + 10.0.0.18 + ARISTA10T2 + 10.0.0.19 + 1 + 180 + 60 + + + ARISTA11T0 + 10.0.0.53 + sonic + 10.0.0.52 + 1 + 180 + 60 + + + sonic + 10.0.0.20 + ARISTA11T2 + 10.0.0.21 + 1 + 180 + 60 + + + ARISTA12T0 + 10.0.0.55 + sonic + 10.0.0.54 + 1 + 180 + 60 + + + sonic + 10.0.0.22 + ARISTA12T2 + 10.0.0.23 + 1 + 180 + 60 + + + ARISTA13T0 + 10.0.0.57 + sonic + 10.0.0.56 + 1 + 180 + 60 + + + sonic + 10.0.0.24 + ARISTA13T2 + 10.0.0.25 + 1 + 180 + 60 + + + ARISTA14T0 + 10.0.0.59 + sonic + 10.0.0.58 + 1 + 180 + 60 + + + sonic + 10.0.0.26 + ARISTA14T2 + 10.0.0.27 + 1 + 180 + 60 + + + ARISTA15T0 + 10.0.0.61 + sonic + 10.0.0.60 + 1 + 180 + 60 + + + sonic + 10.0.0.28 + ARISTA15T2 + 10.0.0.29 + 1 + 180 + 60 + + + ARISTA16T0 + 10.0.0.63 + sonic + 10.0.0.62 + 1 + 180 + 60 + + + sonic + 10.0.0.30 + ARISTA16T2 + 10.0.0.31 + 1 + 180 + 60 + + + + + 65100 + sonic + + +
10.0.0.33
+ + +
+ +
10.0.0.1
+ + +
+ +
10.0.0.35
+ + +
+ +
10.0.0.3
+ + +
+ +
10.0.0.37
+ + +
+ +
10.0.0.5
+ + +
+ +
10.0.0.39
+ + +
+ +
10.0.0.7
+ + +
+ +
10.0.0.41
+ + +
+ +
10.0.0.9
+ + +
+ +
10.0.0.43
+ + +
+ +
10.0.0.11
+ + +
+ +
10.0.0.45
+ + +
+ +
10.0.0.13
+ + +
+ +
10.0.0.47
+ + +
+ +
10.0.0.15
+ + +
+ +
10.0.0.49
+ + +
+ +
10.0.0.17
+ + +
+ +
10.0.0.51
+ + +
+ +
10.0.0.19
+ + +
+ +
10.0.0.53
+ + +
+ +
10.0.0.21
+ + +
+ +
10.0.0.55
+ + +
+ +
10.0.0.23
+ + +
+ +
10.0.0.57
+ + +
+ +
10.0.0.25
+ + +
+ +
10.0.0.59
+ + +
+ +
10.0.0.27
+ + +
+ +
10.0.0.61
+ + +
+ +
10.0.0.29
+ + +
+ +
10.0.0.63
+ + +
+ +
10.0.0.31
+ + +
+
+ +
+ + 64001 + ARISTA01T0 + + + + 65200 + ARISTA01T2 + + + + 64002 + ARISTA02T0 + + + + 65200 + ARISTA02T2 + + + + 64003 + ARISTA03T0 + + + + 65200 + ARISTA03T2 + + + + 64004 + ARISTA04T0 + + + + 65200 + ARISTA04T2 + + + + 64005 + ARISTA05T0 + + + + 65200 + ARISTA05T2 + + + + 64006 + ARISTA06T0 + + + + 65200 + ARISTA06T2 + + + + 64007 + ARISTA07T0 + + + + 65200 + ARISTA07T2 + + + + 64008 + ARISTA08T0 + + + + 65200 + ARISTA08T2 + + + + 64009 + ARISTA09T0 + + + + 65200 + ARISTA09T2 + + + + 64010 + ARISTA10T0 + + + + 65200 + ARISTA10T2 + + + + 64011 + ARISTA11T0 + + + + 65200 + ARISTA11T2 + + + + 64012 + ARISTA12T0 + + + + 65200 + ARISTA12T2 + + + + 64013 + ARISTA13T0 + + + + 65200 + ARISTA13T2 + + + + 64014 + ARISTA14T0 + + + + 65200 + ARISTA14T2 + + + + 64015 + ARISTA15T0 + + + + 65200 + ARISTA15T2 + + + + 64016 + ARISTA16T0 + + + + 65200 + ARISTA16T2 + + +
+
+ + + + + + HostIP + Loopback0 + + 10.1.0.32/32 + + 10.1.0.32/32 + + + + + + + + sonic + + + + + + QSFP1 + 10.0.0.0/31 + + + + QSFP2 + 10.0.0.2/31 + + + + QSFP3 + 10.0.0.4/31 + + + + QSFP4 + 10.0.0.6/31 + + + + QSFP5 + 10.0.0.8/31 + + + + QSFP6 + 10.0.0.10/31 + + + + QSFP7 + 10.0.0.12/31 + + + + QSFP8 + 10.0.0.14/31 + + + + QSFP9 + 10.0.0.16/31 + + + + QSFP10 + 10.0.0.18/31 + + + + QSFP11 + 10.0.0.20/31 + + + + QSFP12 + 10.0.0.22/31 + + + + QSFP13 + 10.0.0.24/31 + + + + QSFP14 + 10.0.0.26/31 + + + + QSFP15 + 10.0.0.28/31 + + + + QSFP16 + 10.0.0.30/31 + + + + QSFP17 + 10.0.0.32/31 + + + + QSFP18 + 10.0.0.34/31 + + + + QSFP19 + 10.0.0.36/31 + + + + QSFP20 + 10.0.0.38/31 + + + + QSFP21 + 10.0.0.40/31 + + + + QSFP22 + 10.0.0.42/31 + + + + QSFP23 + 10.0.0.44/31 + + + + QSFP24 + 10.0.0.46/31 + + + + QSFP25 + 10.0.0.48/31 + + + + QSFP26 + 10.0.0.50/31 + + + + QSFP27 + 10.0.0.52/31 + + + + QSFP28 + 10.0.0.54/31 + + + + QSFP29 + 10.0.0.56/31 + + + + QSFP30 + 10.0.0.58/31 + + + + QSFP31 + 10.0.0.60/31 + + + + QSFP32 + 10.0.0.62/31 + + + + + + + + + + + + + sonic + AS14-40D + + + + + + + sonic + + + DhcpResources + + + + + NtpResources + + 0.debian.pool.ntp.org;1.debian.pool.ntp.org;2.debian.pool.ntp.org;3.debian.pool.ntp.org + + + SyslogResources + + + + + ErspanDestinationIpv4 + + 2.2.2.2 + + + + + + + sonic + AS14-40D + diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/opennsl-postinit.cfg b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/opennsl-postinit.cfg new file mode 100644 index 000000000000..7008c14c0ffc --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/opennsl-postinit.cfg @@ -0,0 +1,3 @@ +linkscan 250000; port xe,ce linkscan=on +sleep 1 +led auto on; led start diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/cputemputil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/cputemputil.py new file mode 100644 index 000000000000..ac2589d044fd --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/cputemputil.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# +# cputemputil.py +# +# Platform-specific CPU temperature Interface for SONiC +# + +__author__ = 'Wirut G.' +__license__ = "GPL" +__version__ = "0.1.0" +__status__ = "Development" + + +import subprocess +import requests + + +class CpuTempUtil(): + """Platform-specific CpuTempUtil class""" + + def __init__(self): + pass + + def get_cpu_temp(self): + + # Get list of temperature of CPU cores. + p = subprocess.Popen(['sensors', '-Au', 'coretemp-isa-0000'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = p.communicate() + raw_data_list = out.splitlines() + temp_string_list = [i for i, s in enumerate( + raw_data_list) if '_input' in s] + tmp_list = [0] + + for temp_string in temp_string_list: + tmp_list.append(float(raw_data_list[temp_string].split(":")[1])) + + return tmp_list + + def get_max_cpu_tmp(self): + # Get maximum temperature from list of temperature of CPU cores. + return max(self.get_cpu_temp()) diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/eeprom.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/eeprom.py new file mode 100644 index 000000000000..9f42b56ce7c2 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/eeprom.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica DX010 +# +# 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/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fanutil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fanutil.py new file mode 100644 index 000000000000..dab2f64dd5e0 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fanutil.py @@ -0,0 +1,310 @@ +#!/usr/bin/env python + +__author__ = 'Wirut G.' +__license__ = "GPL" +__version__ = "0.1.2" +__status__ = "Development" + +import requests +import re + + +class FanUtil(): + """Platform-specific FanUtil class""" + + def __init__(self): + + self.fan_fru_url = "http://240.1.1.1:8080/api/sys/fruid/fan" + self.sensor_url = "http://240.1.1.1:8080/api/sys/sensors" + self.fru_data_list = None + self.sensor_data_list = None + + def request_data(self): + # Reqest data from BMC if not exist. + if self.fru_data_list is None or self.sensor_data_list is None: + fru_data_req = requests.get(self.fan_fru_url) + sensor_data_req = requests.get(self.sensor_url) + fru_json = fru_data_req.json() + sensor_json = sensor_data_req.json() + self.fru_data_list = fru_json.get('Information') + self.sensor_data_list = sensor_json.get('Information') + return self.fru_data_list, self.sensor_data_list + + def name_to_index(self, fan_name): + # Get fan index from fan name + match = re.match(r"(FAN)([0-9]+)-(1|2)", fan_name, re.I) + fan_index = None + if match: + i_list = list(match.groups()) + fan_index = int(i_list[1])*2 - (int(i_list[2]) % 2) + return fan_index + + def get_num_fans(self): + """ + Get the number of fans + :return: int num_fans + """ + num_fans = 8 + + return num_fans + + def get_fan_speed(self, fan_name): + """ + Get the current speed of the fan, the unit is "RPM" + :return: int fan_speed + """ + + try: + # Get real fan index + index = self.name_to_index(fan_name) + + # Set key and index. + fan_speed = 0 + position_key = "Front" if index % 2 != 0 else "Rear" + index = int(round(float(index)/2)) + fan_key = "Fan " + str(index) + " " + position_key + + # Request and validate fan information. + self.fru_data_list, self.sensor_data_list = self.request_data() + + # Get fan's speed. + for sensor_data in self.sensor_data_list: + sensor_name = sensor_data.get('name') + if "fan" in str(sensor_name): + fan_data = sensor_data.get(fan_key) + fan_sp_list = map(int, re.findall(r'\d+', fan_data)) + fan_speed = fan_sp_list[0] + + except: + return 0 + + return fan_speed + + def get_fan_low_threshold(self, fan_name): + """ + Get the low speed threshold of the fan. + if the current speed < low speed threshold, + the status of the fan is not ok. + :return: int fan_low_threshold + """ + + try: + # Get real fan index + index = self.name_to_index(fan_name) + + # Set key and index. + fan_low_threshold = 0 + position_key = "Front" if index % 2 != 0 else "Rear" + index = int(round(float(index)/2)) + fan_key = "Fan " + str(index) + " " + position_key + + # Request and validate fan information. + self.fru_data_list, self.sensor_data_list = self.request_data() + + # Get fan's threshold. + for sensor_data in self.sensor_data_list: + sensor_name = sensor_data.get('name') + if "fan" in str(sensor_name): + fan_data = sensor_data.get(fan_key) + fan_sp_list = map(int, re.findall(r'\d+', fan_data)) + fan_low_threshold = fan_sp_list[1] + + except: + return "N/A" + + return fan_low_threshold + + def get_fan_high_threshold(self, fan_name): + """ + Get the hight speed threshold of the fan, + if the current speed > high speed threshold, + the status of the fan is not ok + :return: int fan_high_threshold + """ + + try: + # Get real fan index + index = self.name_to_index(fan_name) + + # Set key and index. + fan_high_threshold = 0 + position_key = "Front" if index % 2 != 0 else "Rear" + index = int(round(float(index)/2)) + fan_key = "Fan " + str(index) + " " + position_key + + # Request and validate fan information. + self.fru_data_list, self.sensor_data_list = self.request_data() + + # Get fan's threshold. + for sensor_data in self.sensor_data_list: + sensor_name = sensor_data.get('name') + if "fan" in str(sensor_name): + fan_data = sensor_data.get(fan_key) + fan_sp_list = map(int, re.findall(r'\d+', fan_data)) + fan_high_threshold = fan_sp_list[2] + + except: + return 0 + + return fan_high_threshold + + def get_fan_pn(self, fan_name): + """ + Get the product name of the fan + :return: str fan_pn + """ + + try: + # Get real fan index + index = self.name_to_index(fan_name) + + # Set key and index. + fan_pn = "N/A" + index = int(round(float(index)/2)) + fan_fru_key = "Fantray" + str(index) + + # Request and validate fan information. + self.fru_data_list, self.sensor_data_list = self.request_data() + + # Get fan's fru. + for fan_fru in self.fru_data_list: + matching_fan = [s for s in fan_fru if fan_fru_key in s] + if matching_fan: + pn = [s for s in fan_fru if "Part" in s] + fan_pn = pn[0].split()[4] + + except: + return "N/A" + + return fan_pn + + def get_fan_sn(self, fan_name): + """ + Get the serial number of the fan + :return: str fan_sn + """ + try: + # Get real fan index + index = self.name_to_index(fan_name) + + # Set key and index. + fan_sn = "N/A" + index = int(round(float(index)/2)) + fan_fru_key = "Fantray" + str(index) + + # Request and validate fan information. + self.fru_data_list, self.sensor_data_list = self.request_data() + + # Get fan's fru. + for fan_fru in self.fru_data_list: + matching_fan = [s for s in fan_fru if fan_fru_key in s] + if matching_fan: + serial = [s for s in fan_fru if "Serial" in s] + fan_sn = serial[0].split()[3] + + except: + return "N/A" + + return fan_sn + + def get_fans_name_list(self): + """ + Get list of fan name. + :return: list fan_names + """ + fan_names = [] + + # Get the number of fans + n_fan = self.get_num_fans() + + # Set fan name and add to the list. + for x in range(1, n_fan + 1): + f_index = int(round(float(x)/2)) + pos = 1 if x % 2 else 2 + fan_name = 'FAN{}_{}'.format(f_index, pos) + fan_names.append(fan_name) + + return fan_names + + def get_all(self): + """ + Get all information of system FANs, returns JSON objects in python 'DICT'. + Number, mandatory, max number of FAN, integer + FAN1_1, FAN1_2, ... mandatory, FAN name, string + Present, mandatory for each FAN, present status, boolean, True for present, False for NOT present, read directly from h/w + Running, conditional, if PRESENT is True, running status of the FAN, True for running, False for stopped, read directly from h/w + Speed, conditional, if PRESENT is True, real FAN speed, float, read directly from h/w + LowThd, conditional, if PRESENT is True, lower bound of FAN speed, float, read from h/w + HighThd, conditional, if PRESENT is True, upper bound of FAN speed, float, read from h/w + PN, conditional, if PRESENT is True, PN of the FAN, string + SN, conditional, if PRESENT is True, SN of the FAN, string) + """ + + self.fru_data_list, self.sensor_data_list = self.request_data() + all_fan_dict = dict() + + # Get the number of fans + n_fan = self.get_num_fans() + all_fan_dict["Number"] = n_fan + + # Set fan FRU data. + fan_fru_dict = dict() + fan_raw_idx = 1 + for fan_fru in self.fru_data_list: + fru_dict = dict() + fan_ps = False + + if len(fan_fru) == 0: + fan_idx = fan_raw_idx + fan_pn = "N/A" + fan_sn = "N/A" + else: + fan_key = fan_fru[0].split() + if str(fan_key[-1]).lower() == "absent": + fan_idx = int(re.findall('\d+', fan_key[0])[0]) + + else: + fan_idx = int(re.findall('\d+', fan_key[-1])[0]) + fan_ps = True + pn = [s for s in fan_fru if "Part" in s] + sn = [s for s in fan_fru if "Serial" in s] + fan_pn = pn[0].split( + ":")[-1].strip() if len(pn) > 0 else 'N/A' + fan_sn = sn[0].split( + ":")[-1].strip() if len(sn) > 0 else 'N/A' + + fru_dict["PN"] = "N/A" if not fan_pn or fan_pn == "" else fan_pn + fru_dict["SN"] = "N/A" if not fan_sn or fan_sn == "" else fan_sn + fru_dict["Present"] = fan_ps + fan_fru_dict[fan_idx] = fru_dict + fan_raw_idx += 1 + + # Set fan sensor data. + for sensor_data in self.sensor_data_list: + sensor_name = sensor_data.get('name') + if "fan" in str(sensor_name): + for x in range(1, n_fan + 1): + fan_dict = dict() + f_index = int(round(float(x)/2)) + pos = 1 if x % 2 else 2 + position_key = "Front" if x % 2 != 0 else "Rear" + fan_key = "Fan " + str(f_index) + " " + position_key + fan_data = sensor_data.get(fan_key) + fan_sp_list = map(int, re.findall(r'\d+', fan_data)) + fan_dict["Present"] = fan_fru_dict[f_index]["Present"] + if fan_dict["Present"] or fan_sp_list[0] > 0: + fan_dict["Present"] = True + fan_dict["Speed"] = fan_sp_list[0] + fan_dict["Running"] = True if fan_dict["Speed"] > 0 else False + fan_dict["LowThd"] = fan_sp_list[1] + fan_dict["HighThd"] = fan_sp_list[2] + fan_dict["PN"] = fan_fru_dict[f_index]["PN"] + fan_dict["SN"] = fan_fru_dict[f_index]["SN"] + fan_dict["AirFlow"] = "FTOB" if "R1241-F9001" in fan_dict["PN"] else "Unknown" + fan_dict["AirFlow"] = "BTOF" if "R1241-F9002" in fan_dict["PN"] else fan_dict["AirFlow"] + fan_dict["Status"] = True if fan_dict["AirFlow"] != "Unknown" else False + fan_name = 'FAN{}_{}'.format(f_index, pos) + all_fan_dict[fan_name] = fan_dict + break + + return all_fan_dict diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fwmgrutil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fwmgrutil.py new file mode 100644 index 000000000000..c1fb40cebfb8 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fwmgrutil.py @@ -0,0 +1,882 @@ +# fwmgrutil.py +# +# Platform-specific firmware management interface for SONiC +# + +import subprocess +import requests +import os +import pexpect +import base64 +import time +import json +import logging +import ast +from datetime import datetime + +try: + from sonic_fwmgr.fwgmr_base import FwMgrUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class FwMgrUtil(FwMgrUtilBase): + + """Platform-specific FwMgrUtil class""" + + def __init__(self): + self.platform_name = "AS1332h" + self.onie_config_file = "/host/machine.conf" + self.bmc_info_url = "http://240.1.1.1:8080/api/sys/bmc" + self.bmc_raw_command_url = "http://240.1.1.1:8080/api/sys/raw" + self.fw_upgrade_url = "http://240.1.1.1:8080/api/sys/upgrade" + self.onie_config_file = "/host/machine.conf" + self.fw_upgrade_logger_path = "/var/log/fw_upgrade.log" + self.cpldb_version_path = "/sys/devices/platform/%s.cpldb/getreg" % self.platform_name + self.fpga_version_path = "/sys/devices/platform/%s.switchboard/FPGA/getreg" % self.platform_name + self.switchboard_cpld1_path = "/sys/devices/platform/%s.switchboard/CPLD1/getreg" % self.platform_name + self.switchboard_cpld2_path = "/sys/devices/platform/%s.switchboard/CPLD2/getreg" % self.platform_name + self.switchboard_cpld3_path = "/sys/devices/platform/%s.switchboard/CPLD3/getreg" % self.platform_name + self.switchboard_cpld4_path = "/sys/devices/platform/%s.switchboard/CPLD4/getreg" % self.platform_name + self.bmc_pwd_path = "/usr/local/etc/bmcpwd" + + def __get_register_value(self, path, register): + cmd = "echo {1} > {0}; cat {0}".format(path, register) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err is not '': + return 'None' + else: + return raw_data.strip() + + def __update_fw_upgrade_logger(self, header, message): + if not os.path.isfile(self.fw_upgrade_logger_path): + cmd = "sudo touch %s && sudo chmod +x %s" % ( + self.fw_upgrade_logger_path, self.fw_upgrade_logger_path) + subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + logging.basicConfig(filename=self.fw_upgrade_logger_path, + filemode='a', + format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s', + datefmt='%b %d %H:%M:%S', + level=logging.INFO) + + log_message = "%s : %s" % (header, message) + if header != "last_upgrade_result": + print(log_message) + return logging.info(log_message) + + def get_bmc_pass(self): + if os.path.exists(self.bmc_pwd_path): + with open(self.bmc_pwd_path) as file: + data = file.read() + + key = "bmc" + dec = [] + enc = base64.urlsafe_b64decode(data) + for i in range(len(enc)): + key_c = key[i % len(key)] + dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256) + dec.append(dec_c) + return "".join(dec) + return False + + def get_bmc_version(self): + """Get BMC version from SONiC + :returns: version string + + """ + bmc_version = None + + bmc_version_key = "OpenBMC Version" + bmc_info_req = requests.get(self.bmc_info_url, timeout=60) + if bmc_info_req.status_code == 200: + bmc_info_json = bmc_info_req.json() + bmc_info = bmc_info_json.get('Information') + bmc_version = bmc_info.get(bmc_version_key) + return str(bmc_version) + + def upload_file_bmc(self, fw_path): + scp_command = 'sudo scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -r %s root@240.1.1.1:/home/root/' % os.path.abspath( + fw_path) + child = pexpect.spawn(scp_command) + i = child.expect(["root@240.1.1.1's password:"], timeout=30) + bmc_pwd = self.get_bmc_pass() + if i == 0 and bmc_pwd: + child.sendline(bmc_pwd) + data = child.read() + print(data) + child.close + return os.path.isfile(fw_path) + return False + + def get_cpld_version(self): + """Get CPLD version from SONiC + :returns: dict like {'CPLD_1': version_string, 'CPLD_2': version_string} + """ + + CPLD_B = self.__get_register_value(self.cpldb_version_path, '0xA100') + CPLD_C = self.__get_register_value(self.cpldb_version_path, '0xA1E0') + CPLD_1 = self.__get_register_value(self.switchboard_cpld1_path, '0x00') + CPLD_2 = self.__get_register_value(self.switchboard_cpld2_path, '0x00') + CPLD_3 = self.__get_register_value(self.switchboard_cpld3_path, '0x00') + CPLD_4 = self.__get_register_value(self.switchboard_cpld4_path, '0x00') + + fan_cpld_key = "FanCPLD Version" + fan_cpld = None + bmc_info_req = requests.get(self.bmc_info_url) + if bmc_info_req.status_code == 200: + bmc_info_json = bmc_info_req.json() + bmc_info = bmc_info_json.get('Information') + fan_cpld = bmc_info.get(fan_cpld_key) + + CPLD_B = 'None' if CPLD_B is 'None' else "{}.{}".format( + int(CPLD_B[2], 16), int(CPLD_B[3], 16)) + CPLD_C = 'None' if CPLD_C is 'None' else "{}.{}".format( + int(CPLD_C[2], 16), int(CPLD_C[3], 16)) + CPLD_1 = 'None' if CPLD_1 is 'None' else "{}.{}".format( + int(CPLD_1[2], 16), int(CPLD_1[3], 16)) + CPLD_2 = 'None' if CPLD_2 is 'None' else "{}.{}".format( + int(CPLD_2[2], 16), int(CPLD_2[3], 16)) + CPLD_3 = 'None' if CPLD_3 is 'None' else "{}.{}".format( + int(CPLD_3[2], 16), int(CPLD_3[3], 16)) + CPLD_4 = 'None' if CPLD_4 is 'None' else "{}.{}".format( + int(CPLD_4[2], 16), int(CPLD_4[3], 16)) + FAN_CPLD = 'None' if fan_cpld is None else "{}.{}".format( + int(fan_cpld[0], 16), int(fan_cpld[1], 16)) + + cpld_version_dict = {} + cpld_version_dict.update({'CPLD_B': CPLD_B}) + cpld_version_dict.update({'CPLD_C': CPLD_C}) + cpld_version_dict.update({'CPLD_1': CPLD_1}) + cpld_version_dict.update({'CPLD_2': CPLD_2}) + cpld_version_dict.update({'CPLD_3': CPLD_3}) + cpld_version_dict.update({'CPLD_4': CPLD_4}) + cpld_version_dict.update({'CPLD_FAN': FAN_CPLD}) + + return cpld_version_dict + + def get_bios_version(self): + """Get BIOS version from SONiC + :returns: version string + + """ + bios_version = None + + p = subprocess.Popen( + ["sudo", "dmidecode", "-s", "bios-version"], stdout=subprocess.PIPE) + raw_data = str(p.communicate()[0]) + if raw_data == '': + return str(None) + raw_data_list = raw_data.split("\n") + bios_version = raw_data_list[0] if len( + raw_data_list) == 1 else raw_data_list[-2] + + return str(bios_version) + + def get_onie_version(self): + """Get ONiE version from SONiC + :returns: version string + + """ + onie_verison = None + + onie_version_keys = "onie_version" + onie_config_file = open(self.onie_config_file, "r") + for line in onie_config_file.readlines(): + if onie_version_keys in line: + onie_version_raw = line.split('=') + onie_verison = onie_version_raw[1].strip() + break + onie_config_file.close() + return str(onie_verison) + + def get_pcie_version(self): + """Get PCiE version from SONiC + :returns: version dict { "PCIE_FW_LOADER": "2.5", "PCIE_FW": "D102_08" } + + """ + cmd = "sudo bcmcmd 'pciephy fw version'" + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + + pcie_version = dict() + pcie_version["PCIE_FW_LOADER"] = 'None' + pcie_version["PCIE_FW"] = 'None' + + if err == '': + lines = raw_data.split('\n') + for line in lines: + if 'PCIe FW loader' in line: + pcie_version["PCIE_FW_LOADER"] = line.split(':')[1].strip() + elif 'PCIe FW version' in line: + pcie_version["PCIE_FW"] = line.split(':')[1].strip() + return pcie_version + + def get_fpga_version(self): + """Get FPGA version from SONiC + :returns: version string + + """ + version = self.__get_register_value(self.fpga_version_path, '0x00') + if version is not 'None': + version = "{}.{}".format( + int(version[2:][:4], 16), int(version[2:][4:], 16)) + return str(version) + + def firmware_upgrade(self, fw_type, fw_path, fw_extra=None): + """ + @fw_type MANDATORY, firmware type, should be one of the strings: 'cpld', 'fpga', 'bios', 'bmc' + @fw_path MANDATORY, target firmware file + @fw_extra OPTIONAL, extra information string, + + for fw_type 'cpld' and 'fpga': it can be used to indicate specific cpld, such as 'cpld1', 'cpld2', ... + or 'cpld_fan_come_board', etc. If None, upgrade all CPLD/FPGA firmware. for fw_type 'bios' and 'bmc', + value should be one of 'master' or 'slave' or 'both' + """ + fw_type = fw_type.lower() + bmc_pwd = self.get_bmc_pass() + if not bmc_pwd and fw_type != "fpga": + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=BMC credential not found") + return False + + if fw_type == 'bmc': + self.__update_fw_upgrade_logger( + "bmc_upgrade", "start BMC upgrade") + # Copy BMC image file to BMC + fw_extra_str = str(fw_extra).lower() + last_fw_upgrade = ["BMC", fw_path, fw_extra_str, "FAILED"] + upload_file = self.upload_file_bmc(fw_path) + if not upload_file: + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=unable to upload BMC image to BMC") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + filename_w_ext = os.path.basename(fw_path) + json_data = dict() + json_data["path"] = "root@127.0.0.1:/home/root/%s" % filename_w_ext + json_data["password"] = bmc_pwd + + # Set flash type + current_bmc = self.get_running_bmc() + flash = fw_extra_str if fw_extra_str in [ + "master", "slave", "both"] else "both" + if fw_extra_str == "pingpong": + # flash = "master" if current_bmc == "slave" else "slave" + flash = "slave" + json_data["flash"] = flash + + # Install BMC + if flash == "both": + self.__update_fw_upgrade_logger( + "bmc_upgrade", "install BMC as master mode") + json_data["flash"] = "master" + r = requests.post(self.bmc_info_url, json=json_data) + if r.status_code != 200 or 'success' not in r.json().get('result'): + self.__update_fw_upgrade_logger( + "bmc_upgrade", "fail, message=BMC API report error code %d" % r.status_code) + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + json_data["flash"] = "slave" + + self.__update_fw_upgrade_logger( + "bmc_upgrade", "install BMC as %s mode" % json_data["flash"]) + r = requests.post(self.bmc_info_url, json=json_data) + if r.status_code == 200 and 'success' in r.json().get('result'): + if fw_extra_str == "pingpong": + flash = "master" if current_bmc == "slave" else "slave" + self.__update_fw_upgrade_logger( + "bmc_upgrade", "switch to boot from %s" % flash) + self.set_bmc_boot_flash(flash) + self.__update_fw_upgrade_logger( + "bmc_upgrade", "reboot BMC") + if not self.reboot_bmc(): + return False + else: + self.__update_fw_upgrade_logger( + "bmc_upgrade", "reboot BMC") + reboot_dict = {} + reboot_dict["reboot"] = "yes" + r = requests.post(self.bmc_info_url, json=reboot_dict) + last_fw_upgrade[3] = "DONE" + else: + self.__update_fw_upgrade_logger( + "bmc_upgrade", "fail, message=unable to install BMC image") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + self.__update_fw_upgrade_logger( + "bmc_upgrade", "done") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return True + + elif fw_type == 'fpga': + last_fw_upgrade = ["FPGA", fw_path, None, "FAILED"] + self.__update_fw_upgrade_logger( + "fpga_upgrade", "start FPGA upgrade") + + if not os.path.isfile(fw_path): + self.__update_fw_upgrade_logger( + "fpga_upgrade", "fail, message=FPGA image not found %s" % fw_path) + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + command = 'fpga_prog ' + fw_path + print("Running command : %s" % command) + process = subprocess.Popen( + command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + + rc = process.returncode + if rc != 0: + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=unable to install FPGA") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + self.__update_fw_upgrade_logger("fpga_upgrade", "done") + last_fw_upgrade[3] = "DONE" + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + self.firmware_refresh(["FPGA"], None, None) + return True + + elif 'cpld' in fw_type: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "start CPLD upgrade") + # Check input + fw_extra_str = str(fw_extra).upper() + if ":" in fw_path and ":" in fw_extra_str: + fw_path_list = fw_path.split(":") + fw_extra_str_list = fw_extra_str.split(":") + else: + fw_path_list = [fw_path] + fw_extra_str_list = [fw_extra_str] + + if len(fw_path_list) != len(fw_extra_str_list): + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=invalid input") + return False + + data_list = list(zip(fw_path_list, fw_extra_str_list)) + refresh_img_path = None + cpld_result_list = ["FAILED" for i in range( + 0, len(fw_extra_str_list))] + last_fw_upgrade = ["CPLD", ":".join( + fw_path_list), ":".join(fw_extra_str_list), ":".join(cpld_result_list)] + for i in range(0, len(data_list)): + data = data_list[i] + fw_path = data[0] + fw_extra_str = data[1] + + # Set fw_extra + fw_extra_str = { + "TOP_LC_CPLD": "top_lc", + "BOT_LC_CPLD": "bottom_lc", + "FAN_CPLD": "fan", + "CPU_CPLD": "cpu", + "BASE_CPLD": "base", + "COMBO_CPLD": "combo", + "SW_CPLD1": "switch", + "SW_CPLD2": "switch", + "REFRESH_CPLD": "refresh" + }.get(fw_extra_str, None) + + if fw_extra_str == "refresh": + refresh_img_path = fw_path + del cpld_result_list[i] + del fw_extra_str_list[i] + continue + + if fw_extra_str is None: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=invalid extra information string") + continue + + # Uploading image to BMC + self.__update_fw_upgrade_logger( + "cpld_upgrade", "start %s upgrade" % data[1]) + upload_file = self.upload_file_bmc(fw_path) + if not upload_file: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=unable to upload BMC image to BMC") + continue + + filename_w_ext = os.path.basename(fw_path) + json_data = dict() + json_data["image_path"] = "root@127.0.0.1:/home/root/%s" % filename_w_ext + json_data["password"] = bmc_pwd + json_data["device"] = "cpld" + json_data["reboot"] = "no" + json_data["type"] = fw_extra_str + + # Call BMC api to install cpld image + print("Installing...") + r = requests.post(self.fw_upgrade_url, json=json_data) + if r.status_code != 200 or 'success' not in r.json().get('result'): + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=invalid cpld image") + continue + + cpld_result_list[i] = "DONE" + self.__update_fw_upgrade_logger( + "cpld_upgrade", "%s upgrade done" % data[1]) + last_fw_upgrade[3] = ":".join(cpld_result_list) + self.__update_fw_upgrade_logger( + "cpld_upgrade", "done") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + + # Refresh CPLD + refresh_img_str_list = [] + for fw_extra in fw_extra_str_list: + if "BASE_CPLD" in fw_extra or "FAN_CPLD" in fw_extra: + refresh_img_str_list.append(refresh_img_path) + else: + refresh_img_str_list.append("None") + self.firmware_refresh(None, fw_extra_str_list, + ":".join(refresh_img_str_list)) + + return True + + elif 'bios' in fw_type: + self.__update_fw_upgrade_logger( + "bios_upgrade", "start BIOS upgrade") + last_fw_upgrade = ["BIOS", fw_path, None, "FAILED"] + fw_extra_str = str(fw_extra).lower() + flash = fw_extra_str if fw_extra_str in [ + "master", "slave"] else "master" + + if not os.path.exists(fw_path): + self.__update_fw_upgrade_logger( + "bios_upgrade", "fail, message=image not found") + return False + + scp_command = 'sudo scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -r %s root@240.1.1.1:/home/root/' % os.path.abspath( + fw_path) + child = pexpect.spawn(scp_command) + i = child.expect(["root@240.1.1.1's password:"], timeout=30) + if i != 0: + self.__update_fw_upgrade_logger( + "bios_upgrade", "fail, message=unable to upload image to BMC") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + child.sendline(bmc_pwd) + data = child.read() + print(data) + child.close + + json_data = dict() + json_data["data"] = "/usr/bin/ipmitool -b 1 -t 0x2c raw 0x2e 0xdf 0x57 0x01 0x00 0x01" + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + self.__update_fw_upgrade_logger( + "bios_upgrade", "fail, message=unable to set state") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + filename_w_ext = os.path.basename(fw_path) + json_data = dict() + json_data["image_path"] = "root@127.0.0.1:/home/root/%s" % filename_w_ext + json_data["password"] = bmc_pwd + json_data["device"] = "bios" + json_data["flash"] = flash + json_data["reboot"] = "no" + + print("Installing...") + r = requests.post(self.fw_upgrade_url, json=json_data) + if r.status_code != 200 or 'success' not in r.json().get('result'): + self.__update_fw_upgrade_logger( + "bios_upgrade", "fail, message=unable install bios") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + last_fw_upgrade[3] = "DONE" + self.__update_fw_upgrade_logger( + "bios_upgrade", "done") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + else: + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=invalid firmware type") + return False + + return True + + def get_last_upgrade_result(self): + """ + Get last firmware upgrade information, inlcudes: + 1) FwType: cpld/fpga/bios/bmc(passed by method 'firmware_upgrade'), string + 2) FwPath: path and file name of firmware(passed by method 'firmware_upgrade'), string + 3) FwExtra: designated string, econdings of this string is determined by vendor(passed by method 'firmware_program') + 4) Result: indicates whether the upgrade action is performed and success/failure status if performed. Values should be one of: "DONE"/"FAILED"/"NOT_PERFORMED". + list of object: + [ + { + "FwType": "cpld", + "FwPath": "cpu_cpld.vme" + "FwExtra":"CPU_CPLD" + "Result": "DONE" + }, + { + "FwType": "cpld", + "FwPath": "fan_cpld.vme" + "FwExtra": "FAN_CPLD" + "Result": "FAILED" + } + ] + """ + last_update_list = [] + + if os.path.exists(self.fw_upgrade_logger_path): + with open(self.fw_upgrade_logger_path, 'r') as file: + lines = file.read().splitlines() + + upgrade_txt = [i for i in reversed( + lines) if "last_upgrade_result" in i] + if len(upgrade_txt) > 0: + last_upgrade_txt = upgrade_txt[0].split( + "last_upgrade_result : ") + last_upgrade_list = ast.literal_eval(last_upgrade_txt[1]) + for x in range(0, len(last_upgrade_list[1].split(":"))): + upgrade_dict = {} + upgrade_dict["FwType"] = last_upgrade_list[0].lower() + upgrade_dict["FwPath"] = last_upgrade_list[1].split(":")[x] + upgrade_dict["FwExtra"] = last_upgrade_list[2].split(":")[ + x] if last_upgrade_list[2] else "None" + upgrade_dict["Result"] = last_upgrade_list[3].split(":")[x] + last_update_list.append(upgrade_dict) + + return last_update_list + + def firmware_program(self, fw_type, fw_path, fw_extra=None): + """ + Program FPGA and/or CPLD firmware only, but do not refresh them + + @param fw_type value can be: FPGA, CPLD + @param fw_path a string of firmware file path, seperated by ':', it should + match the sequence of param @fw_type + @param fw_extra a string of firmware subtype, i.e CPU_CPLD, BOARD_CPLD, + FAN_CPLD, LC_CPLD, etc. Subtypes are seperated by ':' + @return True when all required firmware is program succefully, + False otherwise. + + Example: + self.firmware_program("CPLD", "/cpu_cpld.vme:/lc_cpld", \ + "CPU_CPLD:LC_CPLD") + or + self.firmware_program("FPGA", "/fpga.bin") + """ + fw_type = fw_type.lower() + bmc_pwd = self.get_bmc_pass() + if not bmc_pwd and fw_type != "fpga": + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=BMC credential not found") + return False + + if fw_type == 'fpga': + last_fw_upgrade = ["FPGA", fw_path, None, "FAILED"] + self.__update_fw_upgrade_logger( + "fpga_upgrade", "start FPGA upgrade") + + if not os.path.isfile(fw_path): + self.__update_fw_upgrade_logger( + "fpga_upgrade", "fail, message=FPGA image not found %s" % fw_path) + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + command = 'fpga_prog ' + fw_path + print("Running command: %s" % command) + process = subprocess.Popen( + command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + + rc = process.returncode + if rc != 0: + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=Unable to install FPGA") + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return False + + self.__update_fw_upgrade_logger("fpga_upgrade", "done") + last_fw_upgrade[3] = "DONE" + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return True + + elif 'cpld' in fw_type: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "start CPLD upgrade") + + # Check input + fw_extra_str = str(fw_extra).upper() + if ":" in fw_path and ":" in fw_extra_str: + fw_path_list = fw_path.split(":") + fw_extra_str_list = fw_extra_str.split(":") + else: + fw_path_list = [fw_path] + fw_extra_str_list = [fw_extra_str] + + if len(fw_path_list) != len(fw_extra_str_list): + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=Invalid input") + return False + + cpld_result_list = [] + data_list = list(zip(fw_path_list, fw_extra_str_list)) + for data in data_list: + fw_path = data[0] + fw_extra_str = data[1] + + # Set fw_extra + fw_extra_str = { + "TOP_LC_CPLD": "top_lc", + "BOT_LC_CPLD": "bottom_lc", + "FAN_CPLD": "fan", + "CPU_CPLD": "cpu", + "BASE_CPLD": "base", + "COMBO_CPLD": "combo", + "SW_CPLD1": "switch", + "SW_CPLD2": "switch" + }.get(fw_extra_str, None) + + self.__update_fw_upgrade_logger( + "cpld_upgrade", "start %s upgrade" % data[1]) + upgrade_result = "FAILED" + for x in range(1, 4): + # Set fw_extra + if x > 1: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=Retry to upgrade %s" % data[1]) + + elif fw_extra_str is None: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=Invalid extra information string %s" % data[1]) + break + elif not os.path.isfile(os.path.abspath(fw_path)): + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=CPLD image not found %s" % fw_path) + break + + # Install cpld image via ispvm tool + print("Installing...") + command = 'ispvm %s' % fw_path + if fw_extra_str in ["top_lc", "bottom_lc"]: + option = 1 if fw_extra_str == "top_lc" else 2 + command = "ispvm -c %d %s" % (option, + os.path.abspath(fw_path)) + print("Running command : %s" % command) + process = subprocess.Popen( + command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + + rc = process.returncode + if rc != 0: + self.__update_fw_upgrade_logger( + "cpld_upgrade", "fail, message=Unable to install CPLD") + continue + + upgrade_result = "DONE" + self.__update_fw_upgrade_logger("cpld_upgrade", "done") + break + cpld_result_list.append(upgrade_result) + + last_fw_upgrade = ["CPLD", ":".join( + fw_path_list), ":".join(fw_extra_str_list), ":".join(cpld_result_list)] + self.__update_fw_upgrade_logger( + "last_upgrade_result", str(last_fw_upgrade)) + return "FAILED" not in cpld_result_list + else: + self.__update_fw_upgrade_logger( + "fw_upgrade", "fail, message=Invalid firmware type") + return False + + return True + + def firmware_refresh(self, fpga_list, cpld_list, fw_extra=None): + """ + Refresh firmware and take extra action when necessary. + @param fpga_list a list of FPGA names + @param cpld_list a list of CPLD names + @return True if refresh succefully and no power cycle action is taken. + + @Note extra action should be: power cycle the whole system(except BMC) when + CPU_CPLD or BOARD_CPLD or FPGA is refreshed. + No operation if the power cycle is not needed. + + Example: + self.firmware_refresh( + ["FPGA"], ["BASE_CPLD", "LC_CPLD"],"/tmp/fw/refresh.vme") + or + self.firmware_refresh(["FPGA"], None, None) + or + self.firmware_refresh(None, ["FAN_CPLD", "LC1_CPLD", "BASE_CPLD"], + "/tmp/fw/fan_refresh.vme:none:/tmp/fw/base_refresh.vme") + """ + + if not fpga_list and not cpld_list: + return False + + if type(cpld_list) is list and ("BASE_CPLD" in cpld_list or "FAN_CPLD" in cpld_list): + refresh_list = fpga_list + \ + cpld_list if type(fpga_list) is list else cpld_list + self.__update_fw_upgrade_logger( + "fw_refresh", "start %s refresh" % ",".join(refresh_list)) + fw_path_list = fw_extra.split(':') + command = "echo " + if len(fw_path_list) != len(cpld_list): + self.__update_fw_upgrade_logger( + "cpld_refresh", "fail, message=Invalid fw_extra") + return False + + for idx in range(0, len(cpld_list)): + fw_path = fw_path_list[idx] + refresh_type = { + "BASE_CPLD": "base", + "FAN_CPLD": "fan" + }.get(cpld_list[idx], None) + + if not refresh_type: + continue + elif not self.upload_file_bmc(fw_path): + self.__update_fw_upgrade_logger( + "cpld_refresh", "fail, message=Unable to upload refresh image to BMC") + return False + else: + filename_w_ext = os.path.basename(fw_path) + + sub_command = "%s /home/root/%s > /tmp/cpld_refresh " % ( + refresh_type, filename_w_ext) + command += sub_command + + json_data = dict() + json_data["data"] = command + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + self.__update_fw_upgrade_logger( + "cpld_refresh", "fail, message=%d Invalid refresh image" % r.status_code) + return False + elif type(cpld_list) is list: + refresh_list = fpga_list + \ + cpld_list if type(fpga_list) is list else cpld_list + self.__update_fw_upgrade_logger( + "fw_refresh", "start %s refresh" % ",".join(refresh_list)) + json_data = dict() + json_data["data"] = "echo cpu_cpld > /tmp/cpld_refresh" + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + self.__update_fw_upgrade_logger( + "cpld_refresh", "fail, message=%d Unable to load new CPLD" % r.status_code) + return False + elif type(fpga_list) is list: + self.__update_fw_upgrade_logger( + "fw_refresh", "start FPGA refresh") + json_data = dict() + json_data["data"] = "echo fpga > /tmp/cpld_refresh" + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + self.__update_fw_upgrade_logger( + "cpld_refresh", "fail, message=%d Unable to load new FPGA" % r.status_code) + return False + else: + self.__update_fw_upgrade_logger( + "fw_refresh", "fail, message=Invalid input") + return False + + self.__update_fw_upgrade_logger("fw_refresh", "done") + return True + + def get_running_bmc(self): + """ + Get booting flash of running BMC. + @return a string, "master" or "slave" + """ + json_data = dict() + json_data["data"] = "/usr/local/bin/boot_info.sh" + r = requests.post(self.bmc_raw_command_url, json=json_data) + try: + boot_info_list = r.json().get('result') + for boot_info_raw in boot_info_list: + boot_info = boot_info_raw.split(":") + if "Current Boot Code Source" in boot_info[0]: + flash = "master" if "master "in boot_info[1].lower( + ) else "slave" + return flash + raise Exception( + "Error: Unable to detect booting flash of running BMC") + except Exception as e: + raise Exception(e) + + def set_bmc_boot_flash(self, flash): + """ + Set booting flash of BMC + @param flash should be "master" or "slave" + """ + if flash.lower() not in ["master", "slave"]: + return False + json_data = dict() + json_data["data"] = "source /usr/local/bin/openbmc-utils.sh;bmc_reboot %s" % flash + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + return False + return True + + def reboot_bmc(self): + """ + Reboot BMC + """ + json_data = dict() + json_data["data"] = "source /usr/local/bin/openbmc-utils.sh;bmc_reboot reboot" + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + return False + return True + + def get_current_bios(self): + """ + # Get booting bios image of current running host OS + # @return a string, "master" or "slave" + """ + json_data = dict() + json_data["data"] = "source /usr/local/bin/openbmc-utils.sh;come_boot_info" + r = requests.post(self.bmc_raw_command_url, json=json_data) + try: + cpu_boot_info_list = r.json().get('result') + for cpu_boot_info_raw in cpu_boot_info_list: + if "COMe CPU boots from BIOS" in cpu_boot_info_raw: + bios_image = "master" if "master "in cpu_boot_info_raw.lower( + ) else "slave" + return bios_image + raise Exception( + "Error: Unable to detect current running bios image") + except Exception as e: + raise Exception(e) diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil.py new file mode 100644 index 000000000000..0e5b6a1c7109 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python + +# +# optictemputil.py +# +# Platform-specific Optic module temperature Interface for SONiC +# + +__author__ = 'Pradchaya P.' +__author__ = 'Wirut G.' +__license__ = "GPL" +__version__ = "1.0.0" +__status__ = "Development" + +import os +import sys +import binascii +import subprocess + +class OpticTempUtil(): + """Platform-specific OpticTempUtil class""" + + def __init__(self): + pass + + def read_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes): + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + try: + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + except IOError: + return None + + try: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except: + return None + + return eeprom_raw + + + def twos_comp(self, num, bits): + try: + if ((num & (1 << (bits - 1))) != 0): + num = num - (1 << bits) + return num + except: + return 0 + + + def calc_temperature(self, cal_type, eeprom_data, offset, size): + + msb = int(eeprom_data[offset], 16) + lsb = int(eeprom_data[offset + 1], 16) + + result = (msb << 8) | (lsb & 0xff) + result = self.twos_comp(result, 16) + + if cal_type == 1: + # Internal calibration + result = float(result / 256.0) + retval = '%.4f' %result + + # TODO: Should support external calibration in future. + else: + retval = 0 + + return retval + + ''' TODO: Change busnum to sysfs_sfp_i2c_client_eeprom_path from caller!!! + ''' + def get_optic_temp(self, sysfs_sfp_i2c_client_eeprom_path, port_type): + + EEPROM_ADDR = 0x50 + DOM_ADDR = 0x51 + EEPROM_OFFSET = 0 + DOM_OFFSET = 256 + + SFP_DMT_ADDR = 92 + SFP_DMT_WIDTH = 1 + SFP_TEMP_DATA_ADDR = 96 + SFP_TEMP_DATA_WIDTH = 2 + + QSFP_TEMP_DATA_ADDR = 22 + QSFP_TEMP_DATA_WIDTH = 2 + temperature_raw = None + + + ''' Open file here ''' + try: + sysfsfile_eeprom = open(sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % sysfs_sfp_i2c_client_eeprom_path) + return 0 + + if port_type == 'QSFP': + + # QSFP only have internal calibration mode. + cal_type = 1 + # read temperature raw value + temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(EEPROM_OFFSET+QSFP_TEMP_DATA_ADDR),QSFP_TEMP_DATA_WIDTH) + else: + # read calibration type at bit 5 + cal_type = self.read_eeprom_specific_bytes(sysfsfile_eeprom,EEPROM_OFFSET+SFP_DMT_ADDR,SFP_DMT_WIDTH) + if cal_type is None: + return 0 + else: + cal_type = (int(cal_type[0],16) >> 5 ) & 1 + # read temperature raw value + temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(DOM_OFFSET+SFP_TEMP_DATA_ADDR),SFP_TEMP_DATA_WIDTH) + + try: + sysfsfile_eeprom.close() + except IOError: + print("Error: closing sysfs file %s" % file_path) + return 0 + + #calculate temperature + if temperature_raw is not None: + return self.calc_temperature(cal_type, temperature_raw, 0, 2) + else: + return 0 \ No newline at end of file diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_lp.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_lp.py new file mode 100644 index 000000000000..0e5b6a1c7109 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_lp.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python + +# +# optictemputil.py +# +# Platform-specific Optic module temperature Interface for SONiC +# + +__author__ = 'Pradchaya P.' +__author__ = 'Wirut G.' +__license__ = "GPL" +__version__ = "1.0.0" +__status__ = "Development" + +import os +import sys +import binascii +import subprocess + +class OpticTempUtil(): + """Platform-specific OpticTempUtil class""" + + def __init__(self): + pass + + def read_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes): + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + try: + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + except IOError: + return None + + try: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except: + return None + + return eeprom_raw + + + def twos_comp(self, num, bits): + try: + if ((num & (1 << (bits - 1))) != 0): + num = num - (1 << bits) + return num + except: + return 0 + + + def calc_temperature(self, cal_type, eeprom_data, offset, size): + + msb = int(eeprom_data[offset], 16) + lsb = int(eeprom_data[offset + 1], 16) + + result = (msb << 8) | (lsb & 0xff) + result = self.twos_comp(result, 16) + + if cal_type == 1: + # Internal calibration + result = float(result / 256.0) + retval = '%.4f' %result + + # TODO: Should support external calibration in future. + else: + retval = 0 + + return retval + + ''' TODO: Change busnum to sysfs_sfp_i2c_client_eeprom_path from caller!!! + ''' + def get_optic_temp(self, sysfs_sfp_i2c_client_eeprom_path, port_type): + + EEPROM_ADDR = 0x50 + DOM_ADDR = 0x51 + EEPROM_OFFSET = 0 + DOM_OFFSET = 256 + + SFP_DMT_ADDR = 92 + SFP_DMT_WIDTH = 1 + SFP_TEMP_DATA_ADDR = 96 + SFP_TEMP_DATA_WIDTH = 2 + + QSFP_TEMP_DATA_ADDR = 22 + QSFP_TEMP_DATA_WIDTH = 2 + temperature_raw = None + + + ''' Open file here ''' + try: + sysfsfile_eeprom = open(sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % sysfs_sfp_i2c_client_eeprom_path) + return 0 + + if port_type == 'QSFP': + + # QSFP only have internal calibration mode. + cal_type = 1 + # read temperature raw value + temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(EEPROM_OFFSET+QSFP_TEMP_DATA_ADDR),QSFP_TEMP_DATA_WIDTH) + else: + # read calibration type at bit 5 + cal_type = self.read_eeprom_specific_bytes(sysfsfile_eeprom,EEPROM_OFFSET+SFP_DMT_ADDR,SFP_DMT_WIDTH) + if cal_type is None: + return 0 + else: + cal_type = (int(cal_type[0],16) >> 5 ) & 1 + # read temperature raw value + temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(DOM_OFFSET+SFP_TEMP_DATA_ADDR),SFP_TEMP_DATA_WIDTH) + + try: + sysfsfile_eeprom.close() + except IOError: + print("Error: closing sysfs file %s" % file_path) + return 0 + + #calculate temperature + if temperature_raw is not None: + return self.calc_temperature(cal_type, temperature_raw, 0, 2) + else: + return 0 \ No newline at end of file diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_rl.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_rl.py new file mode 100644 index 000000000000..9f679799aeec --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_rl.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python + +# +# optictemputil.py +# +# Platform-specific Optic module temperature Interface for SONiC +# + +__author__ = 'Pradchaya P.' +__author__ = 'Wirut G.' +__license__ = "GPL" +__version__ = "1.0.0" +__status__ = "Development" + +import os +import sys +import binascii +import subprocess + +class OpticTempUtil(): + """Platform-specific OpticTempUtil class""" + + def __init__(self): + pass + + def read_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes): + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + try: + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + except IOError: + return None + + try: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except: + return None + + return eeprom_raw + + + def twos_comp(self, num, bits): + try: + if ((num & (1 << (bits - 1))) != 0): + num = num - (1 << bits) + return num + except: + return 0 + + + def calc_temperature(self, cal_type, eeprom_data, offset, size): + + msb = int(eeprom_data[offset], 16) + lsb = int(eeprom_data[offset + 1], 16) + + thousand_digit_int = (msb >> 4) & 0x0f + hundred_digit_int = msb & 0x0f + tens_digit_int = (lsb >> 4) & 0x0f + single_digit_int = lsb & 0x0f + + result = thousand_digit_int * 16 * 16 * 16 + hundred_digit_int * 16 * 16 + + tens_digit_int * 16 + single_digit_int + + #result = self.twos_comp(result, 16) + + if cal_type == 1: + # Internal calibration + result = float(result / 256.0) + retval = '%.4f' %result + + # TODO: Should support external calibration in future. + else: + retval = 0 + + return retval + + ''' TODO: Change busnum to sysfs_sfp_i2c_client_eeprom_path from caller!!! + ''' + def get_optic_temp(self, sysfs_sfp_i2c_client_eeprom_path, port_type): + + EEPROM_ADDR = 0x50 + DOM_ADDR = 0x51 + EEPROM_OFFSET = 0 + DOM_OFFSET = 256 + + SFP_DMT_ADDR = 92 + SFP_DMT_WIDTH = 1 + SFP_TEMP_DATA_ADDR = 96 + SFP_TEMP_DATA_WIDTH = 2 + + QSFP_TEMP_DATA_ADDR = 14 + QSFP_TEMP_DATA_WIDTH = 2 + temperature_raw = None + + + ''' Open file here ''' + try: + sysfsfile_eeprom = open(sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % sysfs_sfp_i2c_client_eeprom_path) + return 0 + + if port_type == 'QSFP': + + # QSFP only have internal calibration mode. + cal_type = 1 + # read temperature raw value + temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(EEPROM_OFFSET+QSFP_TEMP_DATA_ADDR),QSFP_TEMP_DATA_WIDTH) + else: + # read calibration type at bit 5 + cal_type = self.read_eeprom_specific_bytes(sysfsfile_eeprom,EEPROM_OFFSET+SFP_DMT_ADDR,SFP_DMT_WIDTH) + if cal_type is None: + return 0 + else: + cal_type = (int(cal_type[0],16) >> 5 ) & 1 + # read temperature raw value + temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(DOM_OFFSET+SFP_TEMP_DATA_ADDR),SFP_TEMP_DATA_WIDTH) + + try: + sysfsfile_eeprom.close() + except IOError: + print("Error: closing sysfs file %s" % file_path) + return 0 + + #calculate temperature + if temperature_raw is not None: + return self.calc_temperature(cal_type, temperature_raw, 0, 2) + else: + return 0 diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/psuutil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/psuutil.py new file mode 100644 index 000000000000..d3a27117f5a2 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/psuutil.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python + +__author__ = 'Wirut G.' +__license__ = "GPL" +__version__ = "0.1.4" +__status__ = "Development" + +import requests +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): + PsuBase.__init__(self) + self.fru_status_url = "http://240.1.1.1:8080/api/sys/fruid/status" + self.psu_info_url = "http://240.1.1.1:8080/api/sys/fruid/psu" + + self.fru_status_list = None + self.psu_info_list = None + + def request_data(self): + # Reqest data from BMC if not exist. + if self.fru_status_list is None or self.psu_info_list is None: + fru_status_req = requests.get(self.fru_status_url) + psu_info_req = requests.get(self.psu_info_url) + fru_status_json = fru_status_req.json() + psu_info_json = psu_info_req.json() + self.fru_status_list = fru_status_json.get('Information') + self.psu_info_list = psu_info_json.get('Information') + return self.fru_status_list, self.psu_info_list + + def airflow_selector(self, pn): + # Set airflow type + pn = pn.upper() + if "DPS-1100FB" in pn: + airflow = "FTOB" + elif "DPS-1100AB" in pn: + airflow = "BTOF" + elif "FSJ026-A20G" in pn: + airflow = "FTOB" + elif "FSJ038-A20G" in pn: + airflow = "BTOF" + else: + airflow = "Unknown" + return airflow + + 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 + """ + + num_psus = 2 + + return num_psus + + 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 + """ + + # init data + psu_key = "PSU" + str(index) + psu_status_key = "Power Status" + psu_power_status = False + + try: + # Request and validate sensor's information + self.fru_status_list, self.psu_info_list = self.request_data() + + # Get PSU power status. + for fru_status in self.fru_status_list: + is_psu = fru_status.get(psu_key) + psu_status = str(fru_status.get(psu_status_key)).strip() + + if is_psu is not None and psu_status == "OK": + psu_power_status = True + + except: + print("Error: Unable to access PSU power status") + return False + + return psu_power_status + + 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 + """ + + # Init data + psu_key = "PSU" + str(index) + psu_presence_key = "Present" + psu_presence_status = False + + try: + # Request and validate sensor's information. + self.fru_status_list, self.psu_info_list = self.request_data() + + # Get PSU present status. + for fru_status in self.fru_status_list: + is_psu = fru_status.get(psu_key) + psu_status = str(fru_status.get(psu_presence_key)).strip() + + if is_psu is not None and psu_status == "Present": + psu_presence_status = True + + except: + print("Error: Unable to access PSU presence status") + return False + + return psu_presence_status + + def get_psu_sn(self, index): + """ + Get the serial number of the psu, + + :param index: An integer, 1-based index of the PSU. + :return: Serial number + """ + serial_number = "N/A" + psu_key = "PSU" + str(index) + " FRU" + psu_sn_key = "Serial Number" + + try: + # Request and validate sensor's information. + self.fru_status_list, self.psu_info_list = self.request_data() + + # Get PSU fru info. + for psu_fru in self.psu_info_list: + psu_sn = str(psu_fru.get(psu_sn_key)).strip() + if psu_fru.get(psu_key) is not None: + serial_number = psu_sn if psu_sn.strip() != "" else "N/A" + break + + except: + return "N/A" + + return serial_number + + def get_psu_pn(self, index): + """ + Get the product name of the psu + + :param index: An integer, 1-based index of the PSU. + :return: Product name + """ + product_name = "N/A" + psu_key = "PSU" + str(index) + " FRU" + psu_pn_key = "Product Name" + + try: + # Request and validate sensor's information + self.fru_status_list, self.psu_info_list = self.request_data() + + # Get PSU fru info. + for psu_fru in self.psu_info_list: + psu_pn = str(psu_fru.get(psu_pn_key)).strip() + if psu_fru.get(psu_key) is not None: + product_name = psu_pn if psu_pn.strip() != "" else "N/A" + break + + except: + return "N/A" + + return product_name + + def get_all(self): + """ + Number: mandatory, max number of PSU, integer + PSU1, PSU2, ...: mandatory, PSU name, string + Present: mandatory for each PSU, present status, boolean, True for present, False for NOT present + PowerStatus: conditional, if PRESENT is True, power status of PSU,boolean, True for powered, False for NOT powered + PN, conditional, if PRESENT is True, PN of the PSU, string + SN, conditional, if PRESENT is True, SN of the PSU, string + """ + + # Init data + all_psu_dict = dict() + all_psu_dict["Number"] = self.get_num_psus() + psu_sn_key_1 = "Serial Number" + psu_sn_key_2 = "Product Serial" + psu_pn_key = "Product Name" + + # Request and validate sensor's information. + self.fru_status_list, self.psu_info_list = self.request_data() + + # Set PSU FRU data. + psu_info_dict = dict() + for psu_fru in self.psu_info_list: + psu_data = dict() + pn = psu_fru.get(psu_pn_key) + sn = psu_fru.get(psu_sn_key_1) or psu_fru.get(psu_sn_key_2) + psu_data["PN"] = "N/A" if not pn or str( + pn).strip() == "" else str(pn).strip() + psu_data["SN"] = "N/A" if not pn or str( + pn).strip() == "" else str(sn).strip() + + fru_check = [psu_fru[v] for v in psu_fru.keys() if 'FRU Info' in v] + non_fru_check = [v for v in psu_fru.keys() if 'PSU' in v] + + if len(non_fru_check) > 0: + psu_idx = int(re.findall('\d+', non_fru_check[0])[0]) + psu_info_dict[psu_idx] = psu_data + elif len(fru_check) > 0: + psu_idx = int(re.findall('\d+', fru_check[0])[0]) + psu_info_dict[psu_idx] = psu_data + + # Set PSU status. + for fru_status in self.fru_status_list: + psu_status_dict = dict() + find_psu = [v for v in fru_status.keys() if "PSU" in v] + if len(find_psu) > 0: + psu_idx = int(re.findall('\d+', find_psu[0])[0]) + psu_ps_status = True if str(fru_status.get( + "Present")).strip() == "Present" else False + psu_pw_status = True if str(fru_status.get( + "Power Status")).strip() == "OK" else False + psu_pw_type = str(fru_status.get( + "Power Type")).strip() + ac_status = True if str(fru_status.get( + "AC Status")).strip().upper() == "OK" else False + + psu_status_dict["Present"] = psu_ps_status + if psu_ps_status: + psu_status_dict["PowerStatus"] = psu_pw_status + psu_status_dict["PN"] = psu_info_dict[psu_idx]["PN"] + psu_status_dict["SN"] = psu_info_dict[psu_idx]["SN"] + psu_status_dict["InputType"] = psu_pw_type + psu_status_dict["InputStatus"] = True if psu_pw_status and psu_ps_status else False + psu_status_dict["OutputStatus"] = ac_status + psu_status_dict["AirFlow"] = self.airflow_selector( + psu_status_dict["PN"]) + all_psu_dict[find_psu[0]] = psu_status_dict + + return all_psu_dict diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sensorutil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sensorutil.py new file mode 100644 index 000000000000..796949126ccc --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sensorutil.py @@ -0,0 +1,369 @@ +#!/usr/bin/env python + +__author__ = 'Wirut G.' +__license__ = "GPL" +__version__ = "0.2.0" +__status__ = "Development" + +import requests + + +class SensorUtil(): + """Platform-specific SensorUtil class""" + + def __init__(self): + self.sensor_url = "http://240.1.1.1:8080/api/sys/sensors" + self.sys_fruid_url = "http://240.1.1.1:8080/api/sys/fruid/sys" + self.sensor_info_list = None + + def request_data(self): + # Reqest data from BMC if not exist. + if self.sensor_info_list is None: + sensor_data_req = requests.get(self.sensor_url) + sensor_json = sensor_data_req.json() + self.sensor_info_list = sensor_json.get('Information') + sys_fruid_req = requests.get(self.sys_fruid_url) + sys_fruid_json = sys_fruid_req.json() + self.sys_fruid_list = sys_fruid_json.get('Information') + return self.sensor_info_list + + def input_type_selector(self, unit): + # Set input type. + return { + "C": "temperature", + "V": "voltage", + "RPM": "RPM", + "A": "amp", + "W": "power" + }.get(unit, unit) + + def input_name_selector(self, sensor_name, input_name): + + self.sensor_name = { + "syscpld-i2c-0-0d": "TEMPERATURE", + "dps1100-i2c-24-58": "PSU1", + "dps1100-i2c-25-59": "PSU2", + "fancpld-i2c-8-0d": "FAN" + }.get(sensor_name, sensor_name) + + if 'dps1100' in sensor_name: + input_name = { + "fan1": self.sensor_name + "_FAN", + "iin": self.sensor_name + "_CURR_I", + "iout1": self.sensor_name + "_CURR_O", + "pin": self.sensor_name + "_POWER_I", + "pout1": self.sensor_name + "_POWER_O", + "temp1": self.sensor_name + "_TEMP1", + "temp2": self.sensor_name + "_TEMP2", + "vin": self.sensor_name + "_VOL_I", + "vout1": self.sensor_name + "_VOL_O" + }.get(input_name, input_name) + + elif 'tmp75' in sensor_name: + input_name = { + "tmp75-i2c-7-4d": "FTB_INLET_RIGHT", + "tmp75-i2c-7-4c": "FTB_INLET_LEFT", + "tmp75-i2c-7-4b": "FTB_SWITCH_OUTLET", + "tmp75-i2c-7-4a": "BTF_SWITCH_OUTLET", + "tmp75-i2c-39-48": "BTF_INLET_RIGHT", + "tmp75-i2c-39-49": "BTF_INLET_LEFT" + }.get(sensor_name, input_name) + if self.get_sys_airflow() == "FTOB" and sensor_name == "tmp75-i2c-7-4d": + input_name = "INLET_TEMP" + + if self.get_sys_airflow() == "BTOF" and sensor_name == "tmp75-i2c-39-48": + input_name = "INLET_TEMP" + + self.sensor_name = "TEMPERATURE" + + elif 'fancpld' in sensor_name: + raw_fan_input = input_name.split() + input_name = raw_fan_input[0] + \ + raw_fan_input[1] + "_" + raw_fan_input[2] + + elif 'ir35' in sensor_name or 'ir38' in sensor_name: + sensor_name_raw = sensor_name.split("-") + sensor_name = sensor_name_raw[0] + self.sensor_name = sensor_name.upper() + + return input_name.replace(" ", "_").upper() + + def get_num_sensors(self): + """ + Get the number of sensors + :return: int num_sensors + """ + + num_sensors = 0 + try: + # Request and validate sensor's information + self.sensor_info_list = self.request_data() + + # Get number of sensors. + num_sensors = len(self.sensor_info_list) + except: + print "Error: Unable to access sensor information" + return 0 + + return num_sensors + + def get_sensor_input_num(self, index): + """ + Get the number of the input items of the specified sensor + :return: int input_num + """ + + input_num = 0 + try: + # Request and validate sensor's information. + self.sensor_info_list = self.request_data() + + # Get sensor's input number. + sensor_data = self.sensor_info_list[index-1] + input_num = len(sensor_data.keys())-2 + except: + print "Error: Unable to access sensor information" + return 0 + + return input_num + + def get_sensor_name(self, index): + """ + Get the device name of the specified sensor. + for example "coretemp-isa-0000" + :return: str sensor_name + """ + + sensor_name = "N/A" + try: + # Request and validate sensor's information. + self.sensor_info_list = self.request_data() + + # Get sensor's name. + sensor_data = self.sensor_info_list[index-1] + sensor_name = sensor_data.get('name') + + except: + return "N/A" + + return sensor_name + + def get_sensor_input_name(self, sensor_index, input_index): + """ + Get the input item name of the specified input item of the + specified sensor index, for example "Physical id 0" + :return: str sensor_input_name + """ + + sensor_input_name = "N/A" + try: + # Request and validate sensor's information. + self.sensor_info_list = self.request_data() + sensor_data = self.sensor_info_list[sensor_index-1].copy() + + # Remove none input key. + del sensor_data["name"] + del sensor_data["Adapter"] + + # Get sensor's input name. + sensor_data_key = sensor_data.keys() + sensor_input_name = sensor_data_key[input_index-1] + except: + return "N/A" + + return sensor_input_name + + def get_sensor_input_type(self, sensor_index, input_index): + """ + Get the item type of the specified input item of the specified sensor index, + The return value should among "valtage","temperature" + :return: str sensor_input_type + """ + + sensor_input_type = "N/A" + try: + # Request and validate sensor's information. + self.sensor_info_list = self.request_data() + sensor_data = self.sensor_info_list[sensor_index-1].copy() + + # Remove none input key. + del sensor_data["name"] + del sensor_data["Adapter"] + + # Get sensor's input type name. + sensor_data_key = sensor_data.keys() + sensor_input_raw = sensor_data.get(sensor_data_key[input_index-1]) + sensor_data_str = sensor_input_raw.split() + sensor_input_type = self.input_type_selector(sensor_data_str[1]) + except: + return "N/A" + + return sensor_input_type + + def get_sensor_input_value(self, sensor_index, input_index): + """ + Get the current value of the input item, the unit is "V" or "C" + :return: float sensor_input_value + """ + + sensor_input_value = 0 + try: + # Request and validate sensor's information. + self.sensor_info_list = self.request_data() + sensor_data = self.sensor_info_list[sensor_index-1].copy() + + # Remove none input key. + del sensor_data["name"] + del sensor_data["Adapter"] + + # Get sensor's input value. + sensor_data_key = sensor_data.keys() + sensor_input_raw = sensor_data.get(sensor_data_key[input_index-1]) + sensor_data_str = sensor_input_raw.split() + sensor_input_value = float( + sensor_data_str[0]) if sensor_data_str[0] != "N/A" else 0 + except: + print "Error: Unable to access sensor information" + return 0 + + return sensor_input_value + + def get_sensor_input_low_threshold(self, sensor_index, input_index): + """ + Get the low threshold of the value, + the status of this item is not ok if the current value 1: + sensor_input_low_threshold = l_thres * \ + 1000 if str(unit[0]).lower() == 'k' else l_thres + except: + print "Error: Unable to access sensor information" + return 0 + + return sensor_input_low_threshold + + def get_sensor_input_high_threshold(self, sensor_index, input_index): + """ + Get the high threshold of the value, + the status of this item is not ok if the current value > high_threshold + :return: float sensor_input_high_threshold + """ + + sensor_input_high_threshold = 0 + try: + # Request and validate sensor's information. + self.sensor_info_list = self.request_data() + sensor_data = self.sensor_info_list[sensor_index-1].copy() + + # Remove none input key. + del sensor_data["name"] + del sensor_data["Adapter"] + + # Get sensor's input high threshold. + sensor_data_key = sensor_data.keys() + sensor_input_raw = sensor_data.get(sensor_data_key[input_index-1]) + sensor_data_str = sensor_input_raw.split() + indices = [i for i, s in enumerate( + sensor_data_str) if 'max' in s or 'high' in s] + h_thres = float( + sensor_data_str[indices[0] + 2]) if len(indices) != 0 else 0 + unit = sensor_data_str[indices[0] + + 3] if len(indices) != 0 else None + if unit is not None and len(unit) > 1: + sensor_input_high_threshold = h_thres * \ + 1000 if str(unit[0]).lower() == 'k' else h_thres + + except: + print "Error: Unable to access sensor information" + return 0 + + return sensor_input_high_threshold + + def get_sys_airflow(self): + sys_air_flow = "Unknown" + sys_pn_data = [ + v.split(":") for v in self.sys_fruid_list if "Product Part Number" in v] + + if len(sys_pn_data) == 0: + return sys_air_flow + + sys_pn = sys_pn_data[0][1] + if "R1241-F0001" in sys_pn: + sys_air_flow = "FTOB" + elif"R1241-F0002" in sys_pn: + sys_air_flow = "BTOF" + + return sys_air_flow + + def get_all(self): + + all_sensor_dict = dict() + + # Request sensor's information. + self.sensor_info_list = self.request_data() + for sensor_data in self.sensor_info_list: + sensor_info = sensor_data.copy() + + # Remove none unuse key. + del sensor_info["name"] + del sensor_info["Adapter"] + + # Set sensor data. + sensor_dict = dict() + for k, v in sensor_info.items(): + sensor_i_dict = dict() + sensor_data_str = v.split() + indices_h = [i for i, s in enumerate( + sensor_data_str) if 'max' in s or 'high' in s] + indices_l = [i for i, s in enumerate( + sensor_data_str) if 'min' in s or 'low' in s] + h_thres = float( + sensor_data_str[indices_h[0] + 2]) if len(indices_h) != 0 else 0 + l_thres = float( + sensor_data_str[indices_l[0] + 2]) if len(indices_l) != 0 else 0 + thres_unit = sensor_data_str[-1] + + sensor_i_dict["Type"] = self.input_type_selector( + sensor_data_str[1]) + sensor_i_dict["Value"] = float( + sensor_data_str[0]) if sensor_data_str[0] != "N/A" else 0 + sensor_i_dict["HighThd"] = h_thres * \ + 1000 if str(thres_unit[0]).lower() == 'k' else h_thres + sensor_i_dict["LowThd"] = l_thres * \ + 1000 if str(thres_unit[0]).lower() == 'k' else l_thres + + k = self.input_name_selector(sensor_data.get('name'), k) + sensor_dict[k] = sensor_i_dict + + if all_sensor_dict.get(self.sensor_name) is None: + all_sensor_dict[self.sensor_name] = dict() + + all_sensor_dict[self.sensor_name].update(sensor_dict) + + sensor_dict = dict() + sensor_dict["Sys_AirFlow"] = self.get_sys_airflow() + all_sensor_dict["TEMPERATURE"].update(sensor_dict) + + return all_sensor_dict diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sfputil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sfputil.py new file mode 100755 index 000000000000..f0187acb4eb6 --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sfputil.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 40 + QSFP_PORT_START = 1 + QSFP_PORT_END = 40 + + EEPROM_OFFSET = 9 + PORT_INFO_PATH = '/sys/class/fishbone2_fpga' + + _port_name = "" + _port_to_eeprom_mapping = { + 1: "/sys/bus/i2c/devices/i2c-42/42-0050/eeprom", 21: "/sys/bus/i2c/devices/i2c-46/46-0050/eeprom", + 2: "/sys/bus/i2c/devices/i2c-43/43-0050/eeprom", 22: "/sys/bus/i2c/devices/i2c-47/47-0050/eeprom", + 3: "/sys/bus/i2c/devices/i2c-10/10-0050/eeprom", 23: "/sys/bus/i2c/devices/i2c-26/26-0050/eeprom", + 4: "/sys/bus/i2c/devices/i2c-11/11-0050/eeprom", 24: "/sys/bus/i2c/devices/i2c-27/27-0050/eeprom", + 5: "/sys/bus/i2c/devices/i2c-12/12-0050/eeprom", 25: "/sys/bus/i2c/devices/i2c-28/28-0050/eeprom", + 6: "/sys/bus/i2c/devices/i2c-13/13-0050/eeprom", 26: "/sys/bus/i2c/devices/i2c-29/29-0050/eeprom", + 7: "/sys/bus/i2c/devices/i2c-14/14-0050/eeprom", 27: "/sys/bus/i2c/devices/i2c-30/30-0050/eeprom", + 8: "/sys/bus/i2c/devices/i2c-15/15-0050/eeprom", 28: "/sys/bus/i2c/devices/i2c-31/31-0050/eeprom", + 9: "/sys/bus/i2c/devices/i2c-16/16-0050/eeprom", 29: "/sys/bus/i2c/devices/i2c-32/32-0050/eeprom", + 10: "/sys/bus/i2c/devices/i2c-17/17-0050/eeprom", 30: "/sys/bus/i2c/devices/i2c-33/33-0050/eeprom", + 11: "/sys/bus/i2c/devices/i2c-18/18-0050/eeprom", 31: "/sys/bus/i2c/devices/i2c-34/34-0050/eeprom", + 12: "/sys/bus/i2c/devices/i2c-19/19-0050/eeprom", 32: "/sys/bus/i2c/devices/i2c-35/35-0050/eeprom", + 13: "/sys/bus/i2c/devices/i2c-20/20-0050/eeprom", 33: "/sys/bus/i2c/devices/i2c-36/36-0050/eeprom", + 14: "/sys/bus/i2c/devices/i2c-21/21-0050/eeprom", 34: "/sys/bus/i2c/devices/i2c-37/37-0050/eeprom", + 15: "/sys/bus/i2c/devices/i2c-22/22-0050/eeprom", 35: "/sys/bus/i2c/devices/i2c-38/38-0050/eeprom", + 16: "/sys/bus/i2c/devices/i2c-23/23-0050/eeprom", 36: "/sys/bus/i2c/devices/i2c-39/39-0050/eeprom", + 17: "/sys/bus/i2c/devices/i2c-24/24-0050/eeprom", 37: "/sys/bus/i2c/devices/i2c-40/40-0050/eeprom", + 18: "/sys/bus/i2c/devices/i2c-25/25-0050/eeprom", 38: "/sys/bus/i2c/devices/i2c-41/41-0050/eeprom", + 19: "/sys/bus/i2c/devices/i2c-44/44-0050/eeprom", 39: "/sys/bus/i2c/devices/i2c-48/48-0050/eeprom", + 20: "/sys/bus/i2c/devices/i2c-45/45-0050/eeprom", 40: "/sys/bus/i2c/devices/i2c-49/49-0050/eeprom", + } + _port_to_i2cbus_mapping = { + 1: 42, 2: 43, 3: 10, 4: 11, 5: 12, 6: 13, 7: 14, 8: 15, 9: 16, 10: 17, + 11: 18, 12: 19, 13: 20, 14: 21, 15: 22, 16: 23, 17: 24, 18: 25, 19: 44, 20: 45, + 21: 46, 22: 47, 23: 26, 24: 27, 25: 28, 26: 29, 27: 30, 28: 31, 29: 32, 30: 33, + 31: 34, 32: 35, 33: 36, 34: 37, 35: 38, 36: 39, 37: 40, 38: 41, 39: 48, 40: 49, + } + + @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.QSFP_PORT_START, self.QSFP_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.qsfp_ports: + self._port_name = "QSFP" + str(port_num - self.QSFP_PORT_START + 1) + else: + self._port_name = "SFP" + str(port_num) + return self._port_name + + 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 __init__(self): + # Override port_to_eeprom_mapping for class initialization + eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + # the following scheme is not correct,use 'i2cdetect -y -l' to detect # + #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) + print("self.port_to_i2cbus_mapping: "+str(self.port_to_i2cbus_mapping)+"\n") + print("self.port_to_eeprom_mapping: "+str(self.port_to_eeprom_mapping)+"\n") + + 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.qsfp_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): + return NotImplementedError + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid QSFP port_num + if port_num not in self.qsfp_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.qsfp_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 + """ + return NotImplementedError + + def tx_disable(self, port_num, disable): + """ + @param port_num index of physical port + @param disable, True -- disable port tx signal + False -- enable port tx signal + @return True when operation success, False on failure. + """ + TX_DISABLE_BYTE_OFFSET = 86 + if port_num not in range(self.port_start, self.port_end + 1) or type(disable) != bool: + return False + + # QSFP, set eeprom to disable tx + if port_num in self.qsfp_ports: + presence = self.get_presence(port_num) + if not presence: + return True + + disable = b'\x0f' if disable else b'\x00' + # open eeprom + try: + with open(self.port_to_eeprom_mapping[port_num], mode="wb", buffering=0) as sysfsfile: + sysfsfile.seek(TX_DISABLE_BYTE_OFFSET) + sysfsfile.write(bytearray(disable)) + except IOError: + return False + except: + return False + + # SFP, set tx_disable pin + else: + try: + disable = hex(1) if disable else hex(0) + port_name = self.get_port_name(port_num) + reg_file = open( + "/".join([self.PORT_INFO_PATH, port_name, "sfp_txdisable"]), "w") + reg_file.write(disable) + reg_file.close() + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + return True diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/td3-as14-40d.config.bcm b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/td3-as14-40d.config.bcm new file mode 100644 index 000000000000..2aaef4ea27ea --- /dev/null +++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/td3-as14-40d.config.bcm @@ -0,0 +1,590 @@ +ifp_inports_support_enable=1 +ipv6_lpm_128b_enable=0x1 +l2_mem_entries=32768 +l2xmsg_mode=1 +l3_max_ecmp_mode=1 +l3_mem_entries=16384 +lpm_scaling_enable=1 +max_vp_lags=0 +mem_cache_enable=0 +miim_intr_enable=0 +module_64ports=1 +oversubscribe_mode=1 +parity_enable=0 +serdes_if_type_ce=14 +#pbmp_xport_xe=0x48878787f8787808dfe1e0203e1e1e022 +pbmp_xport_xe=0x88888888888888882222222222222222 + +#ptp_ts_pll_fref=50000000 +#ptp_bs_fref_0=50000000 +#ptp_bs_fref_1=50000000 +portmap_1.0=1:100 +portmap_5.0=5:100 +portmap_9.0=9:100 +portmap_13.0=13:100 +portmap_17.0=17:100 +portmap_21.0=21:100 +portmap_25.0=25:100 +portmap_29.0=29:100 +portmap_33.0=33:100 +portmap_37.0=37:100 +portmap_41.0=41:100 +portmap_45.0=45:100 +portmap_49.0=49:100 +portmap_53.0=53:100 +portmap_57.0=57:100 +portmap_61.0=61:100 +portmap_67.0=65:100 +portmap_71.0=69:100 +portmap_75.0=73:100 +portmap_79.0=77:100 +portmap_83.0=81:100 +portmap_87.0=85:100 +portmap_91.0=89:100 +portmap_95.0=93:100 +portmap_99.0=97:100 +portmap_103.0=101:100 +portmap_107.0=105:100 +portmap_111.0=109:100 +portmap_115.0=113:100 +portmap_119.0=117:100 +portmap_123.0=121:100 +portmap_127.0=125:100 +portmap_66.0=129:10:m +portmap_130.0=128:10:m + +#wc0 lane swap +phy_chain_tx_lane_map_physical{1.0}=0x0132 +phy_chain_rx_lane_map_physical{1.0}=0x3210 + +#wc1 lane swap +phy_chain_tx_lane_map_physical{5.0}=0x2301 +phy_chain_rx_lane_map_physical{5.0}=0x2031 + +#wc2 lane swap +phy_chain_tx_lane_map_physical{9.0}=0x0132 +phy_chain_rx_lane_map_physical{9.0}=0x3210 + +#wc3 lane swap +phy_chain_tx_lane_map_physical{13.0}=0x3201 +phy_chain_rx_lane_map_physical{13.0}=0x2031 + +#wc4 lane swap +phy_chain_tx_lane_map_physical{17.0}=0x0123 +phy_chain_rx_lane_map_physical{17.0}=0x3210 + +#wc5 lane swap +phy_chain_tx_lane_map_physical{21.0}=0x2301 +phy_chain_rx_lane_map_physical{21.0}=0x2031 + +#wc6 lane swap +phy_chain_tx_lane_map_physical{25.0}=0x0123 +phy_chain_rx_lane_map_physical{25.0}=0x3210 + +#wc7 lane swap +phy_chain_tx_lane_map_physical{29.0}=0x3201 +phy_chain_rx_lane_map_physical{29.0}=0x2031 + +#wc8 lane swap +phy_chain_tx_lane_map_physical{33.0}=0x0213 +phy_chain_rx_lane_map_physical{33.0}=0x1302 + +#wc9 lane swap +phy_chain_tx_lane_map_physical{37.0}=0x1302 +phy_chain_rx_lane_map_physical{37.0}=0x2031 + +#wc10 lane swap +phy_chain_tx_lane_map_physical{41.0}=0x0231 +phy_chain_rx_lane_map_physical{41.0}=0x3120 + +#wc11 lane swap +phy_chain_tx_lane_map_physical{45.0}=0x1302 +phy_chain_rx_lane_map_physical{45.0}=0x2031 + +#wc12 lane swap +phy_chain_tx_lane_map_physical{49.0}=0x2103 +phy_chain_rx_lane_map_physical{49.0}=0x3120 + +#wc13 lane swap +phy_chain_tx_lane_map_physical{53.0}=0x2301 +phy_chain_rx_lane_map_physical{53.0}=0x2031 + +#wc14 lane swap +phy_chain_tx_lane_map_physical{57.0}=0x0123 +phy_chain_rx_lane_map_physical{57.0}=0x2301 + +#wc15 lane swap +phy_chain_tx_lane_map_physical{61.0}=0x3210 +phy_chain_rx_lane_map_physical{61.0}=0x1032 + +#wc16 lane swap +phy_chain_tx_lane_map_physical{65.0}=0x3210 +phy_chain_rx_lane_map_physical{65.0}=0x1023 + +#wc17 lane swap +phy_chain_tx_lane_map_physical{69.0}=0x0123 +phy_chain_rx_lane_map_physical{69.0}=0x1302 + +#wc18 lane swap +phy_chain_tx_lane_map_physical{73.0}=0x2301 +phy_chain_rx_lane_map_physical{73.0}=0x1032 + +#wc19 lane swap +phy_chain_tx_lane_map_physical{77.0}=0x2013 +phy_chain_rx_lane_map_physical{77.0}=0x3120 + +#wc20 lane swap +phy_chain_tx_lane_map_physical{81.0}=0x1302 +phy_chain_rx_lane_map_physical{81.0}=0x2031 + +#wc21 lane swap +phy_chain_tx_lane_map_physical{85.0}=0x0123 +phy_chain_rx_lane_map_physical{85.0}=0x2130 + +#wc22 lane swap +phy_chain_tx_lane_map_physical{89.0}=0x2301 +phy_chain_rx_lane_map_physical{89.0}=0x2031 + +#wc23 lane swap +phy_chain_tx_lane_map_physical{93.0}=0x0312 +phy_chain_rx_lane_map_physical{93.0}=0x2310 + +#wc24 lane swap +phy_chain_tx_lane_map_physical{97.0}=0x2301 +phy_chain_rx_lane_map_physical{97.0}=0x1032 + +#wc25 lane swap +phy_chain_tx_lane_map_physical{101.0}=0x0123 +phy_chain_rx_lane_map_physical{101.0}=0x3210 + +#wc26 lane swap +phy_chain_tx_lane_map_physical{105.0}=0x2301 +phy_chain_rx_lane_map_physical{105.0}=0x1032 + +#wc27 lane swap +phy_chain_tx_lane_map_physical{109.0}=0x0123 +phy_chain_rx_lane_map_physical{109.0}=0x3210 + +#wc28 lane swap +phy_chain_tx_lane_map_physical{113.0}=0x2301 +phy_chain_rx_lane_map_physical{113.0}=0x2031 + +#wc29 lane swap +phy_chain_tx_lane_map_physical{117.0}=0x0123 +phy_chain_rx_lane_map_physical{117.0}=0x3210 + +#wc30 lane swap +phy_chain_tx_lane_map_physical{121.0}=0x2301 +phy_chain_rx_lane_map_physical{121.0}=0x1032 + +#wc31 lane swap +phy_chain_tx_lane_map_physical{125.0}=0x0123 +phy_chain_rx_lane_map_physical{125.0}=0x3210 + +#MC lane swap +phy_chain_tx_lane_map_physical{129.0}=0x3210 +phy_chain_rx_lane_map_physical{129.0}=0x3210 + + +#wc0 P/N flip +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}=0x0 +phy_chain_rx_polarity_flip_physical{3.0}=0x0 +phy_chain_tx_polarity_flip_physical{4.0}=0x1 +phy_chain_rx_polarity_flip_physical{4.0}=0x1 + +#wc1 P/N flip +phy_chain_tx_polarity_flip_physical{5.0}=0x0 +phy_chain_rx_polarity_flip_physical{5.0}=0x0 +phy_chain_tx_polarity_flip_physical{6.0}=0x1 +phy_chain_rx_polarity_flip_physical{6.0}=0x1 +phy_chain_tx_polarity_flip_physical{7.0}=0x0 +phy_chain_rx_polarity_flip_physical{7.0}=0x1 +phy_chain_tx_polarity_flip_physical{8.0}=0x1 +phy_chain_rx_polarity_flip_physical{8.0}=0x1 + +#wc2 P/N flip +phy_chain_tx_polarity_flip_physical{9.0}=0x0 +phy_chain_rx_polarity_flip_physical{9.0}=0x0 +phy_chain_tx_polarity_flip_physical{10.0}=0x0 +phy_chain_rx_polarity_flip_physical{10.0}=0x1 +phy_chain_tx_polarity_flip_physical{11.0}=0x0 +phy_chain_rx_polarity_flip_physical{11.0}=0x0 +phy_chain_tx_polarity_flip_physical{12.0}=0x1 +phy_chain_rx_polarity_flip_physical{12.0}=0x1 + +#wc3 P/N flip +phy_chain_tx_polarity_flip_physical{13.0}=0x0 +phy_chain_rx_polarity_flip_physical{13.0}=0x0 +phy_chain_tx_polarity_flip_physical{14.0}=0x1 +phy_chain_rx_polarity_flip_physical{14.0}=0x1 +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}=0x0 +phy_chain_rx_polarity_flip_physical{16.0}=0x1 + +#wc4 P/N flip +phy_chain_tx_polarity_flip_physical{17.0}=0x0 +phy_chain_rx_polarity_flip_physical{17.0}=0x0 +phy_chain_tx_polarity_flip_physical{18.0}=0x1 +phy_chain_rx_polarity_flip_physical{18.0}=0x1 +phy_chain_tx_polarity_flip_physical{19.0}=0x0 +phy_chain_rx_polarity_flip_physical{19.0}=0x0 +phy_chain_tx_polarity_flip_physical{20.0}=0x1 +phy_chain_rx_polarity_flip_physical{20.0}=0x1 + +#wc5 P/N flip +phy_chain_tx_polarity_flip_physical{21.0}=0x0 +phy_chain_rx_polarity_flip_physical{21.0}=0x0 +phy_chain_tx_polarity_flip_physical{22.0}=0x1 +phy_chain_rx_polarity_flip_physical{22.0}=0x1 +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}=0x1 + +#wc6 P/N flip +phy_chain_tx_polarity_flip_physical{25.0}=0x0 +phy_chain_rx_polarity_flip_physical{25.0}=0x1 +phy_chain_tx_polarity_flip_physical{26.0}=0x1 +phy_chain_rx_polarity_flip_physical{26.0}=0x0 +phy_chain_tx_polarity_flip_physical{27.0}=0x0 +phy_chain_rx_polarity_flip_physical{27.0}=0x1 +phy_chain_tx_polarity_flip_physical{28.0}=0x1 +phy_chain_rx_polarity_flip_physical{28.0}=0x0 + +#wc7 P/N flip +phy_chain_tx_polarity_flip_physical{29.0}=0x1 +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}=0x0 +phy_chain_tx_polarity_flip_physical{31.0}=0x0 +phy_chain_rx_polarity_flip_physical{31.0}=0x0 +phy_chain_tx_polarity_flip_physical{32.0}=0x0 +phy_chain_rx_polarity_flip_physical{32.0}=0x0 + +#wc8 P/N flip +phy_chain_tx_polarity_flip_physical{33.0}=0x1 +phy_chain_rx_polarity_flip_physical{33.0}=0x1 +phy_chain_tx_polarity_flip_physical{34.0}=0x0 +phy_chain_rx_polarity_flip_physical{34.0}=0x0 +phy_chain_tx_polarity_flip_physical{35.0}=0x0 +phy_chain_rx_polarity_flip_physical{35.0}=0x0 +phy_chain_tx_polarity_flip_physical{36.0}=0x1 +phy_chain_rx_polarity_flip_physical{36.0}=0x0 + +#wc9 P/N flip +phy_chain_tx_polarity_flip_physical{37.0}=0x1 +phy_chain_rx_polarity_flip_physical{37.0}=0x1 +phy_chain_tx_polarity_flip_physical{38.0}=0x1 +phy_chain_rx_polarity_flip_physical{38.0}=0x0 +phy_chain_tx_polarity_flip_physical{39.0}=0x1 +phy_chain_rx_polarity_flip_physical{39.0}=0x0 +phy_chain_tx_polarity_flip_physical{40.0}=0x0 +phy_chain_rx_polarity_flip_physical{40.0}=0x1 + +#wc10 P/N flip +phy_chain_tx_polarity_flip_physical{41.0}=0x1 +phy_chain_rx_polarity_flip_physical{41.0}=0x1 +phy_chain_tx_polarity_flip_physical{42.0}=0x0 +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}=0x1 +phy_chain_rx_polarity_flip_physical{44.0}=0x1 + +#wc11 P/N flip +phy_chain_tx_polarity_flip_physical{45.0}=0x1 +phy_chain_rx_polarity_flip_physical{45.0}=0x0 +phy_chain_tx_polarity_flip_physical{46.0}=0x1 +phy_chain_rx_polarity_flip_physical{46.0}=0x0 +phy_chain_tx_polarity_flip_physical{47.0}=0x1 +phy_chain_rx_polarity_flip_physical{47.0}=0x1 +phy_chain_tx_polarity_flip_physical{48.0}=0x0 +phy_chain_rx_polarity_flip_physical{48.0}=0x1 + +#wc12 P/N flip +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}=0x1 +phy_chain_rx_polarity_flip_physical{50.0}=0x0 +phy_chain_tx_polarity_flip_physical{51.0}=0x0 +phy_chain_rx_polarity_flip_physical{51.0}=0x1 +phy_chain_tx_polarity_flip_physical{52.0}=0x1 +phy_chain_rx_polarity_flip_physical{52.0}=0x1 + +#wc13 P/N flip +phy_chain_tx_polarity_flip_physical{53.0}=0x0 +phy_chain_rx_polarity_flip_physical{53.0}=0x0 +phy_chain_tx_polarity_flip_physical{54.0}=0x1 +phy_chain_rx_polarity_flip_physical{54.0}=0x1 +phy_chain_tx_polarity_flip_physical{55.0}=0x0 +phy_chain_rx_polarity_flip_physical{55.0}=0x1 +phy_chain_tx_polarity_flip_physical{56.0}=0x1 +phy_chain_rx_polarity_flip_physical{56.0}=0x1 + +#wc14 P/N flip +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}=0x1 +phy_chain_rx_polarity_flip_physical{58.0}=0x1 +phy_chain_tx_polarity_flip_physical{59.0}=0x0 +phy_chain_rx_polarity_flip_physical{59.0}=0x0 +phy_chain_tx_polarity_flip_physical{60.0}=0x1 +phy_chain_rx_polarity_flip_physical{60.0}=0x1 + +#wc15 P/N flip +phy_chain_tx_polarity_flip_physical{61.0}=0x0 +phy_chain_rx_polarity_flip_physical{61.0}=0x1 +phy_chain_tx_polarity_flip_physical{62.0}=0x1 +phy_chain_rx_polarity_flip_physical{62.0}=0x0 +phy_chain_tx_polarity_flip_physical{63.0}=0x0 +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 + +#wc16 P/N flip +phy_chain_tx_polarity_flip_physical{65.0}=0x1 +phy_chain_rx_polarity_flip_physical{65.0}=0x0 +phy_chain_tx_polarity_flip_physical{66.0}=0x0 +phy_chain_rx_polarity_flip_physical{66.0}=0x0 +phy_chain_tx_polarity_flip_physical{67.0}=0x1 +phy_chain_rx_polarity_flip_physical{67.0}=0x1 +phy_chain_tx_polarity_flip_physical{68.0}=0x0 +phy_chain_rx_polarity_flip_physical{68.0}=0x0 + +#wc17 P/N flip +phy_chain_tx_polarity_flip_physical{69.0}=0x1 +phy_chain_rx_polarity_flip_physical{69.0}=0x1 +phy_chain_tx_polarity_flip_physical{70.0}=0x0 +phy_chain_rx_polarity_flip_physical{70.0}=0x0 +phy_chain_tx_polarity_flip_physical{71.0}=0x1 +phy_chain_rx_polarity_flip_physical{71.0}=0x0 +phy_chain_tx_polarity_flip_physical{72.0}=0x0 +phy_chain_rx_polarity_flip_physical{72.0}=0x0 + +#wc18 P/N flip +phy_chain_tx_polarity_flip_physical{73.0}=0x0 +phy_chain_rx_polarity_flip_physical{73.0}=0x1 +phy_chain_tx_polarity_flip_physical{74.0}=0x1 +phy_chain_rx_polarity_flip_physical{74.0}=0x0 +phy_chain_tx_polarity_flip_physical{75.0}=0x0 +phy_chain_rx_polarity_flip_physical{75.0}=0x1 +phy_chain_tx_polarity_flip_physical{76.0}=0x1 +phy_chain_rx_polarity_flip_physical{76.0}=0x0 + +#wc19 P/N flip +phy_chain_tx_polarity_flip_physical{77.0}=0x0 +phy_chain_rx_polarity_flip_physical{77.0}=0x0 +phy_chain_tx_polarity_flip_physical{78.0}=0x0 +phy_chain_rx_polarity_flip_physical{78.0}=0x0 +phy_chain_tx_polarity_flip_physical{79.0}=0x1 +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}=0x1 + +#wc20 P/N flip +phy_chain_tx_polarity_flip_physical{81.0}=0x0 +phy_chain_rx_polarity_flip_physical{81.0}=0x0 +phy_chain_tx_polarity_flip_physical{82.0}=0x0 +phy_chain_rx_polarity_flip_physical{82.0}=0x0 +phy_chain_tx_polarity_flip_physical{83.0}=0x1 +phy_chain_rx_polarity_flip_physical{83.0}=0x1 +phy_chain_tx_polarity_flip_physical{84.0}=0x1 +phy_chain_rx_polarity_flip_physical{84.0}=0x0 + +#wc21 P/N flip +phy_chain_tx_polarity_flip_physical{85.0}=0x1 +phy_chain_rx_polarity_flip_physical{85.0}=0x1 +phy_chain_tx_polarity_flip_physical{86.0}=0x0 +phy_chain_rx_polarity_flip_physical{86.0}=0x1 +phy_chain_tx_polarity_flip_physical{87.0}=0x1 +phy_chain_rx_polarity_flip_physical{87.0}=0x0 +phy_chain_tx_polarity_flip_physical{88.0}=0x0 +phy_chain_rx_polarity_flip_physical{88.0}=0x0 + +#wc22 P/N flip +phy_chain_tx_polarity_flip_physical{89.0}=0x1 +phy_chain_rx_polarity_flip_physical{89.0}=0x0 +phy_chain_tx_polarity_flip_physical{90.0}=0x0 +phy_chain_rx_polarity_flip_physical{90.0}=0x0 +phy_chain_tx_polarity_flip_physical{91.0}=0x1 +phy_chain_rx_polarity_flip_physical{91.0}=0x1 +phy_chain_tx_polarity_flip_physical{92.0}=0x0 +phy_chain_rx_polarity_flip_physical{92.0}=0x1 + +#wc23 P/N flip +phy_chain_tx_polarity_flip_physical{93.0}=0x1 +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}=0x1 +phy_chain_tx_polarity_flip_physical{95.0}=0x0 +phy_chain_rx_polarity_flip_physical{95.0}=0x0 +phy_chain_tx_polarity_flip_physical{96.0}=0x0 +phy_chain_rx_polarity_flip_physical{96.0}=0x1 + +#wc24 P/N flip +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 + +#wc25 P/N flip +phy_chain_tx_polarity_flip_physical{101.0}=0x1 +phy_chain_rx_polarity_flip_physical{101.0}=0x0 +phy_chain_tx_polarity_flip_physical{102.0}=0x0 +phy_chain_rx_polarity_flip_physical{102.0}=0x1 +phy_chain_tx_polarity_flip_physical{103.0}=0x1 +phy_chain_rx_polarity_flip_physical{103.0}=0x0 +phy_chain_tx_polarity_flip_physical{104.0}=0x0 +phy_chain_rx_polarity_flip_physical{104.0}=0x0 + +#wc26 P/N flip +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 + +#wc27 P/N flip +phy_chain_tx_polarity_flip_physical{109.0}=0x1 +phy_chain_rx_polarity_flip_physical{109.0}=0x1 +phy_chain_tx_polarity_flip_physical{110.0}=0x0 +phy_chain_rx_polarity_flip_physical{110.0}=0x0 +phy_chain_tx_polarity_flip_physical{111.0}=0x1 +phy_chain_rx_polarity_flip_physical{111.0}=0x1 +phy_chain_tx_polarity_flip_physical{112.0}=0x0 +phy_chain_rx_polarity_flip_physical{112.0}=0x0 + +#wc28 P/N flip +phy_chain_tx_polarity_flip_physical{113.0}=0x1 +phy_chain_rx_polarity_flip_physical{113.0}=0x1 +phy_chain_tx_polarity_flip_physical{114.0}=0x0 +phy_chain_rx_polarity_flip_physical{114.0}=0x0 +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}=0x0 + +#wc29 P/N flip +phy_chain_tx_polarity_flip_physical{117.0}=0x1 +phy_chain_rx_polarity_flip_physical{117.0}=0x1 +phy_chain_tx_polarity_flip_physical{118.0}=0x0 +phy_chain_rx_polarity_flip_physical{118.0}=0x0 +phy_chain_tx_polarity_flip_physical{119.0}=0x1 +phy_chain_rx_polarity_flip_physical{119.0}=0x1 +phy_chain_tx_polarity_flip_physical{120.0}=0x0 +phy_chain_rx_polarity_flip_physical{120.0}=0x0 + +#wc30 P/N flip +phy_chain_tx_polarity_flip_physical{121.0}=0x1 +phy_chain_rx_polarity_flip_physical{121.0}=0x0 +phy_chain_tx_polarity_flip_physical{122.0}=0x0 +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}=0x1 + +#wc31 P/N flip +phy_chain_tx_polarity_flip_physical{125.0}=0x1 +phy_chain_rx_polarity_flip_physical{125.0}=0x1 +phy_chain_tx_polarity_flip_physical{126.0}=0x0 +phy_chain_rx_polarity_flip_physical{126.0}=0x0 +phy_chain_tx_polarity_flip_physical{127.0}=0x1 +phy_chain_rx_polarity_flip_physical{127.0}=0x1 +phy_chain_tx_polarity_flip_physical{128.0}=0x0 +phy_chain_rx_polarity_flip_physical{128.0}=0x0 + +#MC P/N flip +phy_chain_tx_polarity_flip_physical{129.0}=0x0 +phy_chain_rx_polarity_flip_physical{129.0}=0x0 +phy_chain_tx_polarity_flip_physical{130.0}=0x0 +phy_chain_rx_polarity_flip_physical{130.0}=0x0 +phy_chain_tx_polarity_flip_physical{131.0}=0x0 +phy_chain_rx_polarity_flip_physical{131.0}=0x0 +phy_chain_tx_polarity_flip_physical{132.0}=0x0 +phy_chain_rx_polarity_flip_physical{132.0}=0x0 + +dport_map_port_1=1 +dport_map_port_5=2 +dport_map_port_9=3 +dport_map_port_13=4 +dport_map_port_17=5 +dport_map_port_21=6 +dport_map_port_25=7 +dport_map_port_29=8 +dport_map_port_33=9 +dport_map_port_37=10 +dport_map_port_41=11 +dport_map_port_45=12 +dport_map_port_49=13 +dport_map_port_53=14 +dport_map_port_57=15 +dport_map_port_61=16 +dport_map_port_67=17 +dport_map_port_71=18 +dport_map_port_75=19 +dport_map_port_79=20 +dport_map_port_83=21 +dport_map_port_87=22 +dport_map_port_91=23 +dport_map_port_95=24 +dport_map_port_99=25 +dport_map_port_103=26 +dport_map_port_107=27 +dport_map_port_111=28 +dport_map_port_115=29 +dport_map_port_119=30 +dport_map_port_123=31 +dport_map_port_127=32 +dport_map_port_66=33 +dport_map_port_130=34 + +# configuration for 100G optical module +serdes_preemphasis_1=0x164608 +serdes_preemphasis_5=0x164608 +serdes_preemphasis_9=0x164608 +serdes_preemphasis_13=0x134908 +serdes_preemphasis_17=0x134908 +serdes_preemphasis_21=0x134908 +serdes_preemphasis_25=0x124a08 +serdes_preemphasis_29=0x124a08 +serdes_preemphasis_33=0x114b08 +serdes_preemphasis_37=0x114b08 +serdes_preemphasis_41=0x0f4d08 +serdes_preemphasis_45=0x0f4d08 +serdes_preemphasis_49=0x0d4f08 +serdes_preemphasis_53=0x0d4f08 +serdes_preemphasis_57=0x0d4f08 +serdes_preemphasis_61=0x0d4f08 +serdes_preemphasis_67=0x0d4f08 +serdes_preemphasis_71=0x0d4f08 +serdes_preemphasis_75=0x0d4f08 +serdes_preemphasis_79=0x0d4f08 +serdes_preemphasis_83=0x0d4f08 +serdes_preemphasis_87=0x0f4d08 +serdes_preemphasis_91=0x0f4d08 +serdes_preemphasis_95=0x0f4d08 +serdes_preemphasis_99=0x114b08 +serdes_preemphasis_103=0x114b08 +serdes_preemphasis_107=0x114b08 +serdes_preemphasis_111=0x124a08 +serdes_preemphasis_115=0x134908 +serdes_preemphasis_119=0x134908 +serdes_preemphasis_123=0x134908 +serdes_preemphasis_127=0x164608 + +schan_intr_enable=0 +stable_size=0x5500000 +tdma_timeout_usec=3000000 diff --git a/platform/broadcom/platform-modules-cel.mk b/platform/broadcom/platform-modules-cel.mk index b7371e3282de..11d05973f365 100644 --- a/platform/broadcom/platform-modules-cel.mk +++ b/platform/broadcom/platform-modules-cel.mk @@ -3,10 +3,12 @@ CEL_DX010_PLATFORM_MODULE_VERSION = 0.9 CEL_HALIBURTON_PLATFORM_MODULE_VERSION = 0.9 CEL_SILVERSTONE_PLATFORM_MODULE_VERSION = 0.9 +CEL_SHAMU_PLATFORM_MODULE_VERSION = 0.9 export CEL_DX010_PLATFORM_MODULE_VERSION export CEL_HALIBURTON_PLATFORM_MODULE_VERSION export CEL_SILVERSTONE_PLATFORM_MODULE_VERSION +export CEL_SHAMU_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 @@ -22,4 +24,8 @@ CEL_SILVERSTONE_PLATFORM_MODULE = platform-modules-silverstone_$(CEL_SILVERSTONE $(CEL_SILVERSTONE_PLATFORM_MODULE)_PLATFORM = x86_64-cel_silverstone-r0 $(eval $(call add_extra_package,$(CEL_DX010_PLATFORM_MODULE),$(CEL_SILVERSTONE_PLATFORM_MODULE))) +CEL_SHAMU_PLATFORM_MODULE = platform-modules-shamu_$(CEL_SHAMU_PLATFORM_MODULE_VERSION)_amd64.deb +$(CEL_SHAMU_PLATFORM_MODULE)_PLATFORM = x86_64-alibaba_as14-40d-cl-r0 +$(eval $(call add_extra_package,$(CEL_DX010_PLATFORM_MODULE),$(CEL_SHAMU_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 4fe6d626eb1c..ed89373f71c3 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/control +++ b/platform/broadcom/sonic-platform-modules-cel/debian/control @@ -20,3 +20,9 @@ Package: platform-modules-silverstone Architecture: amd64 Depends: linux-image-4.9.0-11-2-amd64 Description: kernel modules for platform devices such as led, sfp. + +Package: platform-modules-shamu +Architecture: amd64 +Depends: linux-image-4.9.0-11-2-amd64 +Description: kernel modules for platform devices such as fan, led, sfp + diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.init new file mode 100644 index 000000000000..b8f079cf111b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.init @@ -0,0 +1,45 @@ +#!/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 Jaws board. +### END INIT INFO + +case "$1" in +start) + echo -n "Setting up board... " + + # Add driver to support HW + modprobe i2c-dev + modprobe dimm-bus + modprobe i2c-imc allow_unsafe_access=1 + modprobe baseboard_cpld + modprobe switchboard_fpga + modprobe mc24lc64t + + # Add driver to support TLV - EEPROM + echo 24lc64t 0x56 > /sys/bus/i2c/devices/i2c-0/new_device + echo "done." + ;; + +stop) + echo "done." + ;; + +force-reload|restart) + echo "Not supported" + ;; + +*) + echo "Usage: /etc/init.d/platform-modules-jaws.init {start|stop}" + exit 1 + ;; +esac + +exit 0 diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.install new file mode 100644 index 000000000000..cdc1e9c0c255 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.install @@ -0,0 +1,15 @@ +jaws/cfg/jaws-modules.conf etc/modules-load.d +jaws/systemd/platform-modules-jaws.service lib/systemd/system +tools/sync_bmc/bmc_vlan.service etc/systemd/system +tools/sync_bmc/sync_bmc.service etc/systemd/system +tools/sync_bmc/sync_bmc.timer etc/systemd/system +tools/sync_bmc/bmc_vlan.sh /usr/local/etc/ +tools/sync_bmc/sync_bmc.py /usr/local/etc/ +tools/platformutil.py /usr/local/etc/ +tools/read_optic_temp.py /usr/local/etc/ +tools/bmcutil/bmcpwd /usr/local/etc/ +tools/bmcutil/bmcutil.py /usr/local/etc/ +tools/bmcutil/bmc-exec /usr/local/bin +tools/bmc_wdt/bmc_wdt.service etc/systemd/system +tools/bmc_wdt/bmc_wdt.py /usr/local/etc/ +tools/power_utils/power /usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.postinst new file mode 100644 index 000000000000..4dc1e15f3f9a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.postinst @@ -0,0 +1,15 @@ +depmod -a + +# Enable bmc vlan_ip service +systemctl enable bmc_vlan.service + +systemctl enable platform-modules-jaws.service +systemctl start platform-modules-jaws.service + +# Enable platform-sync_bmc-timer +# systemctl enable sync_bmc.timer +# systemctl start sync_bmc.timer + +# Enable heartbeat timer +systemctl enable bmc_wdt.service +systemctl start bmc_wdt.service diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.init new file mode 100644 index 000000000000..0bb69268b743 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.init @@ -0,0 +1,51 @@ +#!/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 Shamu board. +### END INIT INFO + +case "$1" in +start) + echo -n "Setting up board... " + + # Add driver to support HW + modprobe dimm-bus + modprobe i2c-imc allow_unsafe_access=1 + modprobe i2c-dev + modprobe baseboard_cpld + modprobe switchboard_fpga + modprobe mc24lc64t + + # Add driver to support TLV - EEPROM + echo 24lc64t 0x56 > /sys/bus/i2c/devices/i2c-0/new_device + decode-syseeprom --init 2> /dev/null & + + /bin/sh /usr/local/bin/platform_api_mgnt.sh init + + echo 0x108 0xFF > /sys/devices/platform/AS1440D.switchboard/FPGA/setreg + + echo "done." + ;; + +stop) + echo "done." + ;; + +force-reload|restart) + echo "Not supported" + ;; + +*) + echo "Usage: /etc/init.d/platform-modules-shamu.init {start|stop}" + exit 1 + ;; +esac + +exit 0 diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.install new file mode 100644 index 000000000000..220e18165445 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.install @@ -0,0 +1,20 @@ +shamu/scripts/sensors usr/bin +shamu/scripts/platform_sensors.py usr/local/bin +shamu/cfg/shamu-modules.conf etc/modules-load.d +shamu/systemd/platform-modules-shamu.service lib/systemd/system +shamu/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-alibaba_as14-40d-cl-r0 +services/platform_api/platform_api_mgnt.sh usr/local/bin + +tools/sync_bmc/bmc_vlan.service etc/systemd/system +tools/sync_bmc/sync_bmc.service etc/systemd/system +tools/sync_bmc/sync_bmc.timer etc/systemd/system +tools/sync_bmc/bmc_vlan.sh /usr/local/etc/ +tools/sync_bmc/sync_bmc.py /usr/local/etc/ +tools/platformutil.py /usr/local/etc/ +tools/read_optic_temp.py /usr/local/etc/ +tools/bmcutil/bmcpwd /usr/local/etc/ +tools/bmcutil/bmcutil.py /usr/local/etc/ +tools/bmcutil/bmc-exec /usr/local/bin +tools/bmc_wdt/bmc_wdt.service etc/systemd/system +tools/bmc_wdt/bmc_wdt.py /usr/local/etc/ +tools/power_utils/power /usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.postinst new file mode 100644 index 000000000000..de84287b5b7f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.postinst @@ -0,0 +1,17 @@ +depmod -a + +# Enable bmc vlan_ip service +systemctl enable bmc_vlan.service + +systemctl enable platform-modules-shamu.service +systemctl start platform-modules-shamu.service + +/usr/local/bin/platform_api_mgnt.sh install + +# Enable platform-sync_bmc-timer +# systemctl enable sync_bmc.timer +# systemctl start sync_bmc.timer + +# Enable heartbeat timer +systemctl enable bmc_wdt.service +systemctl start bmc_wdt.service diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/rules b/platform/broadcom/sonic-platform-modules-cel/debian/rules index dd5452ccaa11..b84f840e0863 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 silverstone +MODULE_DIRS:= dx010 haliburton silverstone shamu %: dh $@ @@ -17,13 +17,21 @@ override_dh_auto_build: python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ cd $(MOD_SRC_DIR); \ done) + make -C $(MOD_SRC_DIR)/tools/ispvme_12.2; + gcc -std=c99 $(MOD_SRC_DIR)/tools/fpga_prog/fpga_prog.c -o $(MOD_SRC_DIR)/tools/fpga_prog/fpga_prog; override_dh_auto_install: (for mod in $(MODULE_DIRS); do \ dh_installdirs -pplatform-modules-$${mod} \ $(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + dh_installdirs -pplatform-modules-$${mod} \ + /usr/local/bin; \ cp $(MOD_SRC_DIR)/$${mod}/modules/*.ko \ debian/platform-modules-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + cp $(MOD_SRC_DIR)/tools/ispvme_12.2/ispvm \ + debian/platform-modules-$${mod}/usr/local/bin/; \ + cp $(MOD_SRC_DIR)/tools/fpga_prog/fpga_prog \ + debian/platform-modules-$${mod}/usr/local/bin/; \ done) override_dh_usrlocal: diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/cfg/jaws-modules.conf b/platform/broadcom/sonic-platform-modules-cel/jaws/cfg/jaws-modules.conf new file mode 100644 index 000000000000..574c48f7a66f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/jaws/cfg/jaws-modules.conf @@ -0,0 +1,16 @@ +# /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 +8021q + diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/Makefile b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/Makefile new file mode 100644 index 000000000000..f1777c8c5db9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/Makefile @@ -0,0 +1 @@ +obj-m := mc24lc64t.o baseboard_cpld.o switchboard_fpga.o i2c-imc.o dimm-bus.o diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/baseboard_cpld.c b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/baseboard_cpld.c new file mode 100644 index 000000000000..951eb774a5f6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/baseboard_cpld.c @@ -0,0 +1,417 @@ +/* + * baseboard_cpld.c - The CPLD driver for the Base Board of Phalanxp + * The driver implement sysfs to access CPLD register on the baseboard of Phalanxp 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 "AS14128H.cpldb" +/** + * CPLD register address for read and write. + */ +#define VERSION_ADDR 0xA100 +#define SCRATCH_ADDR 0xA101 +#define SYS_LED_ADDR 0xA162 + +#define CPLD_REGISTER_SIZE 0x7C + +struct cpld_b_data { + struct mutex cpld_lock; + uint16_t read_addr; +}; + +struct cpld_b_data *cpld_data; + +/** + * Read the value from scratch register as hex string. + * @param dev kernel device + * @param devattr kernel device attribute + * @param buf buffer for get value + * @return Hex string read from scratch register. + */ + + +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); +} + +/** + * Set scratch register with specific hex string. + * @param dev kernel device + * @param devattr kernel device attribute + * @param buf buffer of set value + * @param count number of bytes in buffer + * @return number of bytes written, or error code < 0. + */ +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) +{ + int len = 0; + // CPLD register is one byte + mutex_lock(&cpld_data->cpld_lock); + len = sprintf(buf, "0x%2.2x\n",inb(VERSION_ADDR)); + mutex_unlock(&cpld_data->cpld_lock); + return len; +} +static DEVICE_ATTR_RO(version); + + +static ssize_t getreg_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + // CPLD register is one byte + 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; + // CPLD register is one byte + 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) +{ + // CPLD register is one byte + 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. + * @return number of byte read. + */ +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/1k/4k + * @param dev kernel device + * @param devattr kernel device attribute + * @param buf buffer for get value + * @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 ? "4k" : data ==0x01 ? "1k": "on"); +} + +/** + * Set the status of system led - on/off/1k/4k + * @param dev kernel device + * @param devattr kernel device attribute + * @param buf buffer of set value + * @param count number of bytes in buffer + * @return number of bytes written, or error code < 0. + */ +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, "4k")){ + led_status = 0x02; + }else if(sysfs_streq(buf, "1k")){ + 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 + * @param dev kernel device + * @param devattr kernel device attribute + * @param buf buffer for get value + * @return Hex string read from scratch register. + */ +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 + * When both color is selected, only blink 1K or 4K is supported. + * + * @param dev kernel device + * @param devattr kernel device attribute + * @param buf buffer of set value + * @param count number of bytes in buffer + * @return number of bytes written, or error code < 0. + */ +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 struct attribute *cpld_b_attrs[] = { + &dev_attr_version.attr, + &dev_attr_scratch.attr, + &dev_attr_getreg.attr, + &dev_attr_setreg.attr, + &dev_attr_sys_led.attr, + &dev_attr_sys_led_color.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 = 0xA175, + .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("Pradchaya P. "); +MODULE_DESCRIPTION("Celestica Phalanxp CPLD baseboard driver"); +MODULE_VERSION("0.0.2"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.c b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.c new file mode 100644 index 000000000000..9f30945e1d1c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2013-2016 Andrew Lutomirski + * + * 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. + * + * 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. + */ +#include +#include +#include +#include "dimm-bus.h" +static bool probe_addr(struct i2c_adapter *adapter, int addr) +{ + /* + * So far, all known devices that live on DIMMs can be safely + * and reliably detected by trying to read a byte at address + * zero. (The exception is the SPD write protection control, + * which can't be probed and requires special hardware and/or + * quick writes to access, and has no driver.) + */ + union i2c_smbus_data dummy; + return i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_READ, 0, + I2C_SMBUS_BYTE_DATA, &dummy) >= 0; +} +/** + * i2c_scan_dimm_bus() - Scans an SMBUS segment known to contain DIMMs + * @adapter: The SMBUS adapter to scan + * + * This function tells the DIMM-bus code that the adapter is known to + * contain DIMMs. i2c_scan_dimm_bus will probe for devices known to + * live on DIMMs. + * + * Do NOT call this function on general-purpose system SMBUS segments + * unless you know that the only things on the bus are DIMMs. + * Otherwise is it very likely to mis-identify other things on the + * bus. + * + * Callers are advised not to set adapter->class = I2C_CLASS_SPD to + * avoid having two separate mechanisms trying to automatically claim + * devices on the bus. + */ +void i2c_scan_dimm_bus(struct i2c_adapter *adapter) +{ + struct i2c_board_info info = {}; + int slot; + /* + * We probe with "read byte data". If any DIMM SMBUS driver can't + * support that access type, this function should be updated. + */ + if (WARN_ON(!i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA))) + return; + /* + * Addresses on DIMMs use the three low bits to identify the slot + * and the four high bits to identify the device type. Known + * devices include: + * + * - 0x10 - 0x17: NVDIMM controller (pre-standard) + * - 0x18 - 0x1f: TSOD (Temperature Sensor on DIMM) + * - 0x40 - 0x47: JESD245 Byte Addressable Energy Backed Interface + * - 0x50 - 0x57: SPD (Serial Presence Detect) EEPROM + * - 0x30 - 0x37: SPD WP control -- not easy to probe + * + * There's no point in trying to probe the SPD WP control: we'd + * want to probe using quick reads, which i2c-imc doesn't + * support, we don't have a driver for it, we can't really use + * it without special hardware (it's not a normal i2c slave -- + * see the JEDEC docs), and using it risks bricking the DIMM + * it's on anyway. + * + * NB: There's no need to save the return value from + * i2c_new_device, as the core code will unregister it for us + * when the adapter is removed. If users want to bind a + * different driver, nothing stops them from unbinding the + * drivers we request here. + */ + for (slot = 0; slot < 8; slot++) { + /* If there's no SPD, then assume there's no DIMM here. */ + if (!probe_addr(adapter, 0x50 | slot)) + continue; + strcpy(info.type, "ee1004"); + info.addr = 0x50 | slot; + i2c_new_device(adapter, &info); + if (probe_addr(adapter, 0x18 | slot)) { + /* + * This is a temperature sensor. The interface is + * defined in the JEDEC TSE2004av specification. + * Linux's driver for this is called "jc42", which + * is a bit nonsensical (JC-42 is the name of the + * committee, not the sensor). + */ + strcpy(info.type, "jc42"); + info.addr = 0x18 | slot; + i2c_new_device(adapter, &info); + } + } +} +EXPORT_SYMBOL(i2c_scan_dimm_bus); +MODULE_AUTHOR("Andrew Lutomirski "); +MODULE_DESCRIPTION("i2c DIMM bus support"); +MODULE_LICENSE("GPL v2"); + diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.h b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.h new file mode 100644 index 000000000000..8f14d5fb973f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2013-2016 Andrew Lutomirski + * + * 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. + * + * 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. + */ +#ifndef _I2C_DIMM_BUS +#define _I2C_DIMM_BUS +struct i2c_adapter; +void i2c_scan_dimm_bus(struct i2c_adapter *adapter); +#endif /* _I2C_DIMM_BUS */ + diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/i2c-imc.c b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/i2c-imc.c new file mode 100644 index 000000000000..7b053f43916e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/i2c-imc.c @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2013-2016 Andrew Lutomirski + * + * 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. + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include "dimm-bus.h" + +/* + * The datasheet can be found here, for example: + * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e5-1600-2600-vol-2-datasheet.pdf + * + * There seem to be quite a few bugs or spec errors, though: + * + * - A successful transaction sets WOD and RDO. + * + * - The docs for TSOD_POLL_EN make no sense (see imc_channel_claim). + * + * - Erratum BT109, which says: + * + * The processor may not complete SMBus (System Management Bus) + * transactions targeting the TSOD (Temperature Sensor On DIMM) + * when Package C-States are enabled. Due to this erratum, if the + * processor transitions into a Package C-State while an SMBus + * transaction with the TSOD is in process, the processor will + * suspend receipt of the transaction. The transaction completes + * while the processor is in a Package C-State. Upon exiting + * Package C-State, the processor will attempt to resume the + * SMBus transaction, detect a protocol violation, and log an + * error. + * + * The description notwithstanding, I've seen difficult-to-reproduce + * issues when the system goes completely idle (so package C-states can + * be entered) while software-initiated SMBUS transactions are in + * progress. + */ + +/* Register offsets (in PCI configuration space) */ +#define SMBSTAT(i) (0x180 + 0x10*(i)) +#define SMBCMD(i) (0x184 + 0x10*(i)) +#define SMBCNTL(i) (0x188 + 0x10*(i)) +#define SMB_TSOD_POLL_RATE_CNTR(i) (0x18C + 0x10*(i)) +#define SMB_TSOD_POLL_RATE (0x1A8) + +/* SMBSTAT fields */ +#define SMBSTAT_RDO (1U << 31) /* Read Data Valid */ +#define SMBSTAT_WOD (1U << 30) /* Write Operation Done */ +#define SMBSTAT_SBE (1U << 29) /* SMBus Error */ +#define SMBSTAT_SMB_BUSY (1U << 28) /* SMBus Busy State */ +/* 26:24 is the last automatically polled TSOD address */ +#define SMBSTAT_RDATA_MASK 0xffff /* result of a read */ + +/* SMBCMD fields */ +#define SMBCMD_TRIGGER (1U << 31) /* CMD Trigger */ +#define SMBCMD_PNTR_SEL (1U << 30) /* HW polls TSOD with pointer */ +#define SMBCMD_WORD_ACCESS (1U << 29) /* word (vs byte) access */ +#define SMBCMD_TYPE_MASK (3U << 27) /* Mask for access type */ +#define SMBCMD_TYPE_READ (0U << 27) /* Read */ +#define SMBCMD_TYPE_WRITE (1U << 27) /* Write */ +#define SMBCMD_TYPE_PNTR_WRITE (3U << 27) /* Write to pointer */ +#define SMBCMD_SA_MASK (7U << 24) /* Slave Address high bits */ +#define SMBCMD_SA_SHIFT 24 +#define SMBCMD_BA_MASK 0xff0000 /* Bus Txn address */ +#define SMBCMD_BA_SHIFT 16 +#define SMBCMD_WDATA_MASK 0xffff /* data to write */ + +/* SMBCNTL fields */ +#define SMBCNTL_DTI_MASK 0xf0000000 /* Slave Address low bits */ +#define SMBCNTL_DTI_SHIFT 28 /* Slave Address low bits */ +#define SMBCNTL_CKOVRD (1U << 27) /* # Clock Override */ +#define SMBCNTL_DIS_WRT (1U << 26) /* Disable Write (sadly) */ +#define SMBCNTL_SOFT_RST (1U << 10) /* Soft Reset */ +#define SMBCNTL_TSOD_POLL_EN (1U << 8) /* TSOD Polling Enable */ +/* Bits 0-3 and 4-6 indicate TSOD presence in various slots */ + +/* Bits that might randomly change if we race with something. */ +#define SMBCMD_OUR_BITS (~(u32)SMBCMD_TRIGGER) +#define SMBCNTL_OUR_BITS (SMBCNTL_DTI_MASK | SMBCNTL_TSOD_POLL_EN) + +/* System Address Controller, PCI dev 13 fn 6, 8086.3cf5 */ +#define SAD_CONTROL 0xf4 + +#define PCI_DEVICE_ID_INTEL_SBRIDGE_BR 0x3cf5 /* 13.6 */ +#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA 0x3ca8 /* 15.0 */ + +#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA 0x6fa8 +#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TM 0x6f71 +#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TA 0x6f68 +#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TM 0x6f79 + +static atomic_t imc_raced; /* Set permanently to 1 if we screw up. */ + +static bool allow_unsafe_access; + +struct imc_channel { + struct i2c_adapter adapter; + struct mutex mutex; /* protects access to regs and prev_tsod_poll */ + bool can_write, suspended; + bool prev_tsod_poll; +}; + +struct imc_priv { + struct pci_dev *pci_dev; + struct imc_channel channels[2]; +}; + +static bool imc_wait_not_busy(struct imc_priv *priv, int chan, u32 *stat) +{ + /* + * The clock is around 100kHz, and transactions are nine cycles + * per byte plus a few start/stop cycles, plus whatever clock + * streching is involved. This means that polling every 70us + * or so will give decent performance. + * + * Ideally we would calculate a good estimate for the + * transaction time and sleep, but busy-waiting is an effective + * workaround for an apparent Sandy Bridge bug that causes bogus + * output if the system enters a package C-state. (NB: these + * states are systemwide -- we don't need be running on the + * right package for this to work.) + * + * When Ivy Bridge and Haswell support are added, we could + * consider making the busy-wait depend on the platform. + */ + + int i; + + for (i = 0; i < 50; i++) { + pci_read_config_dword(priv->pci_dev, SMBSTAT(chan), stat); + if (!(*stat & SMBSTAT_SMB_BUSY)) + return true; + udelay(70); /* see comment above -- we need to busy-wait */ + } + + return false; +} + +static void imc_channel_release(struct imc_priv *priv, int chan) +{ + /* Return to HW control. */ + if (priv->channels[chan].prev_tsod_poll) { + u32 cntl; + + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl); + cntl |= SMBCNTL_TSOD_POLL_EN; + pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), cntl); + } +} + +static int imc_channel_claim(struct imc_priv *priv, int chan) +{ + /* + * The docs are a bit confused here. We're supposed to disable TSOD + * polling, then wait for busy to be cleared, then set + * SMBCNTL_TSOD_POLL_EN to zero to switch to software control. But + * SMBCNTL_TSOD_POLL_EN is the only documented way to turn off polling. + */ + + u32 cntl, stat; + + if (priv->channels[chan].suspended) + return -EIO; + + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl); + priv->channels[chan].prev_tsod_poll = !!(cntl & SMBCNTL_TSOD_POLL_EN); + cntl &= ~SMBCNTL_TSOD_POLL_EN; + pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), cntl); + + /* Sometimes the hardware won't let go. */ + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl); + if (cntl & SMBCNTL_TSOD_POLL_EN) + return -EBUSY; + + if (!imc_wait_not_busy(priv, chan, &stat)) { + imc_channel_release(priv, chan); + return -EBUSY; /* Someone else is controlling the bus. */ + } + + return 0; /* The channel is ours. */ +} + +static bool imc_channel_can_claim(struct imc_priv *priv, int chan) +{ + u32 orig_cntl, cntl; + + /* See if we can turn off TSOD_POLL_EN. */ + + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &orig_cntl); + pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), + orig_cntl & ~SMBCNTL_TSOD_POLL_EN); + + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl); + if (cntl & SMBCNTL_TSOD_POLL_EN) + return false; /* Failed. */ + + pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), orig_cntl); + return true; +} + +/* + * The iMC supports five access types. The terminology is rather + * inconsistent. These are the types: + * + * "Write to pointer register SMBus": I2C_SMBUS_WRITE, I2C_SMBUS_BYTE + * + * Read byte/word: I2C_SMBUS_READ, I2C_SMBUS_{BYTE|WORD}_DATA + * + * Write byte/word: I2C_SMBUS_WRITE, I2C_SMBUS_{BYTE|WORD}_DATA + * + * The pointer write operations is AFAICT completely useless for + * software control, for two reasons. First, HW periodically polls any + * TSODs on the bus, so it will corrupt the pointer in between SW + * transactions. More importantly, the matching "read byte"/"receive + * byte" (the address-less single-byte read) is not available for SW + * control. Therefore, this driver doesn't implement pointer writes + * + * There is no PEC support. + */ + +static u32 imc_func(struct i2c_adapter *adapter) +{ + int chan; + struct imc_channel *ch; + struct imc_priv *priv = i2c_get_adapdata(adapter); + + chan = (adapter == &priv->channels[0].adapter ? 0 : 1); + ch = &priv->channels[chan]; + + if (ch->can_write) + return I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA; + else + return I2C_FUNC_SMBUS_READ_BYTE_DATA | + I2C_FUNC_SMBUS_READ_WORD_DATA; +} + +static s32 imc_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) +{ + int ret, chan; + u32 cmd = 0, cntl, final_cmd, final_cntl, stat; + struct imc_channel *ch; + struct imc_priv *priv = i2c_get_adapdata(adap); + + if (atomic_read(&imc_raced)) + return -EIO; /* Minimize damage. */ + + chan = (adap == &priv->channels[0].adapter ? 0 : 1); + ch = &priv->channels[chan]; + + /* Encode CMD part of addresses and access size */ + cmd |= ((u32)addr & 0x7) << SMBCMD_SA_SHIFT; + cmd |= ((u32)command) << SMBCMD_BA_SHIFT; + if (size == I2C_SMBUS_WORD_DATA) + cmd |= SMBCMD_WORD_ACCESS; + + /* Encode read/write and data to write */ + if (read_write == I2C_SMBUS_READ) { + cmd |= SMBCMD_TYPE_READ; + } else { + cmd |= SMBCMD_TYPE_WRITE; + cmd |= (size == I2C_SMBUS_WORD_DATA + ? swab16(data->word) + : data->byte); + } + + mutex_lock(&ch->mutex); + + ret = imc_channel_claim(priv, chan); + if (ret) + goto out_unlock; + + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl); + cntl &= ~SMBCNTL_DTI_MASK; + cntl |= ((u32)addr >> 3) << SMBCNTL_DTI_SHIFT; + pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), cntl); + + /* + * This clears SMBCMD_PNTR_SEL. We leave it cleared so that we don't + * need to think about keeping the TSOD pointer state consistent with + * the hardware's expectation. This probably has some miniscule + * power cost, as TSOD polls will take 9 extra cycles. + */ + cmd |= SMBCMD_TRIGGER; + pci_write_config_dword(priv->pci_dev, SMBCMD(chan), cmd); + + if (!imc_wait_not_busy(priv, chan, &stat)) { + /* Timeout. TODO: Reset the controller? */ + ret = -ETIMEDOUT; + dev_dbg(&priv->pci_dev->dev, "controller is wedged\n"); + goto out_release; + } + + /* + * Be paranoid: try to detect races. This will only detect races + * against BIOS, not against hardware. (I've never seen this happen.) + */ + pci_read_config_dword(priv->pci_dev, SMBCMD(chan), &final_cmd); + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &final_cntl); + if (((cmd ^ final_cmd) & SMBCMD_OUR_BITS) || + ((cntl ^ final_cntl) & SMBCNTL_OUR_BITS)) { + WARN(1, "iMC SMBUS raced against firmware"); + dev_err(&priv->pci_dev->dev, + "Access to channel %d raced: cmd 0x%08X->0x%08X, cntl 0x%08X->0x%08X\n", + chan, cmd, final_cmd, cntl, final_cntl); + atomic_set(&imc_raced, 1); + ret = -EIO; + goto out_release; + } + + if (stat & SMBSTAT_SBE) { + /* + * Clear the error to re-enable TSOD polling. The docs say + * that, as long as SBE is set, TSOD polling won't happen. + * The docs also say that writing zero to this bit (which is + * the only writable bit in the whole register) will clear + * the error. Empirically, writing 0 does not clear SBE, but + * it's probably still good to do the write in compliance with + * the spec. (TSOD polling still happens and seems to + * clear SBE on its own.) + */ + pci_write_config_dword(priv->pci_dev, SMBSTAT(chan), 0); + ret = -ENXIO; + goto out_release; + } + + if (read_write == I2C_SMBUS_READ) { + if (!(stat & SMBSTAT_RDO)) { + dev_dbg(&priv->pci_dev->dev, + "Unexpected read status 0x%08X\n", stat); + ret = -EIO; + goto out_release; + } + + /* + * The iMC SMBUS controller thinks of SMBUS words as + * being big-endian (MSB first). Linux treats them as + * little-endian, so we need to swap them. + * + * Note: the controller will often (always?) set WOD + * here. This is probably a hardware bug. + */ + if (size == I2C_SMBUS_WORD_DATA) + data->word = swab16(stat & SMBSTAT_RDATA_MASK); + else + data->byte = stat & 0xFF; + } else { + /* + * Note: the controller will often (always?) set RDO here. + * This is probably a hardware bug. + */ + if (!(stat & SMBSTAT_WOD)) { + dev_dbg(&priv->pci_dev->dev, + "Unexpected write status 0x%08X\n", stat); + ret = -EIO; + } + } + +out_release: + imc_channel_release(priv, chan); + +out_unlock: + mutex_unlock(&ch->mutex); + + return ret; +} + +static const struct i2c_algorithm imc_smbus_algorithm = { + .smbus_xfer = imc_smbus_xfer, + .functionality = imc_func, +}; + +static int imc_init_channel(struct imc_priv *priv, int i, int socket) +{ + int err; + u32 val; + struct imc_channel *ch = &priv->channels[i]; + + /* + * With CLTT enabled, the hardware won't let us turn + * off TSOD polling. The device is completely useless + * when this happens (at least without help from Intel), + * but we can at least minimize confusion. + */ + if (!imc_channel_can_claim(priv, i)) { + dev_warn(&priv->pci_dev->dev, + "iMC channel %d: we cannot control the HW. Is CLTT on?\n", + i); + return -EBUSY; + } + + i2c_set_adapdata(&ch->adapter, priv); + ch->adapter.owner = THIS_MODULE; + ch->adapter.algo = &imc_smbus_algorithm; + ch->adapter.dev.parent = &priv->pci_dev->dev; + + pci_read_config_dword(priv->pci_dev, SMBCNTL(i), &val); + ch->can_write = !(val & SMBCNTL_DIS_WRT); + + mutex_init(&ch->mutex); + + snprintf(ch->adapter.name, sizeof(ch->adapter.name), + "iMC socket %d channel %d", socket, i); + err = i2c_add_adapter(&ch->adapter); + if (err) { + mutex_destroy(&ch->mutex); + return err; + } + + i2c_scan_dimm_bus(&ch->adapter); + + return 0; +} + +static void imc_free_channel(struct imc_priv *priv, int i) +{ + struct imc_channel *ch = &priv->channels[i]; + + i2c_del_adapter(&ch->adapter); + mutex_destroy(&ch->mutex); +} + +static struct pci_dev *imc_get_related_device(struct pci_bus *bus, + unsigned int devfn, u16 devid) +{ + struct pci_dev *dev = pci_get_slot(bus, devfn); + + if (!dev) + return NULL; + if (dev->vendor != PCI_VENDOR_ID_INTEL || dev->device != devid) { + pci_dev_put(dev); + return NULL; + } + return dev; +} + +static int imc_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + int i, j, err; + struct imc_priv *priv; + + priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->pci_dev = dev; + + pci_set_drvdata(dev, priv); + + for (i = 0; i < 1; i++) { + err = imc_init_channel(priv, i, 0); + if (err) + goto exit_free_channels; + printk(KERN_INFO "IMC: Create IMC SMBus OK.\n"); + } + + return 0; + +exit_free_channels: + printk(KERN_INFO "IMC: Free chennel I2C.\n"); + for (j = 0; j < i; j++) + imc_free_channel(priv, j); + return err; +} + +static void imc_remove(struct pci_dev *dev) +{ + int i; + struct imc_priv *priv = pci_get_drvdata(dev); + + for (i = 0; i < 1; i++) + imc_free_channel(priv, i); +} + +static int imc_suspend(struct pci_dev *dev, pm_message_t mesg) +{ + int i; + struct imc_priv *priv = pci_get_drvdata(dev); + + /* BIOS is in charge. We should finish any pending transaction */ + for (i = 0; i < 1; i++) { + mutex_lock(&priv->channels[i].mutex); + priv->channels[i].suspended = true; + mutex_unlock(&priv->channels[i].mutex); + } + + return 0; +} + +static int imc_resume(struct pci_dev *dev) +{ + int i; + struct imc_priv *priv = pci_get_drvdata(dev); + + for (i = 0; i < 1; i++) { + mutex_lock(&priv->channels[i].mutex); + priv->channels[i].suspended = false; + mutex_unlock(&priv->channels[i].mutex); + } + + return 0; +} + +static const struct pci_device_id imc_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA) }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, imc_ids); + +static struct pci_driver imc_pci_driver = { + .name = "imc_smbus", + .id_table = imc_ids, + .probe = imc_probe, + .remove = imc_remove, + .suspend = imc_suspend, + .resume = imc_resume, +}; + +static int __init i2c_imc_init(void) +{ + if (!allow_unsafe_access) + return -ENODEV; + + pr_warn("using this driver is dangerous unless your firmware is specifically designed for it; use at your own risk\n"); + return pci_register_driver(&imc_pci_driver); +} +module_init(i2c_imc_init); + +static void __exit i2c_imc_exit(void) +{ + pci_unregister_driver(&imc_pci_driver); +} +module_exit(i2c_imc_exit); + +module_param(allow_unsafe_access, bool, 0400); +MODULE_PARM_DESC(allow_unsafe_access, "enable i2c_imc despite potential races against BIOS/hardware bus access"); + +MODULE_AUTHOR("Andrew Lutomirski "); +MODULE_DESCRIPTION("iMC SMBus driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/mc24lc64t.c b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/mc24lc64t.c new file mode 100644 index 000000000000..ae79770a4d8e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/mc24lc64t.c @@ -0,0 +1,173 @@ +/* + * 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; + 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"); diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/switchboard_fpga.c b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/switchboard_fpga.c new file mode 100644 index 000000000000..13afba861088 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/switchboard_fpga.c @@ -0,0 +1,2997 @@ +/* + * switchboard.c - Driver for Phalanxp Switch 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 + * \--AS23128h.switchboard + * |--FPGA + * |--CPLD[1..4] + * \--SFF + * \--QSFP[1..128] + * + */ + +#ifndef TEST_MODE +#define MOD_VERSION "0.5.1" +#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 "phalanxp_fpga" +#define DRIVER_NAME "AS14128H.switchboard" +#define FPGA_PCI_NAME "phalanxp_fpga_pci" +#define DEVICE_NAME "fwupgrade" + +static bool allow_unsafe_i2c_access; + +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 i2c_core_init(unsigned int master_bus, unsigned int freq_div,void __iomem *pci_bar); +static void i2c_core_deinit(unsigned int master_bus, void __iomem *pci_bar); +static int i2c_xcvr_access(u8 register_address, unsigned int portid, u8 *data, char rw); + +static int fpgafw_init(void); +static void fpgafw_exit(void); + +/* +======================================== +FPGA PCIe BAR 0 Registers +======================================== +Misc Control 0x00000000 – 0x000000FF +I2C_CH1 0x00000800 - 0x0000081C +I2C_CH2 0x00000820 - 0x0000083C +I2C_CH3 0x00000840 - 0x0000085C +I2C_CH4 0x00000860 - 0x0000087C +I2C_CH5 0x00000880 - 0x0000089C +I2C_CH6 0x000008A0 - 0x000008BC +I2C_CH7 0x000008C0 - 0x000008DC +I2C_CH8 0x000008E0 - 0x000008FC +I2C_CH9 0x00000900 - 0x0000091C +I2C_CH10 0x00000920 - 0x0000093C +I2C_CH11 0x00000940 - 0x0000095C +I2C_CH12 0x00000960 - 0x0000097C +I2C_CH13 0x00000980 - 0x0000099C +I2C_CH14 0x000009A0 - 0x000009BC +SPI Master 0x00000A00 - 0x00000BFC +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 BMC_I2C_SCRATCH 0x0020 +#define FPGA_SLAVE_CPLD_REST 0x0100 +#define FPGA_SWITCH_RESET_CTRL 0x0104 +#define FPAG_PRH_RESER_CTRL 0x0108 +#define FPGA_INT_STATUS 0x0200 +#define FPGA_INT_SRC_STATUS 0x0204 +#define FPGA_INT_FLAG 0x0208 +#define FPGA_INT_MASK 0x020c +#define FPGA_MISC_CTRL 0x0300 +#define FPGA_MISC_STATUS 0x0304 + +/* I2C_MASTER BASE ADDR */ +#define I2C_MASTER_FREQ_L 0x0800 +#define I2C_MASTER_FREQ_H 0x0804 +#define I2C_MASTER_CTRL 0x0808 +#define I2C_MASTER_DATA 0x080c +#define I2C_MASTER_CMD 0x0810 /* Write-Only Register */ +#define I2C_MASTER_STATUS 0x0810 /* Read-Only Register */ +#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_14 14 + +#define I2C_MASTER_CH_TOTAL I2C_MASTER_CH_14 + +/* 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] RSVD +[5] MODSEL 5 +[4] RST 4 +[3:1] RSVD +[0] TXDIS 0 +*/ +#define CTRL_MODSEL 5 +#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 + + +/** + * Switchboard CPLD XCVR registers + */ + +/* PORT SEL REGISTER +[7:5] RSVD +[4:0] ID +*/ +#define I2C_XCVR_SEL 0x10 +#define I2C_SEL_ID 0 + +/* PORT CTRL REGISTER +[7:5] RSVD +[4] RST +[3:1] RSVD +[0] TXDIS/MODSEL +*/ +#define I2C_XCVR_CTRL 0x11 +#define I2C_CTRL_RST 4 +#define I2C_CTRL_MODSEL 0 +#define I2C_CTRL_TXDIS 0 + +/* PORT STATUS REGISTER +[7:5] RSVD +[4] PRESENT/ABS +[3:2] RSVD +[1] TXFAULT +[0] RXLOS/INT_N +*/ +#define I2C_XCVR_STAT 0x12 +#define I2C_STAT_PRESENT 4 +#define I2C_STAT_MODABS 4 +#define I2C_STAT_TXFAULT 1 +#define I2C_STAT_INT_N 0 +#define I2C_STAT_RXLOS 0 + +/* PORT INTRPT REGISTER +[7:5] RSVD +[4] PRESENT/ABS +[3:2] RSVD +[1] TXFAULT +[0] RXLOS/INT_N +*/ +#define I2C_XCVR_INRT 0x13 +#define I2C_INTR_PRESENT 4 +#define I2C_INTR_MODABS 4 +#define I2C_INTR_TXFAULT 1 +#define I2C_INTR_INT_N 0 +#define I2C_INTR_RXLOS 0 + +/* PORT INTR MASK REGISTER +[31:6] RSVD +[5] INT_N 5 +[4] PRESENT 4 +[3] RSVD +[2] RSVD +[1] RXLOS_INT 1 +[0] MODABS 0 +*/ +#define I2C_XCVR_MASK 0x14 +#define I2C_MASK_PRESENT 4 +#define I2C_MASK_MODABS 4 +#define I2C_MASK_TXFAULT 1 +#define I2C_MASK_INT_N 0 +#define I2C_MASK_RXLOS 0 + + +/* I2C master clock speed */ +// NOTE: Only I2C clock in normal mode is support here. +enum { + I2C_DIV_100K = 0x71, +}; + +/* I2C Master control register */ +enum { + I2C_CTRL_IEN = 6, + I2C_CTRL_EN +}; + +/* I2C Master command register */ +enum { + I2C_CMD_IACK = 0, + I2C_CMD_ACK = 3, + I2C_CMD_WR, + I2C_CMD_RD, + I2C_CMD_STO, + I2C_CMD_STA, +}; + +/* I2C Master status register */ +enum { + I2C_STAT_IF = 0, + I2C_STAT_TIP, + I2C_STAT_AL = 5, + I2C_STAT_BUSY, + I2C_STAT_RxACK, +}; + +/** + * + * 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_SFP_PORT 0 +#define VIRTUAL_I2C_QSFP_PORT 128 + +#define SFF_PORT_TOTAL VIRTUAL_I2C_QSFP_PORT + VIRTUAL_I2C_SFP_PORT + +#define VIRTUAL_I2C_BUS_OFFSET 10 +#define BB_CPLD_SLAVE_ADDR 0x0d +#define FAN_CPLD_SLAVE_ADDR 0x0d +#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 + +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]; +static int nack_retry[I2C_MASTER_CH_TOTAL]; +static int need_retry[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[] = { + /* SFP and QSFP front panel I2C */ + {I2C_MASTER_CH_11, 0x70, 0, QSFP, "QSFP1"}, {I2C_MASTER_CH_11, 0x70, 1, QSFP, "QSFP2"}, + {I2C_MASTER_CH_11, 0x70, 2, QSFP, "QSFP3"}, {I2C_MASTER_CH_11, 0x70, 3, QSFP, "QSFP4"}, + {I2C_MASTER_CH_14, 0x73, 7, QSFP, "QSFP5"}, {I2C_MASTER_CH_14, 0x73, 6, QSFP, "QSFP6"}, + {I2C_MASTER_CH_14, 0x73, 5, QSFP, "QSFP7"}, {I2C_MASTER_CH_14, 0x73, 4, QSFP, "QSFP8"}, + {I2C_MASTER_CH_11, 0x70, 4, QSFP, "QSFP9"}, {I2C_MASTER_CH_11, 0x70, 5, QSFP, "QSFP10"}, + {I2C_MASTER_CH_11, 0x70, 6, QSFP, "QSFP11"}, {I2C_MASTER_CH_11, 0x70, 7, QSFP, "QSFP12"}, + {I2C_MASTER_CH_14, 0x73, 3, QSFP, "QSFP13"}, {I2C_MASTER_CH_14, 0x73, 2, QSFP, "QSFP14"}, + {I2C_MASTER_CH_14, 0x73, 1, QSFP, "QSFP15"}, {I2C_MASTER_CH_14, 0x73, 0, QSFP, "QSFP16"}, + + {I2C_MASTER_CH_11, 0x71, 0, QSFP, "QSFP17"}, {I2C_MASTER_CH_11, 0x71, 1, QSFP, "QSFP18"}, + {I2C_MASTER_CH_11, 0x71, 2, QSFP, "QSFP19"}, {I2C_MASTER_CH_11, 0x71, 3, QSFP, "QSFP20"}, + {I2C_MASTER_CH_14, 0x72, 7, QSFP, "QSFP21"}, {I2C_MASTER_CH_14, 0x72, 6, QSFP, "QSFP22"}, + {I2C_MASTER_CH_14, 0x72, 5, QSFP, "QSFP23"}, {I2C_MASTER_CH_14, 0x72, 4, QSFP, "QSFP24"}, + {I2C_MASTER_CH_11, 0x71, 4, QSFP, "QSFP25"}, {I2C_MASTER_CH_11, 0x71, 5, QSFP, "QSFP26"}, + {I2C_MASTER_CH_11, 0x71, 6, QSFP, "QSFP27"}, {I2C_MASTER_CH_11, 0x71, 7, QSFP, "QSFP28"}, + {I2C_MASTER_CH_14, 0x72, 3, QSFP, "QSFP29"}, {I2C_MASTER_CH_14, 0x72, 2, QSFP, "QSFP30"}, + {I2C_MASTER_CH_14, 0x72, 1, QSFP, "QSFP31"}, {I2C_MASTER_CH_14, 0x72, 0, QSFP, "QSFP32"}, + + {I2C_MASTER_CH_11, 0x72, 0, QSFP, "QSFP33"}, {I2C_MASTER_CH_11, 0x72, 1, QSFP, "QSFP34"}, + {I2C_MASTER_CH_11, 0x72, 2, QSFP, "QSFP35"}, {I2C_MASTER_CH_11, 0x72, 3, QSFP, "QSFP36"}, + {I2C_MASTER_CH_14, 0x71, 7, QSFP, "QSFP37"}, {I2C_MASTER_CH_14, 0x71, 6, QSFP, "QSFP38"}, + {I2C_MASTER_CH_14, 0x71, 5, QSFP, "QSFP39"}, {I2C_MASTER_CH_14, 0x71, 4, QSFP, "QSFP40"}, + {I2C_MASTER_CH_11, 0x72, 4, QSFP, "QSFP41"}, {I2C_MASTER_CH_11, 0x72, 5, QSFP, "QSFP42"}, + {I2C_MASTER_CH_11, 0x72, 6, QSFP, "QSFP43"}, {I2C_MASTER_CH_11, 0x72, 7, QSFP, "QSFP44"}, + {I2C_MASTER_CH_14, 0x71, 3, QSFP, "QSFP45"}, {I2C_MASTER_CH_14, 0x71, 2, QSFP, "QSFP46"}, + {I2C_MASTER_CH_14, 0x71, 1, QSFP, "QSFP47"}, {I2C_MASTER_CH_14, 0x71, 0, QSFP, "QSFP48"}, + + {I2C_MASTER_CH_11, 0x73, 0, QSFP, "QSFP49"}, {I2C_MASTER_CH_11, 0x73, 1, QSFP, "QSFP50"}, + {I2C_MASTER_CH_11, 0x73, 2, QSFP, "QSFP51"}, {I2C_MASTER_CH_11, 0x73, 3, QSFP, "QSFP52"}, + {I2C_MASTER_CH_14, 0x70, 7, QSFP, "QSFP53"}, {I2C_MASTER_CH_14, 0x70, 6, QSFP, "QSFP54"}, + {I2C_MASTER_CH_14, 0x70, 5, QSFP, "QSFP55"}, {I2C_MASTER_CH_14, 0x70, 4, QSFP, "QSFP56"}, + {I2C_MASTER_CH_11, 0x73, 4, QSFP, "QSFP57"}, {I2C_MASTER_CH_11, 0x73, 5, QSFP, "QSFP58"}, + {I2C_MASTER_CH_11, 0x73, 6, QSFP, "QSFP59"}, {I2C_MASTER_CH_11, 0x73, 7, QSFP, "QSFP60"}, + {I2C_MASTER_CH_14, 0x70, 3, QSFP, "QSFP61"}, {I2C_MASTER_CH_14, 0x70, 2, QSFP, "QSFP62"}, + {I2C_MASTER_CH_14, 0x70, 1, QSFP, "QSFP63"}, {I2C_MASTER_CH_14, 0x70, 0, QSFP, "QSFP64"}, + + {I2C_MASTER_CH_12, 0x70, 0, QSFP, "QSFP65"}, {I2C_MASTER_CH_12, 0x70, 1, QSFP, "QSFP66"}, + {I2C_MASTER_CH_12, 0x70, 2, QSFP, "QSFP67"}, {I2C_MASTER_CH_12, 0x70, 3, QSFP, "QSFP68"}, + {I2C_MASTER_CH_13, 0x73, 7, QSFP, "QSFP69"}, {I2C_MASTER_CH_13, 0x73, 6, QSFP, "QSFP70"}, + {I2C_MASTER_CH_13, 0x73, 5, QSFP, "QSFP71"}, {I2C_MASTER_CH_13, 0x73, 4, QSFP, "QSFP72"}, + {I2C_MASTER_CH_12, 0x70, 4, QSFP, "QSFP73"}, {I2C_MASTER_CH_12, 0x70, 5, QSFP, "QSFP74"}, + {I2C_MASTER_CH_12, 0x70, 6, QSFP, "QSFP75"}, {I2C_MASTER_CH_12, 0x70, 7, QSFP, "QSFP76"}, + {I2C_MASTER_CH_13, 0x73, 3, QSFP, "QSFP77"}, {I2C_MASTER_CH_13, 0x73, 2, QSFP, "QSFP78"}, + {I2C_MASTER_CH_13, 0x73, 1, QSFP, "QSFP79"}, {I2C_MASTER_CH_13, 0x73, 0, QSFP, "QSFP80"}, + + {I2C_MASTER_CH_12, 0x71, 0, QSFP, "QSFP81"}, {I2C_MASTER_CH_12, 0x71, 1, QSFP, "QSFP82"}, + {I2C_MASTER_CH_12, 0x71, 2, QSFP, "QSFP83"}, {I2C_MASTER_CH_12, 0x71, 3, QSFP, "QSFP84"}, + {I2C_MASTER_CH_13, 0x72, 7, QSFP, "QSFP85"}, {I2C_MASTER_CH_13, 0x72, 6, QSFP, "QSFP86"}, + {I2C_MASTER_CH_13, 0x72, 5, QSFP, "QSFP87"}, {I2C_MASTER_CH_13, 0x72, 4, QSFP, "QSFP88"}, + {I2C_MASTER_CH_12, 0x71, 4, QSFP, "QSFP89"}, {I2C_MASTER_CH_12, 0x71, 5, QSFP, "QSFP90"}, + {I2C_MASTER_CH_12, 0x71, 6, QSFP, "QSFP91"}, {I2C_MASTER_CH_12, 0x71, 7, QSFP, "QSFP92"}, + {I2C_MASTER_CH_13, 0x72, 3, QSFP, "QSFP93"}, {I2C_MASTER_CH_13, 0x72, 2, QSFP, "QSFP94"}, + {I2C_MASTER_CH_13, 0x72, 1, QSFP, "QSFP95"}, {I2C_MASTER_CH_13, 0x72, 0, QSFP, "QSFP96"}, + + {I2C_MASTER_CH_12, 0x72, 0, QSFP, "QSFP97"}, {I2C_MASTER_CH_12, 0x72, 1, QSFP, "QSFP98"}, + {I2C_MASTER_CH_12, 0x72, 2, QSFP, "QSFP99"}, {I2C_MASTER_CH_12, 0x72, 3, QSFP, "QSFP100"}, + {I2C_MASTER_CH_13, 0x71, 7, QSFP, "QSFP101"}, {I2C_MASTER_CH_13, 0x71, 6, QSFP, "QSFP102"}, + {I2C_MASTER_CH_13, 0x71, 5, QSFP, "QSFP103"}, {I2C_MASTER_CH_13, 0x71, 4, QSFP, "QSFP104"}, + {I2C_MASTER_CH_12, 0x72, 4, QSFP, "QSFP105"}, {I2C_MASTER_CH_12, 0x72, 5, QSFP, "QSFP106"}, + {I2C_MASTER_CH_12, 0x72, 6, QSFP, "QSFP107"}, {I2C_MASTER_CH_12, 0x72, 7, QSFP, "QSFP108"}, + {I2C_MASTER_CH_13, 0x71, 3, QSFP, "QSFP109"}, {I2C_MASTER_CH_13, 0x71, 2, QSFP, "QSFP110"}, + {I2C_MASTER_CH_13, 0x71, 1, QSFP, "QSFP111"}, {I2C_MASTER_CH_13, 0x71, 0, QSFP, "QSFP112"}, + + {I2C_MASTER_CH_12, 0x73, 0, QSFP, "QSFP113"}, {I2C_MASTER_CH_12, 0x73, 1, QSFP, "QSFP114"}, + {I2C_MASTER_CH_12, 0x73, 2, QSFP, "QSFP115"}, {I2C_MASTER_CH_12, 0x73, 3, QSFP, "QSFP116"}, + {I2C_MASTER_CH_13, 0x70, 7, QSFP, "QSFP117"}, {I2C_MASTER_CH_13, 0x70, 6, QSFP, "QSFP118"}, + {I2C_MASTER_CH_13, 0x70, 5, QSFP, "QSFP119"}, {I2C_MASTER_CH_13, 0x70, 4, QSFP, "QSFP120"}, + {I2C_MASTER_CH_12, 0x73, 4, QSFP, "QSFP121"}, {I2C_MASTER_CH_12, 0x73, 5, QSFP, "QSFP122"}, + {I2C_MASTER_CH_12, 0x73, 6, QSFP, "QSFP123"}, {I2C_MASTER_CH_12, 0x73, 7, QSFP, "QSFP124"}, + {I2C_MASTER_CH_13, 0x70, 3, QSFP, "QSFP125"}, {I2C_MASTER_CH_13, 0x70, 2, QSFP, "QSFP126"}, + {I2C_MASTER_CH_13, 0x70, 1, QSFP, "QSFP127"}, {I2C_MASTER_CH_13, 0x70, 0, QSFP, "QSFP128"}, + + /* Vritual I2C adapters */ + {I2C_MASTER_CH_1, 0xFF, 0, NONE, "I2C_1"}, // FAN + {I2C_MASTER_CH_2, 0xFF, 0, NONE, "I2C_2"}, + {I2C_MASTER_CH_3, 0xFF, 0, NONE, "I2C_3"}, + {I2C_MASTER_CH_4, 0xFF, 0, NONE, "I2C_4"}, + {I2C_MASTER_CH_5, 0xFF, 0, NONE, "I2C_5"}, // BB + {I2C_MASTER_CH_6, 0xFF, 0, NONE, "I2C_6"}, + {I2C_MASTER_CH_7, 0xFF, 0, NONE, "I2C_7"}, // SW[1-2] + {I2C_MASTER_CH_8, 0xFF, 0, NONE, "I2C_8"}, // SW[3-4] + + // NOTE: Buses below are for front panel port debug + {I2C_MASTER_CH_11, 0xFF, 0, NONE, "I2C_11"}, + {I2C_MASTER_CH_12, 0xFF, 0, NONE, "I2C_12"}, + {I2C_MASTER_CH_13, 0xFF, 0, NONE, "I2C_13"}, + {I2C_MASTER_CH_14, 0xFF, 0, NONE, "I2C_14"}, +}; + +#define VIRTUAL_I2C_PORT_LENGTH ARRAY_SIZE(fpga_i2c_bus_dev) +#define FAN_I2C_CPLD_INDEX SFF_PORT_TOTAL +#define BB_I2C_CPLD_INDEX SFF_PORT_TOTAL + 4 +#define SW1_I2C_CPLD_INDEX SFF_PORT_TOTAL + 6 +#define SW2_I2C_CPLD_INDEX SFF_PORT_TOTAL + 7 + +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 phalanxp_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; + uint8_t cpld3_read_addr; + uint8_t cpld4_read_addr; + uint8_t fancpld_read_addr; +}; + +struct sff_device_data { + int portid; + enum PORT_TYPE port_type; +}; + +struct phalanxp_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; +static struct kobject *cpld3 = NULL; +static struct kobject *cpld4 = NULL; +static struct kobject *fancpld = NULL; + +/** + * Device node in sysfs tree. + */ +static struct device *sff_dev = NULL; + +/** + * 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; +} + +/* 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 struct attribute *fpga_attrs[] = { + &dev_attr_getreg.attr, + &dev_attr_scratch.attr, + &dev_attr_setreg.attr, + NULL, +}; + +static struct attribute_group fpga_attr_grp = { + .attrs = fpga_attrs, +}; + +/* 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[SW1_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[SW1_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[SW1_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[SW1_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_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_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[SW1_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[SW1_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[SW1_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[SW1_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_getreg.attr, + &dev_attr_cpld2_scratch.attr, + &dev_attr_cpld2_setreg.attr, + NULL, +}; + +static struct attribute_group cpld2_attr_grp = { + .attrs = cpld2_attrs, +}; + +static ssize_t cpld3_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[SW2_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, fpga_data->cpld3_read_addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t cpld3_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->cpld3_read_addr = addr; + return size; +} +struct device_attribute dev_attr_cpld3_getreg = __ATTR(getreg, 0600, cpld3_getreg_show, cpld3_getreg_store); + +static ssize_t cpld3_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[SW2_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 cpld3_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[SW2_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_cpld3_scratch = __ATTR(scratch, 0600, cpld3_scratch_show, cpld3_scratch_store); + +static ssize_t cpld3_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[SW2_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_cpld3_setreg = __ATTR(setreg, 0200, NULL, cpld3_setreg_store); + +static struct attribute *cpld3_attrs[] = { + &dev_attr_cpld3_getreg.attr, + &dev_attr_cpld3_scratch.attr, + &dev_attr_cpld3_setreg.attr, + NULL, +}; + +static struct attribute_group cpld3_attr_grp = { + .attrs = cpld3_attrs, +}; + +static ssize_t cpld4_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[SW2_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, fpga_data->cpld4_read_addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t cpld4_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->cpld4_read_addr = addr; + return size; +} +struct device_attribute dev_attr_cpld4_getreg = __ATTR(getreg, 0600, cpld4_getreg_show, cpld4_getreg_store); + +static ssize_t cpld4_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[SW2_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 cpld4_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[SW2_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_cpld4_scratch = __ATTR(scratch, 0600, cpld4_scratch_show, cpld4_scratch_store); + +static ssize_t cpld4_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[SW2_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_cpld4_setreg = __ATTR(setreg, 0200, NULL, cpld4_setreg_store); + +static struct attribute *cpld4_attrs[] = { + &dev_attr_cpld4_getreg.attr, + &dev_attr_cpld4_scratch.attr, + &dev_attr_cpld4_setreg.attr, + NULL, +}; + +static struct attribute_group cpld4_attr_grp = { + .attrs = cpld4_attrs, +}; + +/* FAN CPLD */ +static ssize_t fancpld_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[FAN_I2C_CPLD_INDEX], FAN_CPLD_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, fpga_data->fancpld_read_addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + return sprintf(buf, "0x%2.2x\n", data); +} +static ssize_t fancpld_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->fancpld_read_addr = addr; + return size; +} +struct device_attribute dev_attr_fancpld_getreg = __ATTR(getreg, 0600, fancpld_getreg_show, fancpld_getreg_store); + +static ssize_t fancpld_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[FAN_I2C_CPLD_INDEX], FAN_CPLD_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x04, 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 fancpld_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[FAN_I2C_CPLD_INDEX], FAN_CPLD_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x04, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data); + if (err < 0) + return err; + return size; +} +struct device_attribute dev_attr_fancpld_scratch = __ATTR(scratch, 0600, fancpld_scratch_show, fancpld_scratch_store); + +static ssize_t fancpld_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[FAN_I2C_CPLD_INDEX], FAN_CPLD_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_fancpld_setreg = __ATTR(setreg, 0200, NULL, fancpld_setreg_store); + +static struct attribute *fancpld_attrs[] = { + &dev_attr_fancpld_getreg.attr, + &dev_attr_fancpld_scratch.attr, + &dev_attr_fancpld_setreg.attr, + NULL, +}; + +static struct attribute_group fancpld_attr_grp = { + .attrs = fancpld_attrs, +}; + +static struct attribute *fancpld_no_attrs[] = { + NULL, +}; + +static struct attribute_group fancpld_no_attr_grp = { + .attrs = fancpld_no_attrs, +}; + +/* QSFP/SFP+ attributes */ +static ssize_t qsfp_modirq_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_STAT_INT_N) & 1U); +} +DEVICE_ATTR_RO(qsfp_modirq); + +static ssize_t qsfp_modprs_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_STAT_MODABS) & 1U); +} +DEVICE_ATTR_RO(qsfp_modprs); + +static ssize_t sfp_txfault_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_STAT_TXFAULT) & 1U); +} +DEVICE_ATTR_RO(sfp_txfault); + +static ssize_t sfp_rxlos_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_STAT_RXLOS) & 1U); +} +DEVICE_ATTR_RO(sfp_rxlos); + +static ssize_t sfp_modabs_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_STAT_MODABS) & 1U); +} +DEVICE_ATTR_RO(sfp_modabs); + +static ssize_t qsfp_modsel_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_CTRL_MODSEL) & 1U); +} +static ssize_t qsfp_modsel_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + ssize_t status; + long value; + u8 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + + status = kstrtol(buf, 0, &value); + if (status == 0) { + // if value is 0, clear bit. + i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ); + if (!value) + data = data & ~( 1U << I2C_CTRL_MODSEL ); + else + data = data | ( 1U << I2C_CTRL_MODSEL ); + i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_WRITE); + status = size; + } + return status; +} +DEVICE_ATTR_RW(qsfp_modsel); + +static ssize_t qsfp_reset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_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; + u8 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + + status = kstrtol(buf, 0, &value); + if (status == 0) { + // if value is 0, reset signal is low + i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ); + if (!value) + data = data & ~((u8)0x1 << I2C_CTRL_RST); + else + data = data | ((u8)0x1 << I2C_CTRL_RST); + i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_WRITE); + status = size; + } + return status; +} +DEVICE_ATTR_RW(qsfp_reset); + +static ssize_t sfp_txdisable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_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; + u8 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + + mutex_lock(&fpga_data->fpga_lock); + status = kstrtol(buf, 0, &value); + if (status == 0) { + // check if value is 0 clear + i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ); + if (!value) + data = data & ~((u8)0x1 << I2C_CTRL_TXDIS); + else + data = data | ((u8)0x1 << I2C_CTRL_TXDIS); + i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_WRITE); + 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_modsel.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, led_mode_3, led_mode_4; + int err; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW1_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[SW1_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; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_3); + if (err < 0) + return err; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_4); + if (err < 0) + return err; + return sprintf(buf, "%s %s %s %s\n", + led_mode_1 ? "test" : "normal", + led_mode_2 ? "test" : "normal", + led_mode_3 ? "test" : "normal", + led_mode_4 ? "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[SW1_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[SW1_I2C_CPLD_INDEX], CPLD2_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[SW2_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[SW2_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 green/amber/both/alt-blink/OFF + __u8 led_color1, led_color2, led_color3, led_color4; + int err; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW1_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[SW1_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; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color3); + if (err < 0) + return err; + err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color4); + if (err < 0) + return err; + return sprintf(buf, "%s %s %s %s\n", + led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "amber" : led_color1 == 0x04 ? + "both" : "alt-blink", + led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "amber" : led_color1 == 0x04 ? + "both" : "alt-blink", + led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "amber" : led_color1 == 0x04 ? + "both" : "alt-blink", + led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "amber" : led_color1 == 0x04 ? + "both" : "alt-blink"); +} + +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, "amber")) { + led_color = 0x05; + } else if (sysfs_streq(buf, "both")) { + led_color = 0x04; + } else if (sysfs_streq(buf, "alt-blink")) { + led_color = 0x03; + } else { + status = -EINVAL; + return status; + } + status = fpga_i2c_access(fpga_data->i2c_adapter[SW1_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[SW1_I2C_CPLD_INDEX], CPLD2_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[SW2_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[SW2_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 * phalanxp_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_core_init(unsigned int master_bus, unsigned int freq_div,void __iomem *pci_bar){ + + unsigned int ctrl; + unsigned int REG_FREQ_L; + unsigned int REG_FREQ_H; + unsigned int REG_CTRL; + unsigned int REG_CMD; + + REG_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20; + REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20; + REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20; + REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20; + + if ( freq_div != I2C_DIV_100K ) { + printk(KERN_ERR "FPGA I2C core: Unsupported clock divider: %x\n", freq_div); + return -EINVAL; + } + + // Makes sure core is disable + ctrl = ioread8(pci_bar + REG_CTRL); + iowrite8( ctrl & ~(1 << I2C_CTRL_EN | 1 << I2C_CTRL_IEN), pci_bar + REG_CTRL); + + iowrite8( freq_div & 0xFF , pci_bar + REG_FREQ_L); + iowrite8( freq_div >> 8, pci_bar + REG_FREQ_H); + + /* Only enable EN bit, we only use polling mode */ + iowrite8(1 << I2C_CMD_IACK, pci_bar + REG_CMD); + iowrite8(1 << I2C_CTRL_EN, pci_bar + REG_CTRL); + + return 0; +} + +static void i2c_core_deinit(unsigned int master_bus,void __iomem *pci_bar){ + + unsigned int REG_CTRL; + REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20; + // Disable core + iowrite8( ioread8(pci_bar + REG_CTRL) & ~(1 << I2C_CTRL_EN| 1 << I2C_CTRL_IEN), pci_bar + REG_CTRL); +} + +/** + * We have 2 line cards and each with 2 cplds here. + * Each line card have 64 ports. Each cpld manage 32 ports. + * protid start from 1. + * +---+------------------+------------------+ + * |LC1|1 CPLD1 57|65 CPLD2 121| + * | |4 60|68 124| + * +---+------------------+------------------+ + * |LC2|5 CPLD1 61|69 CPLD2 125| + * | |8 64|72 128| + * +---+------------------+------------------+ + */ +static int i2c_xcvr_access(u8 register_address, unsigned int portid, u8 *data, char rw){ + + u16 dev_addr = 0; + int err; + int lci, cpldi, i2c_adapter_index; + int row, col; + + /* check for portid valid length */ + if(portid < 1 || portid > SFF_PORT_TOTAL){ + return -EINVAL; + } + + lci = ( portid -1 ) % 8; + cpldi = (portid -1 ) / 8; + + /* Normalize the port xposition into 4 x 8 metric. + * Then calculate the cpld's port index from matrix. + */ + row = (portid -1 ) % 4; + col = (portid -1 ) / 8; + + // Line card select top/buttom + if( lci < 4 ){ + i2c_adapter_index = SW1_I2C_CPLD_INDEX; + }else{ + i2c_adapter_index = SW2_I2C_CPLD_INDEX; + } + + // CPLD select left/right + if( cpldi < 8 ){ + dev_addr = CPLD1_SLAVE_ADDR; + }else{ + col -= 8; + dev_addr = CPLD2_SLAVE_ADDR; + } + + // Calculate cpld portid + portid = ( 4 * col ) + row + 1; + + // Select port + err = fpga_i2c_access(fpga_data->i2c_adapter[i2c_adapter_index], dev_addr, 0x00, I2C_SMBUS_WRITE, + I2C_XCVR_SEL, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&portid); + if(err < 0){ + return err; + } + // Read/write port xcvr register + err = fpga_i2c_access(fpga_data->i2c_adapter[i2c_adapter_index], dev_addr, 0x00, rw, + register_address , I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)data); + if(err < 0){ + return err; + } + return 0; +} + +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_FREQ_L; + unsigned int REG_FREQ_H; + unsigned int REG_CMD; + unsigned int REG_CTRL; + unsigned int REG_STAT; + unsigned int REG_DATA; + + 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_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20; + REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20; + REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20; + REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20; + REG_STAT = I2C_MASTER_STATUS + (master_bus - 1) * 0x20; + REG_DATA = I2C_MASTER_DATA + (master_bus - 1) * 0x20; + + check(pci_bar + REG_STAT); + check(pci_bar + REG_CTRL); + + /* + * We wait for the data to be transferred (8bit), + * then we start polling on the ACK/NACK bit + * udelay((8 * 1000) / 100); + */ + udelay(80); + dev_dbg(&a->dev,"Wait for 0x%2.2X\n", 1 << I2C_STAT_TIP); + + timeout = jiffies + msecs_to_jiffies(timeout); + while (1) { + Status = ioread8(pci_bar + REG_STAT); + dev_dbg(&a->dev, "ST:%2.2X\n", Status); + + /* Wait for the TIP bit to be cleared before timeout */ + if ( (Status & ( 1 << I2C_STAT_TIP )) == 0 ) { + dev_dbg(&a->dev, " TIP cleared:0x%2.2X\n", Status); + break; + } + + if (time_after(jiffies, timeout)) { + info("Status %2.2X", Status); + info("Error Timeout"); + error = -ETIMEDOUT; + break; + } + + cpu_relax(); + cond_resched(); + } + info("Status %2.2X", Status); + info("STA:%x",Status); + + if (error < 0) { + dev_dbg(&a->dev, "%s TIMEOUT bit 0x%x not clear in specific time\n", + __func__, (1 << I2C_STAT_TIP)); + return error; + } + + /** There is only one master in each bus. If this error happen something is + * not normal in i2c transfer refer to: + * https://www.i2c-bus.org/i2c-primer/analysing-obscure-problems/master-reports-arbitration-lost + */ + // Arbitration lost + if (Status & (1 << I2C_STAT_AL)) { + info("Error arbitration lost"); + nack_retry[master_bus - 1] = 1; + return -EBUSY; + } + + // Ack not received + if (Status & (1 << I2C_STAT_RxACK)) { + info( "SL No ACK"); + if (writing) { + info("Error No ACK"); + nack_retry[master_bus - 1] = 1; + return -EIO; + } + } else { + info( "SL ACK"); + } + + return error; +} + +static int i2c_wait_stop(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_FREQ_L; + unsigned int REG_FREQ_H; + unsigned int REG_CMD; + unsigned int REG_CTRL; + unsigned int REG_STAT; + unsigned int REG_DATA; + + 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_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20; + REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20; + REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20; + REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20; + REG_STAT = I2C_MASTER_STATUS + (master_bus - 1) * 0x20; + REG_DATA = I2C_MASTER_DATA + (master_bus - 1) * 0x20; + + check(pci_bar + REG_STAT); + check(pci_bar + REG_CTRL); + + dev_dbg(&a->dev,"Wait for 0x%2.2X\n", 1 << I2C_STAT_BUSY); + timeout = jiffies + msecs_to_jiffies(timeout); + while (1) { + Status = ioread8(pci_bar + REG_STAT); + dev_dbg(&a->dev, "ST:%2.2X\n", Status); + if (time_after(jiffies, timeout)) { + info("Status %2.2X", Status); + info("Error Timeout"); + error = -ETIMEDOUT; + break; + } + + /* Wait for the BUSY bit to be cleared before timeout */ + if ( (Status & ( 1 << I2C_STAT_BUSY )) == 0 ) { + dev_dbg(&a->dev, " BUSY cleared:0x%2.2X\n", Status); + break; + } + + cpu_relax(); + cond_resched(); + } + info("Status %2.2X", Status); + info("STA:%x",Status); + + if (error < 0) { + dev_dbg(&a->dev, "%s TIMEOUT bit 0x%x not clear in specific time\n", + __func__, (1 << I2C_STAT_BUSY)); + return error; + } + return 0; +} + +/* SMBUS Xfer for opencore I2C with polling */ +// TODO: Change smbus_xfer to master_xfer - This will support i2c and all smbus emu functions. +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; + int error_stop = 0; + + unsigned int REG_FREQ_L; + unsigned int REG_FREQ_H; + unsigned int REG_CMD; + unsigned int REG_CTRL; + unsigned int REG_STAT; + unsigned int REG_DATA; + + REG_FREQ_L = 0; + REG_FREQ_H = 0; + REG_CTRL = 0; + REG_CMD = 0; + REG_STAT = 0; + REG_DATA = 0; + + /* Write the command register */ + dev_data = i2c_get_adapdata(adapter); + portid = dev_data->portid; + pci_bar = fpga_dev.data_base_addr; + +#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" : + size == 8 ? "I2C_BLOCK_DATA" : "ERROR" + , cmd); +#endif + + master_bus = dev_data->pca9548.master_bus; + error = i2c_core_init(master_bus, I2C_DIV_100K, fpga_dev.data_base_addr); + + /* 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: + case I2C_SMBUS_I2C_BLOCK_DATA: + break; + default: + printk(KERN_INFO "Unsupported transaction %d\n", size); + error = -EOPNOTSUPP; + goto Done; + } + + master_bus = dev_data->pca9548.master_bus; + + if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) { + error = -EINVAL; + goto Done; + } + + REG_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20; + REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20; + REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20; + REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20; + REG_STAT = I2C_MASTER_STATUS + (master_bus - 1) * 0x20; + REG_DATA = I2C_MASTER_DATA + (master_bus - 1) * 0x20; + + ////[S][ADDR/R] + 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_DATA); + } else { + // sent device address with Write mode + iowrite8( (addr << 1) & 0xFE, pci_bar + REG_DATA); + } + iowrite8( 1 << I2C_CMD_STA | 1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + + info( "MS Start"); + + //// Wait {A} + // + IACK + error = i2c_wait_ack(adapter, 30, 1); + if (error < 0) { + info( "get error %d", error); + dev_dbg(&adapter->dev,"START Error: %d\n", error); + goto Done; + } + + //// [CMD]{A} + if (size == I2C_SMBUS_BYTE_DATA || + size == I2C_SMBUS_WORD_DATA || + size == I2C_SMBUS_BLOCK_DATA || + size == I2C_SMBUS_I2C_BLOCK_DATA || + (size == I2C_SMBUS_BYTE && rw == I2C_SMBUS_WRITE)) { + + // sent command code to data register + iowrite8(cmd, pci_bar + REG_DATA); + // Start the transfer + iowrite8(1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + info( "MS Send CMD 0x%2.2X", cmd); + + // Wait {A} + // IACK + error = i2c_wait_ack(adapter, 30, 1); + if (error < 0) { + info( "get error %d", error); + dev_dbg(&adapter->dev,"CMD Error: %d\n", 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: + case I2C_SMBUS_I2C_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 block data write + if (size == I2C_SMBUS_BLOCK_DATA && rw == I2C_SMBUS_WRITE) { + + iowrite8(cnt, pci_bar + REG_DATA); + //Start the transfer + iowrite8(1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + info( "MS Send CNT 0x%2.2X", cnt); + + // Wait {A} + // IACK + error = i2c_wait_ack(adapter, 30, 1); + if (error < 0) { + info( "get error %d", error); + dev_dbg(&adapter->dev,"CNT Error: %d\n", 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 || + size == I2C_SMBUS_I2C_BLOCK_DATA + )) { + int bid = 0; + info( "MS prepare to sent [%d bytes]", cnt); + if (size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_I2C_BLOCK_DATA) { + bid = 1; // block[0] is cnt; + cnt += 1; // offset from block[0] + } + for (; bid < cnt; bid++) { + info("STA:%x", ioread8(pci_bar + REG_STAT) ); + info( " Data > %2.2X", data->block[bid]); + iowrite8(data->block[bid], pci_bar + REG_DATA); + iowrite8(1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + + // Wait {A} + // IACK + error = i2c_wait_ack(adapter, 30, 1); + if (error < 0) { + dev_dbg(&adapter->dev,"Send DATA Error: %d\n", error); + goto Done; + } + } + } + + //REPEATE START + if ( rw == I2C_SMBUS_READ && ( + size == I2C_SMBUS_BYTE_DATA || + size == I2C_SMBUS_WORD_DATA || + size == I2C_SMBUS_BLOCK_DATA || + size == I2C_SMBUS_I2C_BLOCK_DATA + )) { + info( "MS Repeated Start"); + + // sent Address with Read mode + iowrite8( addr << 1 | 0x1 , pci_bar + REG_DATA); + // SET START | WRITE + iowrite8( 1 << I2C_CMD_STA | 1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + + // Wait {A} + error = i2c_wait_ack(adapter, 30, 1); + if (error < 0) { + dev_dbg(&adapter->dev,"Repeat START Error: %d\n", error); + 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 || + size == I2C_SMBUS_I2C_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; + case I2C_SMBUS_I2C_BLOCK_DATA: + cnt = data->block[0]; break; + default: + cnt = 0; break; + } + + info( "MS Receive"); + + for (bid = 0; bid < cnt; bid++) { + + // Start receive FSM + if (bid == cnt - 1) { + info( "READ NACK"); + iowrite8(1 << I2C_CMD_RD | 1 << I2C_CMD_ACK | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + }else{ + + iowrite8(1 << I2C_CMD_RD, pci_bar + REG_CMD); + } + + // Wait {A} + error = i2c_wait_ack(adapter, 30, 0); + if(nack_retry[master_bus - 1] == 1) + { + need_retry[master_bus - 1] = 1; + } + if (error < 0) { + dev_dbg(&adapter->dev,"Receive DATA Error: %d\n", error); + goto Done; + } + if(size == I2C_SMBUS_I2C_BLOCK_DATA){ + /* block[0] is read length */ + data->block[bid+1] = ioread8(pci_bar + REG_DATA); + info( "DATA IN [%d] %2.2X", bid+1, data->block[bid+1]); + }else { + data->block[bid] = ioread8(pci_bar + REG_DATA); + info( "DATA IN [%d] %2.2X", bid, data->block[bid]); + } + if (size == I2C_SMBUS_BLOCK_DATA && bid == 0) { + cnt = data->block[0] + 1; + } + } + } + +Done: + info( "MS STOP"); + // SET STOP + iowrite8( 1 << I2C_CMD_STO | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + // Wait for the STO to finish. + error_stop = i2c_wait_stop(adapter, 30, 0); + if (error_stop < 0) { + dev_dbg(&adapter->dev,"STOP Error: %d\n", error_stop); + } + check(pci_bar + REG_CTRL); + check(pci_bar + REG_STAT); +#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, retval = 0; + struct i2c_dev_data *dev_data; + unsigned char master_bus; + unsigned char switch_addr; + unsigned char channel; + unsigned char *calling_name; + uint16_t prev_port = 0; + unsigned char prev_switch; + unsigned char prev_ch; + uint8_t read_channel; + int retry = 0; + + 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; + calling_name = dev_data->pca9548.calling_name; + + // 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 + // Only select new channel of a switch if they are difference from last channel of a switch + 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", prev_ch, prev_switch, 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", prev_ch, prev_switch, 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 + nack_retry[master_bus - 1] = 0; + need_retry[master_bus - 1] = 0; + error = smbus_access(adapter, addr, flags, rw, cmd, size, data); + if((nack_retry[master_bus - 1]==1)&&(need_retry[master_bus - 1]==1)) + retry = 2000; + else + retry = 5; + // If the first access failed, do retry. + while((nack_retry[master_bus - 1]==1)&&retry) + { + retry--; + nack_retry[master_bus - 1] = 0; + dev_dbg(&adapter->dev,"error = %d\n",error); + error = smbus_access(adapter, addr, flags, rw, cmd, size, data); + dev_dbg(&adapter->dev,"nack retry = %d\n",retry); + } + nack_retry[master_bus - 1] = 0; + need_retry[master_bus - 1] = 0; + + retval = error; + + 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); + }else{ + goto release_unlock; + } + + /** For the bus with PCA9548, try to read PCA9548 one more time. + * For the bus w/o PCA9548 just check the return from last time. + */ + if (switch_addr != 0xFF) { + error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE, (union i2c_smbus_data*)&read_channel); + dev_dbg(&adapter->dev,"Try access I2C switch device at %2.2x\n", switch_addr); + if(error < 0){ + dev_dbg(&adapter->dev,"Unbale to access switch device.\n"); + }else{ + dev_dbg(&adapter->dev,"Read success, register val %2.2x\n", read_channel); + } + } + + // If retry was used up(retry = 0) and the last transfer result is -EBUSY + if(retry <= 0 && error == -EBUSY ){ + retval = error; + // raise device error message + dev_err(&adapter->dev, "I2C bus hangup detected on %s port.\n", calling_name); + + /** + * Phalanxp: Device specific I2C reset topology + */ + if( master_bus == I2C_MASTER_CH_11 || master_bus == I2C_MASTER_CH_12 || + master_bus == I2C_MASTER_CH_13 || master_bus == I2C_MASTER_CH_14 ){ + dev_notice(&adapter->dev, "Trying bus recovery...\n"); + dev_notice(&adapter->dev, "Reset I2C switch device.\n"); + + // reset PCA9548 on the current BUS. + if(master_bus == I2C_MASTER_CH_11){ + // LC1_I2C3_RST_N .. LC1_I2C0_RST_N + iowrite8( ioread8(fpga_dev.data_base_addr + 0x0108) & 0xF0, fpga_dev.data_base_addr + 0x0108); + udelay(1); + iowrite8( ioread8(fpga_dev.data_base_addr + 0x0108) | 0x0F, fpga_dev.data_base_addr + 0x0108); + }else if(master_bus == I2C_MASTER_CH_12){ + // LC1_I2C7_RST_N .. LC1_I2C4_RST_N + iowrite8( ioread8(fpga_dev.data_base_addr + 0x0108) & 0x8F, fpga_dev.data_base_addr + 0x0108); + udelay(1); + iowrite8( ioread8(fpga_dev.data_base_addr + 0x0108) | 0x70, fpga_dev.data_base_addr + 0x0108); + }else if(master_bus == I2C_MASTER_CH_13){ + // LC2_I2C3_RST_N .. LC2_I2C0_RST_N + iowrite8( ioread8(fpga_dev.data_base_addr + 0x010c) & 0xF0, fpga_dev.data_base_addr + 0x010c); + udelay(1); + iowrite8( ioread8(fpga_dev.data_base_addr + 0x010c) | 0x0F, fpga_dev.data_base_addr + 0x010c); + }else if(master_bus == I2C_MASTER_CH_14){ + // LC2_I2C7_RST_N .. LC2_I2C4_RST_N + iowrite8( ioread8(fpga_dev.data_base_addr + 0x010c) & 0x8F, fpga_dev.data_base_addr + 0x010c); + udelay(1); + iowrite8( ioread8(fpga_dev.data_base_addr + 0x010c) | 0x70, fpga_dev.data_base_addr + 0x010c); + } + // clear the last access port + fpga_i2c_lasted_access_port[master_bus - 1] = 0; + }else{ + dev_crit(&adapter->dev, "I2C bus unrecoverable.\n"); + } + } + + +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 retval; +} + +/** + * 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| + I2C_FUNC_SMBUS_I2C_BLOCK; +} + +static const struct i2c_algorithm phalanxp_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 * phalanxp_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; + + 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 = &phalanxp_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_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; +}; + +// I/O resource need. +static struct resource phalanxp_resources[] = { + { + .start = 0x10000000, + .end = 0x10001000, + .flags = IORESOURCE_MEM, + }, +}; + +static void phalanxp_dev_release( struct device * dev) +{ + return; +} + +static struct platform_device phalanxp_dev = { + .name = DRIVER_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(phalanxp_resources), + .resource = phalanxp_resources, + .dev = { + .release = phalanxp_dev_release, + } +}; + +/** + * Board info for QSFP/SFP+ eeprom. + * Note: Using OOM optoe as transceiver 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 phalanxp_drv_probe(struct platform_device *pdev) +{ + struct resource *res; + int ret = 0; + int portid_count; + uint8_t cpld1_version, cpld2_version, cpld3_version, cpld4_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 phalanxp_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]); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(!res)) { + printk(KERN_ERR "Specified Resource Not Available...\n"); + kzfree(fpga_data); + return -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; + } + + cpld3 = kobject_create_and_add("CPLD3", &pdev->dev.kobj); + if (!cpld3) { + 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 -ENOMEM; + } + ret = sysfs_create_group(cpld3, &cpld3_attr_grp); + if (ret != 0) { + printk(KERN_ERR "Cannot create CPLD3 sysfs attributes\n"); + kobject_put(cpld3); + 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; + } + + cpld4 = kobject_create_and_add("CPLD4", &pdev->dev.kobj); + if (!cpld4) { + sysfs_remove_group(cpld3, &cpld3_attr_grp); + kobject_put(cpld3); + 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 -ENOMEM; + } + ret = sysfs_create_group(cpld4, &cpld4_attr_grp); + if (ret != 0) { + printk(KERN_ERR "Cannot create CPLD4 sysfs attributes\n"); + kobject_put(cpld4); + sysfs_remove_group(cpld3, &cpld3_attr_grp); + kobject_put(cpld3); + 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; + } + + fancpld = kobject_create_and_add("FAN_CPLD", &pdev->dev.kobj); + if (!fancpld) { + sysfs_remove_group(cpld4, &cpld4_attr_grp); + kobject_put(cpld4); + sysfs_remove_group(cpld3, &cpld3_attr_grp); + kobject_put(cpld3); + 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 -ENOMEM; + } + if(!allow_unsafe_i2c_access) + ret = sysfs_create_group(fancpld, &fancpld_no_attr_grp); + else + ret = sysfs_create_group(fancpld, &fancpld_attr_grp); + if (ret != 0) { + printk(KERN_ERR "Cannot create FAN_CPLD sysfs attributes\n"); + kobject_put(fancpld); + sysfs_remove_group(cpld4, &cpld4_attr_grp); + kobject_put(cpld4); + sysfs_remove_group(cpld3, &cpld3_attr_grp); + kobject_put(cpld3); + 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; + } + + 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(fancpld, &fancpld_attr_grp); + kobject_put(fancpld); + sysfs_remove_group(cpld4, &cpld4_attr_grp); + kobject_put(cpld4); + sysfs_remove_group(cpld3, &cpld3_attr_grp); + kobject_put(cpld3); + 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(fancpld, &fancpld_attr_grp); + kobject_put(fancpld); + sysfs_remove_group(cpld4, &cpld4_attr_grp); + kobject_put(cpld4); + sysfs_remove_group(cpld3, &cpld3_attr_grp); + kobject_put(cpld3); + 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(fancpld, &fancpld_attr_grp); + kobject_put(fancpld); + sysfs_remove_group(cpld4, &cpld4_attr_grp); + kobject_put(cpld4); + sysfs_remove_group(cpld3, &cpld3_attr_grp); + kobject_put(cpld3); + 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 = I2C_MASTER_CH_1; portid_count <= I2C_MASTER_CH_TOTAL; portid_count++){ + + if(!allow_unsafe_i2c_access){ + if( portid_count < I2C_MASTER_CH_7 || + portid_count == I2C_MASTER_CH_9 || portid_count == I2C_MASTER_CH_10 ) + continue; + } + ret = i2c_core_init(portid_count, I2C_DIV_100K, fpga_dev.data_base_addr); + if (ret < 0) { + dev_err(&pdev->dev, "Unable to init I2C core %d\n", portid_count); + sysfs_remove_group(&sff_dev->kobj, &sff_led_test_grp); + device_destroy(fpgafwclass, MKDEV(0, 0)); + sysfs_remove_group(fancpld, &fancpld_attr_grp); + kobject_put(fancpld); + sysfs_remove_group(cpld4, &cpld4_attr_grp); + kobject_put(cpld4); + sysfs_remove_group(cpld3, &cpld3_attr_grp); + kobject_put(cpld3); + 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++) { + if(!allow_unsafe_i2c_access){ + if( portid_count >= FAN_I2C_CPLD_INDEX && portid_count < SW1_I2C_CPLD_INDEX ){ + fpga_data->i2c_adapter[portid_count] = NULL; + continue; + } + } + fpga_data->i2c_adapter[portid_count] = phalanxp_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] = phalanxp_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"); + } + } + + printk(KERN_INFO "Virtual I2C buses created\n"); + +#ifdef TEST_MODE + return 0; +#endif + fpga_i2c_access(fpga_data->i2c_adapter[SW1_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[SW1_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, + I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld2_version); + fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, + I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld3_version); + fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, + I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld4_version); + + printk(KERN_INFO "Switch CPLD1 Version: %2.2x\n", cpld1_version); + printk(KERN_INFO "Switch CPLD2 Version: %2.2x\n", cpld2_version); + printk(KERN_INFO "Switch CPLD3 Version: %2.2x\n", cpld3_version); + printk(KERN_INFO "Switch CPLD4 Version: %2.2x\n", cpld4_version); + + + /* Init I2C buses that has PCA9548 switch device. */ + for (portid_count = 0; portid_count < VIRTUAL_I2C_PORT_LENGTH; portid_count++) { + + if(!allow_unsafe_i2c_access){ + if( portid_count >= FAN_I2C_CPLD_INDEX && portid_count < SW1_I2C_CPLD_INDEX ){ + continue; + } + } + + 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 phalanxp_drv_remove(struct platform_device *pdev) +{ + int portid_count; + struct sff_device_data *rem_data; + struct i2c_dev_data *adap_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]); + adap_data = i2c_get_adapdata(fpga_data->i2c_adapter[portid_count]); + i2c_del_adapter(fpga_data->i2c_adapter[portid_count]); + } + } + + for (portid_count = I2C_MASTER_CH_1; portid_count <= I2C_MASTER_CH_TOTAL; portid_count++){ + if(!allow_unsafe_i2c_access){ + if( portid_count < I2C_MASTER_CH_7 || + portid_count == I2C_MASTER_CH_9 || portid_count == I2C_MASTER_CH_10 ) + continue; + } + i2c_core_deinit(portid_count, fpga_dev.data_base_addr); + } + + 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(cpld3, &cpld3_attr_grp); + sysfs_remove_group(cpld4, &cpld4_attr_grp); + sysfs_remove_group(fancpld, &fancpld_attr_grp); + sysfs_remove_group(&sff_dev->kobj, &sff_led_test_grp); + kobject_put(fpga); + kobject_put(cpld1); + kobject_put(cpld2); + kobject_put(cpld3); + kobject_put(cpld4); + kobject_put(fancpld); + device_destroy(fpgafwclass, MKDEV(0, 0)); + devm_kfree(&pdev->dev, fpga_data); + return 0; +} + +static struct platform_driver phalanxp_drv = { + .probe = phalanxp_drv_probe, + .remove = __exit_p(phalanxp_drv_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + +#ifdef TEST_MODE +#define FPGA_PCI_BAR_NUM 2 +#else +#define FPGA_PCI_BAR_NUM 0 +#endif + + + +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 = ioremap_nocache(fpga_dev.data_mmio_start, fpga_dev.data_mmio_len); + 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(&phalanxp_dev); + platform_driver_register(&phalanxp_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(&phalanxp_drv); + platform_device_unregister(&phalanxp_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 phalanxp_init(void) +{ + int rc; + rc = pci_register_driver(&pci_dev_ops); + if (rc) + return rc; + return 0; +} + +void phalanxp_exit(void) +{ + pci_unregister_driver(&pci_dev_ops); +} + +module_init(phalanxp_init); +module_exit(phalanxp_exit); + +module_param(allow_unsafe_i2c_access, bool, 0400); +MODULE_PARM_DESC(allow_unsafe_i2c_access, "enable i2c busses despite potential races against BMC bus access"); + +MODULE_AUTHOR("Pradchaya P. "); +MODULE_DESCRIPTION("Celestica phalanxp switchboard platform driver"); +MODULE_VERSION(MOD_VERSION); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/systemd/platform-modules-jaws.service b/platform/broadcom/sonic-platform-modules-cel/jaws/systemd/platform-modules-jaws.service new file mode 100644 index 000000000000..a99d550e0f3c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/jaws/systemd/platform-modules-jaws.service @@ -0,0 +1,14 @@ + +[ Unit] +Description=Celestica Jaws platform modules +After=local-fs.target +Before=pmon.service + +[Service] +Type=oneshot +ExecStart=-/etc/init.d/platform-modules-jaws start +ExecStop=-/etc/init.d/platform-modules-jaws stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/cfg/shamu-modules.conf b/platform/broadcom/sonic-platform-modules-cel/shamu/cfg/shamu-modules.conf new file mode 100644 index 000000000000..66f002a5fc94 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/cfg/shamu-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-gpio +i2c-mux-pca954x + diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/Makefile b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/Makefile new file mode 100644 index 000000000000..99b818ea21fb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/Makefile @@ -0,0 +1 @@ +obj-m := mc24lc64t.o baseboard_cpld.o switchboard_fpga.o dimm-bus.o i2c-imc.o diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/baseboard_cpld.c b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/baseboard_cpld.c new file mode 100644 index 000000000000..a4dfed2ac18a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/baseboard_cpld.c @@ -0,0 +1,409 @@ +/* + * baseboard_cpld.c - driver for Fishbone2 Base Board CPLD + * This driver implement sysfs for CPLD register access using 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 "AS1440D.cpldb" +/** + * CPLD register address for read and write. + */ +#define VERSION_ADDR 0xA100 +#define SCRATCH_ADDR 0xA101 +#define SYS_LED_ADDR 0xA162 + +#define CPLD_REGISTER_SIZE 0x77 + +struct baseboard_cpld_data { + struct mutex cpld_lock; + uint16_t read_addr; +}; + +struct baseboard_cpld_data *cpld_data; + +/** + * Read the value from scratch register as hex string. + * @param dev kernel device + * @param devattr kernel device attribute + * @param buf buffer for get value + * @return Hex string read from scratch register. + */ +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); +} + +/** + * Set scratch register with specific hex string. + * @param dev kernel device + * @param devattr kernel device attribute + * @param buf buffer of set value + * @param count number of bytes in buffer + * @return number of bytes written, or error code < 0. + */ +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) +{ + // CPLD register is one byte + mutex_lock(&cpld_data->cpld_lock); + int len = sprintf(buf, "0x%2.2x\n",inb(VERSION_ADDR)); + mutex_unlock(&cpld_data->cpld_lock); + return len; +} +static DEVICE_ATTR_RO(version); + + +static ssize_t getreg_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + // CPLD register is one byte + 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) +{ + // CPLD register is one byte + mutex_lock(&cpld_data->cpld_lock); + int 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) +{ + // CPLD register is one byte + 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. + * @return number of byte read. + */ +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; +exit: + mutex_unlock(&cpld_data->cpld_lock); + return status; +} +static BIN_ATTR_RO(dump, CPLD_REGISTER_SIZE); + +/** + * Show system led status - on/off/1k/4k + * @param dev kernel device + * @param devattr kernel device attribute + * @param buf buffer for get value + * @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 ? "4k" : data ==0x01 ? "1k": "on"); +} + +/** + * Set the status of system led - on/off/1k/4k + * @param dev kernel device + * @param devattr kernel device attribute + * @param buf buffer of set value + * @param count number of bytes in buffer + * @return number of bytes written, or error code < 0. + */ +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, "4k")){ + led_status = 0x02; + }else if(sysfs_streq(buf, "1k")){ + 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 + * @param dev kernel device + * @param devattr kernel device attribute + * @param buf buffer for get value + * @return Hex string read from scratch register. + */ +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 + * @param dev kernel device + * @param devattr kernel device attribute + * @param buf buffer of set value + * @param count number of bytes in buffer + * @return number of bytes written, or error code < 0. + */ +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 struct attribute *baseboard_cpld_attrs[] = { + &dev_attr_version.attr, + &dev_attr_scratch.attr, + &dev_attr_getreg.attr, + &dev_attr_setreg.attr, + &dev_attr_sys_led.attr, + &dev_attr_sys_led_color.attr, + NULL, +}; + +static struct bin_attribute *baseboard_cpld_bin_attrs[] = { + &bin_attr_dump, + NULL, +}; + +static struct attribute_group baseboard_cpld_attrs_grp = { + .attrs = baseboard_cpld_attrs, + .bin_attrs = baseboard_cpld_bin_attrs, +}; + +static struct resource baseboard_cpld_resources[] = { + { + .start = 0xA100, + .end = 0xA1FF, + .flags = IORESOURCE_IO, + }, +}; + +static void baseboard_cpld_dev_release( struct device * dev) +{ + return; +} + +static struct platform_device baseboard_cpld_dev = { + .name = DRIVER_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(baseboard_cpld_resources), + .resource = baseboard_cpld_resources, + .dev = { + .release = baseboard_cpld_dev_release, + } +}; + +static int baseboard_cpld_drv_probe(struct platform_device *pdev) +{ + struct resource *res; + int ret =0; + int portid_count; + + cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct baseboard_cpld_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 -1; + } + + ret = sysfs_create_group(&pdev->dev.kobj, &baseboard_cpld_attrs_grp); + if (ret) { + printk(KERN_ERR "Cannot create sysfs for baseboard CPLD\n"); + } + return 0; +} + +static int baseboard_cpld_drv_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &baseboard_cpld_attrs_grp); + return 0; +} + +static struct platform_driver baseboard_cpld_drv = { + .probe = baseboard_cpld_drv_probe, + .remove = __exit_p(baseboard_cpld_drv_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + +int baseboard_cpld_init(void) +{ + // Register platform device and platform driver + platform_device_register(&baseboard_cpld_dev); + platform_driver_register(&baseboard_cpld_drv); + return 0; +} + +void baseboard_cpld_exit(void) +{ + // Unregister platform device and platform driver + platform_driver_unregister(&baseboard_cpld_drv); + platform_device_unregister(&baseboard_cpld_dev); +} + +module_init(baseboard_cpld_init); +module_exit(baseboard_cpld_exit); + +MODULE_AUTHOR("Pradchaya Phucharoen "); +MODULE_DESCRIPTION("Celestica Fishbone2 Baseboard CPLD Driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.c b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.c new file mode 100644 index 000000000000..9f30945e1d1c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2013-2016 Andrew Lutomirski + * + * 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. + * + * 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. + */ +#include +#include +#include +#include "dimm-bus.h" +static bool probe_addr(struct i2c_adapter *adapter, int addr) +{ + /* + * So far, all known devices that live on DIMMs can be safely + * and reliably detected by trying to read a byte at address + * zero. (The exception is the SPD write protection control, + * which can't be probed and requires special hardware and/or + * quick writes to access, and has no driver.) + */ + union i2c_smbus_data dummy; + return i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_READ, 0, + I2C_SMBUS_BYTE_DATA, &dummy) >= 0; +} +/** + * i2c_scan_dimm_bus() - Scans an SMBUS segment known to contain DIMMs + * @adapter: The SMBUS adapter to scan + * + * This function tells the DIMM-bus code that the adapter is known to + * contain DIMMs. i2c_scan_dimm_bus will probe for devices known to + * live on DIMMs. + * + * Do NOT call this function on general-purpose system SMBUS segments + * unless you know that the only things on the bus are DIMMs. + * Otherwise is it very likely to mis-identify other things on the + * bus. + * + * Callers are advised not to set adapter->class = I2C_CLASS_SPD to + * avoid having two separate mechanisms trying to automatically claim + * devices on the bus. + */ +void i2c_scan_dimm_bus(struct i2c_adapter *adapter) +{ + struct i2c_board_info info = {}; + int slot; + /* + * We probe with "read byte data". If any DIMM SMBUS driver can't + * support that access type, this function should be updated. + */ + if (WARN_ON(!i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA))) + return; + /* + * Addresses on DIMMs use the three low bits to identify the slot + * and the four high bits to identify the device type. Known + * devices include: + * + * - 0x10 - 0x17: NVDIMM controller (pre-standard) + * - 0x18 - 0x1f: TSOD (Temperature Sensor on DIMM) + * - 0x40 - 0x47: JESD245 Byte Addressable Energy Backed Interface + * - 0x50 - 0x57: SPD (Serial Presence Detect) EEPROM + * - 0x30 - 0x37: SPD WP control -- not easy to probe + * + * There's no point in trying to probe the SPD WP control: we'd + * want to probe using quick reads, which i2c-imc doesn't + * support, we don't have a driver for it, we can't really use + * it without special hardware (it's not a normal i2c slave -- + * see the JEDEC docs), and using it risks bricking the DIMM + * it's on anyway. + * + * NB: There's no need to save the return value from + * i2c_new_device, as the core code will unregister it for us + * when the adapter is removed. If users want to bind a + * different driver, nothing stops them from unbinding the + * drivers we request here. + */ + for (slot = 0; slot < 8; slot++) { + /* If there's no SPD, then assume there's no DIMM here. */ + if (!probe_addr(adapter, 0x50 | slot)) + continue; + strcpy(info.type, "ee1004"); + info.addr = 0x50 | slot; + i2c_new_device(adapter, &info); + if (probe_addr(adapter, 0x18 | slot)) { + /* + * This is a temperature sensor. The interface is + * defined in the JEDEC TSE2004av specification. + * Linux's driver for this is called "jc42", which + * is a bit nonsensical (JC-42 is the name of the + * committee, not the sensor). + */ + strcpy(info.type, "jc42"); + info.addr = 0x18 | slot; + i2c_new_device(adapter, &info); + } + } +} +EXPORT_SYMBOL(i2c_scan_dimm_bus); +MODULE_AUTHOR("Andrew Lutomirski "); +MODULE_DESCRIPTION("i2c DIMM bus support"); +MODULE_LICENSE("GPL v2"); + diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.h b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.h new file mode 100644 index 000000000000..8f14d5fb973f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2013-2016 Andrew Lutomirski + * + * 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. + * + * 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. + */ +#ifndef _I2C_DIMM_BUS +#define _I2C_DIMM_BUS +struct i2c_adapter; +void i2c_scan_dimm_bus(struct i2c_adapter *adapter); +#endif /* _I2C_DIMM_BUS */ + diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/i2c-imc.c b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/i2c-imc.c new file mode 100644 index 000000000000..7b053f43916e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/i2c-imc.c @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2013-2016 Andrew Lutomirski + * + * 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. + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include "dimm-bus.h" + +/* + * The datasheet can be found here, for example: + * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e5-1600-2600-vol-2-datasheet.pdf + * + * There seem to be quite a few bugs or spec errors, though: + * + * - A successful transaction sets WOD and RDO. + * + * - The docs for TSOD_POLL_EN make no sense (see imc_channel_claim). + * + * - Erratum BT109, which says: + * + * The processor may not complete SMBus (System Management Bus) + * transactions targeting the TSOD (Temperature Sensor On DIMM) + * when Package C-States are enabled. Due to this erratum, if the + * processor transitions into a Package C-State while an SMBus + * transaction with the TSOD is in process, the processor will + * suspend receipt of the transaction. The transaction completes + * while the processor is in a Package C-State. Upon exiting + * Package C-State, the processor will attempt to resume the + * SMBus transaction, detect a protocol violation, and log an + * error. + * + * The description notwithstanding, I've seen difficult-to-reproduce + * issues when the system goes completely idle (so package C-states can + * be entered) while software-initiated SMBUS transactions are in + * progress. + */ + +/* Register offsets (in PCI configuration space) */ +#define SMBSTAT(i) (0x180 + 0x10*(i)) +#define SMBCMD(i) (0x184 + 0x10*(i)) +#define SMBCNTL(i) (0x188 + 0x10*(i)) +#define SMB_TSOD_POLL_RATE_CNTR(i) (0x18C + 0x10*(i)) +#define SMB_TSOD_POLL_RATE (0x1A8) + +/* SMBSTAT fields */ +#define SMBSTAT_RDO (1U << 31) /* Read Data Valid */ +#define SMBSTAT_WOD (1U << 30) /* Write Operation Done */ +#define SMBSTAT_SBE (1U << 29) /* SMBus Error */ +#define SMBSTAT_SMB_BUSY (1U << 28) /* SMBus Busy State */ +/* 26:24 is the last automatically polled TSOD address */ +#define SMBSTAT_RDATA_MASK 0xffff /* result of a read */ + +/* SMBCMD fields */ +#define SMBCMD_TRIGGER (1U << 31) /* CMD Trigger */ +#define SMBCMD_PNTR_SEL (1U << 30) /* HW polls TSOD with pointer */ +#define SMBCMD_WORD_ACCESS (1U << 29) /* word (vs byte) access */ +#define SMBCMD_TYPE_MASK (3U << 27) /* Mask for access type */ +#define SMBCMD_TYPE_READ (0U << 27) /* Read */ +#define SMBCMD_TYPE_WRITE (1U << 27) /* Write */ +#define SMBCMD_TYPE_PNTR_WRITE (3U << 27) /* Write to pointer */ +#define SMBCMD_SA_MASK (7U << 24) /* Slave Address high bits */ +#define SMBCMD_SA_SHIFT 24 +#define SMBCMD_BA_MASK 0xff0000 /* Bus Txn address */ +#define SMBCMD_BA_SHIFT 16 +#define SMBCMD_WDATA_MASK 0xffff /* data to write */ + +/* SMBCNTL fields */ +#define SMBCNTL_DTI_MASK 0xf0000000 /* Slave Address low bits */ +#define SMBCNTL_DTI_SHIFT 28 /* Slave Address low bits */ +#define SMBCNTL_CKOVRD (1U << 27) /* # Clock Override */ +#define SMBCNTL_DIS_WRT (1U << 26) /* Disable Write (sadly) */ +#define SMBCNTL_SOFT_RST (1U << 10) /* Soft Reset */ +#define SMBCNTL_TSOD_POLL_EN (1U << 8) /* TSOD Polling Enable */ +/* Bits 0-3 and 4-6 indicate TSOD presence in various slots */ + +/* Bits that might randomly change if we race with something. */ +#define SMBCMD_OUR_BITS (~(u32)SMBCMD_TRIGGER) +#define SMBCNTL_OUR_BITS (SMBCNTL_DTI_MASK | SMBCNTL_TSOD_POLL_EN) + +/* System Address Controller, PCI dev 13 fn 6, 8086.3cf5 */ +#define SAD_CONTROL 0xf4 + +#define PCI_DEVICE_ID_INTEL_SBRIDGE_BR 0x3cf5 /* 13.6 */ +#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA 0x3ca8 /* 15.0 */ + +#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA 0x6fa8 +#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TM 0x6f71 +#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TA 0x6f68 +#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TM 0x6f79 + +static atomic_t imc_raced; /* Set permanently to 1 if we screw up. */ + +static bool allow_unsafe_access; + +struct imc_channel { + struct i2c_adapter adapter; + struct mutex mutex; /* protects access to regs and prev_tsod_poll */ + bool can_write, suspended; + bool prev_tsod_poll; +}; + +struct imc_priv { + struct pci_dev *pci_dev; + struct imc_channel channels[2]; +}; + +static bool imc_wait_not_busy(struct imc_priv *priv, int chan, u32 *stat) +{ + /* + * The clock is around 100kHz, and transactions are nine cycles + * per byte plus a few start/stop cycles, plus whatever clock + * streching is involved. This means that polling every 70us + * or so will give decent performance. + * + * Ideally we would calculate a good estimate for the + * transaction time and sleep, but busy-waiting is an effective + * workaround for an apparent Sandy Bridge bug that causes bogus + * output if the system enters a package C-state. (NB: these + * states are systemwide -- we don't need be running on the + * right package for this to work.) + * + * When Ivy Bridge and Haswell support are added, we could + * consider making the busy-wait depend on the platform. + */ + + int i; + + for (i = 0; i < 50; i++) { + pci_read_config_dword(priv->pci_dev, SMBSTAT(chan), stat); + if (!(*stat & SMBSTAT_SMB_BUSY)) + return true; + udelay(70); /* see comment above -- we need to busy-wait */ + } + + return false; +} + +static void imc_channel_release(struct imc_priv *priv, int chan) +{ + /* Return to HW control. */ + if (priv->channels[chan].prev_tsod_poll) { + u32 cntl; + + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl); + cntl |= SMBCNTL_TSOD_POLL_EN; + pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), cntl); + } +} + +static int imc_channel_claim(struct imc_priv *priv, int chan) +{ + /* + * The docs are a bit confused here. We're supposed to disable TSOD + * polling, then wait for busy to be cleared, then set + * SMBCNTL_TSOD_POLL_EN to zero to switch to software control. But + * SMBCNTL_TSOD_POLL_EN is the only documented way to turn off polling. + */ + + u32 cntl, stat; + + if (priv->channels[chan].suspended) + return -EIO; + + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl); + priv->channels[chan].prev_tsod_poll = !!(cntl & SMBCNTL_TSOD_POLL_EN); + cntl &= ~SMBCNTL_TSOD_POLL_EN; + pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), cntl); + + /* Sometimes the hardware won't let go. */ + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl); + if (cntl & SMBCNTL_TSOD_POLL_EN) + return -EBUSY; + + if (!imc_wait_not_busy(priv, chan, &stat)) { + imc_channel_release(priv, chan); + return -EBUSY; /* Someone else is controlling the bus. */ + } + + return 0; /* The channel is ours. */ +} + +static bool imc_channel_can_claim(struct imc_priv *priv, int chan) +{ + u32 orig_cntl, cntl; + + /* See if we can turn off TSOD_POLL_EN. */ + + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &orig_cntl); + pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), + orig_cntl & ~SMBCNTL_TSOD_POLL_EN); + + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl); + if (cntl & SMBCNTL_TSOD_POLL_EN) + return false; /* Failed. */ + + pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), orig_cntl); + return true; +} + +/* + * The iMC supports five access types. The terminology is rather + * inconsistent. These are the types: + * + * "Write to pointer register SMBus": I2C_SMBUS_WRITE, I2C_SMBUS_BYTE + * + * Read byte/word: I2C_SMBUS_READ, I2C_SMBUS_{BYTE|WORD}_DATA + * + * Write byte/word: I2C_SMBUS_WRITE, I2C_SMBUS_{BYTE|WORD}_DATA + * + * The pointer write operations is AFAICT completely useless for + * software control, for two reasons. First, HW periodically polls any + * TSODs on the bus, so it will corrupt the pointer in between SW + * transactions. More importantly, the matching "read byte"/"receive + * byte" (the address-less single-byte read) is not available for SW + * control. Therefore, this driver doesn't implement pointer writes + * + * There is no PEC support. + */ + +static u32 imc_func(struct i2c_adapter *adapter) +{ + int chan; + struct imc_channel *ch; + struct imc_priv *priv = i2c_get_adapdata(adapter); + + chan = (adapter == &priv->channels[0].adapter ? 0 : 1); + ch = &priv->channels[chan]; + + if (ch->can_write) + return I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA; + else + return I2C_FUNC_SMBUS_READ_BYTE_DATA | + I2C_FUNC_SMBUS_READ_WORD_DATA; +} + +static s32 imc_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) +{ + int ret, chan; + u32 cmd = 0, cntl, final_cmd, final_cntl, stat; + struct imc_channel *ch; + struct imc_priv *priv = i2c_get_adapdata(adap); + + if (atomic_read(&imc_raced)) + return -EIO; /* Minimize damage. */ + + chan = (adap == &priv->channels[0].adapter ? 0 : 1); + ch = &priv->channels[chan]; + + /* Encode CMD part of addresses and access size */ + cmd |= ((u32)addr & 0x7) << SMBCMD_SA_SHIFT; + cmd |= ((u32)command) << SMBCMD_BA_SHIFT; + if (size == I2C_SMBUS_WORD_DATA) + cmd |= SMBCMD_WORD_ACCESS; + + /* Encode read/write and data to write */ + if (read_write == I2C_SMBUS_READ) { + cmd |= SMBCMD_TYPE_READ; + } else { + cmd |= SMBCMD_TYPE_WRITE; + cmd |= (size == I2C_SMBUS_WORD_DATA + ? swab16(data->word) + : data->byte); + } + + mutex_lock(&ch->mutex); + + ret = imc_channel_claim(priv, chan); + if (ret) + goto out_unlock; + + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl); + cntl &= ~SMBCNTL_DTI_MASK; + cntl |= ((u32)addr >> 3) << SMBCNTL_DTI_SHIFT; + pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), cntl); + + /* + * This clears SMBCMD_PNTR_SEL. We leave it cleared so that we don't + * need to think about keeping the TSOD pointer state consistent with + * the hardware's expectation. This probably has some miniscule + * power cost, as TSOD polls will take 9 extra cycles. + */ + cmd |= SMBCMD_TRIGGER; + pci_write_config_dword(priv->pci_dev, SMBCMD(chan), cmd); + + if (!imc_wait_not_busy(priv, chan, &stat)) { + /* Timeout. TODO: Reset the controller? */ + ret = -ETIMEDOUT; + dev_dbg(&priv->pci_dev->dev, "controller is wedged\n"); + goto out_release; + } + + /* + * Be paranoid: try to detect races. This will only detect races + * against BIOS, not against hardware. (I've never seen this happen.) + */ + pci_read_config_dword(priv->pci_dev, SMBCMD(chan), &final_cmd); + pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &final_cntl); + if (((cmd ^ final_cmd) & SMBCMD_OUR_BITS) || + ((cntl ^ final_cntl) & SMBCNTL_OUR_BITS)) { + WARN(1, "iMC SMBUS raced against firmware"); + dev_err(&priv->pci_dev->dev, + "Access to channel %d raced: cmd 0x%08X->0x%08X, cntl 0x%08X->0x%08X\n", + chan, cmd, final_cmd, cntl, final_cntl); + atomic_set(&imc_raced, 1); + ret = -EIO; + goto out_release; + } + + if (stat & SMBSTAT_SBE) { + /* + * Clear the error to re-enable TSOD polling. The docs say + * that, as long as SBE is set, TSOD polling won't happen. + * The docs also say that writing zero to this bit (which is + * the only writable bit in the whole register) will clear + * the error. Empirically, writing 0 does not clear SBE, but + * it's probably still good to do the write in compliance with + * the spec. (TSOD polling still happens and seems to + * clear SBE on its own.) + */ + pci_write_config_dword(priv->pci_dev, SMBSTAT(chan), 0); + ret = -ENXIO; + goto out_release; + } + + if (read_write == I2C_SMBUS_READ) { + if (!(stat & SMBSTAT_RDO)) { + dev_dbg(&priv->pci_dev->dev, + "Unexpected read status 0x%08X\n", stat); + ret = -EIO; + goto out_release; + } + + /* + * The iMC SMBUS controller thinks of SMBUS words as + * being big-endian (MSB first). Linux treats them as + * little-endian, so we need to swap them. + * + * Note: the controller will often (always?) set WOD + * here. This is probably a hardware bug. + */ + if (size == I2C_SMBUS_WORD_DATA) + data->word = swab16(stat & SMBSTAT_RDATA_MASK); + else + data->byte = stat & 0xFF; + } else { + /* + * Note: the controller will often (always?) set RDO here. + * This is probably a hardware bug. + */ + if (!(stat & SMBSTAT_WOD)) { + dev_dbg(&priv->pci_dev->dev, + "Unexpected write status 0x%08X\n", stat); + ret = -EIO; + } + } + +out_release: + imc_channel_release(priv, chan); + +out_unlock: + mutex_unlock(&ch->mutex); + + return ret; +} + +static const struct i2c_algorithm imc_smbus_algorithm = { + .smbus_xfer = imc_smbus_xfer, + .functionality = imc_func, +}; + +static int imc_init_channel(struct imc_priv *priv, int i, int socket) +{ + int err; + u32 val; + struct imc_channel *ch = &priv->channels[i]; + + /* + * With CLTT enabled, the hardware won't let us turn + * off TSOD polling. The device is completely useless + * when this happens (at least without help from Intel), + * but we can at least minimize confusion. + */ + if (!imc_channel_can_claim(priv, i)) { + dev_warn(&priv->pci_dev->dev, + "iMC channel %d: we cannot control the HW. Is CLTT on?\n", + i); + return -EBUSY; + } + + i2c_set_adapdata(&ch->adapter, priv); + ch->adapter.owner = THIS_MODULE; + ch->adapter.algo = &imc_smbus_algorithm; + ch->adapter.dev.parent = &priv->pci_dev->dev; + + pci_read_config_dword(priv->pci_dev, SMBCNTL(i), &val); + ch->can_write = !(val & SMBCNTL_DIS_WRT); + + mutex_init(&ch->mutex); + + snprintf(ch->adapter.name, sizeof(ch->adapter.name), + "iMC socket %d channel %d", socket, i); + err = i2c_add_adapter(&ch->adapter); + if (err) { + mutex_destroy(&ch->mutex); + return err; + } + + i2c_scan_dimm_bus(&ch->adapter); + + return 0; +} + +static void imc_free_channel(struct imc_priv *priv, int i) +{ + struct imc_channel *ch = &priv->channels[i]; + + i2c_del_adapter(&ch->adapter); + mutex_destroy(&ch->mutex); +} + +static struct pci_dev *imc_get_related_device(struct pci_bus *bus, + unsigned int devfn, u16 devid) +{ + struct pci_dev *dev = pci_get_slot(bus, devfn); + + if (!dev) + return NULL; + if (dev->vendor != PCI_VENDOR_ID_INTEL || dev->device != devid) { + pci_dev_put(dev); + return NULL; + } + return dev; +} + +static int imc_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + int i, j, err; + struct imc_priv *priv; + + priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->pci_dev = dev; + + pci_set_drvdata(dev, priv); + + for (i = 0; i < 1; i++) { + err = imc_init_channel(priv, i, 0); + if (err) + goto exit_free_channels; + printk(KERN_INFO "IMC: Create IMC SMBus OK.\n"); + } + + return 0; + +exit_free_channels: + printk(KERN_INFO "IMC: Free chennel I2C.\n"); + for (j = 0; j < i; j++) + imc_free_channel(priv, j); + return err; +} + +static void imc_remove(struct pci_dev *dev) +{ + int i; + struct imc_priv *priv = pci_get_drvdata(dev); + + for (i = 0; i < 1; i++) + imc_free_channel(priv, i); +} + +static int imc_suspend(struct pci_dev *dev, pm_message_t mesg) +{ + int i; + struct imc_priv *priv = pci_get_drvdata(dev); + + /* BIOS is in charge. We should finish any pending transaction */ + for (i = 0; i < 1; i++) { + mutex_lock(&priv->channels[i].mutex); + priv->channels[i].suspended = true; + mutex_unlock(&priv->channels[i].mutex); + } + + return 0; +} + +static int imc_resume(struct pci_dev *dev) +{ + int i; + struct imc_priv *priv = pci_get_drvdata(dev); + + for (i = 0; i < 1; i++) { + mutex_lock(&priv->channels[i].mutex); + priv->channels[i].suspended = false; + mutex_unlock(&priv->channels[i].mutex); + } + + return 0; +} + +static const struct pci_device_id imc_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA) }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, imc_ids); + +static struct pci_driver imc_pci_driver = { + .name = "imc_smbus", + .id_table = imc_ids, + .probe = imc_probe, + .remove = imc_remove, + .suspend = imc_suspend, + .resume = imc_resume, +}; + +static int __init i2c_imc_init(void) +{ + if (!allow_unsafe_access) + return -ENODEV; + + pr_warn("using this driver is dangerous unless your firmware is specifically designed for it; use at your own risk\n"); + return pci_register_driver(&imc_pci_driver); +} +module_init(i2c_imc_init); + +static void __exit i2c_imc_exit(void) +{ + pci_unregister_driver(&imc_pci_driver); +} +module_exit(i2c_imc_exit); + +module_param(allow_unsafe_access, bool, 0400); +MODULE_PARM_DESC(allow_unsafe_access, "enable i2c_imc despite potential races against BIOS/hardware bus access"); + +MODULE_AUTHOR("Andrew Lutomirski "); +MODULE_DESCRIPTION("iMC SMBus driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/mc24lc64t.c b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/mc24lc64t.c new file mode 100644 index 000000000000..ae79770a4d8e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/mc24lc64t.c @@ -0,0 +1,173 @@ +/* + * 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; + 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"); diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/sonic_platform-1.0-py2-none-any.whl b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/sonic_platform-1.0-py2-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..75d574b5a1235de584a966b95640bc1d52de4a9e GIT binary patch literal 8941 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 literal 0 HcmV?d00001 diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/switchboard_fpga.c b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/switchboard_fpga.c new file mode 100644 index 000000000000..e537eb7955c3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/switchboard_fpga.c @@ -0,0 +1,2431 @@ +/* + * switchboard_fpga.c - Driver for Fishbone2 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 + * \--AS1440DF.switchboard + * |--FPGA + * |--CPLD1 + * |--CPLD2 + * \--SFF + * \--QSFP[1..32] + * + */ + +#ifndef TEST_MODE +#define MOD_VERSION "0.5.2" +#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 "fishbone2_fpga" +#define DRIVER_NAME "AS1440D.switchboard" +#define FPGA_PCI_NAME "fishbone2_fpga_pci" +#define DEVICE_NAME "fwupgrade" + +static bool allow_unsafe_i2c_access; + +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 i2c_core_init(unsigned int master_bus, unsigned int freq_div,void __iomem *pci_bar); +static void i2c_core_deinit(unsigned int master_bus, void __iomem *pci_bar); +static int i2c_xcvr_access(u8 register_address, unsigned int portid, u8 *data, char rw); + +static int fpgafw_init(void); +static void fpgafw_exit(void); + +/* +======================================== +FPGA PCIe BAR 0 Registers +======================================== +Misc Control 0x00000000 – 0x000000FF +I2C_CH1 0x00000800 - 0x0000081C +I2C_CH2 0x00000820 - 0x0000083C +I2C_CH3 0x00000840 - 0x0000085C +I2C_CH4 0x00000860 - 0x0000087C +I2C_CH5 0x00000880 - 0x0000089C +I2C_CH6 0x000008A0 - 0x000008BC +I2C_CH7 0x000008C0 - 0x000008DC +I2C_CH8 0x000008E0 - 0x000008FC +I2C_CH9 0x00000900 - 0x0000091C +I2C_CH10 0x00000920 - 0x0000093C +I2C_CH11 0x00000940 - 0x0000095C +I2C_CH12 0x00000960 - 0x0000097C +I2C_CH13 0x00000980 - 0x0000099C +I2C_CH14 0x000009A0 - 0x000009BC +SPI Master 0x00000A00 - 0x00000BFC +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 BMC_I2C_SCRATCH 0x0020 +#define FPGA_SLAVE_CPLD_REST 0x0100 +#define FPGA_SWITCH_RESET_CTRL 0x0104 +#define FPAG_PRH_RESER_CTRL 0x0108 +#define FPGA_INT_STATUS 0x0200 +#define FPGA_INT_SRC_STATUS 0x0204 +#define FPGA_INT_FLAG 0x0208 +#define FPGA_INT_MASK 0x020c +#define FPGA_MISC_CTRL 0x0300 +#define FPGA_MISC_STATUS 0x0304 + +/* I2C_MASTER BASE ADDR */ +#define I2C_MASTER_FREQ_L 0x0800 +#define I2C_MASTER_FREQ_H 0x0804 +#define I2C_MASTER_CTRL 0x0808 +#define I2C_MASTER_DATA 0x080c +#define I2C_MASTER_CMD 0x0810 /* Write-Only Register */ +#define I2C_MASTER_STATUS 0x0810 /* Read-Only Register */ +#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_14 14 + +#define I2C_MASTER_CH_TOTAL I2C_MASTER_CH_14 + +/* 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] RSVD +[5] MODSEL 5 +[4] RST 4 +[3:1] RSVD +[0] TXDIS 0 +*/ +#define CTRL_MODSEL 5 +#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 + + +/** + * Switchboard CPLD XCVR registers + */ + +/* PORT SEL REGISTER +[7:5] RSVD +[4:0] ID +*/ +#define I2C_XCVR_SEL 0x10 +#define I2C_SEL_ID 0 + +/* PORT CTRL REGISTER +[7:5] RSVD +[4] RST +[3:1] RSVD +[0] TXDIS/MODSEL +*/ +#define I2C_XCVR_CTRL 0x11 +#define I2C_CTRL_RST 4 +#define I2C_CTRL_MODSEL 0 +#define I2C_CTRL_TXDIS 0 + +/* PORT STATUS REGISTER +[7:5] RSVD +[4] PRESENT/ABS +[3:2] RSVD +[1] TXFAULT +[0] RXLOS/INT_N +*/ +#define I2C_XCVR_STAT 0x12 +#define I2C_STAT_PRESENT 4 +#define I2C_STAT_MODABS 4 +#define I2C_STAT_TXFAULT 1 +#define I2C_STAT_INT_N 0 +#define I2C_STAT_RXLOS 0 + +/* PORT INTRPT REGISTER +[7:5] RSVD +[4] PRESENT/ABS +[3:2] RSVD +[1] TXFAULT +[0] RXLOS/INT_N +*/ +#define I2C_XCVR_INRT 0x13 +#define I2C_INTR_PRESENT 4 +#define I2C_INTR_MODABS 4 +#define I2C_INTR_TXFAULT 1 +#define I2C_INTR_INT_N 0 +#define I2C_INTR_RXLOS 0 + +/* PORT INTR MASK REGISTER +[31:6] RSVD +[5] INT_N 5 +[4] PRESENT 4 +[3] RSVD +[2] RSVD +[1] RXLOS_INT 1 +[0] MODABS 0 +*/ +#define I2C_XCVR_MASK 0x14 +#define I2C_MASK_PRESENT 4 +#define I2C_MASK_MODABS 4 +#define I2C_MASK_TXFAULT 1 +#define I2C_MASK_INT_N 0 +#define I2C_MASK_RXLOS 0 + + +/* I2C master clock speed */ +// NOTE: Only I2C clock in normal mode is support here. +enum { + I2C_DIV_100K = 0x71, +}; + +/* I2C Master control register */ +enum { + I2C_CTRL_IEN = 6, + I2C_CTRL_EN +}; + +/* I2C Master command register */ +enum { + I2C_CMD_IACK = 0, + I2C_CMD_ACK = 3, + I2C_CMD_WR, + I2C_CMD_RD, + I2C_CMD_STO, + I2C_CMD_STA, +}; + +/* I2C Master status register */ +enum { + I2C_STAT_IF = 0, + I2C_STAT_TIP, + I2C_STAT_AL = 5, + I2C_STAT_BUSY, + I2C_STAT_RxACK, +}; + +/** + * + * 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_SFP_PORT 0 +#define VIRTUAL_I2C_QSFP_PORT 40 + +#define SFF_PORT_TOTAL VIRTUAL_I2C_QSFP_PORT + VIRTUAL_I2C_SFP_PORT + +#define VIRTUAL_I2C_BUS_OFFSET 10 +#define BB_CPLD_SLAVE_ADDR 0x0d +#define FAN_CPLD_SLAVE_ADDR 0x0d +#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 + +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]; +static int nack_retry[I2C_MASTER_CH_TOTAL]; +static int need_retry[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[] = { + /* SFP and QSFP front panel I2C */ + {I2C_MASTER_CH_11, 0x70, 0, QSFP, "QSFP3"}, {I2C_MASTER_CH_11, 0x70, 1, QSFP, "QSFP4"}, + {I2C_MASTER_CH_11, 0x70, 2, QSFP, "QSFP5"}, {I2C_MASTER_CH_11, 0x70, 3, QSFP, "QSFP6"}, + {I2C_MASTER_CH_11, 0x70, 4, QSFP, "QSFP7"}, {I2C_MASTER_CH_11, 0x70, 5, QSFP, "QSFP8"}, + {I2C_MASTER_CH_11, 0x70, 6, QSFP, "QSFP9"}, {I2C_MASTER_CH_11, 0x70, 7, QSFP, "QSFP10"}, + + {I2C_MASTER_CH_11, 0x71, 0, QSFP, "QSFP11"}, {I2C_MASTER_CH_11, 0x71, 1, QSFP, "QSFP12"}, + {I2C_MASTER_CH_11, 0x71, 2, QSFP, "QSFP13"}, {I2C_MASTER_CH_11, 0x71, 3, QSFP, "QSFP14"}, + {I2C_MASTER_CH_11, 0x71, 4, QSFP, "QSFP15"}, {I2C_MASTER_CH_11, 0x71, 5, QSFP, "QSFP16"}, + {I2C_MASTER_CH_11, 0x71, 6, QSFP, "QSFP17"}, {I2C_MASTER_CH_11, 0x71, 7, QSFP, "QSFP18"}, + + {I2C_MASTER_CH_11, 0x72, 0, QSFP, "QSFP23"}, {I2C_MASTER_CH_11, 0x72, 1, QSFP, "QSFP24"}, + {I2C_MASTER_CH_11, 0x72, 2, QSFP, "QSFP25"}, {I2C_MASTER_CH_11, 0x72, 3, QSFP, "QSFP26"}, + {I2C_MASTER_CH_11, 0x72, 4, QSFP, "QSFP27"}, {I2C_MASTER_CH_11, 0x72, 5, QSFP, "QSFP28"}, + {I2C_MASTER_CH_11, 0x72, 6, QSFP, "QSFP29"}, {I2C_MASTER_CH_11, 0x72, 7, QSFP, "QSFP30"}, + + {I2C_MASTER_CH_11, 0x73, 0, QSFP, "QSFP31"}, {I2C_MASTER_CH_11, 0x73, 1, QSFP, "QSFP32"}, + {I2C_MASTER_CH_11, 0x73, 2, QSFP, "QSFP33"}, {I2C_MASTER_CH_11, 0x73, 3, QSFP, "QSFP34"}, + {I2C_MASTER_CH_11, 0x73, 4, QSFP, "QSFP35"}, {I2C_MASTER_CH_11, 0x73, 5, QSFP, "QSFP36"}, + {I2C_MASTER_CH_11, 0x73, 6, QSFP, "QSFP37"}, {I2C_MASTER_CH_11, 0x73, 7, QSFP, "QSFP38"}, + + {I2C_MASTER_CH_11, 0x74, 0, QSFP, "QSFP1"}, {I2C_MASTER_CH_11, 0x74, 1, QSFP, "QSFP2"}, + {I2C_MASTER_CH_11, 0x74, 2, QSFP, "QSFP19"}, {I2C_MASTER_CH_11, 0x74, 3, QSFP, "QSFP20"}, + {I2C_MASTER_CH_11, 0x74, 4, QSFP, "QSFP21"}, {I2C_MASTER_CH_11, 0x74, 5, QSFP, "QSFP22"}, + {I2C_MASTER_CH_11, 0x74, 6, QSFP, "QSFP39"}, {I2C_MASTER_CH_11, 0x74, 7, QSFP, "QSFP40"}, + + /* Vritual I2C adapters */ + {I2C_MASTER_CH_1, 0xFF, 0, NONE, "I2C_1"}, // FAN + {I2C_MASTER_CH_2, 0xFF, 0, NONE, "I2C_2"}, + {I2C_MASTER_CH_3, 0xFF, 0, NONE, "I2C_3"}, + {I2C_MASTER_CH_4, 0xFF, 0, NONE, "I2C_4"}, + {I2C_MASTER_CH_5, 0xFF, 0, NONE, "I2C_5"}, // BB + {I2C_MASTER_CH_6, 0xFF, 0, NONE, "I2C_6"}, + {I2C_MASTER_CH_7, 0xFF, 0, NONE, "I2C_7"}, // SW + + // NOTE: The bus below are for front panel port debug + {I2C_MASTER_CH_11, 0xFF, 0, NONE, "I2C_11"}, // SFF + +}; + +#define VIRTUAL_I2C_PORT_LENGTH ARRAY_SIZE(fpga_i2c_bus_dev) +#define FAN_I2C_CPLD_INDEX SFF_PORT_TOTAL +#define BB_I2C_CPLD_INDEX SFF_PORT_TOTAL + 4 +#define SW_I2C_CPLD_INDEX SFF_PORT_TOTAL + 6 + +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 fishbone2_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 fishbone2_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; + +/** + * 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; +} + +/* 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 struct attribute *fpga_attrs[] = { + &dev_attr_getreg.attr, + &dev_attr_scratch.attr, + &dev_attr_setreg.attr, + NULL, +}; + +static struct attribute_group fpga_attr_grp = { + .attrs = fpga_attrs, +}; + +/* 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_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_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_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) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_STAT_INT_N) & 1U); +} +DEVICE_ATTR_RO(qsfp_modirq); + +static ssize_t qsfp_modprs_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_STAT_MODABS) & 1U); +} +DEVICE_ATTR_RO(qsfp_modprs); + +static ssize_t sfp_txfault_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_STAT_TXFAULT) & 1U); +} +DEVICE_ATTR_RO(sfp_txfault); + +static ssize_t sfp_rxlos_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_STAT_RXLOS) & 1U); +} +DEVICE_ATTR_RO(sfp_rxlos); + +static ssize_t sfp_modabs_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_STAT_MODABS) & 1U); +} +DEVICE_ATTR_RO(sfp_modabs); + +static ssize_t qsfp_modsel_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_CTRL_MODSEL) & 1U); +} +static ssize_t qsfp_modsel_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + ssize_t status; + long value; + u8 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + + status = kstrtol(buf, 0, &value); + if (status == 0) { + // if value is 0, clear bit. + i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ); + if (!value) + data = data & ~( 1U << I2C_CTRL_MODSEL ); + else + data = data | ( 1U << I2C_CTRL_MODSEL ); + i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_WRITE); + status = size; + } + return status; +} +DEVICE_ATTR_RW(qsfp_modsel); + +static ssize_t qsfp_reset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_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; + u8 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + + status = kstrtol(buf, 0, &value); + if (status == 0) { + // if value is 0, reset signal is low + i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ); + if (!value) + data = data & ~((u8)0x1 << I2C_CTRL_RST); + else + data = data | ((u8)0x1 << I2C_CTRL_RST); + i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_WRITE); + status = size; + } + return status; +} +DEVICE_ATTR_RW(qsfp_reset); + +static ssize_t sfp_txdisable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 data; + int err; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + err = i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ); + if(err < 0){ + return err; + } + return sprintf(buf, "%d\n", (data >> I2C_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; + u8 data; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + + mutex_lock(&fpga_data->fpga_lock); + status = kstrtol(buf, 0, &value); + if (status == 0) { + // check if value is 0 clear + i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ); + if (!value) + data = data & ~((u8)0x1 << I2C_CTRL_TXDIS); + else + data = data | ((u8)0x1 << I2C_CTRL_TXDIS); + i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_WRITE); + 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_modsel.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 green/amber/both/alt-blink/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 ? "amber" : led_color1 == 0x04 ? + "both" : "alt-blink", + led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "amber" : led_color1 == 0x04 ? + "both" : "alt-blink"); +} + +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, "amber")) { + led_color = 0x05; + } else if (sysfs_streq(buf, "both")) { + led_color = 0x04; + } else if (sysfs_streq(buf, "alt-blink")) { + led_color = 0x03; + } 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 * fishbone2_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_core_init(unsigned int master_bus, unsigned int freq_div,void __iomem *pci_bar){ + + unsigned int ctrl; + unsigned int REG_FREQ_L; + unsigned int REG_FREQ_H; + unsigned int REG_CTRL; + unsigned int REG_CMD; + + REG_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20; + REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20; + REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20; + REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20; + + if ( freq_div != I2C_DIV_100K ) { + printk(KERN_ERR "FPGA I2C core: Unsupported clock divider: %x\n", freq_div); + return -EINVAL; + } + + // Makes sure core is disable + ctrl = ioread8(pci_bar + REG_CTRL); + iowrite8( ctrl & ~(1 << I2C_CTRL_EN | 1 << I2C_CTRL_IEN), pci_bar + REG_CTRL); + + iowrite8( freq_div & 0xFF , pci_bar + REG_FREQ_L); + iowrite8( freq_div >> 8, pci_bar + REG_FREQ_H); + + /* Only enable EN bit, we only use polling mode */ + iowrite8(1 << I2C_CMD_IACK, pci_bar + REG_CMD); + iowrite8(1 << I2C_CTRL_EN, pci_bar + REG_CTRL); + + return 0; +} + +static void i2c_core_deinit(unsigned int master_bus,void __iomem *pci_bar){ + + unsigned int REG_CTRL; + REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20; + // Disable core + iowrite8( ioread8(pci_bar + REG_CTRL) & ~(1 << I2C_CTRL_EN| 1 << I2C_CTRL_IEN), pci_bar + REG_CTRL); +} + +//FIXME: The hard code seperater below will causing bug! +//Should pass configuration args into function. +static int i2c_xcvr_access(u8 register_address, unsigned int portid, u8 *data, char rw){ + + u16 dev_addr = 0; + int err; + /* check for portid valid length */ + if(portid < 0 || portid > SFF_PORT_TOTAL){ + return -EINVAL; + } + if (portid <= 16 ){ + dev_addr = CPLD1_SLAVE_ADDR; + }else{ + dev_addr = CPLD2_SLAVE_ADDR; + portid = portid - 16; + } + // Select port + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], dev_addr, 0x00, I2C_SMBUS_WRITE, + I2C_XCVR_SEL, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&portid); + if(err < 0){ + return err; + } + // Read/write port xcvr register + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], dev_addr, 0x00, rw, + register_address , I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)data); + if(err < 0){ + return err; + } + return 0; +} + +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_FREQ_L; + unsigned int REG_FREQ_H; + unsigned int REG_CMD; + unsigned int REG_CTRL; + unsigned int REG_STAT; + unsigned int REG_DATA; + + 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_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20; + REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20; + REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20; + REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20; + REG_STAT = I2C_MASTER_STATUS + (master_bus - 1) * 0x20; + REG_DATA = I2C_MASTER_DATA + (master_bus - 1) * 0x20; + + check(pci_bar + REG_STAT); + check(pci_bar + REG_CTRL); + + /* + * We wait for the data to be transferred (8bit), + * then we start polling on the ACK/NACK bit + * udelay((8 * 1000) / 100); + */ + udelay(80); + dev_dbg(&a->dev,"Wait for 0x%2.2X\n", 1 << I2C_STAT_TIP); + + timeout = jiffies + msecs_to_jiffies(timeout); + while (1) { + Status = ioread8(pci_bar + REG_STAT); + dev_dbg(&a->dev, "ST:%2.2X\n", Status); + + /* Wait for the TIP bit to be cleared before timeout */ + if ( (Status & ( 1 << I2C_STAT_TIP )) == 0 ) { + dev_dbg(&a->dev, " TIP cleared:0x%2.2X\n", Status); + break; + } + + if (time_after(jiffies, timeout)) { + info("Status %2.2X", Status); + info("Error Timeout"); + error = -ETIMEDOUT; + break; + } + + cpu_relax(); + cond_resched(); + } + info("Status %2.2X", Status); + info("STA:%x",Status); + + if (error < 0) { + dev_dbg(&a->dev, "%s TIMEOUT bit 0x%x not clear in specific time\n", + __func__, (1 << I2C_STAT_TIP)); + return error; + } + + /** There is only one master in each bus. If this error happen something is + * not normal in i2c transfer refer to: + * https://www.i2c-bus.org/i2c-primer/analysing-obscure-problems/master-reports-arbitration-lost + */ + // Arbitration lost + if (Status & (1 << I2C_STAT_AL)) { + info("Error arbitration lost"); + nack_retry[master_bus - 1] = 1; + return -EBUSY; + } + + // Ack not received + if (Status & (1 << I2C_STAT_RxACK)) { + info( "SL No ACK"); + if (writing) { + info("Error No ACK"); + nack_retry[master_bus - 1] = 1; + return -EIO; + } + } else { + info( "SL ACK"); + } + + return error; +} + +static int i2c_wait_stop(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_FREQ_L; + unsigned int REG_FREQ_H; + unsigned int REG_CMD; + unsigned int REG_CTRL; + unsigned int REG_STAT; + unsigned int REG_DATA; + + 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_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20; + REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20; + REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20; + REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20; + REG_STAT = I2C_MASTER_STATUS + (master_bus - 1) * 0x20; + REG_DATA = I2C_MASTER_DATA + (master_bus - 1) * 0x20; + + check(pci_bar + REG_STAT); + check(pci_bar + REG_CTRL); + + dev_dbg(&a->dev,"Wait for 0x%2.2X\n", 1 << I2C_STAT_BUSY); + timeout = jiffies + msecs_to_jiffies(timeout); + while (1) { + Status = ioread8(pci_bar + REG_STAT); + dev_dbg(&a->dev, "ST:%2.2X\n", Status); + if (time_after(jiffies, timeout)) { + info("Status %2.2X", Status); + info("Error Timeout"); + error = -ETIMEDOUT; + break; + } + + /* Wait for the BUSY bit to be cleared before timeout */ + if ( (Status & ( 1 << I2C_STAT_BUSY )) == 0 ) { + dev_dbg(&a->dev, " BUSY cleared:0x%2.2X\n", Status); + break; + } + + cpu_relax(); + cond_resched(); + } + info("Status %2.2X", Status); + info("STA:%x",Status); + + if (error < 0) { + dev_dbg(&a->dev, "%s TIMEOUT bit 0x%x not clear in specific time\n", + __func__, (1 << I2C_STAT_BUSY)); + return error; + } + return 0; +} + +/* SMBUS Xfer for opencore I2C with polling */ +// TODO: Change smbus_xfer to master_xfer - This will support i2c and all smbus emu functions. +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; + int error_stop = 0; + + unsigned int REG_FREQ_L; + unsigned int REG_FREQ_H; + unsigned int REG_CMD; + unsigned int REG_CTRL; + unsigned int REG_STAT; + unsigned int REG_DATA; + + REG_FREQ_L = 0; + REG_FREQ_H = 0; + REG_CTRL = 0; + REG_CMD = 0; + REG_STAT = 0; + REG_DATA = 0; + + /* Write the command register */ + dev_data = i2c_get_adapdata(adapter); + portid = dev_data->portid; + pci_bar = fpga_dev.data_base_addr; + +#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" : + size == 8 ? "I2C_BLOCK_DATA" : "ERROR" + , cmd); +#endif + + master_bus = dev_data->pca9548.master_bus; + error = i2c_core_init(master_bus, I2C_DIV_100K, fpga_dev.data_base_addr); + + /* 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: + case I2C_SMBUS_I2C_BLOCK_DATA: + break; + default: + printk(KERN_INFO "Unsupported transaction %d\n", size); + error = -EOPNOTSUPP; + goto Done; + } + + master_bus = dev_data->pca9548.master_bus; + + if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) { + error = -EINVAL; + goto Done; + } + + REG_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20; + REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20; + REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20; + REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20; + REG_STAT = I2C_MASTER_STATUS + (master_bus - 1) * 0x20; + REG_DATA = I2C_MASTER_DATA + (master_bus - 1) * 0x20; + + ////[S][ADDR/R] + 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_DATA); + } else { + // sent device address with Write mode + iowrite8( (addr << 1) & 0xFE, pci_bar + REG_DATA); + } + iowrite8( 1 << I2C_CMD_STA | 1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + + info( "MS Start"); + + //// Wait {A} + // + IACK + error = i2c_wait_ack(adapter, 30, 1); + if (error < 0) { + info( "get error %d", error); + dev_dbg(&adapter->dev,"START Error: %d\n", error); + goto Done; + } + + //// [CMD]{A} + if (size == I2C_SMBUS_BYTE_DATA || + size == I2C_SMBUS_WORD_DATA || + size == I2C_SMBUS_BLOCK_DATA || + size == I2C_SMBUS_I2C_BLOCK_DATA || + (size == I2C_SMBUS_BYTE && rw == I2C_SMBUS_WRITE)) { + + // sent command code to data register + iowrite8(cmd, pci_bar + REG_DATA); + // Start the transfer + iowrite8(1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + info( "MS Send CMD 0x%2.2X", cmd); + + // Wait {A} + // IACK + error = i2c_wait_ack(adapter, 30, 1); + if (error < 0) { + info( "get error %d", error); + dev_dbg(&adapter->dev,"CMD Error: %d\n", 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: + case I2C_SMBUS_I2C_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 block data write + if (size == I2C_SMBUS_BLOCK_DATA && rw == I2C_SMBUS_WRITE) { + + iowrite8(cnt, pci_bar + REG_DATA); + //Start the transfer + iowrite8(1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + info( "MS Send CNT 0x%2.2X", cnt); + + // Wait {A} + // IACK + error = i2c_wait_ack(adapter, 30, 1); + if (error < 0) { + info( "get error %d", error); + dev_dbg(&adapter->dev,"CNT Error: %d\n", 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 || + size == I2C_SMBUS_I2C_BLOCK_DATA + )) { + int bid = 0; + info( "MS prepare to sent [%d bytes]", cnt); + if (size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_I2C_BLOCK_DATA) { + bid = 1; // block[0] is cnt; + cnt += 1; // offset from block[0] + } + for (; bid < cnt; bid++) { + info("STA:%x", ioread8(pci_bar + REG_STAT) ); + info( " Data > %2.2X", data->block[bid]); + iowrite8(data->block[bid], pci_bar + REG_DATA); + iowrite8(1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + + // Wait {A} + // IACK + error = i2c_wait_ack(adapter, 30, 1); + if (error < 0) { + dev_dbg(&adapter->dev,"Send DATA Error: %d\n", error); + goto Done; + } + } + } + + //REPEATE START + if ( rw == I2C_SMBUS_READ && ( + size == I2C_SMBUS_BYTE_DATA || + size == I2C_SMBUS_WORD_DATA || + size == I2C_SMBUS_BLOCK_DATA || + size == I2C_SMBUS_I2C_BLOCK_DATA + )) { + info( "MS Repeated Start"); + + // sent Address with Read mode + iowrite8( addr << 1 | 0x1 , pci_bar + REG_DATA); + // SET START | WRITE + iowrite8( 1 << I2C_CMD_STA | 1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + + // Wait {A} + error = i2c_wait_ack(adapter, 30, 1); + if (error < 0) { + dev_dbg(&adapter->dev,"Repeat START Error: %d\n", error); + 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 || + size == I2C_SMBUS_I2C_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; + case I2C_SMBUS_I2C_BLOCK_DATA: + cnt = data->block[0]; break; + default: + cnt = 0; break; + } + + info( "MS Receive"); + + for (bid = 0; bid < cnt; bid++) { + + // Start receive FSM + if (bid == cnt - 1) { + info( "READ NACK"); + iowrite8(1 << I2C_CMD_RD | 1 << I2C_CMD_ACK | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + }else{ + + iowrite8(1 << I2C_CMD_RD, pci_bar + REG_CMD); + } + + // Wait {A} + error = i2c_wait_ack(adapter, 30, 0); + if(nack_retry[master_bus - 1] == 1) + { + need_retry[master_bus - 1] = 1; + } + if (error < 0) { + dev_dbg(&adapter->dev,"Receive DATA Error: %d\n", error); + goto Done; + } + if(size == I2C_SMBUS_I2C_BLOCK_DATA){ + /* block[0] is read length */ + data->block[bid+1] = ioread8(pci_bar + REG_DATA); + info( "DATA IN [%d] %2.2X", bid+1, data->block[bid+1]); + }else { + data->block[bid] = ioread8(pci_bar + REG_DATA); + info( "DATA IN [%d] %2.2X", bid, data->block[bid]); + } + if (size == I2C_SMBUS_BLOCK_DATA && bid == 0) { + cnt = data->block[0] + 1; + } + } + } + +Done: + info( "MS STOP"); + // SET STOP + iowrite8( 1 << I2C_CMD_STO | 1 << I2C_CMD_IACK, pci_bar + REG_CMD); + // Wait for the STO to finish. + error_stop = i2c_wait_stop(adapter, 30, 0); + if (error_stop < 0) { + dev_dbg(&adapter->dev,"STOP Error: %d\n", error_stop); + } + check(pci_bar + REG_CTRL); + check(pci_bar + REG_STAT); +#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, retval = 0; + struct i2c_dev_data *dev_data; + unsigned char master_bus; + unsigned char switch_addr; + unsigned char channel; + unsigned char *calling_name; + uint16_t prev_port = 0; + unsigned char prev_switch; + unsigned char prev_ch; + uint8_t read_channel; + int retry = 0; + + 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; + calling_name = dev_data->pca9548.calling_name; + + // 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 + // Only select new channel of a switch if they are difference from last channel of a switch + 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", prev_ch, prev_switch, 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", prev_ch, prev_switch, 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 + nack_retry[master_bus - 1] = 0; + need_retry[master_bus - 1] = 0; + error = smbus_access(adapter, addr, flags, rw, cmd, size, data); + if((nack_retry[master_bus - 1]==1)&&(need_retry[master_bus - 1]==1)) + retry = 2000; + else + retry = 5; + // If the first access failed, do retry. + while((nack_retry[master_bus - 1]==1)&&retry) + { + retry--; + nack_retry[master_bus - 1] = 0; + dev_dbg(&adapter->dev,"error = %d\n",error); + error = smbus_access(adapter, addr, flags, rw, cmd, size, data); + dev_dbg(&adapter->dev,"nack retry = %d\n",retry); + } + nack_retry[master_bus - 1] = 0; + need_retry[master_bus - 1] = 0; + + retval = error; + + 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); + }else{ + goto release_unlock; + } + + /** For the bus with PCA9548, try to read PCA9548 one more time. + * For the bus w/o PCA9548 just check the return from last time. + */ + if (switch_addr != 0xFF) { + error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE, (union i2c_smbus_data*)&read_channel); + dev_dbg(&adapter->dev,"Try access I2C switch device at %2.2x\n", switch_addr); + if(error < 0){ + dev_dbg(&adapter->dev,"Unbale to access switch device.\n"); + }else{ + dev_dbg(&adapter->dev,"Read success, register val %2.2x\n", read_channel); + } + } + + // If retry was used up(retry = 0) and the last transfer result is -EBUSY + if(retry <= 0 && error == -EBUSY ){ + retval = error; + // raise device error message + dev_err(&adapter->dev, "I2C bus hangup detected on %s port.\n", calling_name); + + /** + * Fishbone2: Device specific I2C reset topology + */ + if( master_bus == I2C_MASTER_CH_11 ){ + dev_notice(&adapter->dev, "Trying bus recovery...\n"); + dev_notice(&adapter->dev, "Reset I2C switch device.\n"); + + // reset PCA9548 on the current BUS. + iowrite8( ioread8(fpga_dev.data_base_addr + 0x0108) & 0xF0, fpga_dev.data_base_addr + 0x0108); + udelay(1); + iowrite8( ioread8(fpga_dev.data_base_addr + 0x0108) | 0x0F, fpga_dev.data_base_addr + 0x0108); + // clear the last access port + fpga_i2c_lasted_access_port[master_bus - 1] = 0; + }else{ + dev_crit(&adapter->dev, "I2C bus unrecoverable.\n"); + } + } + + +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 retval; +} + +/** + * 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| + I2C_FUNC_SMBUS_I2C_BLOCK; +} + +static const struct i2c_algorithm fishbone2_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 * fishbone2_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; + + 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 = &fishbone2_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_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; +}; + +// I/O resource need. +static struct resource fishbone2_resources[] = { + { + .start = 0x10000000, + .end = 0x10001000, + .flags = IORESOURCE_MEM, + }, +}; + +static void fishbone2_dev_release( struct device * dev) +{ + return; +} + +static struct platform_device fishbone2_dev = { + .name = DRIVER_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(fishbone2_resources), + .resource = fishbone2_resources, + .dev = { + .release = fishbone2_dev_release, + } +}; + +/** + * Board info for QSFP/SFP+ eeprom. + * Note: Using OOM optoe as transceiver 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 fishbone2_drv_probe(struct platform_device *pdev) +{ + struct resource *res; + 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 fishbone2_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]); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(!res)) { + printk(KERN_ERR "Specified Resource Not Available...\n"); + kzfree(fpga_data); + return -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 = I2C_MASTER_CH_1; portid_count <= I2C_MASTER_CH_TOTAL; portid_count++){ + if(!allow_unsafe_i2c_access){ + if( portid_count < I2C_MASTER_CH_7 || + portid_count == I2C_MASTER_CH_9 || portid_count == I2C_MASTER_CH_10 ) + continue; + } + ret = i2c_core_init(portid_count, I2C_DIV_100K, fpga_dev.data_base_addr); + if (ret < 0) { + dev_err(&pdev->dev, "Unable to init I2C core %d\n", portid_count); + 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++) { + if(!allow_unsafe_i2c_access){ + if( portid_count >= FAN_I2C_CPLD_INDEX && portid_count < SW_I2C_CPLD_INDEX ){ + fpga_data->i2c_adapter[portid_count] = NULL; + continue; + } + } + fpga_data->i2c_adapter[portid_count] = fishbone2_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] = fishbone2_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"); + } + } + + printk(KERN_INFO "Virtual I2C buses created\n"); + +#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++) { + + if(!allow_unsafe_i2c_access){ + if( portid_count >= FAN_I2C_CPLD_INDEX && portid_count < SW_I2C_CPLD_INDEX ){ + continue; + } + } + + 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 fishbone2_drv_remove(struct platform_device *pdev) +{ + int portid_count; + struct sff_device_data *rem_data; + struct i2c_dev_data *adap_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]); + adap_data = i2c_get_adapdata(fpga_data->i2c_adapter[portid_count]); + i2c_del_adapter(fpga_data->i2c_adapter[portid_count]); + } + } + + for (portid_count = I2C_MASTER_CH_1; portid_count <= I2C_MASTER_CH_TOTAL; portid_count++){ + if(!allow_unsafe_i2c_access){ + if( portid_count < I2C_MASTER_CH_7 || + portid_count == I2C_MASTER_CH_9 || portid_count == I2C_MASTER_CH_10 ) + continue; + } + i2c_core_deinit(portid_count, fpga_dev.data_base_addr); + } + + 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; +} + +static struct platform_driver fishbone2_drv = { + .probe = fishbone2_drv_probe, + .remove = __exit_p(fishbone2_drv_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + +#ifdef TEST_MODE +#define FPGA_PCI_BAR_NUM 2 +#else +#define FPGA_PCI_BAR_NUM 0 +#endif + + + +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 = ioremap_nocache(fpga_dev.data_mmio_start, fpga_dev.data_mmio_len); + 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(&fishbone2_dev); + platform_driver_register(&fishbone2_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(&fishbone2_drv); + platform_device_unregister(&fishbone2_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 fishbone2_init(void) +{ + int rc; + rc = pci_register_driver(&pci_dev_ops); + if (rc) + return rc; + return 0; +} + +void fishbone2_exit(void) +{ + pci_unregister_driver(&pci_dev_ops); +} + +module_init(fishbone2_init); +module_exit(fishbone2_exit); + +module_param(allow_unsafe_i2c_access, bool, 0400); +MODULE_PARM_DESC(allow_unsafe_i2c_access, "enable i2c busses despite potential races against BMC bus access"); + +MODULE_AUTHOR("Pradchaya P. "); +MODULE_DESCRIPTION("Celestica Fishbone2 switchboard platform driver"); +MODULE_VERSION(MOD_VERSION); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-cel/shamu/scripts/platform_sensors.py new file mode 100755 index 000000000000..186ee6c5450e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/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/shamu/scripts/sensors b/platform/broadcom/sonic-platform-modules-cel/shamu/scripts/sensors new file mode 100755 index 000000000000..405d92c2b3cc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/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 "$@" diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/setup.py b/platform/broadcom/sonic-platform-modules-cel/shamu/setup.py new file mode 100644 index 000000000000..20a2b6d1063a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/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', +) diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/PKG-INFO b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/PKG-INFO new file mode 100644 index 000000000000..48ce1ea303bb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/PKG-INFO @@ -0,0 +1,23 @@ +Metadata-Version: 1.2 +Name: sonic-platform +Version: 1.0 +Summary: SONiC platform API implementation on Celestica Platforms +Home-page: https://github.com/Azure/sonic-buildimage +Author: SONiC Team +Author-email: linuxnetdev@microsoft.com +Maintainer: Wirut Getbamrung +Maintainer-email: wgetbumr@celestica.com +License: Apache 2.0 +Description: UNKNOWN +Keywords: sonic SONiC platform PLATFORM +Platform: UNKNOWN +Classifier: Development Status :: 3 - Alpha +Classifier: Environment :: Plugins +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: Information Technology +Classifier: Intended Audience :: System Administrators +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Natural Language :: English +Classifier: Operating System :: POSIX :: Linux +Classifier: Programming Language :: Python :: 2.7 +Classifier: Topic :: Utilities diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/SOURCES.txt b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/SOURCES.txt new file mode 100644 index 000000000000..f14add75ab6f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/SOURCES.txt @@ -0,0 +1,11 @@ +setup.py +../../../../device/celestica/x86_64-cel_silverstone-r0/sonic_platform/__init__.py +../../../../device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py +../../../../device/celestica/x86_64-cel_silverstone-r0/sonic_platform/eeprom.py +../../../../device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py +../../../../device/celestica/x86_64-cel_silverstone-r0/sonic_platform/helper.py +../../../../device/celestica/x86_64-cel_silverstone-r0/sonic_platform/platform.py +sonic_platform.egg-info/PKG-INFO +sonic_platform.egg-info/SOURCES.txt +sonic_platform.egg-info/dependency_links.txt +sonic_platform.egg-info/top_level.txt \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/dependency_links.txt b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/dependency_links.txt new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/top_level.txt b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/top_level.txt new file mode 100644 index 000000000000..82b4b6958796 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/top_level.txt @@ -0,0 +1 @@ +sonic_platform diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/systemd/platform-modules-shamu.service b/platform/broadcom/sonic-platform-modules-cel/shamu/systemd/platform-modules-shamu.service new file mode 100644 index 000000000000..236eba0bd5ec --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/shamu/systemd/platform-modules-shamu.service @@ -0,0 +1,14 @@ + +[Unit] +Description=Celestica shamu platform modules +After=local-fs.target +Before=pmon.service + +[Service] +Type=oneshot +ExecStart=-/etc/init.d/platform-modules-shamu start +ExecStop=-/etc/init.d/platform-modules-shamu stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.py b/platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.py new file mode 100644 index 000000000000..e22d96326b76 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python + +############################################################################# +# # +# Service to control CPU watchdog # +# # +############################################################################# + +import os +import time +import logging +import logging.handlers +import requests +import argparse +import subprocess + +HEARTBEAT_TIME = 20 +MAX_FILE_COUNT = 3 +WDT_TIMEOUT = 60 +MAX_LOG_BYTES = 20 * 1000000 +HOSTNAME = "240.1.1.1" +WDT_URL = "http://240.1.1.1:8080/api/sys/watchdog" +BMC_WDT_LOG = '/var/log/bmc_feed_watchdog.log' + + +lh = logging.handlers.RotatingFileHandler( + filename=BMC_WDT_LOG, maxBytes=MAX_LOG_BYTES, backupCount=MAX_FILE_COUNT) +formatter = logging.Formatter( + fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%b %d %H:%M:%S') +lh.setFormatter(formatter) +logger = logging.getLogger('bmc_feed_watchdog') +logger.addHandler(lh) +logger.setLevel(logging.INFO) + + +def set_wdt_timeout(timeout): + data = dict() + data["wdt"] = str(timeout) + status_code = -1 + message = None + try: + res = requests.post(WDT_URL, json=data, timeout=5) + status_code = res.status_code + message = res.json().get('result') + except: + message = "Unable set watchdog timeout" + + return status_code, message + + +def ping(): + try: + response = subprocess.check_output( + ['ping', '-c', '3', HOSTNAME], + stderr=subprocess.STDOUT, + universal_newlines=True + ) + except subprocess.CalledProcessError: + response = None + return response != None + + +def start(): + logger.info("Started CPU watchdog") + error_flag = 1 + status_code = -1 + while True: + status_code, message = set_wdt_timeout(WDT_TIMEOUT) + + # Error checking + if status_code == 200 and message != 'success': + logger.error(message) + error_flag = 1 + elif status_code != 200 and not ping(): + logger.error("Unable to connect to BMC") + error_flag = 1 + elif status_code != 200 and ping(): + if not error_flag: + logger.error(message) + time.sleep(1) + error_flag = 1 + continue + + # Pass error + if error_flag and status_code == 200 and message == 'success': + error_flag = 0 + logger.info("BMC connection successful") + + time.sleep(HEARTBEAT_TIME) + + +def stop(): + logger.info("Stopping CPU watchdog") + status_code = -1 + while status_code != 200: + status_code, message = set_wdt_timeout(0) + if status_code == 200 and message != 'success': + logger.error(message) + elif status_code != 200 and not ping(): + logger.error("Unable to connect to BMC") + elif ping(): + time.sleep(1) + continue + + logger.info("Stopped CPU watchdog") + + +def main(): + parser = argparse.ArgumentParser(description='') + parser.add_argument('option', choices=["start", "stop"]) + args = parser.parse_args() + if args.option == "start": + start() + stop() + + +if __name__ == "__main__": + main() diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.service b/platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.service new file mode 100755 index 000000000000..88c3b5ceb44b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.service @@ -0,0 +1,10 @@ +[Unit] +Description=Service for enable BMC watchdog. +After=bmc_vlan.service + +[Service] +ExecStart=/usr/bin/python /usr/local/etc/bmc_wdt.py start +ExecStop=/usr/bin/python /usr/local/etc/bmc_wdt.py stop + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmc-exec b/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmc-exec new file mode 100755 index 000000000000..14435e857ff9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmc-exec @@ -0,0 +1,45 @@ +#!/bin/bash +# +# Copyright 2019-present Celestica. All Rights Reserved. +# +# This program file 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. +# +# + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin + +command="$@" + +usage() { + echo "Usage: bmc-exec " + echo +} + +run_cmd() { + echo "Run command: "$command + echo + ret=$(curl -m 5 --silent --header "Content-Type:application/json" -d "{\"data\": \"${command}\"}" http://240.1.1.1:8080/api/sys/raw) + if [ -z "$ret" ]; + then + echo "Failed to connect on BMC" + else + echo $ret | python -c "import sys, json; k = json.load(sys.stdin)['result']; print k if type(k) is not list else '\n'.join(k);" + fi + return 0 +} + +if [ $# -lt 1 ]; then + usage + exit -1 +else + run_cmd +fi + +exit $? diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcpwd b/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcpwd new file mode 100644 index 000000000000..3e24c6b13536 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcpwd @@ -0,0 +1 @@ +kt3I0K_QxQ== \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcutil.py b/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcutil.py new file mode 100644 index 000000000000..7edc55ac8862 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcutil.py @@ -0,0 +1,296 @@ +#!/usr/bin/python + +""" +bmcutil.py +BMC utility, implements management functions provided by BMC RESTful APIs. +""" + +import requests +import re +import hashlib +import binascii +import os +import base64 + + +# Base class of BmcUtil +class BmcUtilBase(object): + def __init__(self): + self.bmc_info_url = "http://240.1.1.1:8080/api/sys/bmc" + self.bmc_eth_info_url = "http://240.1.1.1:8080/api/sys/eth" + self.bmc_raw_command_url = "http://240.1.1.1:8080/api/sys/raw" + self.bmc_pwd_url = "http://240.1.1.1:8080/api/sys/userpassword" + self.bmc_pwd_path = "/usr/local/etc/bmcpwd" + self.bmc_syslog_url = "http://240.1.1.1:8080/api/sys/syslog" + + def request_data(self, url): + # Reqest data from BMC if not exist. + data_req = requests.get(url) + data_json = data_req.json() + data_list = data_json.get('Information') + return data_list + + def save_bmc_password(self, clear_pwd): + enc = [] + key = "bmc" + for i in range(len(clear_pwd)): + key_c = key[i % len(key)] + enc_c = chr((ord(clear_pwd[i]) + ord(key_c)) % 256) + enc.append(enc_c) + enc_pwd = base64.urlsafe_b64encode("".join(enc)) + + with open(self.bmc_pwd_path, 'w') as file: + file.write(enc_pwd) + + def get_bmc_pass(self): + with open(self.bmc_pwd_path) as file: + data = file.read() + + key = "bmc" + dec = [] + enc = base64.urlsafe_b64decode(data) + for i in range(len(enc)): + key_c = key[i % len(key)] + dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256) + dec.append(dec_c) + return "".join(dec) + + def version(self): + """ + Return version information string + @return version string of BMC OS + """ + bmc_version = None + + bmc_version_key = "OpenBMC Version" + bmc_info = self.request_data(self.bmc_info_url) + bmc_version = bmc_info.get(bmc_version_key) + + return str(bmc_version) + + def set_eth0_addr(self, ip_addr, mask): + """ + Set eth0 IPv4 address + @ip_addr MANDATORY, IPv4 ip address string + @mask MANDATORY, IPv4 network mask string + """ + + json_data = dict() + json_data["data"] = "ifconfig eth0 %s netmask %s up" % (ip_addr, mask) + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + return False + return True + + def get_eth0_addr_list(self): + """ + Get eth0 IPv4 address + @return a list of (IPv4 ip address/mask string) + """ + ipv4_adress = [] + eth_data_list = self.request_data(self.bmc_eth_info_url) + + for eth_data in eth_data_list: + if 'inet addr' in eth_data: + ipv4_list = re.findall(r'[0-9]+(?:\.[0-9]+){3}', eth_data) + if len(ipv4_list) == 3: + ipv4 = ipv4_list[0] + "/" + ipv4_list[2] + ipv4_adress.append(ipv4) + + return str(ipv4_adress) + + def set_gateway_ip(self, gw_ip): + """ + Set gateway IPv4 address string + @gw_ip MANATORY, IPv4 address of gateway + """ + + json_data = dict() + json_data["data"] = "route del default" + + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + return False + + json_data["data"] = "route add default gw %s" % gw_ip + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + return False + + return True + + def get_gateway_ip(self): + """ + Get gateway IPv4 address string + @return IPv4 address of gateway + """ + + default_gw = None + + json_data = dict() + json_data["data"] = "route" + + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code == 200: + data_list = r.json().get('result') + for raw_data in data_list: + if 'default' in raw_data: + route_data = raw_data.split() + default_gw = route_data[1] if len(route_data) > 0 else None + + return str(default_gw) + + def set_user_and_passwd(self, user_name, password): + """ + Set BMC user name and password + @user_name MANDATORY, BMC user + @password MANDATORY, BMC user's password + """ + json_data = dict() + json_data["user"] = str(user_name) + json_data["oldpassword"] = self.get_bmc_pass() + json_data["newpassword"] = password + r = requests.post(self.bmc_pwd_url, json=json_data) + return_data = r.json() + + if r.status_code != 200 or 'success' not in return_data.get('result'): + return False + + self.save_bmc_password(password) + return True + + def add_syslog_server(self, svr_ip, svr_port): + """ + Add syslog server for BMC + @svr_ip MANDATORY, syslog server IP string + @svr_port MANDATORY, syslog server destination port + """ + json_data = dict() + json_data["addr"] = str(svr_ip) + json_data["port"] = str(svr_port) + r = requests.post(self.bmc_syslog_url, json=json_data) + if r.status_code != 200 or 'success' not in r.json().get('result'): + return False + return True + + def get_syslog_server_list(self): + """ + # Get syslog server list of BMC + # @return a list of syslog server ip and destination port pair + """ + syslog_ip = None + syslog_port = None + + json_data = dict() + json_data["data"] = "tail -n 1 /etc/rsyslog.conf" + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + return False + + return_data = r.json() + result = return_data.get("result") + ip = re.findall(r'[0-9]+(?:\.[0-9]+){3}', result[0]) + port = str(result[0]).split(":") + syslog_ip = ip[0] if len(ip) > 0 else None + syslog_port = port[1] if len(port) > 1 else None + + return [syslog_ip, syslog_port] + + def del_syslog_server(self, svr_ip, svr_port): + """ + Delete syslog server for BMC + @svr_ip MANDATORY, syslog server IP string + @svr_port MANDATORY, syslog server destination port + """ + json_data = dict() + json_data["addr"] = "127.0.0.1" + json_data["port"] = str(svr_port) + r = requests.post(self.bmc_syslog_url, json=json_data) + if r.status_code != 200 or 'success' not in r.json().get('result'): + return False + return True + + def get_bmc_system_state(self): + """ + Get BMC system state, includes CPU, memory, storage + MUST contains status of: CPU, memory, disk + dict object: + { + "CPU": { + "StateOutputs": "output of command 'top -bn 1'" + "Usage": "10.0" + }, + "MEMORY": { + "StateOutputs": "output of command 'free -m'" + "Usage": "15.0" # caculate: "free -t | grep \"buffers/cache\" | awk '{ printf \"mem usage : %.1f%%\\n\",$3/($3+$4) * 100}'" + }, + "DISK": { + "StateOutput": "output of command 'df -h'" + "Usage": "12.5" + } + } + """ + + state_data = dict() + bmc_info = self.request_data(self.bmc_info_url) + + cpu_key = "CPU Usage" + cpu_data_raw = bmc_info.get(cpu_key) + cpu_usage = cpu_data_raw.split()[1].strip('%') + cpu_data = dict() + cpu_data["StateOutputs"] = "output of command 'top -bn 1'" + cpu_data["Usage"] = "{:.1f}".format(float(cpu_usage)) + state_data["CPU"] = cpu_data + + disk_key = "Disk Usage" + disk_data_raw = bmc_info.get(disk_key) + disk_usage = disk_data_raw.split()[7].strip('%') + disk_data = dict() + disk_data["StateOutputs"] = "output of command 'df -h'" + disk_data["Usage"] = "{:.1f}".format(float(disk_usage)) + state_data["DISK"] = disk_data + + json_data = dict() + json_data["data"] = "free -t" + mem_usage = "None" + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code == 200: + mem_data_raw = r.json().get('result')[2] + mem_u = float(mem_data_raw.split()[2]) + mem_f = float(mem_data_raw.split()[3]) + mem_usage = (mem_u/(mem_u+mem_f)) * 100 + mem_data = dict() + mem_data["StateOutputs"] = "output of command 'free -t'" + mem_data["Usage"] = "{:.1f}".format(mem_usage) + state_data["MEMORY"] = mem_data + + return state_data + + def reboot_bmc(self): + """ + Reboot BMC + """ + json_data = dict() + json_data["data"] = "reboot" + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + return False + + return True + + def set_location_led(self, admin_state): + """ + Enable/disable location LED + @admin_state MANDATORY, should be string "on" or "off" + """ + + json_data = dict() + if str(admin_state).lower() not in ["on", "off"]: + return False + + json_data["data"] = "led_location.sh %s" % admin_state + r = requests.post(self.bmc_raw_command_url, json=json_data) + if r.status_code != 200: + return False + + return True diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/fpga_prog/fpga_prog b/platform/broadcom/sonic-platform-modules-cel/tools/fpga_prog/fpga_prog new file mode 100755 index 0000000000000000000000000000000000000000..edf7916e58b7ca3190da18c0b24a3d1f73a81455 GIT binary patch literal 13768 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 literal 0 HcmV?d00001 diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/fpga_prog/fpga_prog.c b/platform/broadcom/sonic-platform-modules-cel/tools/fpga_prog/fpga_prog.c new file mode 100644 index 000000000000..c640c8ad0064 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/fpga_prog/fpga_prog.c @@ -0,0 +1,282 @@ +/******************************************************************** +Author: Sittisak Sinprem + flash_spi_fpga + + user-space appliction to flash SPI FLASH + + As a "root" previledge, this program can run well + while other user group would report system errors under Linux OS. + +*********************************************************************/ + +#include +#include +#include +#include //for open() +#include //for close() +#include +#include + +/** + * The FPGA SPI Flash update application + * This application read the binary image file and program + * into flash memory. The erasing time can be long the + * the WAIT_WRITE_READY_SEC should be more than 30 seconds. + */ + +#define WAIT_WRITE_READY_SEC 180 +#define WAIT_WRITE_CONTINUE_CYCLE 100000 + +#define REG_SPI_WR_EN 0x1200 +#define REG_SPI_WR_DAT 0x1204 +#define REG_SPI_CHK_ID 0x1208 +#define REG_SPI_VERIFY 0x120C +#define REG_SPI_STAT 0x1210 +#define REG_SPI_RESET 0x1214 + +#define SPI_STAT_MARK_READY (1 << 15) +#define SPI_STAT_MARK_DONE (1 << 14) +#define SPI_STAT_MARK_ERROR_ANY (1 << 13) +#define SPI_STAT_MARK_ERROR_CHKID (1 << 12) +#define SPI_STAT_MARK_ERROR_ERASE (1 << 11) +#define SPI_STAT_MARK_ERROR_PROG (1 << 10) +#define SPI_STAT_MARK_ERROR_TOUT (1 << 9) +#define SPI_STAT_MARK_ERROR_CRC (1 << 8) +#define SPI_STAT_MARK_STG_STARTED (1 << 7) +#define SPI_STAT_MARK_STG_INITED (1 << 6) +#define SPI_STAT_MARK_STG_CHECKED_ID (1 << 5) +#define SPI_STAT_MARK_STG_ERSD_SW (1 << 4) +#define SPI_STAT_MARK_STG_UP_ERSD_IMG (1 << 3) +#define SPI_STAT_MARK_STG_UP_PRG_IMG (1 << 2) +#define SPI_STAT_MARK_STG_VERIFIED (1 << 1) +#define SPI_STAT_MARK_STG_PRG_CMPT (1 << 0) + +#define debug(fmt,args...) printf("debug : "fmt"\n",##args) +#define reg_write(reg,value) func_write(reg,value) +#define reg_read(reg,value) value = func_read(reg) + +#define DEV_CHAR_FILENAME "/dev/fwupgrade" + +struct fpga_reg_data { + uint32_t reg; + uint32_t value; +}; + +enum{ + READREG, + WRITEREG +}; + +unsigned int func_write(int addr,unsigned long value){ + int fd; + int ret; + struct fpga_reg_data fpga_reg; + + fd = open(DEV_CHAR_FILENAME, O_RDWR); + + fpga_reg.reg = addr; + fpga_reg.value = value; + + ioctl(fd, WRITEREG, (void *)&fpga_reg); + + close(fd); + return 0; +} + +unsigned int func_read(int addr){ + int fd; + int ret; + + struct fpga_reg_data fpga_reg; + + fd = open(DEV_CHAR_FILENAME, O_RDWR); + + fpga_reg.reg = addr; + + ioctl(fd, READREG, (void *)&fpga_reg); + + close(fd); + return fpga_reg.value; +} + +void dump_status(int Stat){ + debug("#########################"); + debug("%d ready(1)/busy(0)", (Stat&SPI_STAT_MARK_READY)!=0); + debug("%d done", (Stat&SPI_STAT_MARK_DONE)!=0); + debug("%d error any", (Stat&SPI_STAT_MARK_ERROR_ANY)!=0); + debug("%d error checkId", (Stat&SPI_STAT_MARK_ERROR_CHKID)!=0); + debug("%d error erase", (Stat&SPI_STAT_MARK_ERROR_ERASE)!=0); + debug("%d error program", (Stat&SPI_STAT_MARK_ERROR_PROG)!=0); + debug("%d error timeout", (Stat&SPI_STAT_MARK_ERROR_TOUT)!=0); + debug("%d error crc", (Stat&SPI_STAT_MARK_ERROR_CRC)!=0); + debug("%d stage started", (Stat&SPI_STAT_MARK_STG_STARTED)!=0); + debug("%d stage inited", (Stat&SPI_STAT_MARK_STG_INITED)!=0); + debug("%d stage checked id", (Stat&SPI_STAT_MARK_STG_CHECKED_ID)!=0); + debug("%d stage erasred", (Stat&SPI_STAT_MARK_STG_ERSD_SW)!=0); + debug("%d stage upload erase img", (Stat&SPI_STAT_MARK_STG_UP_ERSD_IMG)!=0); + debug("%d stage upload program img",(Stat&SPI_STAT_MARK_STG_UP_PRG_IMG)!=0); + debug("%d stage verified", (Stat&SPI_STAT_MARK_STG_VERIFIED)!=0); + debug("%d stage completed", (Stat&SPI_STAT_MARK_STG_PRG_CMPT)!=0); +} + +int flash_program(char *data,int lens){ + int ctimeout; + int error =0; + unsigned long Stat = 0; + + reg_read(REG_SPI_RESET,Stat); + printf("Read Reset is %x\n",Stat); + printf("Reset Module \n"); + reg_write(REG_SPI_RESET,0x1); // reset + sleep(1); + reg_write(REG_SPI_RESET,0x0); // normal mode + ctimeout=0; + do{ // wait for done flag + reg_read(REG_SPI_STAT,Stat); + if(Stat & SPI_STAT_MARK_ERROR_ANY){ + dump_status(Stat); + error = Stat; + break; + } + if(ctimeout++ > WAIT_WRITE_READY_SEC){ + error = Stat| SPI_STAT_MARK_ERROR_TOUT; + debug("wait ready timeout . . ."); + break; + } + printf(" waiting status to ready ... %d s. status = %x\n",ctimeout,Stat); + sleep(1); + }while((Stat & 0x80F8) != 0x80F8); + if(error){ + return -1; + } + printf("Ready\n"); + + + for(int i=0;i WAIT_WRITE_CONTINUE_CYCLE){ + error = Stat| SPI_STAT_MARK_ERROR_TOUT; + debug("wait ready timeout . . ."); + break; + } + }while((Stat & 0x80F8) != 0x80F8); + + if(error){ + printf("FPGA programing fail at %d/%d\n",i,lens); + debug("Status = %4.4X",error); + break; + } + + i +=4; + + if(i%(lens/40*4)==0){ + printf("FPGA programing . . . %d/%d\n",i,lens); + } + } + + dump_status(Stat); + printf("Status = %4.4X\n",Stat); + + reg_write(REG_SPI_WR_EN,0x0); // write protect + reg_write(REG_SPI_RESET,0x1); // module reset + + return error; +} + +int main(int argc,char **argv){ + FILE *pFILE; + int filesize; + char *filename; + char *fpga_buff; + int status; + int max_size = 128; + int current_size = max_size; + int i = 0; + int c = EOF; + + printf(" FPGA PROGRAMMNG version 0.1.1 \n"); + printf(" build date : %s %s\n",__DATE__,__TIME__); + + filename = NULL; + filename = malloc(max_size); + if(!filename){ + exit(-12); /* Out of memory */ + } + + if(argc<2){ + printf("please enter filename : "); + while((c = getchar()) != '\n' && c != EOF ){ + + filename[i++] = (char)c; + if(i == current_size){ + current_size += max_size; + filename = realloc(filename, current_size); + } + } + filename[i] = '\0'; + }else{ + i = strlen(argv[1]) + 1; + filename = realloc(filename, i); + strcpy(filename, argv[1]); + } + + pFILE = fopen(filename,"rb"); + free(filename); + if (pFILE == NULL) + { + printf("Could not open the file %s, exit\n",filename); + return -5; + } + + fseek(pFILE , 0 , SEEK_END); + filesize = ftell (pFILE); + rewind(pFILE); + fpga_buff = malloc(filesize); + if(fpga_buff==NULL){ + printf("Can't Allocate memory \n"); + return -5; + } + + fread(fpga_buff,1,filesize,pFILE); + fclose(pFILE); + + printf(" Start FPGA Flash ... \n"); + + status = flash_program(fpga_buff,filesize); + + if(status == 0){ + printf(" Programing finish \n"); + }else{ + printf(" Program Error : error code %4.4x \n",status); + } + + return status; +} diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/Makefile b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/Makefile new file mode 100644 index 000000000000..022bcc566c6d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/Makefile @@ -0,0 +1,25 @@ +CC = gcc +AR = ar +CFLAGS = -Wall -W -Wunused -lpthread -g -O2 -ggdb +#LFLAGS = -lm -pthread -DVME_DEBUG +LFLAGS = -lm -pthread +DEL_FILE = rm -f +MV_FILE = mv -f +OBJ_FILE_NODE = ./*.o +#VPATH = +INCPATH = -I../include/ +TARGET = ispvm + +OBJECTS += hardware.o ispvm_ui.o ivm_core.o + + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< +$(TARGET):$(OBJECTS) + $(CC) $(LFLAGS) -o $(TARGET) $(OBJECTS) + +clean: + -$(DEL_FILE) $(TARGET) + -$(DEL_FILE) $(OBJ_FILE_NODE) + + diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/hardware.c b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/hardware.c new file mode 100644 index 000000000000..7a4d5f5456d3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/hardware.c @@ -0,0 +1,409 @@ +/********************************************************************************* +* Lattice Semiconductor Corp. Copyright 2000-2008 +* +* This is the hardware.c of ispVME V12.1 for JTAG programmable devices. +* All the functions requiring customization are organized into this file for +* the convinience of porting. +*********************************************************************************/ +/********************************************************************************* + * Revision History: + * + * 09/11/07 NN Type cast mismatch variables + * 09/24/07 NN Added calibration function. + * Calibration will help to determine the system clock frequency + * and the count value for one micro-second delay of the target + * specific hardware. + * Modified the ispVMDelay function + * Removed Delay Percent support + * Moved the sclock() function from ivm_core.c to hardware.c + *********************************************************************************/ +#include "vmopcode.h" +#include +#include +#include //for open() +#include //for close() +#include +#include +#include + +/******************************************************************************** +* Declaration of global variables +* +*********************************************************************************/ +static int devmem_c2, devmem_c5; +static void *portC2, *portC5; + +/** + * NOTE: Using only core GPIO here + * FIXME: This should move to config section and support both CORE and SUS region. + */ + +// unsigned long g_siIspPins = 0x00000000; /*Keeper of JTAG pin state*/ +unsigned short g_usCpu_Frequency = CPU_FREQ_MH_CONFIG; /*Enter your CPU frequency here, unit in MHz.*/ + +/********************************************************************************* +* This is the definition of the bit locations of each respective +* signal in the global variable g_siIspPins. +* +* NOTE: Users must add their own implementation here to define +* the bit location of the signal to target their hardware. +* The example below is for the Lattice download cable on +* on the parallel port. +* +*********************************************************************************/ + + +unsigned long g_ucPinTDI = GPIO_TDI_CONFIG; /* Pin nummber of TDI */ +unsigned long g_ucPinTCK = GPIO_TCK_CONFIG; /* Pin nummber of TCK */ +unsigned long g_ucPinTMS = GPIO_TMS_CONFIG; /* Pin nummber of TMS */ +unsigned long g_ucPinENABLE = GPIO_ENABLE_CONFIG; /* Pin nummber of ENABLE */ +unsigned long g_ucPinTRST = GPIO_TRST_CONFIG; /* Pin nummber of TRST */ +unsigned long g_ucPinTDO = GPIO_TDO_CONFIG; /* Pin nummber of TDO */ +unsigned long g_ucInPort = GP_LVL; /* All TCI,TDO,TMS,TCK are on same register */ +unsigned long g_ucOutPort = GP_LVL; /* All TCI,TDO,TMS,TCK are on same register */ + +/* For Denverton CPU */ +// const unsigned long g_ucPinTDI = DNV_GPIO_TDI_CONFIG; +// const unsigned long g_ucPinTCK = DNV_GPIO_TCK_CONFIG; +// const unsigned long g_ucPinTMS = DNV_GPIO_TMS_CONFIG; +// const unsigned long g_ucPinTDO = DNV_GPIO_TDO_CONFIG; + +/*************************************************************** +* +* Functions declared in hardware.c module. +* +***************************************************************/ +void writePort( unsigned long a_ucPins, unsigned char a_ucValue ); +unsigned char readPort(); +void sclock(); +void ispVMDelay( unsigned short a_usTimeDelay ); +void calibration(void); + +/******************************************************************************** +* writePort +* To apply the specified value to the pins indicated. This routine will +* be modified for specific systems. +* As an example, this code uses the IBM-PC standard Parallel port, along with the +* schematic shown in Lattice documentation, to apply the signals to the +* JTAG pins. +* +* PC Parallel port pin Signal name Port bit address +* 2 g_ucPinTDI 1 +* 3 g_ucPinTCK 2 +* 4 g_ucPinTMS 4 +* 5 g_ucPinENABLE 8 +* 6 g_ucPinTRST 16 +* 10 g_ucPinTDO 64 +* +* Parameters: +* - a_ucPins, which is actually a set of bit flags (defined above) +* that correspond to the bits of the data port. Each of the I/O port +* bits that drives an isp programming pin is assigned a flag +* (through a #define) corresponding to the signal it drives. To +* change the value of more than one pin at once, the flags are added +* together, much like file access flags are. +* +* The bit flags are only set if the pin is to be changed. Bits that +* do not have their flags set do not have their levels changed. The +* state of the port is always manintained in the static global +* variable g_siIspPins, so that each pin can be addressed individually +* without disturbing the others. +* +* - a_ucValue, which is either HIGH (0x01 ) or LOW (0x00 ). Only these two +* values are valid. Any non-zero number sets the pin(s) high. +* +*********************************************************************************/ + +void writePort( unsigned long a_ucPins, unsigned char a_ucValue ) +{ + + unsigned long siIspPins = 0; + + /* For Denverton */ + // isp_dnv_gpio_write(a_ucPins, (unsigned int) a_ucValue); + + /* TODO: Convert to bit read/write function */ + siIspPins = inl_p( g_ucOutPort ); + if( a_ucValue ){ + siIspPins |= (1U << a_ucPins); + }else{ + siIspPins &= ~(1U << a_ucPins); + } + outl_p(siIspPins, g_ucOutPort); +} + +/********************************************************************************* +* +* readPort +* +* Returns the value of the TDO from the device. +* +**********************************************************************************/ +unsigned char readPort() +{ + unsigned char ucRet = 0; + + /* For Denverton */ + // if ( isp_dnv_gpio_read(DNV_GPIO_TDO_CONFIG) ) { + // ucRet = 0x01; + // } + // else { + // ucRet = 0x00; + // } + + /* TODO: Convert to bit read/write function */ + if ( inl_p( g_ucInPort ) & (1U << g_ucPinTDO)) { + ucRet = 0x01; + } + else { + ucRet = 0x00; + } + return ( ucRet ); +} + +/********************************************************************************* +* sclock +* +* Apply a pulse to TCK. +* +* This function is located here so that users can modify to slow down TCK if +* it is too fast (> 25MHZ). Users can change the IdleTime assignment from 0 to +* 1, 2... to effectively slowing down TCK by half, quarter... +* +*********************************************************************************/ +void sclock() +{ + unsigned short IdleTime = 0; //change to > 0 if need to slow down TCK + unsigned short usIdleIndex = 0; + IdleTime++; + for ( usIdleIndex = 0; usIdleIndex < IdleTime; usIdleIndex++ ) { + writePort( g_ucPinTCK, 0x01 ); + } + for ( usIdleIndex = 0; usIdleIndex < IdleTime; usIdleIndex++ ) { + writePort( g_ucPinTCK, 0x00 ); + } +} +/******************************************************************************** +* +* ispVMDelay +* +* +* Users must implement a delay to observe a_usTimeDelay, where +* bit 15 of the a_usTimeDelay defines the unit. +* 1 = milliseconds +* 0 = microseconds +* Example: +* a_usTimeDelay = 0x0001 = 1 microsecond delay. +* a_usTimeDelay = 0x8001 = 1 millisecond delay. +* +* This subroutine is called upon to provide a delay from 1 millisecond to a few +* hundreds milliseconds each time. +* It is understood that due to a_usTimeDelay is defined as unsigned short, a 16 bits +* integer, this function is restricted to produce a delay to 64000 micro-seconds +* or 32000 milli-second maximum. The VME file will never pass on to this function +* a delay time > those maximum number. If it needs more than those maximum, the VME +* file will launch the delay function several times to realize a larger delay time +* cummulatively. +* It is perfectly alright to provide a longer delay than required. It is not +* acceptable if the delay is shorter. +* +* Delay function example--using the machine clock signal of the native CPU------ +* When porting ispVME to a native CPU environment, the speed of CPU or +* the system clock that drives the CPU is usually known. +* The speed or the time it takes for the native CPU to execute one for loop +* then can be calculated as follows: +* The for loop usually is compiled into the ASSEMBLY code as shown below: +* LOOP: DEC RA; +* JNZ LOOP; +* If each line of assembly code needs 4 machine cycles to execute, +* the total number of machine cycles to execute the loop is 2 x 4 = 8. +* Usually system clock = machine clock (the internal CPU clock). +* Note: Some CPU has a clock multiplier to double the system clock for + the machine clock. +* +* Let the machine clock frequency of the CPU be F, or 1 machine cycle = 1/F. +* The time it takes to execute one for loop = (1/F ) x 8. +* Or one micro-second = F(MHz)/8; +* +* Example: The CPU internal clock is set to 100Mhz, then one micro-second = 100/8 = 12 +* +* The C code shown below can be used to create the milli-second accuracy. +* Users only need to enter the speed of the cpu. +* +**********************************************************************************/ +void ispVMDelay( unsigned short a_usTimeDelay ) +{ + unsigned short loop_index = 0; + unsigned short ms_index = 0; + unsigned short us_index = 0; + + if ( a_usTimeDelay & 0x8000 ) /*Test for unit*/ + { + a_usTimeDelay &= ~0x8000; /*unit in milliseconds*/ + } + else { /*unit in microseconds*/ + a_usTimeDelay = (unsigned short) (a_usTimeDelay/1000); /*convert to milliseconds*/ + if ( a_usTimeDelay <= 0 ) { + a_usTimeDelay = 1; /*delay is 1 millisecond minimum*/ + } + } + /*Users can replace the following section of code by their own*/ + for( ms_index = 0; ms_index < a_usTimeDelay; ms_index++) + { + /*Loop 1000 times to produce the milliseconds delay*/ + for (us_index = 0; us_index < 1000; us_index++) + { /*each loop should delay for 1 microsecond or more.*/ + loop_index = 0; + do { + /*The NOP fakes the optimizer out so that it doesn't toss out the loop code entirely*/ + asm("nop"); + }while (loop_index++ < ((g_usCpu_Frequency/8)+(+ ((g_usCpu_Frequency % 8) ? 1 : 0))));/*use do loop to force at least one loop*/ + } + } +} + +/********************************************************************************* +* +* calibration +* +* It is important to confirm if the delay function is indeed providing +* the accuracy required. Also one other important parameter needed +* checking is the clock frequency. +* Calibration will help to determine the system clock frequency +* and the loop_per_micro value for one micro-second delay of the target +* specific hardware. +* +**********************************************************************************/ +void calibration(void) +{ + /*Apply 2 pulses to TCK.*/ + writePort( g_ucPinTCK, 0x00 ); + writePort( g_ucPinTCK, 0x01 ); + writePort( g_ucPinTCK, 0x00 ); + writePort( g_ucPinTCK, 0x01 ); + writePort( g_ucPinTCK, 0x00 ); + + /*Delay for 1 millisecond. Pass on 1000 or 0x8001 both = 1ms delay.*/ + ispVMDelay(0x8001); + + /*Apply 2 pulses to TCK*/ + writePort( g_ucPinTCK, 0x01 ); + writePort( g_ucPinTCK, 0x00 ); + writePort( g_ucPinTCK, 0x01 ); + writePort( g_ucPinTCK, 0x00 ); + + ispVMDelay(0x8001); +} + +void port_test(void) +{ + int siRetCode; + unsigned char cbit; + + printf("TDI set HIGH.\n"); + if(scanf("%d",&siRetCode)){} + writePort( g_ucPinTDI, 0x01); + printf("TDI set LOW.\n"); + if(scanf("%d",&siRetCode)){} + writePort( g_ucPinTDI, 0x00); + printf("TMS set HIGH.\n"); + if(scanf("%d",&siRetCode)){} + writePort(g_ucPinTMS, 0x01); + printf("TMS set LOW.\n"); + if(scanf("%d",&siRetCode)){} + writePort(g_ucPinTMS, 0x00); + printf("TCK set HIGH.\n"); + if(scanf("%d",&siRetCode)){} + writePort(g_ucPinTCK, 0x01); + printf("TCK set LOW.\n"); + if(scanf("%d",&siRetCode)){} + writePort(g_ucPinTCK, 0x00); + printf("write finished.read begin:\n"); + if(scanf("%d",&siRetCode)){} + cbit = readPort(); + printf("Read date is %d\n", cbit); + printf("read begin:\n"); + if(scanf("%d",&siRetCode)){} + cbit = readPort(); + printf("Read date is %d\n", cbit); + printf("read finished.\n"); + if(scanf("%d",&siRetCode)){} +} + + +void isp_dnv_gpio_config(unsigned int gpio, unsigned int dir) +{ + volatile unsigned int *buffer; + // Select community + if(GET_PORT(gpio) == 0xC5){ + buffer = (volatile unsigned int *)(portC5 + OFFSET_ADDR(gpio)); + }else{ + buffer = (volatile unsigned int *)(portC2 + OFFSET_ADDR(gpio)); + } + // set mode to GPIO, set pin direction. + *buffer &= (~((unsigned int)7)) << 10; // clear [12:10] + *buffer &= (~((unsigned int)3)) << 8; // clear [9:8] + *buffer |= ((unsigned int)dir & 0x3) << 8; // set [9:8] +} + +void isp_dnv_gpio_write(unsigned int gpio, unsigned int value) +{ + volatile unsigned char *buffer; + // Select community + if(GET_PORT(gpio) == 0xC5){ + buffer = (volatile unsigned char *)(portC5 + OFFSET_ADDR(gpio)); + }else{ + buffer = (volatile unsigned char *)(portC2 + OFFSET_ADDR(gpio)); + } + if(value) { + *buffer = DNV_GPIO_LVL_HIGH; + } else { + *buffer = DNV_GPIO_LVL_LOW; + } +} + +int isp_dnv_gpio_read(unsigned int gpio) +{ + volatile unsigned int *buffer; + // Select community + if(GET_PORT(gpio) == 0xC5){ + buffer = (volatile unsigned int *)(portC5 + OFFSET_ADDR(gpio)); + }else{ + buffer = (volatile unsigned int *)(portC2 + OFFSET_ADDR(gpio)); + } + return (int)((*buffer & 0x2) >> 1); +} + + +void isp_dnv_gpio_init(void){ + + devmem_c2 = open("/dev/mem", O_RDWR | O_SYNC); + if (devmem_c2 == -1){ + perror("Can't open /dev/mem."); + return; + } + + devmem_c5 = open("/dev/mem", O_RDWR | O_SYNC); + if (devmem_c5 == -1){ + perror("Can't open /dev/mem."); + return; + } + + portC2 = mmap(NULL, MAP_SIZE(g_ucPinTCK) , PROT_READ | PROT_WRITE, MAP_SHARED, devmem_c2, g_ucPinTCK & ~MAP_MASK); + if (portC2 == MAP_FAILED) { + perror("Can't map memory: "); + return; + } + portC5 = mmap(NULL, MAP_SIZE(g_ucPinTDO) , PROT_READ | PROT_WRITE, MAP_SHARED, devmem_c5, g_ucPinTDO & ~MAP_MASK); + if (portC2 == MAP_FAILED) { + perror("Can't map memory: "); + return; + } +} + +void isp_dnv_gpio_deinit(void){ + munmap(portC2, MAP_SIZE(g_ucPinTCK)); + munmap(portC5, MAP_SIZE(g_ucPinTDO)); + close(devmem_c2); + close(devmem_c5); +} diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ispvm b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ispvm new file mode 100755 index 0000000000000000000000000000000000000000..202103900f69b4c1664a00f46a9786e9d6ddc6f9 GIT binary patch literal 106272 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 Cle=pG literal 0 HcmV?d00001 diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ispvm_ui.c b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ispvm_ui.c new file mode 100644 index 000000000000..6180007d74d0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ispvm_ui.c @@ -0,0 +1,1043 @@ +/************************************************************** +* +* Lattice Semiconductor Corp. Copyright 2008 +* +* ispVME Embedded allows programming of Lattice's suite of FPGA +* devices on embedded systems through the JTAG port. The software +* is distributed in source code form and is open to re - distribution +* and modification where applicable. +* +* ispVME Embedded C Source comprised with 3 modules: +* ispvm_ui.c is the module provides input and output support. +* ivm_core.c is the module interpret the VME file(s). +* hardware.c is the module access the JTAG port of the device(s). +* +* The optional module cable.c is for supporting Lattice's parallel +* port ispDOWNLOAD cable on DOS and Windows 95/98 O/S. It can be +* requested from Lattice's ispVMSupport. +* +***************************************************************/ + + +/************************************************************** +* +* Revision History of ispvm_ui.c +* +* 3/6/07 ht Added functions vme_out_char(),vme_out_hex(), +* vme_out_string() to provide output resources. +* Consolidate all printf() calls into the added output +* functions. +* +* 09/11/07 NN Added Global variables initialization +* 09/24/07 NN Added a switch allowing users to do calibration. +* Calibration will help to determine the system clock frequency +* and the count value for one micro-second delay of the target +* specific hardware. +* Removed Delay Percent support +* 11/15/07 NN moved the checking of the File CRC to the end of processing +* 08/28/08 NN Added Calculate checksum support. +***************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include "vmopcode.h" + +/*************************************************************** +* +* File pointer to the VME file. +* +***************************************************************/ + +FILE * g_pVMEFile = NULL; + +#define VME_DEBUG + +#define DEBUG +#ifdef DEBUG +#define Debug_printf(fmt, args...) printf(fmt, ##args); +#else +#define Debug_printf(fmt, args...) +#endif + +/*************************************************************** +* +* Functions declared in this ispvm_ui.c module +* +***************************************************************/ +unsigned char GetByte(void); +void vme_out_char(unsigned char charOut); +void vme_out_hex(unsigned char hexOut); +void vme_out_string(char *stringOut); +void ispVMMemManager( signed char cTarget, unsigned short usSize ); +void ispVMFreeMem(void); +void error_handler( short a_siRetCode, char * pszMessage ); +signed char ispVM( const char * a_pszFilename ); +long isp_vme_file_size_get(void); +int isp_vme_file_size_set(char *file_name); +int isp_print_progess_bar(long pec); +void print_usage(char *app_name); +/*************************************************************** +* +* Global variables. +* +***************************************************************/ +unsigned short g_usPreviousSize = 0; +unsigned short g_usExpectedCRC = 0; +static unsigned long vme_file_size = 0; + +/*************************************************************** +* +* External variables and functions declared in ivm_core.c module. +* +***************************************************************/ +extern signed char ispVMCode(); +extern void ispVMCalculateCRC32( unsigned char a_ucData ); +extern void ispVMStart(); +extern void ispVMEnd(); +extern unsigned short g_usCalculatedCRC; +extern unsigned short g_usDataType; +extern unsigned char * g_pucOutMaskData, + * g_pucInData, + * g_pucOutData, + * g_pucHIRData, + * g_pucTIRData, + * g_pucHDRData, + * g_pucTDRData, + * g_pucOutDMaskData, + * g_pucIntelBuffer; +extern unsigned char * g_pucHeapMemory; +extern unsigned short g_iHeapCounter; +extern unsigned short g_iHEAPSize; +extern unsigned short g_usIntelDataIndex; +extern unsigned short g_usIntelBufferSize; +extern LVDSPair * g_pLVDSList; +//08/28/08 NN Added Calculate checksum support. +extern unsigned long g_usChecksum; +extern unsigned int g_uiChecksumIndex; +/*************************************************************** +* +* External variables and functions declared in hardware.c module. +* +***************************************************************/ +extern void calibration(void); +extern void writePort( unsigned long a_ucPins, unsigned char a_ucValue ); +extern unsigned short g_usCpu_Frequency; +extern unsigned long g_ucInPort; +extern unsigned long g_ucOutPort; + +#define SYS_CMD_LEN (100) +#define PCA9536_INPUT_REG (0) +#define PCA9536_OUTPUT_REG (1) +#define PCA9536_POL_INV_REG (2) +#define PCA9536_CFG_REG (3) +#define PCA9536_I2C_BUS (0) +#define PCA9536_I2C_ADDR (0x41) +enum cel_error{ +CEL_NO_ERR = 0, +CEL_ERR_INVALID_DATA, +}; +enum IOx_index { +CPLD_BB_INDEX = 0, +CPLD_CB_INDEX, +CPLD_FCB_INDEX, +CPLD_SWB_INDEX, +CPLD_TOTAL_NUM, + +}; +char IOx_map[] = { +1,//IOx index of pca9536 corresponding to CPLD_BB +2,//IOx index of pca9536 corresponding to CPLD_CB +0,//IOx index of pca9536 corresponding to CPLD_FCB +3,//IOx index of pca9536 corresponding to CPLD_SWB +}; +/*************************************************************** +* +* Supported VME versions. +* +***************************************************************/ + +const char * const g_szSupportedVersions[] = { "__VME2.0", "__VME3.0", "____12.0", "____12.1", 0 }; + + +/*************************************************************** +* +* GetByte +* +* Returns a byte to the caller. The returned byte depends on the +* g_usDataType register. If the HEAP_IN bit is set, then the byte +* is returned from the HEAP. If the LHEAP_IN bit is set, then +* the byte is returned from the intelligent buffer. Otherwise, +* the byte is returned directly from the VME file. +* +***************************************************************/ + +unsigned char GetByte() +{ + unsigned char ucData = 0; + /* Prepare progress bar calculation */ + static long offset = 0; + int pec = 0; + long file_size = isp_vme_file_size_get(); + int bytes_pec = (file_size + 99) / 100; + + if ( g_usDataType & HEAP_IN ) { + + /*************************************************************** + * + * Get data from repeat buffer. + * + ***************************************************************/ + + if ( g_iHeapCounter > g_iHEAPSize ) { + + /*************************************************************** + * + * Data over-run. + * + ***************************************************************/ + + return 0xFF; + } + + ucData = g_pucHeapMemory[ g_iHeapCounter++ ]; + } + else if ( g_usDataType & LHEAP_IN ) { + + /*************************************************************** + * + * Get data from intel buffer. + * + ***************************************************************/ + + if ( g_usIntelDataIndex >= g_usIntelBufferSize ) { + + /*************************************************************** + * + * Data over-run. + * + ***************************************************************/ + + return 0xFF; + } + + ucData = g_pucIntelBuffer[ g_usIntelDataIndex++ ]; + } + else { + + /*************************************************************** + * + * Get data from file. + * + ***************************************************************/ + + ucData = (unsigned char)fgetc( g_pVMEFile ); + /* Update the progress bar */ + pec = ++offset / bytes_pec; + if(offset <= (pec * bytes_pec)) + isp_print_progess_bar(pec); + else if(offset >= (file_size - 2)) + isp_print_progess_bar(100); + if ( feof( g_pVMEFile ) ) { + + /*************************************************************** + * + * Reached EOF. + * + ***************************************************************/ + + return 0xFF; + } + /*************************************************************** + * + * Calculate the 32-bit CRC if the expected CRC exist. + * + ***************************************************************/ + if( g_usExpectedCRC != 0) + { + ispVMCalculateCRC32(ucData); + } + } + + return ( ucData ); +} + +/*************************************************************** +* +* vme_out_char +* +* Send a character out to the output resource if available. +* The monitor is the default output resource. +* +* +***************************************************************/ +void vme_out_char(unsigned char charOut) +{ + printf("%c",charOut); +} +/*************************************************************** +* +* vme_out_hex +* +* Send a character out as in hex format to the output resource +* if available. The monitor is the default output resource. +* +* +***************************************************************/ +void vme_out_hex(unsigned char hexOut) +{ + printf("%.2X",hexOut); +} +/*************************************************************** +* +* vme_out_string +* +* Send a text string out to the output resource if available. +* The monitor is the default output resource. +* +* +***************************************************************/ +void vme_out_string(char *stringOut) +{ + if(stringOut) + { + printf("%s",stringOut); + } + +} +/*************************************************************** +* +* ispVMMemManager +* +* Allocate memory based on cTarget. The memory size is specified +* by usSize. +* +***************************************************************/ + +void ispVMMemManager( signed char cTarget, unsigned short usSize ) +{ + switch ( cTarget ) { + case XTDI: + case TDI: + if ( g_pucInData != NULL ) { + if ( g_usPreviousSize == usSize ) {/*memory exist*/ + break; + } + else { + free( g_pucInData ); + g_pucInData = NULL; + } + } + g_pucInData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + g_usPreviousSize = usSize; + /* FALLTHRU */ + case XTDO: + case TDO: + if ( g_pucOutData!= NULL ) { + if ( g_usPreviousSize == usSize ) { /*already exist*/ + break; + } + else { + free( g_pucOutData ); + g_pucOutData = NULL; + } + } + g_pucOutData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + g_usPreviousSize = usSize; + break; + case MASK: + if ( g_pucOutMaskData != NULL ) { + if ( g_usPreviousSize == usSize ) {/*already allocated*/ + break; + } + else { + free( g_pucOutMaskData ); + g_pucOutMaskData = NULL; + } + } + g_pucOutMaskData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + g_usPreviousSize = usSize; + break; + case HIR: + if ( g_pucHIRData != NULL ) { + free( g_pucHIRData ); + g_pucHIRData = NULL; + } + g_pucHIRData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + break; + case TIR: + if ( g_pucTIRData != NULL ) { + free( g_pucTIRData ); + g_pucTIRData = NULL; + } + g_pucTIRData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + break; + case HDR: + if ( g_pucHDRData != NULL ) { + free( g_pucHDRData ); + g_pucHDRData = NULL; + } + g_pucHDRData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + break; + case TDR: + if ( g_pucTDRData != NULL ) { + free( g_pucTDRData ); + g_pucTDRData = NULL; + } + g_pucTDRData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + break; + case HEAP: + if ( g_pucHeapMemory != NULL ) { + free( g_pucHeapMemory ); + g_pucHeapMemory = NULL; + } + g_pucHeapMemory = ( unsigned char * ) malloc( usSize + 2 ); + break; + case DMASK: + if ( g_pucOutDMaskData != NULL ) { + if ( g_usPreviousSize == usSize ) { /*already allocated*/ + break; + } + else { + free( g_pucOutDMaskData ); + g_pucOutDMaskData = NULL; + } + } + g_pucOutDMaskData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + g_usPreviousSize = usSize; + break; + case LHEAP: + if ( g_pucIntelBuffer != NULL ) { + free( g_pucIntelBuffer ); + g_pucIntelBuffer = NULL; + } + g_pucIntelBuffer = ( unsigned char * ) malloc( usSize + 2 ); + break; + case LVDS: + if ( g_pLVDSList != NULL ) { + free( g_pLVDSList ); + g_pLVDSList = NULL; + } + g_pLVDSList = ( LVDSPair * ) calloc( usSize, sizeof( LVDSPair ) ); + break; + default: + return; + } +} + +/*************************************************************** +* +* ispVMFreeMem +* +* Free memory that were dynamically allocated. +* +***************************************************************/ + +void ispVMFreeMem() +{ + if ( g_pucHeapMemory != NULL ) { + free( g_pucHeapMemory ); + g_pucHeapMemory = NULL; + } + + if ( g_pucOutMaskData != NULL ) { + free( g_pucOutMaskData ); + g_pucOutMaskData = NULL; + } + + if ( g_pucInData != NULL ) { + free( g_pucInData ); + g_pucInData = NULL; + } + + if ( g_pucOutData != NULL ) { + free( g_pucOutData ); + g_pucOutData = NULL; + } + + if ( g_pucHIRData != NULL ) { + free( g_pucHIRData ); + g_pucHIRData = NULL; + } + + if ( g_pucTIRData != NULL ) { + free( g_pucTIRData ); + g_pucTIRData = NULL; + } + + if ( g_pucHDRData != NULL ) { + free( g_pucHDRData ); + g_pucHDRData = NULL; + } + + if ( g_pucTDRData != NULL ) { + free( g_pucTDRData ); + g_pucTDRData = NULL; + } + + if ( g_pucOutDMaskData != NULL ) { + free( g_pucOutDMaskData ); + g_pucOutDMaskData = NULL; + } + + if ( g_pucIntelBuffer != NULL ) { + free( g_pucIntelBuffer ); + g_pucIntelBuffer = NULL; + } + + if ( g_pLVDSList != NULL ) { + free( g_pLVDSList ); + g_pLVDSList = NULL; + } +} + +/*************************************************************** +* +* error_handler +* +* Reports the error message. +* +***************************************************************/ + +void error_handler( short a_siRetCode, char * pszMessage ) +{ + const char * pszErrorMessage[] = { "pass", + "verification fail", + "can't find the file", + "wrong file type", + "file error", + "option error", + "crc verification error" }; + + strcpy( pszMessage, pszErrorMessage[ -a_siRetCode ] ); +} +/*************************************************************** +* +* ispVM +* +* The entry point of the ispVM embedded. If the version and CRC +* are verified, then the VME will be processed. +* +***************************************************************/ + +signed char ispVM( const char * a_pszFilename ) +{ + char szFileVersion[ 9 ] = { 0 }; + signed char cRetCode = 0; + signed char cIndex = 0; + signed char cVersionIndex = 0; + unsigned char ucReadByte = 0; + + /*************************************************************** + * + * Global variables initialization. + * + * 09/11/07 NN Added + ***************************************************************/ + g_pucHeapMemory = NULL; + g_iHeapCounter = 0; + g_iHEAPSize = 0; + g_usIntelDataIndex = 0; + g_usIntelBufferSize = 0; + g_usPreviousSize = 0; + + /*************************************************************** + * + * Open a file pointer to the VME file. + * + ***************************************************************/ + + if ( ( g_pVMEFile = fopen( a_pszFilename, "rb" ) ) == NULL ) { + return VME_FILE_READ_FAILURE; + } + g_usCalculatedCRC = 0; + g_usExpectedCRC = 0; + ucReadByte = GetByte(); + switch( ucReadByte ) { + case FILE_CRC: + + /*************************************************************** + * + * Read and store the expected CRC to do the comparison at the end. + * Only versions 3.0 and higher support CRC protection. + * + ***************************************************************/ + + g_usExpectedCRC = (unsigned char ) fgetc( g_pVMEFile ); + g_usExpectedCRC <<= 8; + g_usExpectedCRC |= fgetc( g_pVMEFile ); + + + /*************************************************************** + * + * Read and store the version of the VME file. + * + ***************************************************************/ + + for ( cIndex = 0; cIndex < 8; cIndex++ ) { + szFileVersion[ cIndex ] = GetByte(); + } + + break; + default: + + /*************************************************************** + * + * Read and store the version of the VME file. Must be version 2.0. + * + ***************************************************************/ + + szFileVersion[ 0 ] = ( signed char ) ucReadByte; + for ( cIndex = 1; cIndex < 8; cIndex++ ) { + szFileVersion[ cIndex ] = GetByte(); + } + + break; + } + + /*************************************************************** + * + * Compare the VME file version against the supported version. + * + ***************************************************************/ + for ( cVersionIndex = 0; g_szSupportedVersions[ cVersionIndex ] != 0; cVersionIndex++ ) { + for ( cIndex = 0; cIndex < 8; cIndex++ ) { + if ( szFileVersion[ cIndex ] != g_szSupportedVersions[ cVersionIndex ][ cIndex ] ) { + cRetCode = VME_VERSION_FAILURE; + break; + } + cRetCode = 0; + } + + if ( cRetCode == 0 ) { + + /*************************************************************** + * + * Found matching version, break. + * + ***************************************************************/ + + break; + } + } + + if ( cRetCode < 0 ) { + + /*************************************************************** + * + * VME file version failed to match the supported versions. + * + ***************************************************************/ + + fclose( g_pVMEFile ); + g_pVMEFile = NULL; + return VME_VERSION_FAILURE; + } + + /*************************************************************** + * + * Enable the JTAG port to communicate with the device. + * Set the JTAG state machine to the Test-Logic/Reset State. + * + ***************************************************************/ + + ispVMStart(); + + /*************************************************************** + * + * Process the VME file. + * + ***************************************************************/ + + cRetCode = ispVMCode(); + + /*************************************************************** + * + * Set the JTAG State Machine to Test-Logic/Reset state then disable + * the communication with the JTAG port. + * + ***************************************************************/ + + ispVMEnd(); + + fclose( g_pVMEFile ); + g_pVMEFile = NULL; + + + ispVMFreeMem(); + + /*************************************************************** + * + * Compare the expected CRC versus the calculated CRC. + * + ***************************************************************/ + + if ( cRetCode == 0 && g_usExpectedCRC != 0 && ( g_usExpectedCRC != g_usCalculatedCRC ) ) { + printf( "Expected CRC: 0x%.4X\n", g_usExpectedCRC ); + printf( "Calculated CRC: 0x%.4X\n", g_usCalculatedCRC ); + return VME_CRC_FAILURE; + } + + return ( cRetCode ); +} + +// inline char *strlwr(char *str) +// { +// char *orig = str; + +// for (; *str != '\0'; str++) +// *str = tolower(*str); + +// return orig; +// } + +int isp_vme_file_size_set(char *file_name) +{ + struct stat statbuf; + + stat(file_name, &statbuf); + vme_file_size = statbuf.st_size; + + return 0; +} + +long isp_vme_file_size_get(void) +{ + return vme_file_size; +} + +int isp_print_progess_bar(long pec) +{ + int i = 0; + + printf("["); + for(i = 0; i < (pec / 2); i++) { + printf("="); + } + for(i = pec / 2; i < 50; i++) { + printf(" "); + } + printf("]"); + printf(" [%ld%%]\r", pec); + fflush(stdout); + if(pec == 100) + printf("\n"); + + return 0; +} + +void print_usage(char *app_name){ + printf(" usage: %s [options] [filename]\n", app_name); + printf(" Options:\n"); + printf(" -h : to print this message.\n"); + printf(" -c : to select the JTAG chain 0,1,2\n"); + printf(" default is at 0.\n"); + printf(" -f : to specify CPU clock frequency in MHz.\n"); + printf(" -i : set output channel of pca9536, range:\n"); + printf(" 0 - CPLD_BB \n"); + printf(" 1 - CPLD_CB \n"); + printf(" 2 - CPLD_FCB \n"); + printf(" 3 - CPLD_SWB \n"); +} + +/*Description: execute a system command contained in a string +*param_in: tmp - system command string +*param_out: NONE +*ret_val: 0 - on successful +* 1 - on failed +*/ +int exec_cmd (char * tmp) +{ + int status; + status = system(tmp); + if (-1 ==status){ + return CEL_ERR_INVALID_DATA; + }else{ + if (WIFEXITED(status)){ + if (0 == WEXITSTATUS(status)){ + return CEL_NO_ERR; + }else{ + return CEL_ERR_INVALID_DATA; + } + }else{ + return CEL_ERR_INVALID_DATA; + } + } + return CEL_NO_ERR; +} +/*Description: set pca9536 IO0~IO3 output level +*param_in: io_index - index of IO pin +*param_out:NONE +*ret_val: 0 - on successful +* -1 - on failed +*/ +int set_pca9536_output(int io_index) +{ + int sys_cmd_rc = 0; + char sys_cmd[SYS_CMD_LEN] = {0}; + char reg_val = 0xFF & (~(1 << IOx_map[io_index])); + printf("set pca9536 IO%d to level 0 \n", IOx_map[io_index]); + memset(sys_cmd, 0, SYS_CMD_LEN); + sprintf(sys_cmd, "i2cset -y %d 0x%x 0x%x 0x%x", PCA9536_I2C_BUS, + PCA9536_I2C_ADDR, PCA9536_OUTPUT_REG, reg_val); + sys_cmd_rc = exec_cmd(sys_cmd); + if (sys_cmd_rc != 0) { + printf("set pca9536 IO%d to level 0 failed!\n", IOx_map[io_index]); + return -1; + } + return sys_cmd_rc; +} + +/*************************************************************** +* +* main +* +***************************************************************/ +int main( int argc, char * argv[] ) +{ + short siRetCode = 0; + short sicalibrate = 1; + short setCpuFrequency = 0; + /* ChannelIndex: indicate which channel on PCA9536 is selected */ + int ChannelIndex = -1; + char sys_cmd[SYS_CMD_LEN] = {0}; + int setChannel = 0; + int sys_cmd_rc = 0; + + char *cpld_img = "cpld.vme"; + int JTAG_chain = 0; + int option; + //08/28/08 NN Added Calculate checksum support. + g_usChecksum = 0; + g_uiChecksumIndex = 0; + + vme_out_string( " Lattice Semiconductor Corp.\n" ); + vme_out_string( "\n ispVME(tm) V"); + vme_out_string( VME_VERSION_NUMBER ); + vme_out_string(" Copyright 1998-2011.\n"); + vme_out_string( "\nFor daisy chain programming of all in-system programmable devices\n" ); + vme_out_string( "\nCLS internal version 1.1.0 for Phalanx, Fishbone48, and Fishbone32.\n\n" ); + + while( ( option = getopt(argc, argv, "i:f:c:h")) != -1 ){ + switch (option){ + case 'h': + print_usage(argv[0]); + return 0; + case 'c': + // set JTAG chain number + JTAG_chain = atoi(optarg); + break; + case 'f': + // set CPU frequency + g_usCpu_Frequency = atoi(optarg); + setCpuFrequency = 1; + break; + case 'i': + ChannelIndex = atoi(optarg); + /* printf("channel_index=%d\n", ChannelIndex); */ + break; + case '?': + print_usage(argv[0]); + return -1; + } + } + + if( argc - optind ) + cpld_img = argv[optind]; + + if( JTAG_chain < 0 || JTAG_chain > 2 ){ + //print usage and return error + printf("Invalid JTAG chain specify: %d\n", JTAG_chain); + print_usage(argv[0]); + return -1; + } + + if( g_usCpu_Frequency <= 0 && setCpuFrequency ){ + //print usage and return error + printf("Invalid CPU frequency specify: %d\n", g_usCpu_Frequency); + print_usage(argv[0]); + return -1; + } + + if (ChannelIndex != -1) { + if (ChannelIndex < 0 || ChannelIndex > 3) { + printf("Invalid pca9536 channel index! \n"); + print_usage(argv[0]); + return -1; + } else { + printf("pca9536 channel index: %d \n", ChannelIndex); + setChannel = 1; + } + } else { + printf("pca9536 output channel not set,use default value 0 ! \n"); + ChannelIndex = 0; + setChannel = 1; + } + /*printf("exit programm 1 \n"); + * exit(1); + */ + if (iopl(3)) + { + perror("iopl"); + exit(1);/* reminder here: do not use "return", I warned */ + } + else + { + + /* For Denvertion CPU */ + // isp_dnv_gpio_init(); + // isp_dnv_gpio_config(GPIO_TCK_CONFIG, GPIO_DIR_OUTPUT); + // isp_dnv_gpio_config(GPIO_TMS_CONFIG, GPIO_DIR_OUTPUT); + // isp_dnv_gpio_config(GPIO_TDI_CONFIG, GPIO_DIR_OUTPUT); + // isp_dnv_gpio_config(GPIO_TDO_CONFIG, GPIO_DIR_INPUT); + + + /* TODO: Convert to bit read/write function */ + // Set ICHx GPIO_USE_SEL of TDI,TDO,TMS,TCK,GPIO14 + unsigned long data = 0; + data = inl_p(GPIO_USE_SEL); + data |= (1U << GPIO_TCK_CONFIG); + data |= (1U << GPIO_TMS_CONFIG); + data |= (1U << GPIO_TDI_CONFIG); + data |= (1U << GPIO_TDO_CONFIG); + data |= (1U << 14); + outl_p(data, GPIO_USE_SEL); + // Set ICHx GP_IO_SEL of TDI,TDO,TMS,TCK,GPIO14 + data = inl_p(GP_IO_SEL); + data &= ~(1U << GPIO_TCK_CONFIG); + data &= ~(1U << GPIO_TMS_CONFIG); + data &= ~(1U << GPIO_TDI_CONFIG); + data &= ~(1U << 14); + data |= (1U << GPIO_TDO_CONFIG); + outl_p(data, GP_IO_SEL); + + // Set ICHx GPIO_USE_SEL of GPIO70 + data = inl_p(GPIO_USE_SEL3); + data |= (1U << 6); + outl_p(data, GPIO_USE_SEL3); + // Set ICHx GP_IO_SEL of GPIO70 + data = inl_p(GP_IO_SEL3); + data &= ~(1U << 6); + outl_p(data, GP_IO_SEL3); + } + + /* FIXME: export and setting GPIO register bank on the fly could cause a bug. + * Plan to add the function to set/clear GPIO register bit for more sucure. + */ + /* Switch to control JTAG chain muxes */ + switch (JTAG_chain){ + case 0: + printf("Select main JTAG chain\n"); + // Set GPIO70 to Low + g_ucOutPort = GP_LVL3; + writePort( 6, 0x00 ); + break; + case 1: + printf("Select Top line card JTAG chain\n"); + // Ste GPIO70 to High + g_ucOutPort = GP_LVL3; + writePort( 6, 0x01 ); + // Ste GPIO14 to Low + g_ucOutPort = GP_LVL; + writePort( 14, 0x00 ); + break; + case 2: + printf("Select Buttom line card JTAG chain\n"); + // Ste GPIO70 to High + g_ucOutPort = GP_LVL3; + writePort( 6, 0x01 ); + // Ste GPIO14 to High + g_ucOutPort = GP_LVL; + writePort( 14, 0x01 ); + break; + } + + /* FIXME: This line is very important for TDI,TMS,TCK,TDO */ + // Set the register back to first bank! + g_ucOutPort = GP_LVL; + + printf("Set CPU frequency to %d MHz\n", g_usCpu_Frequency); + + if (setChannel) { + printf("Set pca9536 output channel index to %d \n", ChannelIndex); + /* exit(0); */ + memset(sys_cmd, 0, SYS_CMD_LEN); + sprintf(sys_cmd, "sudo su"); + sys_cmd_rc = exec_cmd(sys_cmd); + if (sys_cmd_rc != 0) { + printf("sudo su failed!\n"); + return -1; + } + memset(sys_cmd, 0, SYS_CMD_LEN); + sprintf(sys_cmd, "echo jtag_sel 0x41 > /sys/bus/i2c/devices/i2c-0/new_device"); + sys_cmd_rc = exec_cmd(sys_cmd); + if (sys_cmd_rc != 0) { + printf("add pca9536 to i2c-0 failed!\n"); + return -1; + } + memset(sys_cmd, 0, SYS_CMD_LEN); + sprintf(sys_cmd, "i2cset -y %d 0x%x 0x%x 0xf0", PCA9536_I2C_BUS, PCA9536_I2C_ADDR, PCA9536_CFG_REG); + sys_cmd_rc = exec_cmd(sys_cmd); + if (sys_cmd_rc != 0) { + printf("set pca9536 IO0~IO3 to output mode failed!\n"); + return -1; + } + sys_cmd_rc = set_pca9536_output(ChannelIndex); + if (sys_cmd_rc != 0) { + printf("set pca9536 IO%d output 0 failed!\n", IOx_map[ChannelIndex]); + return -1; + } + } + + siRetCode = 0; + if(sicalibrate) + { + vme_out_string ("calibration ....\n\n"); + calibration(); + } + + printf( "Processing virtual machine file ("); + printf( "%s",cpld_img); + printf(")......\n\n"); + isp_vme_file_size_set(cpld_img); + siRetCode = ispVM(cpld_img); + + /* Set JTAG chain muxes to default chain. */ + // Set GPIO70 to Low + g_ucOutPort = GP_LVL3; + writePort( 6, 0x00 ); + + /* For Denverton CPU */ + // isp_dnv_gpio_deinit(); + + if ( siRetCode < 0 ) { + vme_out_string( "Failed due to "); + printf( " return code %d\n\n", siRetCode); + vme_out_string( "+=======+\n" ); + vme_out_string( "| FAIL! |\n" ); + vme_out_string( "+=======+\n\n" ); + }else { + vme_out_string( "+=======+\n" ); + vme_out_string( "| PASS! |\n" ); + vme_out_string( "+=======+\n\n" ); + //08/28/08 NN Added Calculate checksum support. + if(g_usChecksum != 0) + { + g_usChecksum &= 0xFFFF; + printf("Data Checksum: %.4lx\n\n",g_usChecksum); + g_usChecksum = 0; + } + } + + if (iopl(0)) + { + perror("iopl"); + exit(1);/* reminder here: do not use "return", I warned */ + } + exit( siRetCode ); +} + diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ivm_core.c b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ivm_core.c new file mode 100644 index 000000000000..fd6fa7b987c2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ivm_core.c @@ -0,0 +1,3081 @@ +/*************************************************************** + * + * Lattice Semiconductor Corp. Copyright 2009 + * + * ispVME Embedded allows programming of Lattice's suite of FPGA + * devices on embedded systems through the JTAG port. The software + * is distributed in source code form and is open to re - distribution + * and modification where applicable. + * + * Revision History of ivm_core.c module: + * 4/25/06 ht Change some variables from unsigned short or int + * to long int to make the code compiler independent. + * 5/24/06 ht Support using RESET (TRST) pin as a special purpose + * control pin such as triggering the loading of known + * state exit. + * 3/6/07 ht added functions to support output to terminals + * + * 09/24/07 NN Type cast mismatch variables + * Moved the sclock() function to hardware.c + * 08/28/08 NN Added Calculate checksum support. + * 4/1/09 Nguyen replaced the recursive function call codes on + * the ispVMLCOUNT function + * + ***************************************************************/ + +#include +#include +#include "vmopcode.h" + +/*************************************************************** + * + * Global variables used to specify the flow control and data type. + * + * g_usFlowControl: flow control register. Each bit in the + * register can potentially change the + * personality of the embedded engine. + * g_usDataType: holds the data type of the current row. + * + ***************************************************************/ + +unsigned short g_usFlowControl = 0x0000; +unsigned short g_usDataType = 0x0000; + +/*************************************************************** + * + * Global variables used to specify the ENDDR and ENDIR. + * + * g_ucEndDR: the state that the device goes to after SDR. + * g_ucEndIR: the state that the device goes to after SIR. + * + ***************************************************************/ + +unsigned char g_ucEndDR = DRPAUSE; +unsigned char g_ucEndIR = IRPAUSE; + +/*************************************************************** + * + * Global variables used to support header/trailer. + * + * g_usHeadDR: the number of lead devices in bypass. + * g_usHeadIR: the sum of IR length of lead devices. + * g_usTailDR: the number of tail devices in bypass. + * g_usTailIR: the sum of IR length of tail devices. + * + ***************************************************************/ + +unsigned short g_usHeadDR = 0; +unsigned short g_usHeadIR = 0; +unsigned short g_usTailDR = 0; +unsigned short g_usTailIR = 0; + +/*************************************************************** + * + * Global variable to store the number of bits of data or instruction + * to be shifted into or out from the device. + * + ***************************************************************/ + +unsigned short g_usiDataSize = 0; + +/*************************************************************** + * + * Stores the frequency. Default to 1 MHz. + * + ***************************************************************/ + +int g_iFrequency = 1000; + +/*************************************************************** + * + * Stores the maximum amount of ram needed to hold a row of data. + * + ***************************************************************/ + +unsigned short g_usMaxSize = 0; + +/*************************************************************** + * + * Stores the LSH or RSH value. + * + ***************************************************************/ + +unsigned short g_usShiftValue = 0; + +/*************************************************************** + * + * Stores the current repeat loop value. + * + ***************************************************************/ + +unsigned short g_usRepeatLoops = 0; + +/*************************************************************** + * + * Stores the current vendor. + * + ***************************************************************/ + +signed char g_cVendor = LATTICE; + +/*************************************************************** + * + * Stores the VME file CRC. + * + ***************************************************************/ + +unsigned short g_usCalculatedCRC = 0; + +/*************************************************************** + * + * Stores the Device Checksum. + * + ***************************************************************/ +//08/28/08 NN Added Calculate checksum support. +unsigned long g_usChecksum = 0; +unsigned int g_uiChecksumIndex = 0; + +/*************************************************************** + * + * Stores the current state of the JTAG state machine. + * + ***************************************************************/ + +signed char g_cCurrentJTAGState = 0; + +/*************************************************************** + * + * Global variables used to support looping. + * + * g_pucHeapMemory: holds the entire repeat loop. + * g_iHeapCounter: points to the current byte in the repeat loop. + * g_iHEAPSize: the current size of the repeat in bytes. + * + ***************************************************************/ + +unsigned char * g_pucHeapMemory = NULL; +unsigned short g_iHeapCounter = 0; +unsigned short g_iHEAPSize = 0; + +/*************************************************************** + * + * Global variables used to support intelligent programming. + * + * g_usIntelDataIndex: points to the current byte of the + * intelligent buffer. + * g_usIntelBufferSize: holds the size of the intelligent + * buffer. + * + ***************************************************************/ + +unsigned short g_usIntelDataIndex = 0; +unsigned short g_usIntelBufferSize = 0; + +/**************************************************************************** + * + * Holds the maximum size of each respective buffer. These variables are used + * to write the HEX files when converting VME to HEX. + * + *****************************************************************************/ + +unsigned short g_usTDOSize = 0; +unsigned short g_usMASKSize = 0; +unsigned short g_usTDISize = 0; +unsigned short g_usDMASKSize = 0; +unsigned short g_usLCOUNTSize = 0; +unsigned short g_usHDRSize = 0; +unsigned short g_usTDRSize = 0; +unsigned short g_usHIRSize = 0; +unsigned short g_usTIRSize = 0; +unsigned short g_usHeapSize = 0; + +/*************************************************************** + * + * Global variables used to store data. + * + * g_pucOutMaskData: local RAM to hold one row of MASK data. + * g_pucInData: local RAM to hold one row of TDI data. + * g_pucOutData: local RAM to hold one row of TDO data. + * g_pucHIRData: local RAM to hold the current SIR header. + * g_pucTIRData: local RAM to hold the current SIR trailer. + * g_pucHDRData: local RAM to hold the current SDR header. + * g_pucTDRData: local RAM to hold the current SDR trailer. + * g_pucIntelBuffer: local RAM to hold the current intelligent buffer. + * g_pucOutDMaskData: local RAM to hold one row of DMASK data. + * + ***************************************************************/ + +unsigned char * g_pucOutMaskData = NULL, + * g_pucInData = NULL, + * g_pucOutData = NULL, + * g_pucHIRData = NULL, + * g_pucTIRData = NULL, + * g_pucHDRData = NULL, + * g_pucTDRData = NULL, + * g_pucIntelBuffer = NULL, + * g_pucOutDMaskData = NULL; + +/*************************************************************** + * + * JTAG state machine transition table. + * + ***************************************************************/ + +struct { + unsigned char CurState; /* From this state */ + unsigned char NextState; /* Step to this state */ + unsigned char Pattern; /* The tragetory of TMS */ + unsigned char Pulses; /* The number of steps */ +} g_JTAGTransistions[ 25 ] = { + { RESET, RESET, 0xFC, 6 }, /* Transitions from RESET */ + { RESET, IDLE, 0x00, 1 }, + { RESET, DRPAUSE, 0x50, 5 }, + { RESET, IRPAUSE, 0x68, 6 }, + { IDLE, RESET, 0xE0, 3 }, /* Transitions from IDLE */ + { IDLE, DRPAUSE, 0xA0, 4 }, + { IDLE, IRPAUSE, 0xD0, 5 }, + { DRPAUSE, RESET, 0xF8, 5 }, /* Transitions from DRPAUSE */ + { DRPAUSE, IDLE, 0xC0, 3 }, + { DRPAUSE, IRPAUSE, 0xF4, 7 }, + { DRPAUSE, DRPAUSE, 0xE8, 6 }, /* 06/14/06 Support POLING STATUS LOOP*/ + { IRPAUSE, RESET, 0xF8, 5 }, /* Transitions from IRPAUSE */ + { IRPAUSE, IDLE, 0xC0, 3 }, + { IRPAUSE, DRPAUSE, 0xE8, 6 }, + { DRPAUSE, SHIFTDR, 0x80, 2 }, /* Extra transitions using SHIFTDR */ + { IRPAUSE, SHIFTDR, 0xE0, 5 }, + { SHIFTDR, DRPAUSE, 0x80, 2 }, + { SHIFTDR, IDLE, 0xC0, 3 }, + { IRPAUSE, SHIFTIR, 0x80, 2 }, /* Extra transitions using SHIFTIR */ + { SHIFTIR, IRPAUSE, 0x80, 2 }, + { SHIFTIR, IDLE, 0xC0, 3 }, + { DRPAUSE, DRCAPTURE, 0xE0, 4 }, /* 11/15/05 Support DRCAPTURE*/ + { DRCAPTURE, DRPAUSE, 0x80, 2 }, + { IDLE, DRCAPTURE, 0x80, 2 }, + { IRPAUSE, DRCAPTURE, 0xE0, 4 } +}; + +/*************************************************************** + * + * List to hold all LVDS pairs. + * + ***************************************************************/ + +LVDSPair * g_pLVDSList = NULL; +unsigned short g_usLVDSPairCount = 0; + +/*************************************************************** + * + * Function prototypes. + * + ***************************************************************/ + +signed char ispVMCode(); +signed char ispVMDataCode(); +long int ispVMDataSize(); +void ispVMData( unsigned char * Data ); +signed char ispVMShift( signed char Code ); +signed char ispVMAmble( signed char Code ); +signed char ispVMLoop( unsigned short a_usLoopCount ); +signed char ispVMBitShift( signed char mode, unsigned short bits ); +void ispVMComment( unsigned short a_usCommentSize ); +void ispVMHeader( unsigned short a_usHeaderSize ); +signed char ispVMLCOUNT( unsigned short a_usCountSize ); +void ispVMClocks( unsigned short Clocks ); +void ispVMBypass( signed char ScanType, unsigned short Bits ); +void ispVMStateMachine( signed char NextState ); +void ispVMStart(); +void ispVMEnd(); +signed char ispVMSend(unsigned short int); +signed char ispVMRead(unsigned short int); +signed char ispVMReadandSave(unsigned short int); +signed char ispVMProcessLVDS( unsigned short a_usLVDSCount ); + + +/*************************************************************** + * + * External variables and functions in ispvm_ui.c module + * + ***************************************************************/ +extern void vme_out_char(unsigned char charOut); +extern void vme_out_hex(unsigned char hexOut); +extern void vme_out_string(char *stringOut); +extern unsigned char GetByte(); +extern void ispVMMemManager( signed char types, unsigned short size ); + +/*************************************************************** + * + * External variables and functions in hardware.c module + * + ***************************************************************/ +extern void ispVMDelay( unsigned short int a_usMicroSecondDelay ); +extern unsigned char readPort(); +extern void writePort( unsigned long pins, unsigned char value ); +extern void sclock(); +extern signed char g_cCurrentJTAGState; +extern const unsigned long g_ucPinTDI; +extern const unsigned long g_ucPinTCK; +extern const unsigned long g_ucPinTMS; +extern const unsigned long g_ucPinENABLE; +extern const unsigned long g_ucPinTRST; +extern const unsigned long g_ucPinTDO; + +#ifdef VME_DEBUG + +/*************************************************************** + * + * GetState + * + * Returns the state as a string based on the opcode. Only used + * for debugging purposes. + * + ***************************************************************/ + +const char * GetState( unsigned char a_ucState ) +{ + switch( a_ucState ) { + case RESET: + return( "RESET" ); + case IDLE: + return( "IDLE" ); + case IRPAUSE: + return( "IRPAUSE" ); + case DRPAUSE: + return( "DRPAUSE" ); + case SHIFTIR: + return( "SHIFTIR" ); + case SHIFTDR: + return( "SHIFTDR" ); + case DRCAPTURE:/* 11/15/05 support DRCAPTURE*/ + return( "DRCAPTURE" ); + default: + break; + } + + return 0; +} + +/*************************************************************** + * + * PrintData + * + * Prints the data. Only used for debugging purposes. + * + ***************************************************************/ + +void PrintData( unsigned short a_iDataSize, unsigned char * a_pucData ) +{ + //09/11/07 NN added local variables initialization + unsigned short usByteSize = 0; + unsigned short usBitIndex = 0; + signed short usByteIndex = 0; + unsigned char ucByte = 0; + unsigned char ucFlipByte = 0; + + if ( a_iDataSize % 8 ) { + //09/11/07 NN Type cast mismatch variables + usByteSize = (unsigned short)(a_iDataSize / 8 + 1); + } + else { + //09/11/07 NN Type cast mismatch variables + usByteSize = (unsigned short)(a_iDataSize / 8); + } + printf( "(" ); + //09/11/07 NN Type cast mismatch variables + for ( usByteIndex = (signed short)(usByteSize - 1); usByteIndex >= 0; usByteIndex-- ) { + ucByte = a_pucData[ usByteIndex ]; + ucFlipByte = 0x00; + + /*************************************************************** + * + * Flip each byte. + * + ***************************************************************/ + + for ( usBitIndex = 0; usBitIndex < 8; usBitIndex++ ) { + ucFlipByte <<= 1; + if ( ucByte & 0x1) { + ucFlipByte |= 0x1; + } + + ucByte >>= 1; + } + + /*************************************************************** + * + * Print the flipped byte. + * + ***************************************************************/ + + printf( "%.02X", ucFlipByte ); + if ( ( usByteSize - usByteIndex ) % 40 == 39 ) { + printf( "\n\t\t" ); + } + if(usByteIndex < 0) + break; + } + printf( ")" ); +} +#endif //VME_DEBUG + +/*************************************************************** + * + * ispVMDataSize + * + * Returns a VME-encoded number, usually used to indicate the + * bit length of an SIR/SDR command. + * + ***************************************************************/ + +long int ispVMDataSize() +{ + //09/11/07 NN added local variables initialization + long int iSize = 0; + signed char cCurrentByte = 0; + signed char cIndex = 0; + cIndex = 0; + while ( ( cCurrentByte = GetByte() ) & 0x80 ) { + iSize |= ( ( long int ) ( cCurrentByte & 0x7F ) ) << cIndex; + cIndex += 7; + } + iSize |= ( ( long int ) ( cCurrentByte & 0x7F ) ) << cIndex; + return iSize; +} + +/*************************************************************** + * + * ispVMCode + * + * This is the heart of the embedded engine. All the high-level opcodes + * are extracted here. Once they have been identified, then it + * will call other functions to handle the processing. + * + ***************************************************************/ + +signed char ispVMCode() +{ + //09/11/07 NN added local variables initialization + unsigned short iRepeatSize = 0; + signed char cOpcode = 0; + signed char cRetCode = 0; + unsigned char ucState = 0; + unsigned short usDelay = 0; + unsigned short usToggle = 0; + unsigned char usByte = 0; + + /*************************************************************** + * + * Check the compression flag only if this is the first time + * this function is entered. Do not check the compression flag if + * it is being called recursively from other functions within + * the embedded engine. + * + ***************************************************************/ + + if ( !( g_usDataType & LHEAP_IN ) && !( g_usDataType & HEAP_IN ) ) { + usByte = GetByte(); + if ( usByte == 0xf1 ) { + g_usDataType |= COMPRESS; + } + else if ( usByte == 0xf2 ) { + g_usDataType &= ~COMPRESS; + } + else { + return VME_INVALID_FILE; + } + } + + /*************************************************************** + * + * Begin looping through all the VME opcodes. + * + ***************************************************************/ + + while ( ( cOpcode = GetByte() ) >= 0 ) { + + switch ( cOpcode ) { + case STATE: + + /*************************************************************** + * + * Step the JTAG state machine. + * + ***************************************************************/ + + ucState = GetByte(); + + /*************************************************************** + * + * Step the JTAG state machine to DRCAPTURE to support Looping. + * + ***************************************************************/ + + if ( (g_usDataType & LHEAP_IN) && + (ucState == DRPAUSE ) && + ( g_cCurrentJTAGState == ucState )) + { + ispVMStateMachine( DRCAPTURE ); + } + + ispVMStateMachine( ucState ); + +#ifdef VME_DEBUG + if ( g_usDataType & LHEAP_IN ) { + printf( "LDELAY %s ", GetState( ucState ) ); + } + else { + printf( "STATE %s;\n", GetState( ucState ) ); + } +#endif //VME_DEBUG + break; + case SIR: + case SDR: + case XSDR: + +#ifdef VME_DEBUG + switch( cOpcode ) { + case SIR: + printf( "SIR " ); + break; + case SDR: + case XSDR: + if ( g_usDataType & LHEAP_IN ) { + printf( "LSDR " ); + } + else { + printf( "SDR " ); + } + break; + } +#endif //VME_DEBUG + /*************************************************************** + * + * Shift in data into the device. + * + ***************************************************************/ + + cRetCode = ispVMShift( cOpcode ); + if ( cRetCode != 0 ) { + return ( cRetCode ); + } + break; + case WAIT: + + /*************************************************************** + * + * Observe delay. + * + ***************************************************************/ + + //09/11/07 NN Type cast mismatch variables + usDelay = (unsigned short) ispVMDataSize(); + ispVMDelay( usDelay ); + +#ifdef VME_DEBUG + if ( usDelay & 0x8000 ) { + + /*************************************************************** + * + * Since MSB is set, the delay time must be decoded to + * millisecond. The SVF2VME encodes the MSB to represent + * millisecond. + * + ***************************************************************/ + + usDelay &= ~0x8000; + if ( g_usDataType & LHEAP_IN ) { + printf( "%.2E SEC;\n", ( float ) usDelay / 1000 ); + } + else { + printf( "RUNTEST %.2E SEC;\n", ( float ) usDelay / 1000 ); + } + } + else { + + /*************************************************************** + * + * Since MSB is not set, the delay time is given as microseconds. + * + ***************************************************************/ + + if ( g_usDataType & LHEAP_IN ) { + printf( "%.2E SEC;\n", ( float ) usDelay / 1000000 ); + } + else { + printf( "RUNTEST %.2E SEC;\n", ( float ) usDelay / 1000000 ); + } + } +#endif //VME_DEBUG + break; + case TCK: + + /*************************************************************** + * + * Issue clock toggles. + * + ***************************************************************/ + + //09/11/07 NN Type cast mismatch variables + usToggle = (unsigned short) ispVMDataSize(); + ispVMClocks( usToggle ); + +#ifdef VME_DEBUG + printf( "RUNTEST %d TCK;\n", usToggle ); +#endif //VME_DEBUG + break; + case ENDDR: + + /*************************************************************** + * + * Set the ENDDR. + * + ***************************************************************/ + + g_ucEndDR = GetByte(); + +#ifdef VME_DEBUG + printf( "ENDDR %s;\n", GetState( g_ucEndDR ) ); +#endif //VME_DEBUG + break; + case ENDIR: + + /*************************************************************** + * + * Set the ENDIR. + * + ***************************************************************/ + + g_ucEndIR = GetByte(); + +#ifdef VME_DEBUG + printf( "ENDIR %s;\n", GetState( g_ucEndIR ) ); +#endif //VME_DEBUG + break; + case HIR: + case TIR: + case HDR: + case TDR: + +#ifdef VME_DEBUG + switch( cOpcode ) { + case HIR: + printf( "HIR " ); + break; + case TIR: + printf( "TIR " ); + break; + case HDR: + printf( "HDR " ); + break; + case TDR: + printf( "TDR " ); + break; + } +#endif //VME_DEBUG + + /*************************************************************** + * + * Set the header/trailer of the device in order to bypass + * successfully. + * + ***************************************************************/ + + cRetCode = ispVMAmble( cOpcode ); + if ( cRetCode != 0 ) { + return ( cRetCode ); + } + +#ifdef VME_DEBUG + printf( ";\n" ); +#endif //VME_DEBUG + break; + case MEM: + + /*************************************************************** + * + * The maximum RAM required to support processing one row of the + * VME file. + * + ***************************************************************/ + + //09/11/07 NN Type cast mismatch variables + g_usMaxSize = (unsigned short) ispVMDataSize(); + +#ifdef VME_DEBUG + printf( "// MEMSIZE %d\n", g_usMaxSize ); +#endif //VME_DEBUG + break; + case VENDOR: + + /*************************************************************** + * + * Set the VENDOR type. + * + ***************************************************************/ + + cOpcode = GetByte(); + switch ( cOpcode ) { + case LATTICE: +#ifdef VME_DEBUG + printf( "// VENDOR LATTICE\n" ); +#endif //VME_DEBUG + g_cVendor = LATTICE; + break; + case ALTERA: +#ifdef VME_DEBUG + printf( "// VENDOR ALTERA\n" ); +#endif //VME_DEBUG + g_cVendor = ALTERA; + break; + case XILINX: +#ifdef VME_DEBUG + printf( "// VENDOR XILINX\n" ); +#endif //VME_DEBUG + g_cVendor = XILINX; + break; + default: + break; + } + break; + case SETFLOW: + + /*************************************************************** + * + * Set the flow control. Flow control determines the personality + * of the embedded engine. + * + ***************************************************************/ + + //09/11/07 NN Type cast mismatch variables + g_usFlowControl |= (unsigned short) ispVMDataSize(); + break; + case RESETFLOW: + + /*************************************************************** + * + * Unset the flow control. + * + ***************************************************************/ + + //09/11/07 NN Type cast mismatch variables + g_usFlowControl &= (unsigned short) ~( ispVMDataSize() ); + break; + case HEAP: + + /*************************************************************** + * + * Allocate heap size to store loops. + * + ***************************************************************/ + + cRetCode = GetByte(); + if ( cRetCode != SECUREHEAP ) { + return VME_INVALID_FILE; + } + //09/11/07 NN Type cast mismatch variables + g_iHEAPSize = (unsigned short) ispVMDataSize(); + + /**************************************************************************** + * + * Store the maximum size of the HEAP buffer. Used to convert VME to HEX. + * + *****************************************************************************/ + + if ( g_iHEAPSize > g_usHeapSize ) { + g_usHeapSize = g_iHEAPSize; + } + + ispVMMemManager( HEAP, ( unsigned short ) g_iHEAPSize ); + break; + case REPEAT: + + /*************************************************************** + * + * Execute loops. + * + ***************************************************************/ + + g_usRepeatLoops = 0; + + //09/11/07 NN Type cast mismatch variables + iRepeatSize = (unsigned short) ispVMDataSize(); + + cRetCode = ispVMLoop( ( unsigned short ) iRepeatSize ); + if ( cRetCode != 0 ) { + return ( cRetCode ); + } + break; + case ENDLOOP: + + /*************************************************************** + * + * Exit point from processing loops. + * + ***************************************************************/ + + return ( cRetCode ); + case ENDVME: + + /*************************************************************** + * + * The only valid exit point that indicates end of programming. + * + ***************************************************************/ + + return ( cRetCode ); + case SHR: + + /*************************************************************** + * + * Right-shift address. + * + ***************************************************************/ + + g_usFlowControl |= SHIFTRIGHT; + + //09/11/07 NN Type cast mismatch variables + g_usShiftValue = (unsigned short) (g_usRepeatLoops * (unsigned short)GetByte()); + break; + case SHL: + + /*************************************************************** + * + * Left-shift address. + * + ***************************************************************/ + + g_usFlowControl |= SHIFTLEFT; + + //09/11/07 NN Type cast mismatch variables + g_usShiftValue = (unsigned short)(g_usRepeatLoops * (unsigned short)GetByte()); + break; + case FREQUENCY: + + /*************************************************************** + * + * Set the frequency. + * + ***************************************************************/ + + //09/11/07 NN Type cast mismatch variables + g_iFrequency = (int) (ispVMDataSize() ); + //10/23/08 NN changed to check if the frequency smaller than 1000 + if(g_iFrequency >= 1000) + { + g_iFrequency = g_iFrequency / 1000; + if(g_iFrequency == 1) + g_iFrequency = 1000; +#ifdef VME_DEBUG + printf( "FREQUENCY %.2E HZ;\n", ( float ) g_iFrequency * 1000 ); +#endif //VME_DEBUG + } + else + { + if(g_iFrequency == 0) + g_iFrequency = 1000; +#ifdef VME_DEBUG + printf( "FREQUENCY %.2E HZ;\n", ( float ) g_iFrequency ); +#endif //VME_DEBUG + } + break; + case LCOUNT: + + /*************************************************************** + * + * Process LCOUNT command. + * + ***************************************************************/ + + cRetCode = ispVMLCOUNT( ( unsigned short ) ispVMDataSize() ); + if ( cRetCode != 0 ) { + return ( cRetCode ); + } + break; + case VUES: + + /*************************************************************** + * + * Set the flow control to verify USERCODE. + * + ***************************************************************/ + + g_usFlowControl |= VERIFYUES; + break; + case COMMENT: + + /*************************************************************** + * + * Display comment. + * + ***************************************************************/ + + ispVMComment( ( unsigned short ) ispVMDataSize() ); + break; + case LVDS: + + /*************************************************************** + * + * Process LVDS command. + * + ***************************************************************/ + + ispVMProcessLVDS( ( unsigned short ) ispVMDataSize() ); + break; + case HEADER: + + /*************************************************************** + * + * Discard header. + * + ***************************************************************/ + + ispVMHeader( ( unsigned short ) ispVMDataSize() ); + break; + /* 03/14/06 Support Toggle ispENABLE signal*/ + case ispEN: + ucState = GetByte(); + if((ucState == ON)||(ucState == 0x01)) + writePort( g_ucPinENABLE, 0x01 ); + else + writePort( g_ucPinENABLE, 0x00 ); + ispVMDelay( 1 ); + break; + /* 05/24/06 support Toggle TRST pin*/ + case TRST: + ucState = GetByte(); + if(ucState == 0x01) + writePort( g_ucPinTRST, 0x01 ); + else + writePort( g_ucPinTRST, 0x00 ); + ispVMDelay( 1 ); + break; + default: + + /*************************************************************** + * + * Invalid opcode encountered. + * + ***************************************************************/ + +#ifdef VME_DEBUG + printf( "\nINVALID OPCODE: 0x%.2X\n", cOpcode ); +#endif //VME_DEBUG + + return VME_INVALID_FILE; + } + } + + /*************************************************************** + * + * Invalid exit point. Processing the token 'ENDVME' is the only + * valid way to exit the embedded engine. + * + ***************************************************************/ + + return ( VME_INVALID_FILE ); +} + +/*************************************************************** + * + * ispVMDataCode + * + * Processes the TDI/TDO/MASK/DMASK etc of an SIR/SDR command. + * + ***************************************************************/ + +signed char ispVMDataCode() +{ + //09/11/07 NN added local variables initialization + signed char cDataByte = 0; + signed char siDataSource = 0; /*source of data from file by default*/ + + if ( g_usDataType & HEAP_IN ) { + siDataSource = 1; /*the source of data from memory*/ + } + + /**************************************************************************** + * + * Clear the data type register. + * + *****************************************************************************/ + + g_usDataType &= ~( MASK_DATA + TDI_DATA + TDO_DATA + DMASK_DATA + CMASK_DATA ); + + /**************************************************************************** + * + * Iterate through SIR/SDR command and look for TDI, TDO, MASK, etc. + * + *****************************************************************************/ + + while ( ( cDataByte = GetByte() ) >= 0 ) { + + ispVMMemManager( cDataByte, g_usMaxSize ); + switch ( cDataByte ) { + case TDI: + + /**************************************************************************** + * + * Store the maximum size of the TDI buffer. Used to convert VME to HEX. + * + *****************************************************************************/ + + if ( g_usiDataSize > g_usTDISize ) { + g_usTDISize = g_usiDataSize; + } + /**************************************************************************** + * + * Updated data type register to indicate that TDI data is currently being + * used. Process the data in the VME file into the TDI buffer. + * + *****************************************************************************/ + + g_usDataType |= TDI_DATA; + ispVMData( g_pucInData ); + break; + case XTDO: + + /**************************************************************************** + * + * Store the maximum size of the TDO buffer. Used to convert VME to HEX. + * + *****************************************************************************/ + + if ( g_usiDataSize > g_usTDOSize ) { + g_usTDOSize = g_usiDataSize; + } + + /**************************************************************************** + * + * Updated data type register to indicate that TDO data is currently being + * used. + * + *****************************************************************************/ + + g_usDataType |= TDO_DATA; + break; + case TDO: + + /**************************************************************************** + * + * Store the maximum size of the TDO buffer. Used to convert VME to HEX. + * + *****************************************************************************/ + + if ( g_usiDataSize > g_usTDOSize ) { + g_usTDOSize = g_usiDataSize; + } + + /**************************************************************************** + * + * Updated data type register to indicate that TDO data is currently being + * used. Process the data in the VME file into the TDO buffer. + * + *****************************************************************************/ + + g_usDataType |= TDO_DATA; + ispVMData( g_pucOutData ); + break; + case MASK: + + /**************************************************************************** + * + * Store the maximum size of the MASK buffer. Used to convert VME to HEX. + * + *****************************************************************************/ + + if ( g_usiDataSize > g_usMASKSize ) { + g_usMASKSize = g_usiDataSize; + } + + /**************************************************************************** + * + * Updated data type register to indicate that MASK data is currently being + * used. Process the data in the VME file into the MASK buffer. + * + *****************************************************************************/ + + g_usDataType |= MASK_DATA; + ispVMData( g_pucOutMaskData ); + break; + case DMASK: + + /**************************************************************************** + * + * Store the maximum size of the DMASK buffer. Used to convert VME to HEX. + * + *****************************************************************************/ + + if ( g_usiDataSize > g_usDMASKSize ) { + g_usDMASKSize = g_usiDataSize; + } + + /**************************************************************************** + * + * Updated data type register to indicate that DMASK data is currently being + * used. Process the data in the VME file into the DMASK buffer. + * + *****************************************************************************/ + + g_usDataType |= DMASK_DATA; + ispVMData( g_pucOutDMaskData ); + break; + case CMASK: + + /**************************************************************************** + * + * Updated data type register to indicate that CMASK data is currently being + * used. Process the data in the VME file into the CMASK buffer. + * + *****************************************************************************/ + + g_usDataType |= CMASK_DATA; + ispVMData( g_pucOutMaskData ); + break; + case CONTINUE: + return ( 0 ); + default: + + /**************************************************************************** + * + * Encountered invalid opcode. + * + *****************************************************************************/ + + return ( VME_INVALID_FILE ); + } + + switch ( cDataByte ) { + case TDI: + + /**************************************************************************** + * + * Left bit shift. Used when performing algorithm looping. + * + *****************************************************************************/ + + if ( g_usFlowControl & SHIFTLEFT ) { + ispVMBitShift( SHL, g_usShiftValue ); + g_usFlowControl &= ~SHIFTLEFT; + } + + /**************************************************************************** + * + * Right bit shift. Used when performing algorithm looping. + * + *****************************************************************************/ + + if ( g_usFlowControl & SHIFTRIGHT ) { + ispVMBitShift( SHR, g_usShiftValue ); + g_usFlowControl &= ~SHIFTRIGHT; + } + default: + break; + } + + if ( siDataSource ) { + g_usDataType |= HEAP_IN; /*restore data from memory*/ + } + } + + if ( siDataSource ) { /*fetch data from heap memory upon return*/ + g_usDataType |= HEAP_IN; + } + + if ( cDataByte < 0 ) { + + /**************************************************************************** + * + * Encountered invalid opcode. + * + *****************************************************************************/ + + return ( VME_INVALID_FILE ); + } + else { + return ( 0 ); + } +} + +/*************************************************************** + * + * ispVMData + * Extract one row of data operand from the current data type opcode. Perform + * the decompression if necessary. Extra RAM is not required for the + * decompression process. The decompression scheme employed in this module + * is on row by row basis. The format of the data stream: + * [compression code][compressed data stream] + * 0x00 --No compression + * 0x01 --Compress by 0x00. + * Example: + * Original stream: 0x000000000000000000000001 + * Compressed stream: 0x01000901 + * Detail: 0x01 is the code, 0x00 is the key, + * 0x09 is the count of 0x00 bytes, + * 0x01 is the uncompressed byte. + * 0x02 --Compress by 0xFF. + * Example: + * Original stream: 0xFFFFFFFFFFFFFFFFFFFFFF01 + * Compressed stream: 0x02FF0901 + * Detail: 0x02 is the code, 0xFF is the key, + * 0x09 is the count of 0xFF bytes, + * 0x01 is the uncompressed byte. + * 0x03 + * : : + * 0xFE -- Compress by nibble blocks. + * Example: + * Original stream: 0x84210842108421084210 + * Compressed stream: 0x0584210 + * Detail: 0x05 is the code, means 5 nibbles block. + * 0x84210 is the 5 nibble blocks. + * The whole row is 80 bits given by g_usiDataSize. + * The number of times the block repeat itself + * is found by g_usiDataSize/(4*0x05) which is 4. + * 0xFF -- Compress by the most frequently happen byte. + * Example: + * Original stream: 0x04020401030904040404 + * Compressed stream: 0xFF04(0,1,0x02,0,1,0x01,1,0x03,1,0x09,0,0,0) + * or: 0xFF044090181C240 + * Detail: 0xFF is the code, 0x04 is the key. + * a bit of 0 represent the key shall be put into + * the current bit position and a bit of 1 + * represent copying the next of 8 bits of data + * in. + * + ***************************************************************/ + +void ispVMData( unsigned char * ByteData ) +{ + //09/11/07 NN added local variables initialization + unsigned short size = 0; + unsigned short i, j, m, getData = 0; + unsigned char cDataByte = 0; + unsigned char compress = 0; + unsigned short FFcount = 0; + unsigned char compr_char = 0xFF; + unsigned short index = 0; + signed char compression = 0; + + /*convert number in bits to bytes*/ + if (g_usiDataSize%8>0) { + //09/11/07 NN Type cast mismatch variables + size = (unsigned short)(g_usiDataSize/8 + 1); + } + else { + //09/11/07 NN Type cast mismatch variables + size = (unsigned short)(g_usiDataSize/8); + } + + /* If there is compression, then check if compress by key of 0x00 or 0xFF + or by other keys or by nibble blocks*/ + + if ( g_usDataType & COMPRESS ) { + compression = 1; + if ( ( ( compress = GetByte() ) == VAR ) && ( g_usDataType & HEAP_IN ) ) { + getData = 1; + g_usDataType &= ~(HEAP_IN); + compress = GetByte(); + } + + switch (compress){ + case 0x00: + /* No compression */ + compression = 0; + break; + case 0x01: + /* Compress by byte 0x00 */ + compr_char = 0x00; + break; + case 0x02: + /* Compress by byte 0xFF */ + compr_char = 0xFF; + break; + case 0xFF: + /* Huffman encoding */ + compr_char = GetByte(); + i = 8; + for ( index = 0; index < size; index++ ) { + ByteData[ index ] = 0x00; + if ( i > 7 ) { + cDataByte = GetByte(); + i = 0; + } + if ((cDataByte << i++) & 0x80) + m = 8; + else { + ByteData[index] = compr_char; + m = 0; + } + + for (j = 0; j < m; j++) { + if (i > 7) { + cDataByte = GetByte(); + i = 0; + } + ByteData[index] |=((cDataByte << i++)&0x80) >> j; + } + } + size = 0; + break; + default: + for (index = 0; index < size; index++) + ByteData[index] = 0x00; + for (index = 0; index < compress; index++) { + if (index%2 == 0) + cDataByte = GetByte(); + for (i = 0; i < size*2/compress; i++){ + //09/11/07 NN Type cast mismatch variables + j = (unsigned short)(index + (i*(unsigned short)compress)); + /*clear the nibble to zero first*/ + if (j%2) { + if (index%2) + ByteData[j/2] |= cDataByte & 0x0F; + else + ByteData[j/2] |= cDataByte >> 4; + } + else { + if (index%2) + ByteData[j/2] |= cDataByte << 4; + else + ByteData[j/2] |= cDataByte & 0xF0; + } + } + } + size = 0; + break; + } + } + + FFcount = 0; + + /* Decompress by byte 0x00 or 0xFF */ + for (index = 0; index < size; index++) { + if (FFcount <= 0) { + cDataByte = GetByte(); + if ((cDataByte == VAR) && (g_usDataType&HEAP_IN) && !getData && !(g_usDataType&COMPRESS)) { + getData = 1; + g_usDataType &= ~(HEAP_IN); + cDataByte = GetByte(); + } + ByteData[index] = cDataByte; + if ((compression) &&(cDataByte == compr_char)) /*decompression is on*/ + //09/11/07 NN Type cast mismatch variables + FFcount = (unsigned short) ispVMDataSize(); /*The number of 0xFF or 0x00 bytes*/ + } + else { + FFcount--; /*Use up the 0xFF chain first*/ + ByteData[index] = compr_char; + } + } + + if (getData) { + g_usDataType |= HEAP_IN; + getData = 0; + } +} + +/*************************************************************** + * + * ispVMShift + * + * Processes the SDR/XSDR/SIR commands. + * + ***************************************************************/ + +signed char ispVMShift( signed char a_cCode ) +{ + //09/11/07 NN added local variables initialization + unsigned short iDataIndex = 0; + unsigned short iReadLoop = 0; + signed char cRetCode = 0; + + cRetCode=0; + //09/11/07 NN Type cast mismatch variables + g_usiDataSize = (unsigned short) ispVMDataSize(); + + g_usDataType &= ~( SIR_DATA + EXPRESS + SDR_DATA ); /*clear the flags first*/ + switch ( a_cCode ) { + case SIR: + g_usDataType |= SIR_DATA; + /* 1/15/04 If performing cascading, then go directly to SHIFTIR. Else, + go to IRPAUSE before going to SHIFTIR */ + if ( g_usFlowControl & CASCADE ) { + ispVMStateMachine( SHIFTIR ); + } + else { + ispVMStateMachine( IRPAUSE ); + ispVMStateMachine( SHIFTIR ); + if ( g_usHeadIR > 0 ){ + ispVMBypass( HIR, g_usHeadIR ); + sclock(); + } + } + break; + case XSDR: + g_usDataType |= EXPRESS; /*mark simultaneous in and out*/ + /* FALLTHRU */ + case SDR: + g_usDataType |= SDR_DATA; + /* 1/15/04 If already in SHIFTDR, then do not move state or shift in header. + This would imply that the previously shifted frame was a cascaded frame. */ + if ( g_cCurrentJTAGState != SHIFTDR ) { + /* 1/15/04 If performing cascading, then go directly to SHIFTDR. Else, + go to DRPAUSE before going to SHIFTDR */ + if ( g_usFlowControl & CASCADE ) { + if ( g_cCurrentJTAGState == DRPAUSE ) { + ispVMStateMachine( SHIFTDR ); + /* 1/15/04 If cascade flag has been set and the current state is + DRPAUSE, this implies that the first cascaded frame is about to + be shifted in. The header must be shifted prior to shifting + the first cascaded frame. */ + if ( g_usHeadDR > 0 ) { + ispVMBypass( HDR, g_usHeadDR ); + sclock(); + } + } + else { + ispVMStateMachine( SHIFTDR ); + } + } + else { + ispVMStateMachine( DRPAUSE ); + ispVMStateMachine( SHIFTDR ); + if ( g_usHeadDR > 0 ) { + ispVMBypass( HDR, g_usHeadDR ); + sclock(); + } + } + } + break; + default: + return ( VME_INVALID_FILE ); + } + + cRetCode = ispVMDataCode(); + + if ( cRetCode != 0 ) { + return ( VME_INVALID_FILE ); + } + +#ifdef VME_DEBUG + printf( "%d ", g_usiDataSize ); + + if ( g_usDataType & TDI_DATA ) { + printf( "TDI " ); + PrintData( g_usiDataSize, g_pucInData ); + } + + if ( g_usDataType & TDO_DATA ) { + printf( "\n\t\tTDO " ); + PrintData( g_usiDataSize, g_pucOutData ); + } + + if ( g_usDataType & MASK_DATA ) { + printf( "\n\t\tMASK " ); + PrintData( g_usiDataSize, g_pucOutMaskData ); + } + + if ( g_usDataType & DMASK_DATA ) { + printf( "\n\t\tDMASK " ); + PrintData( g_usiDataSize, g_pucOutDMaskData ); + } + + printf( ";\n" ); +#endif //VME_DEBUG + + if ( g_usDataType & TDO_DATA || g_usDataType & DMASK_DATA ) { + if(g_usDataType & DMASK_DATA){ + cRetCode = ispVMReadandSave( g_usiDataSize ); + if(!cRetCode){ + if ( g_usTailDR > 0 ) { + sclock(); + ispVMBypass( TDR, g_usTailDR ); + } + ispVMStateMachine( DRPAUSE ); + ispVMStateMachine( SHIFTDR ); + if( g_usHeadDR > 0 ){ + ispVMBypass( HDR, g_usHeadDR ); + sclock(); + } + for ( iDataIndex=0; iDataIndex < g_usiDataSize / 8 + 1; iDataIndex++ ) + g_pucInData[ iDataIndex ] = g_pucOutData[ iDataIndex ]; + g_usDataType &= ~( TDO_DATA+ DMASK_DATA ); + cRetCode = ispVMSend( g_usiDataSize ); + } + } + else{ + cRetCode = ispVMRead( g_usiDataSize ); + if ( cRetCode == -1 && g_cVendor == XILINX ) { + for( iReadLoop = 0; iReadLoop < 30; iReadLoop++ ){ + cRetCode = ispVMRead( g_usiDataSize ); + if( !cRetCode ) { + break; + } + else { + ispVMStateMachine( DRPAUSE ); /*Always DRPAUSE*/ + /*Bypass other devices when appropriate*/ + ispVMBypass( TDR, g_usTailDR ); + ispVMStateMachine( g_ucEndDR ); + ispVMStateMachine( IDLE ); + ispVMDelay( 0x8001 ); + } + } + } + } + } + else { /*TDI only*/ + cRetCode = ispVMSend( g_usiDataSize ); + } + + /*transfer the input data to the output buffer for the next verify*/ + if ( ( g_usDataType & EXPRESS ) || ( a_cCode == SDR ) ) { + if ( g_pucOutData ) { + for ( iDataIndex=0; iDataIndex < g_usiDataSize / 8 + 1; iDataIndex++ ) + g_pucOutData[ iDataIndex ] = g_pucInData[ iDataIndex ]; + } + } + + switch( a_cCode ) { + case SIR: + /* 1/15/04 If not performing cascading, then shift ENDIR */ + if ( !( g_usFlowControl & CASCADE ) ) { + if ( g_usTailIR > 0 ) { + sclock(); + ispVMBypass( TIR, g_usTailIR ); + } + ispVMStateMachine( g_ucEndIR ); + } + break; + case XSDR: + case SDR: + /* 1/15/04 If not performing cascading, then shift ENDDR */ + if ( !( g_usFlowControl & CASCADE ) ) { + if ( g_usTailDR > 0 ) { + sclock(); + ispVMBypass( TDR, g_usTailDR ); + } + ispVMStateMachine( g_ucEndDR ); + } + break; + default: + break; + } + + return ( cRetCode ); +} + +/*************************************************************** + * + * ispVMAmble + * + * This routine is to extract Header and Trailer parameter for SIR and + * SDR operations. + * + * The Header and Trailer parameter are the pre-amble and post-amble bit + * stream need to be shifted into TDI or out of TDO of the devices. Mostly + * is for the purpose of bypassing the leading or trailing devices. ispVM + * supports only shifting data into TDI to bypass the devices. + * + * For a single device, the header and trailer parameters are all set to 0 + * as default by ispVM. If it is for multiple devices, the header and trailer + * value will change as specified by the VME file. + * + ***************************************************************/ + +signed char ispVMAmble( signed char Code ) +{ + signed char compress = 0; + //09/11/07 NN Type cast mismatch variables + g_usiDataSize = (unsigned short)ispVMDataSize(); + +#ifdef VME_DEBUG + printf( "%d", g_usiDataSize ); +#endif //VME_DEBUG + + if ( g_usiDataSize ) { + + /**************************************************************************** + * + * Discard the TDI byte and set the compression bit in the data type register + * to false if compression is set because TDI data after HIR/HDR/TIR/TDR is not + * compressed. + * + *****************************************************************************/ + + GetByte(); + if ( g_usDataType & COMPRESS ) { + g_usDataType &= ~( COMPRESS ); + compress = 1; + } + } + + switch ( Code ) { + case HIR: + + /**************************************************************************** + * + * Store the maximum size of the HIR buffer. Used to convert VME to HEX. + * + *****************************************************************************/ + + if ( g_usiDataSize > g_usHIRSize ) { + g_usHIRSize = g_usiDataSize; + } + + /**************************************************************************** + * + * Assign the HIR value and allocate memory. + * + *****************************************************************************/ + + g_usHeadIR = g_usiDataSize; + if ( g_usHeadIR ) { + ispVMMemManager( HIR, g_usHeadIR ); + ispVMData( g_pucHIRData ); + +#ifdef VME_DEBUG + printf( " TDI " ); + PrintData( g_usHeadIR, g_pucHIRData ); +#endif //VME_DEBUG + } + break; + case TIR: + + /**************************************************************************** + * + * Store the maximum size of the TIR buffer. Used to convert VME to HEX. + * + *****************************************************************************/ + + if ( g_usiDataSize > g_usTIRSize ) { + g_usTIRSize = g_usiDataSize; + } + + /**************************************************************************** + * + * Assign the TIR value and allocate memory. + * + *****************************************************************************/ + + g_usTailIR = g_usiDataSize; + if ( g_usTailIR ) { + ispVMMemManager( TIR, g_usTailIR ); + ispVMData( g_pucTIRData ); + +#ifdef VME_DEBUG + printf( " TDI " ); + PrintData( g_usTailIR, g_pucTIRData ); +#endif //VME_DEBUG + } + break; + case HDR: + + /**************************************************************************** + * + * Store the maximum size of the HDR buffer. Used to convert VME to HEX. + * + *****************************************************************************/ + + if ( g_usiDataSize > g_usHDRSize ) { + g_usHDRSize = g_usiDataSize; + } + + /**************************************************************************** + * + * Assign the HDR value and allocate memory. + * + *****************************************************************************/ + + g_usHeadDR = g_usiDataSize; + if ( g_usHeadDR ) { + ispVMMemManager( HDR, g_usHeadDR ); + ispVMData( g_pucHDRData ); + +#ifdef VME_DEBUG + printf( " TDI " ); + PrintData( g_usHeadDR, g_pucHDRData ); +#endif //VME_DEBUG + } + break; + case TDR: + + /**************************************************************************** + * + * Store the maximum size of the TDR buffer. Used to convert VME to HEX. + * + *****************************************************************************/ + + if ( g_usiDataSize > g_usTDRSize ) { + g_usTDRSize = g_usiDataSize; + } + + /**************************************************************************** + * + * Assign the TDR value and allocate memory. + * + *****************************************************************************/ + + g_usTailDR = g_usiDataSize; + if ( g_usTailDR ) { + ispVMMemManager( TDR, g_usTailDR ); + ispVMData( g_pucTDRData ); + +#ifdef VME_DEBUG + printf( " TDI " ); + PrintData( g_usTailDR, g_pucTDRData ); +#endif //VME_DEBUG + } + break; + default: + break; + } + + /**************************************************************************** + * + * Re-enable compression if it was previously set. + * + *****************************************************************************/ + + if ( compress ) { + g_usDataType |= COMPRESS; + } + + if ( g_usiDataSize ) { + Code = GetByte(); + if ( Code == CONTINUE ) { + return 0; + } + else { + + /**************************************************************************** + * + * Encountered invalid opcode. + * + *****************************************************************************/ + + return VME_INVALID_FILE; + } + } + + return 0; +} + +/*************************************************************** + * + * ispVMLoop + * + * Perform the function call upon by the REPEAT opcode. + * Memory is to be allocated to store the entire loop from REPEAT to ENDLOOP. + * After the loop is stored then execution begin. The REPEATLOOP flag is set + * on the g_usFlowControl register to indicate the repeat loop is in session + * and therefore fetch opcode from the memory instead of from the file. + * + ***************************************************************/ + +signed char ispVMLoop(unsigned short a_usLoopCount) +{ + //09/11/07 NN added local variables initialization + signed char cRetCode = 0; + unsigned short iHeapIndex = 0; + unsigned short iLoopIndex = 0; + + g_usShiftValue = 0; + for ( iHeapIndex = 0; iHeapIndex < g_iHEAPSize; iHeapIndex++ ) { + g_pucHeapMemory[ iHeapIndex ] = GetByte(); + } + + if ( g_pucHeapMemory[ iHeapIndex - 1 ] != ENDLOOP ) { + return( VME_INVALID_FILE ); + } + + g_usFlowControl |= REPEATLOOP; + g_usDataType |= HEAP_IN; + + for ( iLoopIndex = 0; iLoopIndex < a_usLoopCount; iLoopIndex++ ) { + g_iHeapCounter = 0; + cRetCode = ispVMCode(); + g_usRepeatLoops++; + if ( cRetCode < 0 ) { + break; + } + } + + g_usDataType &= ~( HEAP_IN ); + g_usFlowControl &= ~( REPEATLOOP ); + return ( cRetCode ); +} + +/*************************************************************** + * + * ispVMBitShift + * + * Shift the TDI stream left or right by the number of bits. The data in + * *g_pucInData is of the VME format, so the actual shifting is the reverse of + * IEEE 1532 or SVF format. + * + ***************************************************************/ + +signed char ispVMBitShift(signed char mode, unsigned short bits) +{ + //09/11/07 NN added local variables initialization + unsigned short i = 0; + unsigned short size = 0; + unsigned short tmpbits = 0; + + if (g_usiDataSize%8>0) { + //09/11/07 NN Type cast mismatch variables + size = (unsigned short)(g_usiDataSize/8 + 1); + } + else { + //09/11/07 NN Type cast mismatch variables + size = (unsigned short)(g_usiDataSize/8); + } + + switch(mode) { + case SHR: + for (i = 0; i < size; i++) { + if (g_pucInData[i] != 0) { + tmpbits = bits; + while (tmpbits > 0) { + g_pucInData[i] <<= 1; + if (g_pucInData[i] == 0) { + i--; + g_pucInData[i] = 1; + } + tmpbits--; + } + } + } + break; + case SHL: + for (i = 0; i < size; i++) { + if (g_pucInData[i] != 0) { + tmpbits = bits; + while (tmpbits > 0) { + g_pucInData[i] >>= 1; + if (g_pucInData[i] == 0) { + i--; + g_pucInData[i] = 8; + } + tmpbits--; + } + } + } + break; + default: + return ( VME_INVALID_FILE ); + } + + return (0); +} + +/*************************************************************** + * + * ispVMComment + * + * Displays the SVF comments. + * + ***************************************************************/ + +void ispVMComment( unsigned short a_usCommentSize ) +{ + char cCurByte = 0; + for ( ; a_usCommentSize > 0; a_usCommentSize-- ) { + /**************************************************************************** + * + * Print character to the terminal. + * + *****************************************************************************/ + cCurByte = GetByte(); + vme_out_char( cCurByte ); + } + cCurByte = '\n'; + vme_out_char(cCurByte ); +} + +/*************************************************************** + * + * ispVMHeader + * + * Iterate the length of the header and discard it. + * + ***************************************************************/ + +void ispVMHeader( unsigned short a_usHeaderSize ) +{ + for ( ; a_usHeaderSize > 0; a_usHeaderSize-- ) { + GetByte(); + } +} + +/*************************************************************** + * + * ispVMCalculateCRC32 + * + * Calculate the 32-bit CRC. + * + ***************************************************************/ + +void ispVMCalculateCRC32( unsigned char a_ucData ) +{ + //09/11/07 NN added local variables initialization + unsigned char ucIndex = 0; + unsigned char ucFlipData = 0; + unsigned short usCRCTableEntry = 0; + unsigned int crc_table[ 16 ] = { + 0x0000, 0xCC01, 0xD801, + 0x1400, 0xF001, 0x3C00, + 0x2800, 0xE401, 0xA001, + 0x6C00, 0x7800, 0xB401, + 0x5000, 0x9C01, 0x8801, + 0x4400 + }; + + for ( ucIndex = 0; ucIndex < 8; ucIndex++ ) { + ucFlipData <<= 1; + if ( a_ucData & 0x01 ) { + ucFlipData |= 0x01; + } + a_ucData >>= 1; + } + + //09/11/07 NN Type cast mismatch variables + usCRCTableEntry = (unsigned short)(crc_table[ g_usCalculatedCRC & 0xF ]); + g_usCalculatedCRC = (unsigned short)(( g_usCalculatedCRC >> 4 ) & 0x0FFF); + g_usCalculatedCRC = (unsigned short)(g_usCalculatedCRC ^ usCRCTableEntry ^ crc_table[ ucFlipData & 0xF ]); + usCRCTableEntry = (unsigned short)(crc_table[ g_usCalculatedCRC & 0xF ]); + g_usCalculatedCRC = (unsigned short)(( g_usCalculatedCRC >> 4 ) & 0x0FFF); + g_usCalculatedCRC = (unsigned short)(g_usCalculatedCRC ^ usCRCTableEntry ^ crc_table[ ( ucFlipData >> 4 ) & 0xF ]); +} + +/*************************************************************** + * + * ispVMLCOUNT + * + * Process the intelligent programming loops. + * + ***************************************************************/ + +signed char ispVMLCOUNT( unsigned short a_usCountSize ) +{ + unsigned short usContinue = 1; + unsigned short usIntelBufferIndex = 0; + unsigned short usCountIndex = 0; + signed char cRetCode = 0; + signed char cRepeatHeap = 0; + signed char cOpcode = 0; + unsigned char ucState = 0; + unsigned short usDelay = 0; + unsigned short usToggle = 0; + // unsigned char usByte = 0; + + g_usIntelBufferSize = (unsigned short)ispVMDataSize(); + + /**************************************************************************** + * + * Allocate memory for intel buffer. + * + *****************************************************************************/ + + ispVMMemManager( LHEAP, g_usIntelBufferSize ); + + /**************************************************************************** + * + * Store the maximum size of the intelligent buffer. Used to convert VME to HEX. + * + *****************************************************************************/ + + if ( g_usIntelBufferSize > g_usLCOUNTSize ) { + g_usLCOUNTSize = g_usIntelBufferSize; + } + + /**************************************************************************** + * + * Copy intel data to the buffer. + * + *****************************************************************************/ + + for ( usIntelBufferIndex = 0; usIntelBufferIndex < g_usIntelBufferSize; usIntelBufferIndex++ ) { + g_pucIntelBuffer[ usIntelBufferIndex ] = GetByte(); + } + + /**************************************************************************** + * + * Set the data type register to get data from the intelligent data buffer. + * + *****************************************************************************/ + + g_usDataType |= LHEAP_IN; + + /**************************************************************************** + * + * If the HEAP_IN flag is set, temporarily unset the flag so data will be + * retrieved from the status buffer. + * + *****************************************************************************/ + + if ( g_usDataType & HEAP_IN ) { + g_usDataType &= ~HEAP_IN; + cRepeatHeap = 1; + } + +#ifdef VME_DEBUG + printf( "LCOUNT %d;\n", a_usCountSize ); +#endif //VME_DEBUG + + /**************************************************************************** + * + * Iterate through the intelligent programming command. + * + *****************************************************************************/ + + for ( usCountIndex = 0; usCountIndex < a_usCountSize; usCountIndex++ ) { + + /**************************************************************************** + * + * Initialize the intel data index to 0 before each iteration. + * + *****************************************************************************/ + + g_usIntelDataIndex = 0; + cOpcode = 0; + ucState = 0; + usDelay = 0; + usToggle = 0; + // usByte = 0; + usContinue = 1; + + /*************************************************************** + * + * Begin looping through all the VME opcodes. + * + ***************************************************************/ + /*************************************************************** + * 4/1/09 Nguyen replaced the recursive function call codes on + * the ispVMLCOUNT function + * + ***************************************************************/ + while ( usContinue ) + { + cOpcode = GetByte(); + switch ( cOpcode ) { + case HIR: + case TIR: + case HDR: + case TDR: + /*************************************************************** + * + * Set the header/trailer of the device in order to bypass + * successfully. + * + ***************************************************************/ + + ispVMAmble( cOpcode ); + break; + case STATE: + + /*************************************************************** + * + * Step the JTAG state machine. + * + ***************************************************************/ + + ucState = GetByte(); + /*************************************************************** + * + * Step the JTAG state machine to DRCAPTURE to support Looping. + * + ***************************************************************/ + + if ( (g_usDataType & LHEAP_IN) && + (ucState == DRPAUSE ) && + ( g_cCurrentJTAGState == ucState )) + { + ispVMStateMachine( DRCAPTURE ); + } + ispVMStateMachine( ucState ); +#ifdef VME_DEBUG + printf( "LDELAY %s ", GetState( ucState ) ); +#endif //VME_DEBUG + break; + case SIR: +#ifdef VME_DEBUG + printf( "SIR " ); +#endif //VME_DEBUG + /*************************************************************** + * + * Shift in data into the device. + * + ***************************************************************/ + + cRetCode = ispVMShift( cOpcode ); + break; + case SDR: + +#ifdef VME_DEBUG + printf( "LSDR " ); +#endif //VME_DEBUG + /*************************************************************** + * + * Shift in data into the device. + * + ***************************************************************/ + + cRetCode = ispVMShift( cOpcode ); + break; + case WAIT: + + /*************************************************************** + * + * Observe delay. + * + ***************************************************************/ + + usDelay = (unsigned short)ispVMDataSize(); + ispVMDelay( usDelay ); + +#ifdef VME_DEBUG + if ( usDelay & 0x8000 ) { + + /*************************************************************** + * + * Since MSB is set, the delay time must be decoded to + * millisecond. The SVF2VME encodes the MSB to represent + * millisecond. + * + ***************************************************************/ + + usDelay &= ~0x8000; + printf( "%.2E SEC;\n", ( float ) usDelay / 1000 ); + } + else { + + /*************************************************************** + * + * Since MSB is not set, the delay time is given as microseconds. + * + ***************************************************************/ + + printf( "%.2E SEC;\n", ( float ) usDelay / 1000000 ); + } +#endif //VME_DEBUG + break; + case TCK: + + /*************************************************************** + * + * Issue clock toggles. + * + ***************************************************************/ + + usToggle = (unsigned short)ispVMDataSize(); + ispVMClocks( usToggle ); + +#ifdef VME_DEBUG + printf( "RUNTEST %d TCK;\n", usToggle ); +#endif //VME_DEBUG + break; + case ENDLOOP: + + /*************************************************************** + * + * Exit point from processing loops. + * + ***************************************************************/ + usContinue = 0; + break; + + case COMMENT: + + /*************************************************************** + * + * Display comment. + * + ***************************************************************/ + + ispVMComment( ( unsigned short ) ispVMDataSize() ); + break; + case ispEN: + ucState = GetByte(); + if((ucState == ON)||(ucState == 0x01)) + writePort( g_ucPinENABLE, 0x01 ); + else + writePort( g_ucPinENABLE, 0x00 ); + ispVMDelay( 1 ); + break; + case TRST: + if(GetByte() == 0x01) + writePort( g_ucPinTRST, 0x01 ); + else + writePort( g_ucPinTRST, 0x00 ); + ispVMDelay( 1 ); + break; + default: + + /*************************************************************** + * + * Invalid opcode encountered. + * + ***************************************************************/ + +#ifdef VME_DEBUG + printf( "\nINVALID OPCODE: 0x%.2X\n", cOpcode ); +#endif //VME_DEBUG + + return VME_INVALID_FILE; + } + } + if ( cRetCode >= 0 ) { + /**************************************************************************** + * + * Break if intelligent programming is successful. + * + *****************************************************************************/ + + break; + } + + } + /**************************************************************************** + * + * If HEAP_IN flag was temporarily disabled, re-enable it before exiting. + * + *****************************************************************************/ + + if ( cRepeatHeap ) { + g_usDataType |= HEAP_IN; + } + + /**************************************************************************** + * + * Set the data type register to not get data from the intelligent data buffer. + * + *****************************************************************************/ + + g_usDataType &= ~LHEAP_IN; + return cRetCode; +} + +/*************************************************************** + * + * ispVMClocks + * + * Applies the specified number of pulses to TCK. + * + ***************************************************************/ + +void ispVMClocks( unsigned short Clocks ) +{ + unsigned short iClockIndex = 0; + for ( iClockIndex = 0; iClockIndex < Clocks; iClockIndex++ ) { + sclock(); + } +} + +/*************************************************************** + * + * ispVMBypass + * + * This procedure takes care of the HIR, HDR, TIR, TDR for the + * purpose of putting the other devices into Bypass mode. The + * current state is checked to find out if it is at DRPAUSE or + * IRPAUSE. If it is at DRPAUSE, perform bypass register scan. + * If it is at IRPAUSE, scan into instruction registers the bypass + * instruction. + * + ***************************************************************/ + +void ispVMBypass( signed char ScanType, unsigned short Bits ) +{ + //09/11/07 NN added local variables initialization + unsigned short iIndex = 0; + unsigned short iSourceIndex = 0; + unsigned char cBitState = 0; + unsigned char cCurByte = 0; + unsigned char * pcSource = NULL; + + if ( Bits <= 0 ) { + return; + } + + switch ( ScanType ) { + case HIR: + pcSource = g_pucHIRData; + break; + case TIR: + pcSource = g_pucTIRData; + break; + case HDR: + pcSource = g_pucHDRData; + break; + case TDR: + pcSource = g_pucTDRData; + break; + default: + break; + } + if(pcSource) + { + iSourceIndex = 0; + cBitState = 0; + for ( iIndex = 0; iIndex < Bits - 1; iIndex++ ) { + /* Scan instruction or bypass register */ + if ( iIndex % 8 == 0 ) { + cCurByte = pcSource[ iSourceIndex++ ]; + } + cBitState = ( unsigned char ) ( ( ( cCurByte << iIndex % 8 ) & 0x80 ) ? 0x01 : 0x00 ); + writePort( g_ucPinTDI, cBitState ); + sclock(); + } + + if ( iIndex % 8 == 0 ) { + cCurByte = pcSource[ iSourceIndex++ ]; + } + + cBitState = ( unsigned char ) ( ( ( cCurByte << iIndex % 8 ) & 0x80 ) ? 0x01 : 0x00 ); + writePort( g_ucPinTDI, cBitState ); + } +} + +/*************************************************************** + * + * ispVMStateMachine + * + * This procedure steps all devices in the daisy chain from a given + * JTAG state to the next desirable state. If the next state is TLR, + * the JTAG state machine is brute forced into TLR by driving TMS + * high and pulse TCK 6 times. + * + ***************************************************************/ + +void ispVMStateMachine( signed char cNextJTAGState ) +{ + //09/11/07 NN added local variables initialization + signed char cPathIndex = 0; + signed char cStateIndex = 0; + short int found = 0; + + if ( ( g_cCurrentJTAGState == cNextJTAGState ) && ( cNextJTAGState != RESET ) ) { + return; + } + + for ( cStateIndex = 0; cStateIndex < 25; cStateIndex++ ) { + if ( ( g_cCurrentJTAGState == g_JTAGTransistions[ cStateIndex ].CurState ) && ( cNextJTAGState == g_JTAGTransistions[cStateIndex].NextState ) ) { + found = 1; + break; + } + } + if(found) + { + g_cCurrentJTAGState = cNextJTAGState; + for ( cPathIndex = 0; cPathIndex < g_JTAGTransistions[ cStateIndex ].Pulses; cPathIndex++ ) { + if ( ( g_JTAGTransistions[ cStateIndex ].Pattern << cPathIndex ) & 0x80 ) { + writePort( g_ucPinTMS, ( unsigned char ) 0x01 ); + } + else { + writePort( g_ucPinTMS, ( unsigned char ) 0x00 ); + } + sclock(); + } + + writePort( g_ucPinTDI, 0x00 ); + writePort( g_ucPinTMS, 0x00 ); + } +} + +/*************************************************************** + * + * ispVMStart + * + * Enable the port to the device and set the state to RESET (TLR). + * + ***************************************************************/ + +void ispVMStart() +{ +#ifdef VME_DEBUG + printf( "// ISPVM EMBEDDED ADDED\n" ); + printf( "STATE RESET;\n" ); +#endif + + ispVMStateMachine( RESET ); /*step devices to RESET state*/ +} + +/*************************************************************** + * + * ispVMEnd + * + * Set the state of devices to RESET to enable the devices and disable + * the port. + * + ***************************************************************/ + +void ispVMEnd() +{ +#ifdef VME_DEBUG + printf( "// ISPVM EMBEDDED ADDED\n" ); + printf( "STATE RESET;\n" ); + printf( "RUNTEST 1.00E-001 SEC;\n" ); +#endif + + ispVMStateMachine( RESET ); /*step devices to RESET state */ + ispVMDelay( 0x8001 ); /*wake up devices*/ +} + +/*************************************************************** + * + * ispVMSend + * + * Send the TDI data stream to devices. The data stream can be + * instructions or data. + * + ***************************************************************/ + +signed char ispVMSend( unsigned short a_usiDataSize ) +{ + //09/11/07 NN added local variables initialization + unsigned short iIndex = 0; + unsigned short iInDataIndex = 0; + unsigned char cCurByte = 0; + unsigned char cBitState = 0; + + for ( iIndex = 0; iIndex < a_usiDataSize - 1; iIndex++ ) { + if ( iIndex % 8 == 0 ) { + cCurByte = g_pucInData[ iInDataIndex++ ]; + } + cBitState = ( unsigned char ) ( ( ( cCurByte << iIndex % 8 ) & 0x80 ) ? 0x01 : 0x00 ); + writePort( g_ucPinTDI, cBitState ); + sclock(); + } + + if ( iIndex % 8 == 0 ) { + /* Take care of the last bit */ + cCurByte = g_pucInData[ iInDataIndex ]; + } + + cBitState = ( unsigned char ) ( ( ( cCurByte << iIndex % 8 ) & 0x80 ) ? 0x01 : 0x00 ); + + writePort( g_ucPinTDI, cBitState ); + if ( g_usFlowControl & CASCADE ) { + /* 1/15/04 Clock in last bit for the first n-1 cascaded frames */ + sclock(); + } + + return 0; +} + +/*************************************************************** + * + * ispVMRead + * + * Read the data stream from devices and verify. + * + ***************************************************************/ + +signed char ispVMRead( unsigned short a_usiDataSize ) +{ + //09/11/07 NN added local variables initialization + unsigned short usDataSizeIndex = 0; + unsigned short usErrorCount = 0; + unsigned short usLastBitIndex = 0; + unsigned char cDataByte = 0; + unsigned char cMaskByte = 0; + unsigned char cInDataByte = 0; + unsigned char cCurBit = 0; + unsigned char cByteIndex = 0; + unsigned short usBufferIndex = 0; + unsigned char ucDisplayByte = 0x00; + unsigned char ucDisplayFlag = 0x01; + char StrChecksum[256] = {0}; + unsigned char g_usCalculateChecksum = 0x00; + + //09/11/07 NN Type cast mismatch variables + usLastBitIndex = (unsigned short)(a_usiDataSize - 1); + +#ifndef VME_DEBUG + /**************************************************************************** + * + * If mask is not all zeros, then set the display flag to 0x00, otherwise + * it shall be set to 0x01 to indicate that data read from the device shall + * be displayed. If VME_DEBUG is defined, always display data. + * + *****************************************************************************/ + + for ( usDataSizeIndex = 0; usDataSizeIndex < ( a_usiDataSize + 7 ) / 8; usDataSizeIndex++ ) { + if ( g_usDataType & MASK_DATA ) { + if ( g_pucOutMaskData[ usDataSizeIndex ] != 0x00 ) { + ucDisplayFlag = 0x00; + break; + } + } + else if ( g_usDataType & CMASK_DATA ) { + g_usCalculateChecksum = 0x01; + ucDisplayFlag = 0x00; + break; + } + else { + ucDisplayFlag = 0x00; + break; + } + } +#endif //VME_DEBUG + + /**************************************************************************** + * + * Begin shifting data in and out of the device. + * + *****************************************************************************/ + + for ( usDataSizeIndex = 0; usDataSizeIndex < a_usiDataSize; usDataSizeIndex++ ) { + if ( cByteIndex == 0 ) { + + /*************************************************************** + * + * Grab byte from TDO buffer. + * + ***************************************************************/ + + if ( g_usDataType & TDO_DATA ) { + cDataByte = g_pucOutData[ usBufferIndex ]; + } + + /*************************************************************** + * + * Grab byte from MASK buffer. + * + ***************************************************************/ + + if ( g_usDataType & MASK_DATA ) { + cMaskByte = g_pucOutMaskData[ usBufferIndex ]; + } + else { + cMaskByte = 0xFF; + } + + /*************************************************************** + * + * Grab byte from CMASK buffer. + * + ***************************************************************/ + + if ( g_usDataType & CMASK_DATA ) { + cMaskByte = 0x00; + g_usCalculateChecksum = 0x01; + } + + /*************************************************************** + * + * Grab byte from TDI buffer. + * + ***************************************************************/ + + if ( g_usDataType & TDI_DATA ) { + cInDataByte = g_pucInData[ usBufferIndex ]; + } + + usBufferIndex++; + } + + cCurBit = readPort(); + + if ( ucDisplayFlag ) { + ucDisplayByte <<= 1; + ucDisplayByte |= cCurBit; + } + + /**************************************************************************** + * + * Check if data read from port matches with expected TDO. + * + *****************************************************************************/ + + if ( g_usDataType & TDO_DATA ) { + //08/28/08 NN Added Calculate checksum support. + if( g_usCalculateChecksum ) + { + if(cCurBit == 0x01) + g_usChecksum += (1 << (g_uiChecksumIndex % 8)); + g_uiChecksumIndex++; + } + else + { + if ( ( ( ( cMaskByte << cByteIndex ) & 0x80 ) ? 0x01 : 0x00 ) ) { + if ( cCurBit != ( unsigned char ) ( ( ( cDataByte << cByteIndex ) & 0x80 ) ? 0x01 : 0x00 ) ) { + usErrorCount++; + } + } + } + } + + /**************************************************************************** + * + * Write TDI data to the port. + * + *****************************************************************************/ + + writePort( g_ucPinTDI, ( unsigned char ) ( ( ( cInDataByte << cByteIndex ) & 0x80 ) ? 0x01 : 0x00 ) ); + + if ( usDataSizeIndex < usLastBitIndex ) { + + /**************************************************************************** + * + * Clock data out from the data shift register. + * + *****************************************************************************/ + + sclock(); + } + else if ( g_usFlowControl & CASCADE ) { + + /**************************************************************************** + * + * Clock in last bit for the first N - 1 cascaded frames. + * + *****************************************************************************/ + + sclock(); + } + + /*************************************************************** + * + * Increment the byte index. If it exceeds 7, then reset it back + * to zero. + * + ***************************************************************/ + + cByteIndex++; + if ( cByteIndex >= 8 ) { + if ( ucDisplayFlag ) { + + /*************************************************************** + * + * Store displayed data in the TDO buffer. By reusing the TDO + * buffer to store displayed data, there is no need to allocate + * a buffer simply to hold display data. This will not cause any + * false verification errors because the true TDO byte has already + * been consumed. + * + ***************************************************************/ + + g_pucOutData[ usBufferIndex - 1 ] = ucDisplayByte; + ucDisplayByte = 0; + } + + cByteIndex = 0; + } + //09/12/07 Nguyen changed to display the 1 bit expected data + else if(a_usiDataSize == 1) + { + if ( ucDisplayFlag ) { + + /*************************************************************** + * + * Store displayed data in the TDO buffer. By reusing the TDO + * buffer to store displayed data, there is no need to allocate + * a buffer simply to hold display data. This will not cause any + * false verification errors because the true TDO byte has already + * been consumed. + * + ***************************************************************/ + + /**************************************************************************** + * + * Flip ucDisplayByte and store it in cDataByte. + * + *****************************************************************************/ + cDataByte = 0x00; + for ( usBufferIndex = 0; usBufferIndex < 8; usBufferIndex++ ) { + cDataByte <<= 1; + if ( ucDisplayByte & 0x01 ) { + cDataByte |= 0x01; + } + ucDisplayByte >>= 1; + } + g_pucOutData[ 0 ] = cDataByte; + ucDisplayByte = 0; + } + + cByteIndex = 0; + } + } + if ( ucDisplayFlag ) { + + /**************************************************************************** + * + * Display data read from the device. + * + *****************************************************************************/ + +#ifdef VME_DEBUG + printf( "RECIEVED TDO (" ); +#else + vme_out_string( "Display Data: 0x" ); +#endif //VME_DEBUG + + //09/11/07 NN Type cast mismatch variables + for ( usDataSizeIndex = (unsigned short)( ( a_usiDataSize + 7 ) / 8 ); usDataSizeIndex > 0 ; usDataSizeIndex-- ) { + cMaskByte = g_pucOutData[ usDataSizeIndex - 1 ]; + cDataByte = 0x00; + + /**************************************************************************** + * + * Flip cMaskByte and store it in cDataByte. + * + *****************************************************************************/ + + for ( usBufferIndex = 0; usBufferIndex < 8; usBufferIndex++ ) { + cDataByte <<= 1; + if ( cMaskByte & 0x01 ) { + cDataByte |= 0x01; + } + cMaskByte >>= 1; + } +#ifdef VME_DEBUG + printf( "%.2X", cDataByte ); + if ( ( ( ( a_usiDataSize + 7 ) / 8 ) - usDataSizeIndex ) % 40 == 39 ) { + printf( "\n\t\t" ); + } +#else + vme_out_hex( cDataByte ); +#endif //VME_DEBUG + } + +#ifdef VME_DEBUG + printf( ")\n\n" ); +#else + vme_out_string( "\n\n" ); +#endif //VME_DEBUG + //09/02/08 Nguyen changed to display the data Checksum + if(g_usChecksum != 0) + { + g_usChecksum &= 0xFFFF; + sprintf(StrChecksum,"Data Checksum: %04lx\n\n",g_usChecksum); + vme_out_string(StrChecksum); + g_usChecksum = 0; + } + } + + if ( usErrorCount > 0 ) { + if ( g_usFlowControl & VERIFYUES ) { + vme_out_string( "USERCODE verification failed. Continue programming......\n\n" ); + g_usFlowControl &= ~( VERIFYUES ); + return 0; + } + else { + +#ifdef VME_DEBUG + printf( "TOTAL ERRORS: %d\n", usErrorCount ); +#endif //VME_DEBUG + + return VME_VERIFICATION_FAILURE; + } + } + else { + if ( g_usFlowControl & VERIFYUES ) { + vme_out_string( "USERCODE verification passed. Programming aborted. \n\n" ); + g_usFlowControl &= ~( VERIFYUES ); + return 1; + } + else { + return 0; + } + } +} + +/*************************************************************** + * + * ispVMReadandSave + * + * Support dynamic I/O. + * + ***************************************************************/ + +signed char ispVMReadandSave( unsigned short int a_usiDataSize ) +{ + //09/11/07 NN added local variables initialization + unsigned short int usDataSizeIndex = 0; + unsigned short int usLastBitIndex = 0; + unsigned short int usBufferIndex = 0; + unsigned short int usOutBitIndex = 0; + unsigned short int usLVDSIndex = 0; + unsigned char cDataByte = 0; + unsigned char cDMASKByte = 0; + unsigned char cInDataByte = 0; + unsigned char cCurBit = 0; + unsigned char cByteIndex = 0; + signed char cLVDSByteIndex = 0; + + //09/11/07 NN Type cast mismatch variables + usLastBitIndex = (unsigned short) (a_usiDataSize - 1); + + /*************************************************************** + * + * Iterate through the data bits. + * + ***************************************************************/ + + for ( usDataSizeIndex = 0; usDataSizeIndex < a_usiDataSize; usDataSizeIndex++ ) { + if ( cByteIndex == 0 ) { + + /*************************************************************** + * + * Grab byte from DMASK buffer. + * + ***************************************************************/ + + if ( g_usDataType & DMASK_DATA ) { + cDMASKByte = g_pucOutDMaskData[ usBufferIndex ]; + } + else { + cDMASKByte = 0x00; + } + + /*************************************************************** + * + * Grab byte from TDI buffer. + * + ***************************************************************/ + + if ( g_usDataType & TDI_DATA ) { + cInDataByte = g_pucInData[ usBufferIndex ]; + } + + usBufferIndex++; + } + + cCurBit = readPort(); + cDataByte = ( unsigned char ) ( ( ( cInDataByte << cByteIndex ) & 0x80 ) ? 0x01 : 0x00 ); + + /*************************************************************** + * + * Initialize the byte to be zero. + * + ***************************************************************/ + + if ( usOutBitIndex % 8 == 0 ) { + g_pucOutData[ usOutBitIndex / 8 ] = 0x00; + } + + /*************************************************************** + * + * Use TDI, DMASK, and device TDO to create new TDI (actually + * stored in g_pucOutData). + * + ***************************************************************/ + + if ( ( ( ( cDMASKByte << cByteIndex ) & 0x80 ) ? 0x01 : 0x00 ) ) { + + if ( g_pLVDSList ) { + for ( usLVDSIndex = 0; usLVDSIndex < g_usLVDSPairCount; usLVDSIndex++ ) { + if ( g_pLVDSList[ usLVDSIndex ].usNegativeIndex == usDataSizeIndex ) { + g_pLVDSList[ usLVDSIndex ].ucUpdate = 0x01; + break; + } + } + } + + /*************************************************************** + * + * DMASK bit is 1, use TDI. + * + ***************************************************************/ + + g_pucOutData[ usOutBitIndex / 8 ] |= ( unsigned char ) ( ( ( cDataByte & 0x1 ) ? 0x01 : 0x00 ) << ( 7 - usOutBitIndex % 8 ) ); + } + else { + + /*************************************************************** + * + * DMASK bit is 0, use device TDO. + * + ***************************************************************/ + + g_pucOutData[ usOutBitIndex / 8 ] |= ( unsigned char ) ( ( ( cCurBit & 0x1 ) ? 0x01 : 0x00 ) << ( 7 - usOutBitIndex % 8 ) ); + } + + /*************************************************************** + * + * Shift in TDI in order to get TDO out. + * + ***************************************************************/ + + usOutBitIndex++; + writePort( g_ucPinTDI, cDataByte ); + if ( usDataSizeIndex < usLastBitIndex ) { + sclock(); + } + + /*************************************************************** + * + * Increment the byte index. If it exceeds 7, then reset it back + * to zero. + * + ***************************************************************/ + + cByteIndex++; + if ( cByteIndex >= 8 ) { + cByteIndex = 0; + } + } + + /*************************************************************** + * + * If g_pLVDSList exists and pairs need updating, then update + * the negative-pair to receive the flipped positive-pair value. + * + ***************************************************************/ + + if ( g_pLVDSList ) { + for ( usLVDSIndex = 0; usLVDSIndex < g_usLVDSPairCount; usLVDSIndex++ ) { + if ( g_pLVDSList[ usLVDSIndex ].ucUpdate ) { + + /*************************************************************** + * + * Read the positive value and flip it. + * + ***************************************************************/ + + cDataByte = ( unsigned char ) ( ( ( g_pucOutData[ g_pLVDSList[ usLVDSIndex ].usPositiveIndex / 8 ] << ( g_pLVDSList[ usLVDSIndex ].usPositiveIndex % 8 ) ) & 0x80 ) ? 0x01 : 0x00 ); + //09/11/07 NN Type cast mismatch variables + cDataByte = ( unsigned char ) (!cDataByte); + + /*************************************************************** + * + * Get the byte that needs modification. + * + ***************************************************************/ + + cInDataByte = g_pucOutData[ g_pLVDSList[ usLVDSIndex ].usNegativeIndex / 8 ]; + + if ( cDataByte ) { + + /*************************************************************** + * + * Copy over the current byte and set the negative bit to 1. + * + ***************************************************************/ + + cDataByte = 0x00; + for ( cLVDSByteIndex = 7; cLVDSByteIndex >= 0; cLVDSByteIndex-- ) { + cDataByte <<= 1; + if ( 7 - ( g_pLVDSList[ usLVDSIndex ].usNegativeIndex % 8 ) == cLVDSByteIndex ) { + + /*************************************************************** + * + * Set negative bit to 1. + * + ***************************************************************/ + + cDataByte |= 0x01; + } + else if ( cInDataByte & 0x80 ) { + cDataByte |= 0x01; + } + + cInDataByte <<= 1; + } + + /*************************************************************** + * + * Store the modified byte. + * + ***************************************************************/ + + g_pucOutData[ g_pLVDSList[ usLVDSIndex ].usNegativeIndex / 8 ] = cDataByte; + } + else { + + /*************************************************************** + * + * Copy over the current byte and set the negative bit to 0. + * + ***************************************************************/ + + cDataByte = 0x00; + for ( cLVDSByteIndex = 7; cLVDSByteIndex >= 0; cLVDSByteIndex-- ) { + cDataByte <<= 1; + if ( 7 - ( g_pLVDSList[ usLVDSIndex ].usNegativeIndex % 8 ) == cLVDSByteIndex ) { + + /*************************************************************** + * + * Set negative bit to 0. + * + ***************************************************************/ + + cDataByte |= 0x00; + } + else if ( cInDataByte & 0x80 ) { + cDataByte |= 0x01; + } + + cInDataByte <<= 1; + } + + /*************************************************************** + * + * Store the modified byte. + * + ***************************************************************/ + + g_pucOutData[ g_pLVDSList[ usLVDSIndex ].usNegativeIndex / 8 ] = cDataByte; + } + + break; + } + } + } + + return( 0 ); +} + +signed char ispVMProcessLVDS( unsigned short a_usLVDSCount ) +{ + unsigned short usLVDSIndex = 0; + + /*************************************************************** + * + * Allocate memory to hold LVDS pairs. + * + ***************************************************************/ + + ispVMMemManager( LVDS, a_usLVDSCount ); + g_usLVDSPairCount = a_usLVDSCount; + +#ifdef VME_DEBUG + printf( "LVDS %d (", a_usLVDSCount ); +#endif //VME_DEBUG + + /*************************************************************** + * + * Iterate through each given LVDS pair. + * + ***************************************************************/ + + for ( usLVDSIndex = 0; usLVDSIndex < g_usLVDSPairCount; usLVDSIndex++ ) { + + /*************************************************************** + * + * Assign the positive and negative indices of the LVDS pair. + * + ***************************************************************/ + + //09/11/07 NN Type cast mismatch variables + g_pLVDSList[ usLVDSIndex ].usPositiveIndex = (unsigned short) ispVMDataSize(); + //09/11/07 NN Type cast mismatch variables + g_pLVDSList[ usLVDSIndex ].usNegativeIndex = (unsigned short)ispVMDataSize(); + +#ifdef VME_DEBUG + if ( usLVDSIndex < g_usLVDSPairCount - 1 ) { + printf( "%d:%d, ", g_pLVDSList[ usLVDSIndex ].usPositiveIndex, g_pLVDSList[ usLVDSIndex ].usNegativeIndex ); + } + else { + printf( "%d:%d", g_pLVDSList[ usLVDSIndex ].usPositiveIndex, g_pLVDSList[ usLVDSIndex ].usNegativeIndex ); + } +#endif //VME_DEBUG + + } + +#ifdef VME_DEBUG + printf( ");\n", a_usLVDSCount ); +#endif //VME_DEBUG + + return( 0 ); +} diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/origi_ispvm_ui.c b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/origi_ispvm_ui.c new file mode 100644 index 000000000000..112633de87c6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/origi_ispvm_ui.c @@ -0,0 +1,908 @@ +/************************************************************** +* +* Lattice Semiconductor Corp. Copyright 2008 +* +* ispVME Embedded allows programming of Lattice's suite of FPGA +* devices on embedded systems through the JTAG port. The software +* is distributed in source code form and is open to re - distribution +* and modification where applicable. +* +* ispVME Embedded C Source comprised with 3 modules: +* ispvm_ui.c is the module provides input and output support. +* ivm_core.c is the module interpret the VME file(s). +* hardware.c is the module access the JTAG port of the device(s). +* +* The optional module cable.c is for supporting Lattice's parallel +* port ispDOWNLOAD cable on DOS and Windows 95/98 O/S. It can be +* requested from Lattice's ispVMSupport. +* +***************************************************************/ + + +/************************************************************** +* +* Revision History of ispvm_ui.c +* +* 3/6/07 ht Added functions vme_out_char(),vme_out_hex(), +* vme_out_string() to provide output resources. +* Consolidate all printf() calls into the added output +* functions. +* +* 09/11/07 NN Added Global variables initialization +* 09/24/07 NN Added a switch allowing users to do calibration. +* Calibration will help to determine the system clock frequency +* and the count value for one micro-second delay of the target +* specific hardware. +* Removed Delay Percent support +* 11/15/07 NN moved the checking of the File CRC to the end of processing +* 08/28/08 NN Added Calculate checksum support. +***************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include "vmopcode.h" + +/*************************************************************** +* +* File pointer to the VME file. +* +***************************************************************/ + +FILE * g_pVMEFile = NULL; + +#define VME_DEBUG + +#define DEBUG +#ifdef DEBUG +#define Debug_printf(fmt, args...) printf(fmt, ##args); +#else +#define Debug_printf(fmt, args...) +#endif + +/*************************************************************** +* +* Functions declared in this ispvm_ui.c module +* +***************************************************************/ +unsigned char GetByte(void); +void vme_out_char(unsigned char charOut); +void vme_out_hex(unsigned char hexOut); +void vme_out_string(char *stringOut); +void ispVMMemManager( signed char cTarget, unsigned short usSize ); +void ispVMFreeMem(void); +void error_handler( short a_siRetCode, char * pszMessage ); +signed char ispVM( const char * a_pszFilename ); +long isp_vme_file_size_get(void); +int isp_vme_file_size_set(char *file_name); +int isp_print_progess_bar(long pec); +void print_usage(char *app_name); +/*************************************************************** +* +* Global variables. +* +***************************************************************/ +unsigned short g_usPreviousSize = 0; +unsigned short g_usExpectedCRC = 0; +static unsigned long vme_file_size = 0; + +/*************************************************************** +* +* External variables and functions declared in ivm_core.c module. +* +***************************************************************/ +extern signed char ispVMCode(); +extern void ispVMCalculateCRC32( unsigned char a_ucData ); +extern void ispVMStart(); +extern void ispVMEnd(); +extern unsigned short g_usCalculatedCRC; +extern unsigned short g_usDataType; +extern unsigned char * g_pucOutMaskData, + * g_pucInData, + * g_pucOutData, + * g_pucHIRData, + * g_pucTIRData, + * g_pucHDRData, + * g_pucTDRData, + * g_pucOutDMaskData, + * g_pucIntelBuffer; +extern unsigned char * g_pucHeapMemory; +extern unsigned short g_iHeapCounter; +extern unsigned short g_iHEAPSize; +extern unsigned short g_usIntelDataIndex; +extern unsigned short g_usIntelBufferSize; +extern LVDSPair * g_pLVDSList; +//08/28/08 NN Added Calculate checksum support. +extern unsigned long g_usChecksum; +extern unsigned int g_uiChecksumIndex; +/*************************************************************** +* +* External variables and functions declared in hardware.c module. +* +***************************************************************/ +extern void calibration(void); +extern void writePort( unsigned long a_ucPins, unsigned char a_ucValue ); +extern unsigned short g_usCpu_Frequency; +extern unsigned long g_ucInPort; +extern unsigned long g_ucOutPort; + +/*************************************************************** +* +* Supported VME versions. +* +***************************************************************/ + +const char * const g_szSupportedVersions[] = { "__VME2.0", "__VME3.0", "____12.0", "____12.1", 0 }; + + +/*************************************************************** +* +* GetByte +* +* Returns a byte to the caller. The returned byte depends on the +* g_usDataType register. If the HEAP_IN bit is set, then the byte +* is returned from the HEAP. If the LHEAP_IN bit is set, then +* the byte is returned from the intelligent buffer. Otherwise, +* the byte is returned directly from the VME file. +* +***************************************************************/ + +unsigned char GetByte() +{ + unsigned char ucData = 0; + /* Prepare progress bar calculation */ + static long offset = 0; + int pec = 0; + long file_size = isp_vme_file_size_get(); + int bytes_pec = (file_size + 99) / 100; + + if ( g_usDataType & HEAP_IN ) { + + /*************************************************************** + * + * Get data from repeat buffer. + * + ***************************************************************/ + + if ( g_iHeapCounter > g_iHEAPSize ) { + + /*************************************************************** + * + * Data over-run. + * + ***************************************************************/ + + return 0xFF; + } + + ucData = g_pucHeapMemory[ g_iHeapCounter++ ]; + } + else if ( g_usDataType & LHEAP_IN ) { + + /*************************************************************** + * + * Get data from intel buffer. + * + ***************************************************************/ + + if ( g_usIntelDataIndex >= g_usIntelBufferSize ) { + + /*************************************************************** + * + * Data over-run. + * + ***************************************************************/ + + return 0xFF; + } + + ucData = g_pucIntelBuffer[ g_usIntelDataIndex++ ]; + } + else { + + /*************************************************************** + * + * Get data from file. + * + ***************************************************************/ + + ucData = (unsigned char)fgetc( g_pVMEFile ); + /* Update the progress bar */ + pec = ++offset / bytes_pec; + if(offset <= (pec * bytes_pec)) + isp_print_progess_bar(pec); + else if(offset >= (file_size - 2)) + isp_print_progess_bar(100); + if ( feof( g_pVMEFile ) ) { + + /*************************************************************** + * + * Reached EOF. + * + ***************************************************************/ + + return 0xFF; + } + /*************************************************************** + * + * Calculate the 32-bit CRC if the expected CRC exist. + * + ***************************************************************/ + if( g_usExpectedCRC != 0) + { + ispVMCalculateCRC32(ucData); + } + } + + return ( ucData ); +} + +/*************************************************************** +* +* vme_out_char +* +* Send a character out to the output resource if available. +* The monitor is the default output resource. +* +* +***************************************************************/ +void vme_out_char(unsigned char charOut) +{ + printf("%c",charOut); +} +/*************************************************************** +* +* vme_out_hex +* +* Send a character out as in hex format to the output resource +* if available. The monitor is the default output resource. +* +* +***************************************************************/ +void vme_out_hex(unsigned char hexOut) +{ + printf("%.2X",hexOut); +} +/*************************************************************** +* +* vme_out_string +* +* Send a text string out to the output resource if available. +* The monitor is the default output resource. +* +* +***************************************************************/ +void vme_out_string(char *stringOut) +{ + if(stringOut) + { + printf("%s",stringOut); + } + +} +/*************************************************************** +* +* ispVMMemManager +* +* Allocate memory based on cTarget. The memory size is specified +* by usSize. +* +***************************************************************/ + +void ispVMMemManager( signed char cTarget, unsigned short usSize ) +{ + switch ( cTarget ) { + case XTDI: + case TDI: + if ( g_pucInData != NULL ) { + if ( g_usPreviousSize == usSize ) {/*memory exist*/ + break; + } + else { + free( g_pucInData ); + g_pucInData = NULL; + } + } + g_pucInData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + g_usPreviousSize = usSize; + /* FALLTHRU */ + case XTDO: + case TDO: + if ( g_pucOutData!= NULL ) { + if ( g_usPreviousSize == usSize ) { /*already exist*/ + break; + } + else { + free( g_pucOutData ); + g_pucOutData = NULL; + } + } + g_pucOutData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + g_usPreviousSize = usSize; + break; + case MASK: + if ( g_pucOutMaskData != NULL ) { + if ( g_usPreviousSize == usSize ) {/*already allocated*/ + break; + } + else { + free( g_pucOutMaskData ); + g_pucOutMaskData = NULL; + } + } + g_pucOutMaskData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + g_usPreviousSize = usSize; + break; + case HIR: + if ( g_pucHIRData != NULL ) { + free( g_pucHIRData ); + g_pucHIRData = NULL; + } + g_pucHIRData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + break; + case TIR: + if ( g_pucTIRData != NULL ) { + free( g_pucTIRData ); + g_pucTIRData = NULL; + } + g_pucTIRData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + break; + case HDR: + if ( g_pucHDRData != NULL ) { + free( g_pucHDRData ); + g_pucHDRData = NULL; + } + g_pucHDRData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + break; + case TDR: + if ( g_pucTDRData != NULL ) { + free( g_pucTDRData ); + g_pucTDRData = NULL; + } + g_pucTDRData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + break; + case HEAP: + if ( g_pucHeapMemory != NULL ) { + free( g_pucHeapMemory ); + g_pucHeapMemory = NULL; + } + g_pucHeapMemory = ( unsigned char * ) malloc( usSize + 2 ); + break; + case DMASK: + if ( g_pucOutDMaskData != NULL ) { + if ( g_usPreviousSize == usSize ) { /*already allocated*/ + break; + } + else { + free( g_pucOutDMaskData ); + g_pucOutDMaskData = NULL; + } + } + g_pucOutDMaskData = ( unsigned char * ) malloc( usSize / 8 + 2 ); + g_usPreviousSize = usSize; + break; + case LHEAP: + if ( g_pucIntelBuffer != NULL ) { + free( g_pucIntelBuffer ); + g_pucIntelBuffer = NULL; + } + g_pucIntelBuffer = ( unsigned char * ) malloc( usSize + 2 ); + break; + case LVDS: + if ( g_pLVDSList != NULL ) { + free( g_pLVDSList ); + g_pLVDSList = NULL; + } + g_pLVDSList = ( LVDSPair * ) calloc( usSize, sizeof( LVDSPair ) ); + break; + default: + return; + } +} + +/*************************************************************** +* +* ispVMFreeMem +* +* Free memory that were dynamically allocated. +* +***************************************************************/ + +void ispVMFreeMem() +{ + if ( g_pucHeapMemory != NULL ) { + free( g_pucHeapMemory ); + g_pucHeapMemory = NULL; + } + + if ( g_pucOutMaskData != NULL ) { + free( g_pucOutMaskData ); + g_pucOutMaskData = NULL; + } + + if ( g_pucInData != NULL ) { + free( g_pucInData ); + g_pucInData = NULL; + } + + if ( g_pucOutData != NULL ) { + free( g_pucOutData ); + g_pucOutData = NULL; + } + + if ( g_pucHIRData != NULL ) { + free( g_pucHIRData ); + g_pucHIRData = NULL; + } + + if ( g_pucTIRData != NULL ) { + free( g_pucTIRData ); + g_pucTIRData = NULL; + } + + if ( g_pucHDRData != NULL ) { + free( g_pucHDRData ); + g_pucHDRData = NULL; + } + + if ( g_pucTDRData != NULL ) { + free( g_pucTDRData ); + g_pucTDRData = NULL; + } + + if ( g_pucOutDMaskData != NULL ) { + free( g_pucOutDMaskData ); + g_pucOutDMaskData = NULL; + } + + if ( g_pucIntelBuffer != NULL ) { + free( g_pucIntelBuffer ); + g_pucIntelBuffer = NULL; + } + + if ( g_pLVDSList != NULL ) { + free( g_pLVDSList ); + g_pLVDSList = NULL; + } +} + +/*************************************************************** +* +* error_handler +* +* Reports the error message. +* +***************************************************************/ + +void error_handler( short a_siRetCode, char * pszMessage ) +{ + const char * pszErrorMessage[] = { "pass", + "verification fail", + "can't find the file", + "wrong file type", + "file error", + "option error", + "crc verification error" }; + + strcpy( pszMessage, pszErrorMessage[ -a_siRetCode ] ); +} +/*************************************************************** +* +* ispVM +* +* The entry point of the ispVM embedded. If the version and CRC +* are verified, then the VME will be processed. +* +***************************************************************/ + +signed char ispVM( const char * a_pszFilename ) +{ + char szFileVersion[ 9 ] = { 0 }; + signed char cRetCode = 0; + signed char cIndex = 0; + signed char cVersionIndex = 0; + unsigned char ucReadByte = 0; + + /*************************************************************** + * + * Global variables initialization. + * + * 09/11/07 NN Added + ***************************************************************/ + g_pucHeapMemory = NULL; + g_iHeapCounter = 0; + g_iHEAPSize = 0; + g_usIntelDataIndex = 0; + g_usIntelBufferSize = 0; + g_usPreviousSize = 0; + + /*************************************************************** + * + * Open a file pointer to the VME file. + * + ***************************************************************/ + + if ( ( g_pVMEFile = fopen( a_pszFilename, "rb" ) ) == NULL ) { + return VME_FILE_READ_FAILURE; + } + g_usCalculatedCRC = 0; + g_usExpectedCRC = 0; + ucReadByte = GetByte(); + switch( ucReadByte ) { + case FILE_CRC: + + /*************************************************************** + * + * Read and store the expected CRC to do the comparison at the end. + * Only versions 3.0 and higher support CRC protection. + * + ***************************************************************/ + + g_usExpectedCRC = (unsigned char ) fgetc( g_pVMEFile ); + g_usExpectedCRC <<= 8; + g_usExpectedCRC |= fgetc( g_pVMEFile ); + + + /*************************************************************** + * + * Read and store the version of the VME file. + * + ***************************************************************/ + + for ( cIndex = 0; cIndex < 8; cIndex++ ) { + szFileVersion[ cIndex ] = GetByte(); + } + + break; + default: + + /*************************************************************** + * + * Read and store the version of the VME file. Must be version 2.0. + * + ***************************************************************/ + + szFileVersion[ 0 ] = ( signed char ) ucReadByte; + for ( cIndex = 1; cIndex < 8; cIndex++ ) { + szFileVersion[ cIndex ] = GetByte(); + } + + break; + } + + /*************************************************************** + * + * Compare the VME file version against the supported version. + * + ***************************************************************/ + for ( cVersionIndex = 0; g_szSupportedVersions[ cVersionIndex ] != 0; cVersionIndex++ ) { + for ( cIndex = 0; cIndex < 8; cIndex++ ) { + if ( szFileVersion[ cIndex ] != g_szSupportedVersions[ cVersionIndex ][ cIndex ] ) { + cRetCode = VME_VERSION_FAILURE; + break; + } + cRetCode = 0; + } + + if ( cRetCode == 0 ) { + + /*************************************************************** + * + * Found matching version, break. + * + ***************************************************************/ + + break; + } + } + + if ( cRetCode < 0 ) { + + /*************************************************************** + * + * VME file version failed to match the supported versions. + * + ***************************************************************/ + + fclose( g_pVMEFile ); + g_pVMEFile = NULL; + return VME_VERSION_FAILURE; + } + + /*************************************************************** + * + * Enable the JTAG port to communicate with the device. + * Set the JTAG state machine to the Test-Logic/Reset State. + * + ***************************************************************/ + + ispVMStart(); + + /*************************************************************** + * + * Process the VME file. + * + ***************************************************************/ + + cRetCode = ispVMCode(); + + /*************************************************************** + * + * Set the JTAG State Machine to Test-Logic/Reset state then disable + * the communication with the JTAG port. + * + ***************************************************************/ + + ispVMEnd(); + + fclose( g_pVMEFile ); + g_pVMEFile = NULL; + + + ispVMFreeMem(); + + /*************************************************************** + * + * Compare the expected CRC versus the calculated CRC. + * + ***************************************************************/ + + if ( cRetCode == 0 && g_usExpectedCRC != 0 && ( g_usExpectedCRC != g_usCalculatedCRC ) ) { + printf( "Expected CRC: 0x%.4X\n", g_usExpectedCRC ); + printf( "Calculated CRC: 0x%.4X\n", g_usCalculatedCRC ); + return VME_CRC_FAILURE; + } + + return ( cRetCode ); +} + +// inline char *strlwr(char *str) +// { +// char *orig = str; + +// for (; *str != '\0'; str++) +// *str = tolower(*str); + +// return orig; +// } + +int isp_vme_file_size_set(char *file_name) +{ + struct stat statbuf; + + stat(file_name, &statbuf); + vme_file_size = statbuf.st_size; + + return 0; +} + +long isp_vme_file_size_get(void) +{ + return vme_file_size; +} + +int isp_print_progess_bar(long pec) +{ + int i = 0; + + printf("["); + for(i = 0; i < (pec / 2); i++) { + printf("="); + } + for(i = pec / 2; i < 50; i++) { + printf(" "); + } + printf("]"); + printf(" [%ld%%]\r", pec); + fflush(stdout); + if(pec == 100) + printf("\n"); + + return 0; +} + +void print_usage(char *app_name){ + printf(" usage: %s [options] [filename]\n", app_name); + printf(" Options:\n"); + printf(" -h : to print this message.\n"); + printf(" -c : to select the JTAG chain 0,1,2\n"); + printf(" default is at 0.\n"); + printf(" -f : to specify CPU clock frequency in MHz.\n"); +} + +/*************************************************************** +* +* main +* +***************************************************************/ +int main( int argc, char * argv[] ) +{ + short siRetCode = 0; + short sicalibrate = 1; + short setCpuFrequency = 0; + + char *cpld_img = "cpld.vme"; + int JTAG_chain = 0; + int option; + //08/28/08 NN Added Calculate checksum support. + g_usChecksum = 0; + g_uiChecksumIndex = 0; + + vme_out_string( " Lattice Semiconductor Corp.\n" ); + vme_out_string( "\n ispVME(tm) V"); + vme_out_string( VME_VERSION_NUMBER ); + vme_out_string(" Copyright 1998-2011.\n"); + vme_out_string( "\nFor daisy chain programming of all in-system programmable devices\n" ); + vme_out_string( "\nCLS internal version 1.1.0 for Phalanx, Fishbone48, and Fishbone32.\n\n" ); + + while( ( option = getopt(argc, argv, "f:c:h")) != -1 ){ + switch (option){ + case 'h': + print_usage(argv[0]); + return 0; + case 'c': + // set JTAG chain number + JTAG_chain = atoi(optarg); + break; + case 'f': + // set CPU frequency + g_usCpu_Frequency = atoi(optarg); + setCpuFrequency = 1; + break; + case '?': + print_usage(argv[0]); + return -1; + } + } + + if( argc - optind ) + cpld_img = argv[optind]; + + if( JTAG_chain < 0 || JTAG_chain > 2 ){ + //print usage and return error + printf("Invalid JTAG chain specify: %d\n", JTAG_chain); + print_usage(argv[0]); + return -1; + } + + if( g_usCpu_Frequency <= 0 && setCpuFrequency ){ + //print usage and return error + printf("Invalid CPU frequency specify: %d\n", g_usCpu_Frequency); + print_usage(argv[0]); + return -1; + } + + if (iopl(3)) + { + perror("iopl"); + exit(1);/* reminder here: do not use "return", I warned */ + } + else + { + + /* For Denvertion CPU */ + // isp_dnv_gpio_init(); + // isp_dnv_gpio_config(GPIO_TCK_CONFIG, GPIO_DIR_OUTPUT); + // isp_dnv_gpio_config(GPIO_TMS_CONFIG, GPIO_DIR_OUTPUT); + // isp_dnv_gpio_config(GPIO_TDI_CONFIG, GPIO_DIR_OUTPUT); + // isp_dnv_gpio_config(GPIO_TDO_CONFIG, GPIO_DIR_INPUT); + + + /* TODO: Convert to bit read/write function */ + // Set ICHx GPIO_USE_SEL of TDI,TDO,TMS,TCK,GPIO14 + unsigned long data = 0; + data = inl_p(GPIO_USE_SEL); + data |= (1U << GPIO_TCK_CONFIG); + data |= (1U << GPIO_TMS_CONFIG); + data |= (1U << GPIO_TDI_CONFIG); + data |= (1U << GPIO_TDO_CONFIG); + data |= (1U << 14); + outl_p(data, GPIO_USE_SEL); + // Set ICHx GP_IO_SEL of TDI,TDO,TMS,TCK,GPIO14 + data = inl_p(GP_IO_SEL); + data &= ~(1U << GPIO_TCK_CONFIG); + data &= ~(1U << GPIO_TMS_CONFIG); + data &= ~(1U << GPIO_TDI_CONFIG); + data &= ~(1U << 14); + data |= (1U << GPIO_TDO_CONFIG); + outl_p(data, GP_IO_SEL); + + // Set ICHx GPIO_USE_SEL of GPIO70 + data = inl_p(GPIO_USE_SEL3); + data |= (1U << 6); + outl_p(data, GPIO_USE_SEL3); + // Set ICHx GP_IO_SEL of GPIO70 + data = inl_p(GP_IO_SEL3); + data &= ~(1U << 6); + outl_p(data, GP_IO_SEL3); + } + + /* FIXME: export and setting GPIO register bank on the fly could cause a bug. + * Plan to add the function to set/clear GPIO register bit for more sucure. + */ + /* Switch to control JTAG chain muxes */ + switch (JTAG_chain){ + case 0: + printf("Select main JTAG chain\n"); + // Set GPIO70 to Low + g_ucOutPort = GP_LVL3; + writePort( 6, 0x00 ); + break; + case 1: + printf("Select Top line card JTAG chain\n"); + // Ste GPIO70 to High + g_ucOutPort = GP_LVL3; + writePort( 6, 0x01 ); + // Ste GPIO14 to Low + g_ucOutPort = GP_LVL; + writePort( 14, 0x00 ); + break; + case 2: + printf("Select Buttom line card JTAG chain\n"); + // Ste GPIO70 to High + g_ucOutPort = GP_LVL3; + writePort( 6, 0x01 ); + // Ste GPIO14 to High + g_ucOutPort = GP_LVL; + writePort( 14, 0x01 ); + break; + } + + /* FIXME: This line is very important for TDI,TMS,TCK,TDO */ + // Set the register back to first bank! + g_ucOutPort = GP_LVL; + + printf("Set CPU frequency to %d MHz\n", g_usCpu_Frequency); + + siRetCode = 0; + if(sicalibrate) + { + vme_out_string ("calibration ....\n\n"); + calibration(); + } + + printf( "Processing virtual machine file ("); + printf( "%s",cpld_img); + printf(")......\n\n"); + isp_vme_file_size_set(cpld_img); + siRetCode = ispVM(cpld_img); + + /* Set JTAG chain muxes to default chain. */ + // Set GPIO70 to Low + g_ucOutPort = GP_LVL3; + writePort( 6, 0x00 ); + + /* For Denverton CPU */ + // isp_dnv_gpio_deinit(); + + if ( siRetCode < 0 ) { + vme_out_string( "Failed due to "); + printf( " return code %d\n\n", siRetCode); + vme_out_string( "+=======+\n" ); + vme_out_string( "| FAIL! |\n" ); + vme_out_string( "+=======+\n\n" ); + }else { + vme_out_string( "+=======+\n" ); + vme_out_string( "| PASS! |\n" ); + vme_out_string( "+=======+\n\n" ); + //08/28/08 NN Added Calculate checksum support. + if(g_usChecksum != 0) + { + g_usChecksum &= 0xFFFF; + printf("Data Checksum: %.4lx\n\n",g_usChecksum); + g_usChecksum = 0; + } + } + + if (iopl(0)) + { + perror("iopl"); + exit(1);/* reminder here: do not use "return", I warned */ + } + exit( siRetCode ); +} + diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/vmopcode.h b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/vmopcode.h new file mode 100644 index 000000000000..6b2c94d510f7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/vmopcode.h @@ -0,0 +1,233 @@ +/*************************************************************** +* +* This is the include file for Lattice Semiconductor's ispVM +* Embedded software application. +* +***************************************************************/ + +/*************************************************************** +* +* VME version. +* +* History: +* +***************************************************************/ +#define VME_VERSION_NUMBER "12.2" + +/*************************************************************** +* +* Maximum declarations. +* +***************************************************************/ + +#define VMEHEXMAX 60000L /* The hex file is split 60K per file. */ +#define SCANMAX 64000L /* The maximum SDR/SIR burst. */ + +/*************************************************************** +* +* Supported JTAG state transitions. +* +***************************************************************/ + +#define RESET 0x00 +#define IDLE 0x01 +#define IRPAUSE 0x02 +#define DRPAUSE 0x03 +#define SHIFTIR 0x04 +#define SHIFTDR 0x05 +#define DRCAPTURE 0x06 + +/*************************************************************** +* +* Flow control register bit definitions. A set bit indicates +* that the register currently exhibits the corresponding mode. +* +***************************************************************/ + +#define INTEL_PRGM 0x0001 /* Intelligent programming is in effect. */ +#define CASCADE 0x0002 /* Currently splitting large SDR. */ +#define REPEATLOOP 0x0008 /* Currently executing a repeat loop. */ +#define SHIFTRIGHT 0x0080 /* The next data stream needs a right shift. */ +#define SHIFTLEFT 0x0100 /* The next data stream needs a left shift. */ +#define VERIFYUES 0x0200 /* Continue if fail is in effect. */ + +/*************************************************************** +* +* DataType register bit definitions. A set bit indicates +* that the register currently holds the corresponding type of data. +* +***************************************************************/ + +#define EXPRESS 0x0001 /* Simultaneous program and verify. */ +#define SIR_DATA 0x0002 /* SIR is the active SVF command. */ +#define SDR_DATA 0x0004 /* SDR is the active SVF command. */ +#define COMPRESS 0x0008 /* Data is compressed. */ +#define TDI_DATA 0x0010 /* TDI data is present. */ +#define TDO_DATA 0x0020 /* TDO data is present. */ +#define MASK_DATA 0x0040 /* MASK data is present. */ +#define HEAP_IN 0x0080 /* Data is from the heap. */ +#define LHEAP_IN 0x0200 /* Data is from intel data buffer. */ +#define VARIABLE 0x0400 /* Data is from a declared variable. */ +#define CRC_DATA 0x0800 /* CRC data is pressent. */ +#define CMASK_DATA 0x1000 /* CMASK data is pressent. */ +#define RMASK_DATA 0x2000 /* RMASK data is pressent. */ +#define READ_DATA 0x4000 /* READ data is pressent. */ +#define DMASK_DATA 0x8000 /* DMASK data is pressent. */ + +/*************************************************************** +* +* Pin opcodes. +* +***************************************************************/ + +#define signalENABLE 0x1C /* ispENABLE pin. */ +#define signalTMS 0x1D /* TMS pin. */ +#define signalTCK 0x1E /* TCK pin. */ +#define signalTDI 0x1F /* TDI pin. */ +#define signalTRST 0x20 /* TRST pin. */ + +/*************************************************************** +* +* Supported vendors. +* +***************************************************************/ + +#define VENDOR 0x56 +#define LATTICE 0x01 +#define ALTERA 0x02 +#define XILINX 0x03 + +/*************************************************************** +* +* Opcode definitions. +* +* Note: opcodes must be unique. +* +***************************************************************/ + +#define ENDDATA 0x00 /* The end of the current SDR data stream. */ +#define RUNTEST 0x01 /* The duration to stay at the stable state. */ +#define ENDDR 0x02 /* The stable state after SDR. */ +#define ENDIR 0x03 /* The stable state after SIR. */ +#define ENDSTATE 0x04 /* The stable state after RUNTEST. */ +#define TRST 0x05 /* Assert the TRST pin. */ +#define HIR 0x06 /* The sum of the IR bits of the leading devices. */ +#define TIR 0x07 /* The sum of the IR bits of the trailing devices. */ +#define HDR 0x08 /* The number of leading devices. */ +#define TDR 0x09 /* The number of trailing devices. */ +#define ispEN 0x0A /* Assert the ispEN pin. */ +#define FREQUENCY 0x0B /* The maximum clock rate to run the JTAG state machine. */ +#define STATE 0x10 /* Move to the next stable state. */ +#define SIR 0x11 /* The instruction stream follows. */ +#define SDR 0x12 /* The data stream follows. */ +#define TDI 0x13 /* The following data stream feeds into the device. */ +#define TDO 0x14 /* The following data stream is compared against the device. */ +#define MASK 0x15 /* The following data stream is used as mask. */ +#define XSDR 0x16 /* The following data stream is for simultaneous program and verify. */ +#define XTDI 0x17 /* The following data stream is for shift in only. It must be stored for the next XSDR. */ +#define XTDO 0x18 /* There is not data stream. The data stream was stored from the previous XTDI. */ +#define MEM 0x19 /* The maximum memory needed to allocate in order hold one row of data. */ +#define WAIT 0x1A /* The duration of delay to observe. */ +#define TCK 0x1B /* The number of TCK pulses. */ +#define SHR 0x23 /* Set the flow control register for right shift. */ +#define SHL 0x24 /* Set the flow control register for left shift. */ +#define HEAP 0x32 /* The memory size needed to hold one loop. */ +#define REPEAT 0x33 /* The beginning of the loop. */ +#define LEFTPAREN 0x35 /* The beginning of data following the loop. */ +#define VAR 0x55 /* Plac holder for loop data. */ +#define SEC 0x1C /* The delay time in seconds that must be observed. */ +#define SMASK 0x1D /* The mask for TDI data. */ +#define MAX 0x1E /* The absolute maximum wait time. */ +#define ON 0x1F /* Assert the targeted pin. */ +#define OFF 0x20 /* Dis-assert the targeted pin. */ +#define SETFLOW 0x30 /* Change the flow control register. */ +#define RESETFLOW 0x31 /* Clear the flow control register. */ +#define CRC 0x47 /* The following data stream is used for CRC calculation. */ +#define CMASK 0x48 /* The following data stream is used as mask for CRC calculation. */ +#define RMASK 0x49 /* The following data stream is used as mask for read and save. */ +#define READ 0x50 /* The following data stream is used for read and save. */ +#define ENDLOOP 0x59 /* The end of the repeat loop. */ +#define SECUREHEAP 0x60 /* Used to secure the HEAP opcode. */ +#define VUES 0x61 /* Support continue if fail. */ +#define DMASK 0x62 /* The following data stream is used for dynamic I/O. */ +#define COMMENT 0x63 /* Support SVF comments in the VME file. */ +#define HEADER 0x64 /* Support header in VME file. */ +#define FILE_CRC 0x65 /* Support crc-protected VME file. */ +#define LCOUNT 0x66 /* Support intelligent programming. */ +#define LDELAY 0x67 /* Support intelligent programming. */ +#define LSDR 0x68 /* Support intelligent programming. */ +#define LHEAP 0x69 /* Memory needed to hold intelligent data buffer */ +#define CONTINUE 0x70 /* Allow continuation. */ +#define LVDS 0x71 /* Support LVDS. */ +#define ENDVME 0x7F /* End of the VME file. */ +#define HIGH 0x80 /* Assert the targeted pin. */ +#define LOW 0x81 /* Dis-assert the targeted pin. */ +#define ENDFILE 0xFF /* End of file. */ + +/* Denverton GPIO MAPPING */ +#define MAP_MASK (sysconf(_SC_PAGE_SIZE)-1) +#define MAP_SIZE(addr) ( (addr & MAP_MASK) + 8 ) +#define OFFSET_ADDR(addr) (addr & MAP_MASK) +#define GET_PORT(addr) ( (addr >> 16) & 0xFF ) +#define DNV_BAR 0xFD000000 +#define DNV_GPIO_TCK_CONFIG 0xFDC20510 +#define DNV_GPIO_TMS_CONFIG 0xFDC20508 +#define DNV_GPIO_TDI_CONFIG 0xFDC204D8 +#define DNV_GPIO_TDO_CONFIG 0xFDC50570 +#define DNV_GPIO_DIR_INPUT 1 +#define DNV_GPIO_DIR_OUTPUT 0 +#define DNV_GPIO_LVL_HIGH 1 +#define DNV_GPIO_LVL_LOW 0 + +// FIXME: This only works on Fishbone/Phalanx +#define CPU_FREQ_MH_CONFIG 2200 /* in MHz */ +#define GPIO_USE_SEL 0x500 +#define GP_IO_SEL 0x504 +#define GP_LVL 0x50C +#define GPIO_USE_SEL2 0x530 +#define GP_IO_SEL2 0x534 +#define GP_LVL2 0x538 +#define GPIO_USE_SEL3 0x540 +#define GP_IO_SEL3 0x544 +#define GP_LVL3 0x548 + +#define GPIO_TCK_CONFIG 18 +#define GPIO_TMS_CONFIG 9 +#define GPIO_TDI_CONFIG 8 +#define GPIO_TDO_CONFIG 10 +#define GPIO_ENABLE_CONFIG 13 /* GPIO 13 is unused */ +#define GPIO_TRST_CONFIG 13 /* GPIO 13 is unused */ + +/*************************************************************** +* +* ispVM Embedded Return Codes. +* +***************************************************************/ + +#define VME_VERIFICATION_FAILURE -1 +#define VME_FILE_READ_FAILURE -2 +#define VME_VERSION_FAILURE -3 +#define VME_INVALID_FILE -4 +#define VME_ARGUMENT_FAILURE -5 +#define VME_CRC_FAILURE -6 + + +/*************************************************************** +* +* Type definitions. +* +***************************************************************/ + +/* Support LVDS */ +typedef struct { + unsigned short usPositiveIndex; + unsigned short usNegativeIndex; + unsigned char ucUpdate; +} LVDSPair; + +void isp_dnv_gpio_config( unsigned int gpio, unsigned int dir ); +void isp_dnv_gpio_write( unsigned int gpio, unsigned int value); +int isp_dnv_gpio_read( unsigned int gpio); + +void isp_dnv_gpio_init(void); +void isp_dnv_gpio_deinit(void); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/platformutil.py b/platform/broadcom/sonic-platform-modules-cel/tools/platformutil.py new file mode 100644 index 000000000000..5c73dd9870f3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/platformutil.py @@ -0,0 +1,642 @@ +#!/usr/bin/env python +# +# platformutil/main.py +# +# Command-line utility for interacting with PSU in SONiC +# +# example output +# platformutil psu status +# PSU Presence Status PN SN +# PSU 1 PRESENT OK CSU550AP-3-300 M623TW004ZAAL +# PSU 2 NOT_PRESENT N/A N/A N/A +# +# platformutil fan status +# FAN Status Speed Low_thd High_thd PN SN +# FAN 1 OK 10169 RPM 300 RPM 16000 RPM M6510-FAN-F 1000000000014 +# FAN 2 NOT_OK 20000 RPM 300 RPM 16000 RPM M6510-FAN-F 1000000000014 +# +# platformutil sensor status +#Sensor InputName State Value Low_thd High_thd +#----------------- ------------------- ------- -------- --------- ---------- +#syscpld-i2c-0-0d CPU temp NOT_OK 41.0 C 0 C 0.0 C +#syscpld-i2c-0-0d Optical temp NOT_OK 26.0 C 0 C 0.0 C +#syscpld-i2c-0-0d Switch temp NOT_OK 35.0 C 0 C 0.0 C +# +# should implenmet the below classes in the specified plugin +# +# class PsuUtil: +# int get_num_psus(); //get the number of power supply units +# bool get_psu_presence(int index) //get the power status of the psu, index:1,2 +# bool get_psu_status(int index) //get the running status of the psu,index:1,2 +# str get_psu_sn(int index) //get the serial number of the psu, return value example: "M623TW004ZAAL" +# str get_psu_pn(int index) //get the product name of the psu, return value example: "CSU550AP-3-300" +# +# // Get all information of PSUs, returns JSON objects in python 'DICT'. +# // return value of get_all(): +# // Number: mandatory, max number of PSU, integer +# // PSU1, PSU2, ...: mandatory, PSU name, string +# // Present: mandatory for each PSU, present status, boolean, True for present, False for NOT present +# // PowerStatus: conditional, if PRESENT is True, power status of PSU, +# // boolean, True for powered, False for NOT powered +# // PN, conditional, if PRESENT is True, PN of the PSU, string +# // SN, conditional, if PRESENT is True, SN of the PSU, string +# // example: +# // { +# // "Number": 2, +# // "PSU1": { +# // "Present": True, +# // "PowerStatus": True, +# // "PN": "PN-EXAMPLE-123", +# // "SN": "SN-EXAMPLE-123", +# // "InputStatus": True, +# // "OutputStatus": True, +# // "InputType": "DC" +# // "AirFlow": "BTOF" +# // }, +# // "PSU2": { +# // "Present": False +# // } +# // } +# dict get_all() + +# class FanUtil: +# int get_fans_name_list(); //get the names of all the fans(FAN1-1,FAN1-2,FAN2-1,FAN2-2...) +# int get_fan_speed(int index); //get the current speed of the fan, the unit is "RPM" +# int get_fan_low_threshold(int index); //get the low speed threshold of the fan, if the current speed < low speed threshold, the status of the fan is ok. +# int get_fan_high_threshold(int index); //get the hight speed threshold of the fan, if the current speed > high speed threshold, the status of the fan is not ok +# str get_fan_pn(int index);//get the product name of the fan +# str get_fan_sn(int index);//get the serial number of the fan +# // Get all information of system FANs, returns JSON objects in python 'DICT'. +# // Number, mandatory, max number of FAN, integer +# // FAN1_1, FAN1_2, ... mandatory, FAN name, string +# // Present, mandatory for each FAN, present status, boolean, True for present, False for NOT present, read directly from h/w +# // Running, conditional, if PRESENT is True, running status of the FAN, True for running, False for stopped, read directly from h/w +# // Speed, conditional, if PRESENT is True, real FAN speed, float, read directly from h/w +# // LowThd, conditional, if PRESENT is True, lower bound of FAN speed, float, read from h/w +# // HighThd, conditional, if PRESENT is True, upper bound of FAN speed, float, read from h/w +# // PN, conditional, if PRESENT is True, PN of the FAN, string +# // SN, conditional, if PRESENT is True, SN of the FAN, string +# // Return value python 'dict' object example: +# // { +# // "Number": 3, +# // "FAN1_1": { +# // "Present": True, +# // "Running": True, +# // "Speed": 2000.0, +# // "LowThd": 1000.0, +# // "HighThd": 15000.0, +# // "PN": "PN-EXAMPLE-123", +# // "SN": "SN-EXAMPLE-123" +# // "Status": True, +# // "AirFlow": "FTOB" +# // }, +# // "FAN1_2": { +# // "Present": True, +# // "Running": True, +# // "Speed": 2500.0, +# // "LowThd": 1000.0, +# // "HighThd": 15000.0, +# // "PN": "PN-EXAMPLE-456", +# // "SN": "SN-EXAMPLE-456" +# // "Status": True, +# // "AirFlow": "BTOF" +# // }, +# // "FAN2_1": { +# // "Present": True, +# // "Running": False +# // }, +# // "FAN2_2": { +# // "Present": True, +# // "Running": False +# // }, +# // "FAN3_1": { +# // "Present": False +# // }, +# // "FAN3_2": { +# // "Present": False +# // } +# // } +# dict get_all() +# +# class SensorUtil: +# int get_num_sensors(); //get the number of sensors +# int get_sensor_input_num(int index); //get the number of the input items of the specified sensor +# str get_sensor_name(int index);// get the device name of the specified sensor.for example "coretemp-isa-0000" +# str get_sensor_input_name(int sensor_index, int input_index); //get the input item name of the specified input item of the specified sensor index, for example "Physical id 0" +# str get_sensor_input_type(int sensor_index, int input_index); //get the item type of the specified input item of the specified sensor index, the return value should +# //among "voltage","temperature"... +# float get_sensor_input_value(int sensor_index, int input_index);//get the current value of the input item, the unit is "V" or "C"... +# float get_sensor_input_low_threshold(int sensor_index, int input_index); //get the low threshold of the value, the status of this item is not ok if the current +# //value high_threshold +# // Get all information of system sensors, returns JSON objects in python 'DICT'. +# // SensorName1, SensorName2, ... optional, string +# // SensorInput1, SensorInput2, ... optional, string +# // Type, mandatory in SensorInput$INDEX, should be on of { "temperature", "voltage", "power", "amp", "RPM" } +# // Value, mandatory in SensorInput$INDEX, float , real value +# // LowThd, mandatory in SensorInput$INDEX, float , lower bound of value +# // HighThd, mandatory in SensorInput$INDEX, float , upper bound of value +# // Return python 'dict' objects, example: +# // { +# // "SensorName1": { +# // "CPU_TEMP": +# // "Type": "temperature", +# // "Value": 37.3, +# // "LowThd": 0.0, +# // "HighThd": 110.0 +# // }, +# // "SWITCH_TEMP": { +# // "Type": "temperature", +# // "Value": 45.2, +# // "LowThd": 0.0, +# // "HighThd": 108.0 +# // }, +# // "INLET_TEMP": { +# // "Type": "temperature", +# // "Value": 22.0, +# // "LowThd": 0.0, +# // "HighThd": 70.0 +# // }, +# // "Sys_AirFlow": "BTOF", +# // "Switch_VDDCore_0.8v": { +# // "Type": "voltage", +# // "Value": 0.75, +# // "LowThd": 0.7, +# // "HighThd": 0.85 +# // }, +# // "Cpu_VDDCore_0.8v": { +# // "Type": "voltage", +# // "Value": 0.75, +# // "LowThd": 0.7, +# // "HighThd": 0.85 +# // }, +# // "SensorInput1": { +# // "Type": "temperature", +# // "Value": 30.0, +# // "LowThd": 0.0, +# // "HighThd": 100.0" +# // }, +# // "SensorInput2": { +# // "Type": "voltage", +# // "Value": 0.5, +# // "LowThd": 0.0, +# // "HighThd": 1.5 +# // }, +# // "SensorInput3": { +# // "Type": "power", +# // "Value": 2.5, +# // "LowThd": 0.0, +# // "HighThd": 5.0 +# // } +# // }, +# // "SensorName2": { +# // "SensorInput1": { +# // "Type": "RPM", +# // "Value": 2000.0, +# // "LowThd": 1000.0, +# // "HighThd": 15000.0 +# // }, +# // "SensorInputName2": { +# // "Type": "amp", +# // "Value": 0.1, +# // "LowThd": 0.0, +# // "HighThd": 0.3 +# // } +# // } +# // } + +try: + import sys + import os + import subprocess + import click + import imp + import syslog + import types + import traceback + from tabulate import tabulate +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +VERSION = '1.2' + +SYSLOG_IDENTIFIER = "platformutil" +PLATFORM_PSU_MODULE_NAME = "psuutil" +PLATFORM_PSU_CLASS_NAME = "PsuUtil" + +#gongjian add +PLATFORM_SENSOR_MODULE_NAME = "sensorutil" +PLATFORM_SENSOR_CLASS_NAME = "SensorUtil" + +PLATFORM_FAN_MODULE_NAME = "fanutil" +PLATFORM_FAN_CLASS_NAME = "FanUtil" +#end gongjian add + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +PLATFORM_ROOT_PATH_DOCKER = '/usr/share/sonic/platform' +SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen' +MINIGRAPH_PATH = '/etc/sonic/minigraph.xml' +HWSKU_KEY = "DEVICE_METADATA['localhost']['hwsku']" +PLATFORM_KEY = "DEVICE_METADATA['localhost']['platform']" + +# Global platform-specific psuutil class instance +platform_psuutil = None + +#gongjian add +platform_sensorutil = None +Platform_fanutil = None +#end gongjian add + +# ========================== 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: + click.echo(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: + click.echo(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: + click.echo(msg) + + +# ==================== Methods for initialization ==================== + +# Returns platform and HW SKU +def get_platform_and_hwsku(): + try: + proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY], + stdout=subprocess.PIPE, + shell=False, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + platform = stdout.rstrip('\n') + + proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY], + stdout=subprocess.PIPE, + shell=False, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + hwsku = stdout.rstrip('\n') + except OSError, e: + raise OSError("Cannot detect platform") + + return (platform, hwsku) + + +# Loads platform specific psuutil module from source +def load_platform_util(): + global platform_psuutil + #gongjian add + global platform_sensorutil + global platform_fanutil + + # Get platform and hwsku + (platform, hwsku) = get_platform_and_hwsku() + + # Load platform module from source + platform_path = '' + if len(platform) != 0: + platform_path = "/".join([PLATFORM_ROOT_PATH, platform]) + else: + platform_path = PLATFORM_ROOT_PATH_DOCKER + hwsku_path = "/".join([platform_path, hwsku]) + + try: + module_file_psu = "/".join([platform_path, "plugins", PLATFORM_PSU_MODULE_NAME + ".py"]) + module_psu = imp.load_source(PLATFORM_PSU_MODULE_NAME, module_file_psu) + except IOError, e: + log_error("Failed to load platform module '%s': %s" % (PLATFORM_PSU_MODULE_NAME, str(e)), True) + return -1 + + try: + platform_psuutil_class = getattr(module_psu, PLATFORM_PSU_CLASS_NAME) + platform_psuutil = platform_psuutil_class() + except AttributeError, e: + log_error("Failed to instantiate '%s' class: %s" % (PLATFORM_PSU_CLASS_NAME, str(e)), True) + return -2 + + + #gongjian add + try: + module_file_sensor = "/".join([platform_path, "plugins", PLATFORM_SENSOR_MODULE_NAME + ".py"]) + module_sensor = imp.load_source(PLATFORM_SENSOR_MODULE_NAME, module_file_sensor) + except IOError, e: + log_error("Failed to load platform module '%s': %s" % (PLATFORM_SENSOR_MODULE_NAME, str(e)), True) + return -1 + + try: + platform_sensorutil_class = getattr(module_sensor, PLATFORM_SENSOR_CLASS_NAME) + platform_sensorutil = platform_sensorutil_class() + except AttributeError, e: + log_error("Failed to instantiate '%s' class: %s" % (PLATFORM_SENSOR_CLASS_NAME, str(e)), True) + return -2 + + try: + module_file_fan = "/".join([platform_path, "plugins", PLATFORM_FAN_MODULE_NAME + ".py"]) + module_fan = imp.load_source(PLATFORM_FAN_MODULE_NAME, module_file_fan) + except IOError, e: + log_error("Failed to load platform module '%s': %s" % (PLATFORM_FAN_MODULE_NAME, str(e)), True) + return -1 + + try: + platform_fanutil_class = getattr(module_fan, PLATFORM_FAN_CLASS_NAME) + platform_fanutil = platform_fanutil_class() + except AttributeError, e: + log_error("Failed to instantiate '%s' class: %s" % (PLATFORM_FAN_CLASS_NAME, str(e)), True) + return -2 + #end gongjian add + return 0 + + +# ==================== CLI commands and groups ==================== + + +# This is our main entrypoint - the main 'psuutil' command +@click.group() +def cli(): + """platformutil - Command line utility for providing platform status""" + + if os.geteuid() != 0: + click.echo("Root privileges are required for this operation") + sys.exit(1) + + # Load platform-specific psuutil, fanutil and sensorutil class + err = load_platform_util() + if err != 0: + sys.exit(2) + +#'fan' subcommand +@cli.group() +@click.pass_context +def fan(ctx): + """fan state""" + ctx.obj = "fan" + +# 'sensor' subcommand +@cli.group() +@click.pass_context +def sensor(ctx): + """sensor state""" + ctx.obj = "sensor" + +# 'psu' subcommand +@cli.group() +@click.pass_context +def psu(ctx): + """psu state""" + ctx.obj = "psu" + +# 'version' subcommand +@cli.command() +def version(): + """Display version info""" + click.echo("platformutil version {0}".format(VERSION)) + + +# 'num' subcommand +@click.command() +@click.pass_context +def num(ctx): + """Display number of supported sensor/fan/psu device""" + if ctx.obj == "psu": + click.echo(str(platform_psuutil.get_num_psus())) + if ctx.obj == "fan": + click.echo(str(len(platform_fanutil.get_fans_name_list()))) + if ctx.obj == "sensor": + click.echo(str(platform_sensorutil.get_num_sensors())) + +psu.add_command(num) +sensor.add_command(num) +fan.add_command(num) + +# 'status' subcommand +#all API should return "N/A" or float("-intf") if not supported +@click.command() +@click.pass_context +def status(ctx): + if ctx.obj == 'psu': + psu_dict = platform_psuutil.get_all() + if psu_dict == None: + print 'Error: psuutil.get_all() failed' + return + + psu_nr = psu_dict.get('Number') + if psu_nr == None: + print 'Error: PSU get all format invalid, prop "Number" missing.' + return + + psu_names = [ k for k in psu_dict.keys() if cmp('Number', k) != 0 ] + psu_names.sort() + header = ['PSU', 'Presence', 'InputStatus', 'InputType', 'OutputStatus', 'PN', 'SN', 'AirFlow'] + status_table = [] + for psu_name in psu_names: + psu = psu_dict[psu_name] + presence = psu.get('Present') + pn = psu.get('PN') + sn = psu.get('SN') + in_status = psu.get('InputStatus') + out_status = psu.get('OutputStatus') + in_type = psu.get('InputType') + airflow = psu.get('AirFlow') + + if presence == None: + print 'Error: PSU get all format invaid, prop "Present" is missing.' + continue + elif presence == False: + presence = 'NOT_PRESENT' + in_status = 'N/A' + out_status = 'N/A' + in_type = 'N/A' + pn = 'N/A' + pn = 'N/A' + else: + presence = 'PRESENT' + if in_status == None: + in_status = 'N/A' + elif in_status == True: + in_status = 'OK' + else: + in_status = 'NOT_OK' + + if in_type == None: + in_type = 'N/A' + + if out_status == None: + out_status = 'N/A' + elif out_status == True: + out_status = 'OK' + else: + out_status = 'NOT_OK' + + if pn == None: + pn = 'N/A' + if sn == None: + sn = 'N/A' + if airflow == None: + airflow = 'N/A' + status_table.append([psu_name, presence, in_status, in_type, out_status, pn, sn, airflow]) + + if len(status_table) != psu_nr: + print 'Error: PSU get all missing some PSU information.' + + if len(status_table) > 0: + click.echo(tabulate(status_table, header, tablefmt='simple')) + + if ctx.obj == 'fan': + fan_dict = platform_fanutil.get_all() + if fan_dict == None: + print 'Error: fanutil.get_all() failed' + return + + fan_nr = fan_dict.get('Number') + if fan_nr == None: + print 'Error: FAN get all format invalid, prop "Number" missing.' + return + + header = [ 'FAN', 'Presence', 'Status', 'Speed', 'LowThd', 'HighThd', 'PN', 'SN', 'AirFlow' ] + status_table = [] + fan_names = [ k for k in fan_dict.keys() if cmp('Number', k) != 0 ] + fan_names.sort() + for fan_name in fan_names: + fan = fan_dict[fan_name] + presence = fan.get('Present') + speed = fan.get('Speed') + low = fan.get('LowThd') + high = fan.get('HighThd') + pn = fan.get('PN') + sn = fan.get('SN') + status = fan.get('Status') + airflow = fan.get('AirFlow') + + if presence == None: + print 'Error: FAN get all format invaid, prop "Present" missing.' + continue + elif presence == False: + presence = 'NOT_PRESENT' + status = 'N/A' + speed = 'N/A' + low = 'N/A' + high = 'N/A' + pn = 'N/A' + sn = 'N/A' + airflow = 'N/A' + else: + presence = 'PRESENT' + if status == None: + status = 'N/A' + elif status == True: + status = 'OK' + else: + status = 'NOT_OK' + if airflow == None: + airflow = 'N/A' + if speed == None: + speed = 'N/A' + if low == None: + low = 'N/A' + if high == None: + high = 'N/A' + if pn == None: + pn = 'N/A' + if sn == None: + sn = 'N/A' + + status_table.append([fan_name, presence, status, speed, low, high, pn, sn, airflow]) + + if len(status_table) != fan_nr: + print 'Error: FAN get all missing some FAN information.' + + if len(status_table) > 0: + click.echo(tabulate(status_table, header, tablefmt='simple')) + + if ctx.obj == 'sensor': + sensor_dict = platform_sensorutil.get_all() + if sensor_dict == None: + print 'Error: sensors.get_all() failed' + return + + header = [ 'Sensor', 'InputName', 'State', 'Value', 'LowThd', 'HighThd' ] + status_table = [] + type2unit = { 'temperature' : ' C', 'voltage' : ' V', 'RPM' : ' RPM', 'amp' : ' A', 'power' : ' W'} + type_keys = type2unit.keys() + for sensor_name, sensor_obj in sensor_dict.items(): + if cmp(sensor_name, 'Number') == 0: + continue + + si_names = [ k for k in sensor_obj.keys() ] + si_names.sort() + for si_name in si_names: + si = sensor_obj[si_name] + if si_name == "Sys_AirFlow": + status = 'OK' + airflow = si + status_table.append([sensor_name, si_name, status, airflow, airflow, airflow]) + continue + + stype = si.get('Type') + sval = si.get('Value') + slow = si.get('LowThd') + shigh = si.get('HighThd') + sunit = ' ' + fault = False + if stype != None: + sunit = type2unit.get(stype) + if sunit == None: + sunit = ' ' + try: + sval = float(sval) + except: + sval = 0.0 + fault = True + + try: + slow = float(slow) + except: + slow = 0.0 + fault = True + + try: + shigh = float(shigh) + except: + shigh = 0.0 + fault = True + + status = 'NOT_OK' + if fault == False and sval > slow and sval < shigh: + status = 'OK' + + status_table.append([sensor_name, si_name, status, (str(sval)+sunit), (str(slow)+sunit), (str(shigh)+sunit)]) + + if len(status_table) > 0: + click.echo(tabulate(status_table, header, tablefmt="simple")) + + return + +psu.add_command(status) +sensor.add_command(status) +fan.add_command(status) + + +if __name__ == '__main__': + cli() diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/power_utils/power b/platform/broadcom/sonic-platform-modules-cel/tools/power_utils/power new file mode 100755 index 000000000000..e3d42d5c0353 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/power_utils/power @@ -0,0 +1,86 @@ +#!/bin/bash +# +# Copyright 2019-present Celestica. All Rights Reserved. +# +# This program file 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. +# +# + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin + +prog="$0" + +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" + exit 1 +fi + +usage() { + echo "Usage: power " + echo + echo "Commands:" + echo + echo " cycle cpu: To power cycle the CPU" + echo + echo " cycle system : To reboot the whole system" + echo +} + +cpu_cycle() { + echo "Power cycling CPU..." + curl -m 5 -d '{"data":"/usr/local/bin/wedge_power.sh off;/usr/local/bin/wedge_power.sh on"}' http://240.1.1.1:8080/api/sys/raw + ret=$? + if [ $ret -ne 0 ]; then + echo "Failed to power cycle the CPU" + fi + return 0 +} + +system_cycle() { + echo "Power cycling system..." + curl -m 5 -d '{"data":"/usr/local/bin/wedge_power.sh off;/usr/local/bin/wedge_power.sh on;reboot"}' http://240.1.1.1:8080/api/sys/raw + ret=$? + if [ $ret -ne 0 ]; then + echo "Failed to power cycle the system" + fi + return 0 +} + +if [ $# -lt 1 ]; then + usage + exit -1 +fi + +command="$1" +component="$2" +shift + +case "$command" in +cycle) + case "$component" in + cpu) + cpu_cycle + ;; + system) + system_cycle + ;; + *) + usage + exit -1 + ;; + esac + ;; +*) + usage + exit -1 + ;; +esac + +exit $? diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/read_optic_temp.py b/platform/broadcom/sonic-platform-modules-cel/tools/read_optic_temp.py new file mode 100644 index 000000000000..97e4641066ba --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/read_optic_temp.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python +# +# read_optic_temp.py +# +# Command-line utility for read the temperature of optic modules. +# + +try: + import sys + import os + import subprocess + import click + import imp + import multiprocessing.pool + import threading +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen' +HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku' +PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform' + +PLATFORM_SPECIFIC_SFP_MODULE_NAME = "sfputil" +PLATFORM_SPECIFIC_SFP_CLASS_NAME = "SfpUtil" + +PLATFORM_SPECIFIC_OPTICTEMP_MODULE_NAME = "optictemputil" +PLATFORM_SPECIFIC_OPTICTEMP_CLASS_NAME = "OpticTempUtil" + +# Global platform-specific psuutil class instance +platform_optictemputil = None +platform_sfputil = None + + +# ==================== Methods for initialization ==================== + +# Returns platform and HW SKU +def get_platform_and_hwsku(): + try: + proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY], + stdout=subprocess.PIPE, + shell=False, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + platform = stdout.rstrip('\n') + + proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY], + stdout=subprocess.PIPE, + shell=False, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + hwsku = stdout.rstrip('\n') + except OSError, e: + raise OSError("Cannot detect platform") + + return (platform, hwsku) + + +# Returns path to port config file +def get_path_to_port_config_file(): + # Get platform and hwsku + (platform, hwsku) = get_platform_and_hwsku() + + # Load platform module from source + platform_path = "/".join([PLATFORM_ROOT_PATH, platform]) + hwsku_path = "/".join([platform_path, hwsku]) + + # First check for the presence of the new 'port_config.ini' file + port_config_file_path = "/".join([hwsku_path, "port_config.ini"]) + if not os.path.isfile(port_config_file_path): + # port_config.ini doesn't exist. Try loading the legacy 'portmap.ini' file + port_config_file_path = "/".join([hwsku_path, "portmap.ini"]) + + return port_config_file_path + + +def load_platform_util(module_name, class_name): + + # Get platform and hwsku + (platform, hwsku) = get_platform_and_hwsku() + + # Load platform module from source + platform_path = "/".join([PLATFORM_ROOT_PATH, platform]) + hwsku_path = "/".join([platform_path, hwsku]) + + try: + module_file = "/".join([platform_path, "plugins", module_name + ".py"]) + module = imp.load_source(module_name, module_file) + except IOError, e: + print("Failed to load platform module '%s': %s" % (module_name, str(e))) + sys.exit(1) + + try: + platform_util_class = getattr(module, class_name) + platform_util = platform_util_class() + except AttributeError, e: + print("Failed to instantiate '%s' class: %s" % (class_name, str(e))) + sys.exit(1) + + return platform_util + + +def get_optic_temp(port_list): + temp_list = [] + for idx, port_num in enumerate(port_list[0]): + temp = platform_optictemputil.get_optic_temp( + port_num, port_list[1][idx]) + temp_list.append(round(float(temp), 2)) + return temp_list + + +# ========================= CLI commands ========================= + +# This is our main entrypoint - the main 'opticutil' command +@click.command() +@click.option('--port_num', '-p', type=int, help='Specific port number') +def cli(port_num): + """optictemputil - Command line utility for providing platform status""" + + # Check root privileges + if os.geteuid() != 0: + click.echo("Root privileges are required for this operation") + sys.exit(1) + + global platform_optictemputil + global platform_sfputil + + # Load platform-specific class + platform_sfputil = load_platform_util( + PLATFORM_SPECIFIC_SFP_MODULE_NAME, PLATFORM_SPECIFIC_SFP_CLASS_NAME) + platform_optictemputil = load_platform_util( + PLATFORM_SPECIFIC_OPTICTEMP_MODULE_NAME, PLATFORM_SPECIFIC_OPTICTEMP_CLASS_NAME) + + # Load port config + port_config_file_path = get_path_to_port_config_file() + platform_sfputil.read_porttab_mappings(port_config_file_path) + port_list = platform_sfputil.port_to_i2cbus_mapping + port_eeprom_list = platform_sfputil.port_to_eeprom_mapping + qsfp_port_list = platform_sfputil.qsfp_ports + + port_dict = {} + temp_list = [0] + i2c_block_size = 32 + concurrent = 10 + + port_data_list = [] + port_bus_list = [] + port_type_list = [] + + # Read port temperature + if port_num: + if port_num not in port_list: + click.echo("Invalid port") + sys.exit(1) + port_list = {port_num: port_list.get(port_num)} + + for port_num, bus_num in port_list.items(): + port_type = "QSFP" if port_num in qsfp_port_list else "SFP" + port_bus_list.append(port_eeprom_list[port_num]) + port_type_list.append(port_type) + if len(port_bus_list) >= i2c_block_size: + port_tub = (port_bus_list, port_type_list) + port_data_list.append(port_tub) + port_bus_list = [] + port_type_list = [] + + if port_bus_list != []: + port_tub = (port_bus_list, port_type_list) + port_data_list.append(port_tub) + + pool = multiprocessing.pool.ThreadPool(processes=concurrent) + temp_list = pool.map(get_optic_temp, port_data_list, chunksize=1) + pool.close() + + flat_list = [item for sublist in temp_list for item in sublist] + click.echo("| PORT_NO\t| PORT_TYPE\t| TEMPERATURE\t|") + for port_num, bus_num in port_list.items(): + port_type = "QSFP" if port_num in qsfp_port_list else "SFP" + temp_idx = port_list.keys().index(port_num) + temp = flat_list[temp_idx] + click.echo('| {}\t\t| {}\t\t| {}\t\t|'.format( + port_num, port_type, temp)) + + +if __name__ == '__main__': + cli() diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.service b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.service new file mode 100644 index 000000000000..9aeeead72394 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.service @@ -0,0 +1,12 @@ +[Unit] +Description="Service for add vlan for rsyslog" +After=network.target +Before=rsyslog-config.service +Before=ntp.service + +[Service] +Type=forking +ExecStart=/bin/sh /usr/local/etc/bmc_vlan.sh + +[Install] +WantedBy=rsyslog.service \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.sh b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.sh new file mode 100644 index 000000000000..1d439915efb0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Add vlan +ip link add link eth0 name eth0.4088 type vlan id 4088 +ip addr add 240.1.1.2/30 dev eth0.4088 +ip link set eth0.4088 up +exit 0 \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.py b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.py new file mode 100644 index 000000000000..3065e8a21ebf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python + +############################################################################# +# # +# Platform and model specific service for send data to BMC # +# # +# # +############################################################################# + +import subprocess +import requests +import os +import imp +import multiprocessing.pool +import threading + + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen' +HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku' +PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform' +TEMP_URL = 'http://240.1.1.1:8080/api/sys/temp' + +PLATFORM_SPECIFIC_SFP_MODULE_NAME = "sfputil" +PLATFORM_SPECIFIC_SFP_CLASS_NAME = "SfpUtil" + +PLATFORM_SPECIFIC_OPTICTEMP_MODULE_NAME = "optictemputil" +PLATFORM_SPECIFIC_OPTICTEMP_CLASS_NAME = "OpticTempUtil" + +PLATFORM_SPECIFIC_CPUTEMP_MODULE_NAME = "cputemputil" +PLATFORM_SPECIFIC_CPUTEMP_CLASS_NAME = "CpuTempUtil" + +platform_sfputil = None +platform_optictemputil = None +platform_cputemputil = None + + +# Returns platform and HW SKU +def get_platform_and_hwsku(): + try: + proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY], + stdout=subprocess.PIPE, + shell=False, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + platform = stdout.rstrip('\n') + + proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY], + stdout=subprocess.PIPE, + shell=False, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + hwsku = stdout.rstrip('\n') + except OSError, e: + raise OSError("Cannot detect platform") + + return (platform, hwsku) + + +# Returns path to port config file +def get_path_to_port_config_file(): + # Get platform and hwsku + (platform, hwsku) = get_platform_and_hwsku() + + # Load platform module from source + platform_path = "/".join([PLATFORM_ROOT_PATH, platform]) + hwsku_path = "/".join([platform_path, hwsku]) + + # First check for the presence of the new 'port_config.ini' file + port_config_file_path = "/".join([hwsku_path, "port_config.ini"]) + if not os.path.isfile(port_config_file_path): + # port_config.ini doesn't exist. Try loading the legacy 'portmap.ini' file + port_config_file_path = "/".join([hwsku_path, "portmap.ini"]) + + return port_config_file_path + + +def load_platform_util(module_name, class_name): + + # Get platform and hwsku + (platform, hwsku) = get_platform_and_hwsku() + + # Load platform module from source + platform_path = "/".join([PLATFORM_ROOT_PATH, platform]) + hwsku_path = "/".join([platform_path, hwsku]) + + try: + module_file = "/".join([platform_path, "plugins", module_name + ".py"]) + module = imp.load_source(module_name, module_file) + except IOError, e: + print("Failed to load platform module '%s': %s" % ( + module_name, str(e)), True) + return -1 + + try: + platform_util_class = getattr(module, class_name) + platform_util = platform_util_class() + except AttributeError, e: + print("Failed to instantiate '%s' class: %s" % + (class_name, str(e)), True) + return -2 + + return platform_util + + +def get_optic_temp(port_list): + temp_list = [] + for idx, port_eeprom in enumerate(port_list[0]): + temp = platform_optictemputil.get_optic_temp( + port_eeprom, port_list[1][idx]) if port_list[2][idx] else 0 + temp_list.append(round(float(temp), 2)) + return max(temp_list) + + +def get_max_optic_temp(): + port_config_file_path = get_path_to_port_config_file() + platform_sfputil.read_porttab_mappings(port_config_file_path) + port_list = platform_sfputil.port_to_i2cbus_mapping + port_eeprom_list = platform_sfputil.port_to_eeprom_mapping + qsfp_port_list = platform_sfputil.qsfp_ports + + port_data_list = [] + temp_list = [0] + i2c_block_size = 32 + concurrent = 10 + + port_bus_list = [] + port_type_list = [] + port_presence_list = [] + + for port_num, bus_num in port_list.items(): + port_type = "QSFP" if port_num in qsfp_port_list else "SFP" + port_bus_list.append(port_eeprom_list[port_num]) + port_type_list.append(port_type) + status = platform_sfputil.get_presence(port_num) + port_presence_list.append(status) + if len(port_bus_list) >= i2c_block_size: + port_tub = (port_bus_list, port_type_list, port_presence_list) + port_data_list.append(port_tub) + port_bus_list = [] + port_type_list = [] + port_presence_list = [] + + if port_bus_list != []: + port_tub = (port_bus_list, port_type_list, port_presence_list) + port_data_list.append(port_tub) + + pool = multiprocessing.pool.ThreadPool(processes=concurrent) + temp_list = pool.map(get_optic_temp, port_data_list, chunksize=1) + pool.close() + return max(temp_list) + + +# Send CPU temperature to BMC. +def send_cpu_temp(): + max_cpu_tmp = platform_cputemputil.get_max_cpu_tmp() + json_input = { + "chip": "cpu", + "option": "input", + "value": str(int(max_cpu_tmp)) + } + print "send ", json_input + requests.post(TEMP_URL, json=json_input) + + +# Send maximum optic module temperature to BMC. +def send_optic_temp(): + max_optic_temp = get_max_optic_temp() + json_input = { + "chip": "optical", + "option": "input", + "value": str(int(max_optic_temp)) + } + print "send ", json_input + requests.post(TEMP_URL, json=json_input) + + +def main(): + global platform_sfputil + global platform_cputemputil + global platform_optictemputil + + try: + platform_sfputil = load_platform_util( + PLATFORM_SPECIFIC_SFP_MODULE_NAME, PLATFORM_SPECIFIC_SFP_CLASS_NAME) + platform_cputemputil = load_platform_util( + PLATFORM_SPECIFIC_CPUTEMP_MODULE_NAME, PLATFORM_SPECIFIC_CPUTEMP_CLASS_NAME) + platform_optictemputil = load_platform_util( + PLATFORM_SPECIFIC_OPTICTEMP_MODULE_NAME, PLATFORM_SPECIFIC_OPTICTEMP_CLASS_NAME) + + t1 = threading.Thread(target=send_cpu_temp) + t2 = threading.Thread(target=send_optic_temp) + t1.start() + t2.start() + except Exception, e: + print e + pass + + +if __name__ == "__main__": + main() diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.service b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.service new file mode 100644 index 000000000000..334485342510 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.service @@ -0,0 +1,10 @@ +[Unit] +Description=Service for send sensor data value to BMC. +After=multi-user.target + +[Service] +Type=idle +ExecStart=/usr/bin/python /usr/local/etc/sync_bmc.py + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.timer b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.timer new file mode 100644 index 000000000000..71666cc99887 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Timer send sensor data value to BMC. + +[Timer] +OnUnitActiveSec=5s +OnBootSec=5s +AccuracySec=1us + +[Install] +WantedBy=timers.target \ No newline at end of file