From 16b7c2028f0f732f5bd53b59cfd9a41cd37008d6 Mon Sep 17 00:00:00 2001 From: Arun LK Date: Tue, 24 Aug 2021 15:29:33 +0530 Subject: [PATCH 1/4] DellEMC: N3248PXE Initial platform commit --- .../DELLEMC-N3248PXE/buffers.json.j2 | 2 + .../DELLEMC-N3248PXE/buffers_defaults_t0.j2 | 41 + .../DELLEMC-N3248PXE/buffers_defaults_t1.j2 | 41 + .../DELLEMC-N3248PXE/custom_led.bin | Bin 0 -> 606 bytes .../DELLEMC-N3248PXE/linkscan_led_fw.bin | Bin 0 -> 6100 bytes .../DELLEMC-N3248PXE/pg_profile_lookup.ini | 17 + .../DELLEMC-N3248PXE/port_config.ini | 55 + .../DELLEMC-N3248PXE/qos.json.j2 | 1 + .../DELLEMC-N3248PXE/qos_config_t1.j2 | 175 +++ .../DELLEMC-N3248PXE/sai.profile | 1 + .../DELLEMC-N3248PXE/sai_preinit_cmd.soc | 2 + ...-n3248pxe-48x10GCU+4x25G-2x100G.config.bcm | 364 +++++ .../default_sku | 1 + .../installer.conf | 2 + .../led_proc_init.soc | 7 + .../plugins/eeprom.py | 22 + .../plugins/fanutil.py | 73 + .../plugins/psuutil.py | 191 +++ .../plugins/sfputil.py | 176 +++ .../pmon_daemon_control.json | 3 + .../sensors.conf | 58 + platform/broadcom/one-image.mk | 1 + platform/broadcom/platform-modules-dell.mk | 6 + .../debian/control | 5 + .../debian/platform-modules-n3248pxe.init | 39 + .../debian/platform-modules-n3248pxe.install | 12 + .../debian/platform-modules-n3248pxe.postinst | 7 + .../sonic-platform-modules-dell/debian/rules | 13 +- .../n3248pxe/cfg/n3248pxe-modules.conf | 14 + .../n3248pxe/modules/Makefile | 2 + .../n3248pxe/modules/dell_n3248pxe_platform.c | 1207 +++++++++++++++++ .../n3248pxe/modules/emc2305.c | 877 ++++++++++++ .../n3248pxe/modules/pmbus.h | 425 ++++++ .../n3248pxe/scripts/fancontrol.sh | 78 ++ .../n3248pxe/scripts/n3248pxe_platform.sh | 141 ++ .../n3248pxe/scripts/platform_sensors.py | 139 ++ .../n3248pxe/scripts/portiocfg.py | 106 ++ .../n3248pxe/scripts/ports_xcvrd_notify.py | 113 ++ .../n3248pxe/scripts/sensors | 8 + .../n3248pxe/setup.py | 1 + .../n3248pxe/sonic_platform/__init__.py | 8 + .../n3248pxe/sonic_platform/chassis.py | 344 +++++ .../n3248pxe/sonic_platform/component.py | 84 ++ .../n3248pxe/sonic_platform/eeprom.py | 134 ++ .../n3248pxe/sonic_platform/fan.py | 171 +++ .../n3248pxe/sonic_platform/fan_drawer.py | 37 + .../n3248pxe/sonic_platform/ipmihelper.py | 269 ++++ .../n3248pxe/sonic_platform/platform.py | 24 + .../n3248pxe/sonic_platform/psu.py | 204 +++ .../n3248pxe/sonic_platform/sfp.py | 785 +++++++++++ .../n3248pxe/sonic_platform/thermal.py | 145 ++ .../n3248pxe/sonic_platform/watchdog.py | 214 +++ .../systemd/platform-modules-n3248pxe.service | 13 + 53 files changed, 6857 insertions(+), 1 deletion(-) create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/buffers.json.j2 create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/buffers_defaults_t0.j2 create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/buffers_defaults_t1.j2 create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/custom_led.bin create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/linkscan_led_fw.bin create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/pg_profile_lookup.ini create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/port_config.ini create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/qos.json.j2 create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/qos_config_t1.j2 create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/sai.profile create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/sai_preinit_cmd.soc create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/td3-x5-n3248pxe-48x10GCU+4x25G-2x100G.config.bcm create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/default_sku create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/installer.conf create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/led_proc_init.soc create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/eeprom.py create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/fanutil.py create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/psuutil.py create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/sfputil.py create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/pmon_daemon_control.json create mode 100644 device/dell/x86_64-dellemc_n3248pxe_c3338-r0/sensors.conf create mode 100755 platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-n3248pxe.init create mode 100644 platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-n3248pxe.install create mode 100644 platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-n3248pxe.postinst create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/cfg/n3248pxe-modules.conf create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/dell_n3248pxe_platform.c create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/emc2305.c create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/pmbus.h create mode 100755 platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/fancontrol.sh create mode 100755 platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/n3248pxe_platform.sh create mode 100755 platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/platform_sensors.py create mode 100755 platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/portiocfg.py create mode 100755 platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/ports_xcvrd_notify.py create mode 100755 platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/sensors create mode 120000 platform/broadcom/sonic-platform-modules-dell/n3248pxe/setup.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/__init__.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/chassis.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/component.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/eeprom.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan_drawer.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/ipmihelper.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/platform.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/psu.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/sfp.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/thermal.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/watchdog.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/n3248pxe/systemd/platform-modules-n3248pxe.service diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/buffers.json.j2 b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/buffers.json.j2 new file mode 100644 index 000000000000..1083a6210fc9 --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/buffers.json.j2 @@ -0,0 +1,2 @@ +{%- set default_topo = 't0' %} +{%- include 'buffers_config.j2' %} diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/buffers_defaults_t0.j2 b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/buffers_defaults_t0.j2 new file mode 100644 index 000000000000..bfd81d10049f --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/buffers_defaults_t0.j2 @@ -0,0 +1,41 @@ +{%- set default_cable = '5m' %} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {% for port_idx in range(0,32) %} + {% if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{% endif %} + {% endfor %} +{%- endmacro %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "8192000", + "type": "ingress", + "mode": "dynamic", + "xoff": "196608" + }, + "egress_lossless_pool": { + "size": "8388608", + "type": "egress", + "mode": "static" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "dynamic_th":"3" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"0", + "static_th":"8388608" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/buffers_defaults_t1.j2 b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/buffers_defaults_t1.j2 new file mode 100644 index 000000000000..3b9cd1f104d6 --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/buffers_defaults_t1.j2 @@ -0,0 +1,41 @@ +{%- set default_cable = '300m' %} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {% for port_idx in range(0,32) %} + {% if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{% endif %} + {% endfor %} +{%- endmacro %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "8192000", + "type": "ingress", + "mode": "dynamic", + "xoff": "196608" + }, + "egress_lossless_pool": { + "size": "8388608", + "type": "egress", + "mode": "static" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "dynamic_th":"3" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"0", + "static_th":"8388608" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/custom_led.bin b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/custom_led.bin new file mode 100644 index 0000000000000000000000000000000000000000..631b4712fa28c7bfb63dc04864b96e88166f1939 GIT binary patch literal 606 zcmW-cy>C)s6vm(TUJ#Jd+9I~dEiJqSELU2~hiK6X7kU~(8WTx0K%=E5=B6_PBZkCi zyZEtybTZw#)J8jLV&dp>S#|MGVAjQhXFkvK`#q!2Pv{|SQ;9~Ox~CHw-XQ#_+=;2O zM~c+)$0X!?@@TEh;aub8;Q961hNI)rIAZ;k;?5t_L+sgJHJJ(ta#_u_EH7U#u`6!?JVS@wYzaZkn~KNFSdm zNoRaGL}c-PCpxD2^KPwX)Cv{jh;mvh)hAusPyMM^g98Y&R)?H4JXY82kx>%s-nJ{Z zW9$^9CQ=6uVeOGOAJ_JiWjd&f^|u(HU{)U}8E4|xP{{AQkZLn4i%pyCHr3NRUtUw6 zKF|q`zJ84dihT8@P*2Y@v+G7>QfR;wCakBZVZ^_-mEF6P(gH zz055!Zi{fMBeODy2<0Fzf$^h#+H!Z9Oa7pZm{+83*C3Lx_rGposIGZS^|;VI$*X#V66@wioj7W&gBOLZDL3;78z)R zak*uPkNLrIC0>|F2z5fg%XBW`AKuTfUln@!MnC1-=x_FI6yD{VdA~sM9;=^!PJr1^XAn;d zP<7B%K0M?b;L8&zkqbn(`A+!K$T>di9T@xf4BP7i2^c> zoE8qcJ|6}q5Cs=|4(T)u;*_s<@4CIPTvi3o%C*DKZve{evkP3z0sl$XJN{9ZXOS(OZ>K z^Reg6sZsNgjwqw%<0!d+eVP~7Wz%;BTAUFR(cqk-w0OA_*PurFv;-^6Q}nY6eRb56 zQ=?2oZ?``~rC!T|gBFd5w>fG;ea#qScyJVmELsgPQu+x=YLc340^Q`sx;aWIBex2> zT=Y4aE6~CUtOW!!_6A!1vYl31Q?~;kY7lr0O9U|vQDz7=qP42c2iH`YLo=#X>--zm z{_TUl4cH6DQ@dQM;jpFOr5)BKz`vq=hb36q>!L=kY9kQQ*fX9I8mhhA5{sANIfrFv zE!647=5^Xr`&??VcOBGGVr*T1OSjeBaAEX#3`qi@h5$hre27uDDd z^e1jAWzT+!NZ%u=$!B~u?tO(s5gvxveqFFw;LQ%|BQqoL3D6?KZ8*wVA*EX+zX1EF z)Y*)d0AowMs^3jCHS{5|Z4T|{{?+2OfxVf#&oYfTY9Hp-dH=c0Z&}9EPwwJR@(+>% zA5`t~6|8>W*J*8Ay^zrLpO3OuIMna@{fO*6-t6&qs^$o4L@!pNM&9;NKCms}n|(NQ zu7>}Iq&f00t)0R?7d@g@G^4SX&|dD<);>hV%}uv-p&!$tM(G1PRqbHBoW;^F(>6N9ET9b>`7M${eO)P1Q`gi`&r#_L#+6wSr?UeckVLn@ONW9vf)M zufMl7Xz|*YWAD|LN3OLvoPm~1q)4%Oe-1)0r&x3ny;DcN^i!#o8CQjkI8a09bLgk2 z-x!xs){%)eVbp5H{$r$yU>p;SiN|3Ld3(in_~Y`qe%9)-ZgWALX7;%*jqpO9KZq7c zk3cFZ^;>x!!jugJJqL&MXw{kM<;eCy4d}&-{`o>cc+926SP|n4gDGXUv81Nfj~1al z_$(al+6t$=^*BSf^;vm_>R-DqkI>;Dlsc)@{Tcls)Gu!kOYO*!Iw9%9^kGWSFdvqg z5;V#@ll;GAIB}J+vivF!;wqiIHXKc6BBewJ1`!VGNg*PW^F!(bsks6eQ$j{L6TRcQ zwe-RBUH=G|y#2T)2-gWgX!OeaOGm2O`v!}N2Fzj;O1bDqtW(cRu8Kwl-v-22tKh4- zwr2=K>X5`%Kqw%*Mdl&ORLGdvg(#1AZHJNNHz_D@RZxZ}54pY`*(jW})cNx}xCM6* z;Hj|s$siOZ09LU8CM*+o18^#U{^+SjbtBUy&KAx z%UFA?effC~%lZW7g=8S22A!De$hqs#K1`E{dYnqg5uuKZq35fxMI|z*gYNM_w7Zfw z1VM8C#3`j$PRdc^@L+iu9Jh$64yfKhOt0`1Yn9Sxq-UU~tJ_MmpSzt-w#&@XY{2_> zUQ@%xQK%6pnEfJHLYA;R_HAjwiXKw3qJT_iY4(7N7Ts(ww_y1u>%6%aM$5zNt<-YU zoKHr9nTeRHP*-Eg6h`ztgKh>=9!Udth;<|h;ZC9st3lwv+yiC_nv8n!>5vV=_&1KH6(nd&~%ynB$4Od3r zKx_ab<!p8-mo%To9ZN`Xkv6FDHSapVKHS-lMD-s(%TovQiwk zDMvroZS7xfYWN1xD0;CMclD4m#%ZUYD<6Q=yj;->z?8q-3wz3b)HUbfPW=U4J;z#C zdJ7zX9ziSa+P2iAFGE}Ih1FfG^+(D|d)uMLIbTpTm(EdS0OobAw;EZy*EHwyHGNSb zO3~MU;)tKPf86SH!itg=D%6@0wWbyWt<9`+UO#76H22x)I`{0C>UK=#${?!7&1Mtw%tXVkTW)3 z^gP%cNWD2;6prZ@$4&Tc7UdCg|KPakFpcXs?N=+Kj*ScCMvN!d=OC+=05o81abUSV z_n43*$%$=JT9+#ff#b&blBJ71Tfw>DRM$6MJ!H76ke$ZvaZw^weF^Q~0cm?*-WZC zVpo#=(VWp@jIgBXTgnNhhH=E(V2DyqlWAmaly>y}c?t^C?$5bA|fWx)lk z_21S&$mvLb1l4QYRF%!rLwJm99D zkkUsngEoxb=MMG&)m)7Jtz(OuSt_)Vrx+)nLt8`7s?}nwWi2-lQ%IL^qJ8#fzyTsv zYYK0&4!XWM4>x}gPaHkjh3I;$qSsWH9aUF(JRV#{FV4{XdpRqXBc^QKe&oJgv{TEi z=6OFS&O{ShfSk*@D{ppa&fVJD4?#N8`Z`o@BaZKdH9Iy z?eoCAk!*_Ku0^)e-p(4dBIPI*g8*fCy9+f%0Z$DJu23yfNKHqIiYKs#wqYb-w22$s z_*)^5rEE0j!y6Fgrl`(i6rdhu+51?xK+B#mbw@I(rkNSEg}2Z)pc!$a%?+>(XrPP!eZw=TDF8J>WRW8%2}HfH&0wCChI1scg->ls=GQFiZZcIDt8d&IDk^{oYi7 z`^C(GLL_V5fffS;D$H9M7QY1w4G}4QQQDz4nAnwgd&62%sku5KYIVcrKufttACSK> zok2J)bmDmtE2g>Ae4yn9*=Bwk)5VGdEhV0q)*$TkcN#jWSP{+b#M^wKyBqUTcw8PK zYtU0U9uKtWl-A&1v|?OCe{I4wFUFFJ9B7?Yb3)kPcA)(w%{~Fo@dCuLs-FeQU zp1#lO{U43F5%$8poAUDLt8^Y6tndRSSq9K*fLc{UR%8CP(oV zW{2hd2N_2O^Bg!NrEkn?fL1I$7p2e-@dYERA}M}uD`sX`b7j?N+jUBmw`JwiU{Dwm z7H~tj7H2@d&&s}4)gh&ab2Hn)VMhOyX?(57mAieyK#K)^i<0=wQu;%sRZDnW139R_qY?v{SKIhTL<~|Z zvrU9XWQU|2WR?eO7%I5Dn|0KzI zlgwF!ycWz)XJ=(Tz&8W7viIm6IJ=adod!B7n=KA;5%v|t z_1HHfu@Fbsh<9QO9WTI^qC^8}R8V;*lgFzL@xr@9m`XsHw!7~6DyhQSSW=DObW)4o zKPPqg{W@vD@5Q7Mzh7Xc3O3m1$DM7+sG<0bYBoH5g@ZW;(Sf_znZb)(>cxykTX5sF znGDF;YyQ4&l;j*kzPZoAx0RA9da;zjY(#EdDP5kT1nFXOzH&SHImYHp)Qxtx7|VbU z;HL!OGn}G&Op=cMha_dHDG=V1q|`Y{;vddQu}c$@Gg3fg&tmXB#E>W?XW6G+nvn|f z1nZeugI~7n2GUsxbG|Seg@l;RuChz4g=5lGx?J>b#|f4S=9DyE!@L&KFg&SHZK zwoDoNrlL0MM%)RbmOgy}+z8L6zursm>XR zM}WF)9O{kYbm6h`r(Ehd2o{T(HxoMHtI9dc62bW!{hg5Dgy}pTQzz&OGv+^E#?i*{ zZM13X1uhlUwrbsGUfWtyKCB;x#W9L$;y+Awp?rA`wHGjO0MH5jNz}m*)Q{l_C%?;5 r32LZh7SzipUVi`b`|m0o-h^13!6LsQJYocJBmG@}mEYC*|LFT~Y{;3K literal 0 HcmV?d00001 diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/pg_profile_lookup.ini b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/pg_profile_lookup.ini new file mode 100644 index 000000000000..6d91d03ae684 --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/pg_profile_lookup.ini @@ -0,0 +1,17 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold xon_offset + 10000 5m 9427 0 50176 1 3584 + 25000 5m 9427 0 50176 1 3584 + 40000 5m 9427 0 50176 1 3584 + 50000 5m 9427 0 50176 1 3584 + 100000 5m 9427 0 50176 1 3584 + 10000 40m 9427 0 50176 1 3584 + 25000 40m 9427 0 50176 1 3584 + 40000 40m 9427 0 50176 1 3584 + 50000 40m 9427 0 50176 1 3584 + 100000 40m 9427 0 50176 1 3584 + 10000 300m 9427 0 50176 1 3584 + 25000 300m 9427 0 50176 1 3584 + 40000 300m 9427 0 50176 1 3584 + 50000 300m 9427 0 50176 1 3584 + 100000 300m 9427 0 50176 1 3584 diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/port_config.ini b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/port_config.ini new file mode 100644 index 000000000000..e4ba2868ee3d --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/port_config.ini @@ -0,0 +1,55 @@ +# name lanes alias index speed +Ethernet0 62 tenGigE1/1 1 10000 +Ethernet1 61 tenGigE1/2 2 10000 +Ethernet2 64 tenGigE1/3 3 10000 +Ethernet3 63 tenGigE1/4 4 10000 +Ethernet4 66 tenGigE1/5 5 10000 +Ethernet5 65 tenGigE1/6 6 10000 +Ethernet6 68 tenGigE1/7 7 10000 +Ethernet7 67 tenGigE1/8 8 10000 +Ethernet8 70 tenGigE1/9 9 10000 +Ethernet9 69 tenGigE1/10 10 10000 +Ethernet10 72 tenGigE1/11 11 10000 +Ethernet11 71 tenGigE1/12 12 10000 +Ethernet12 74 tenGigE1/13 13 10000 +Ethernet13 73 tenGigE1/14 14 10000 +Ethernet14 76 tenGigE1/15 15 10000 +Ethernet15 75 tenGigE1/16 16 10000 +Ethernet16 78 tenGigE1/17 17 10000 +Ethernet17 77 tenGigE1/18 18 10000 +Ethernet18 80 tenGigE1/19 19 10000 +Ethernet19 79 tenGigE1/20 20 10000 +Ethernet20 3 tenGigE1/21 21 10000 +Ethernet21 4 tenGigE1/22 22 10000 +Ethernet22 1 tenGigE1/23 23 10000 +Ethernet23 2 tenGigE1/24 24 10000 +Ethernet24 7 tenGigE1/25 25 10000 +Ethernet25 8 tenGigE1/26 26 10000 +Ethernet26 5 tenGigE1/27 27 10000 +Ethernet27 6 tenGigE1/28 28 10000 +Ethernet28 11 tenGigE1/29 29 10000 +Ethernet29 12 tenGigE1/30 30 10000 +Ethernet30 9 tenGigE1/31 31 10000 +Ethernet31 10 tenGigE1/32 32 10000 +Ethernet32 15 tenGigE1/33 33 10000 +Ethernet33 16 tenGigE1/34 34 10000 +Ethernet34 13 tenGigE1/35 35 10000 +Ethernet35 14 tenGigE1/36 36 10000 +Ethernet36 19 tenGigE1/37 37 10000 +Ethernet37 20 tenGigE1/38 38 10000 +Ethernet38 17 tenGigE1/39 39 10000 +Ethernet39 18 tenGigE1/40 40 10000 +Ethernet40 23 tenGigE1/41 41 10000 +Ethernet41 24 tenGigE1/42 42 10000 +Ethernet42 21 tenGigE1/43 43 10000 +Ethernet43 22 tenGigE1/44 44 10000 +Ethernet44 27 tenGigE1/45 45 10000 +Ethernet45 28 tenGigE1/46 46 10000 +Ethernet46 25 tenGigE1/47 47 10000 +Ethernet47 26 tenGigE1/48 48 10000 +Ethernet48 40 twentyfiveGigE1/49 49 25000 +Ethernet49 39 twentyfiveGigE1/50 50 25000 +Ethernet50 38 twentyfiveGigE1/51 51 25000 +Ethernet51 37 twentyfiveGigE1/52 52 25000 +Ethernet52 41,42,43,44 hundredGigE1/53 53 100000 +Ethernet56 45,46,47,48 hundredGigE1/54 54 100000 diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/qos.json.j2 b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/qos.json.j2 new file mode 100644 index 000000000000..ee67c6e26221 --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/qos.json.j2 @@ -0,0 +1 @@ +{%- include 'qos_config_t1.j2' %} diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/qos_config_t1.j2 b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/qos_config_t1.j2 new file mode 100644 index 000000000000..5fe5324a85c1 --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/qos_config_t1.j2 @@ -0,0 +1,175 @@ +{%- set PORT_ALL = [] %} +{%- for port in PORT %} + {%- if PORT_ALL.append(port) %}{% endif %} +{%- endfor %} +{%- if PORT_ALL | sort_by_port_index %}{% endif %} + +{%- set port_names_list_all = [] %} +{%- for port in PORT_ALL %} + {%- if port_names_list_all.append(port) %}{% endif %} +{%- endfor %} +{%- set port_names_all = port_names_list_all | join(',') -%} + + +{%- set PORT_ACTIVE = [] %} +{%- if DEVICE_NEIGHBOR is not defined %} + {%- set PORT_ACTIVE = PORT_ALL %} +{%- else %} + {%- for port in DEVICE_NEIGHBOR.keys() %} + {%- if PORT_ACTIVE.append(port) %}{%- endif %} + {%- endfor %} +{%- endif %} +{%- if PORT_ACTIVE | sort_by_port_index %}{% endif %} + +{%- set port_names_list_active = [] %} +{%- for port in PORT_ACTIVE %} + {%- if port_names_list_active.append(port) %}{%- endif %} +{%- endfor %} +{%- set port_names_active = port_names_list_active | join(',') -%} + + +{%- set pfc_to_pg_map_supported_asics = ['mellanox', 'barefoot', 'marvell'] -%} + + +{ +{% if generate_tc_to_pg_map is defined %} + {{- generate_tc_to_pg_map() }} +{% else %} + "TC_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "0": "0", + "1": "0", + "2": "0", + "3": "3", + "4": "4", + "5": "0", + "6": "0", + "7": "7" + } + }, +{% endif %} + "MAP_PFC_PRIORITY_TO_QUEUE": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "TC_TO_QUEUE_MAP": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "DSCP_TO_TC_MAP": { + "AZURE": { + "0" : "1", + "1" : "1", + "2" : "1", + "3" : "3", + "4" : "4", + "5" : "2", + "6" : "1", + "7" : "1", + "8" : "0", + "9" : "1", + "10": "1", + "11": "1", + "12": "1", + "13": "1", + "14": "1", + "15": "1", + "16": "1", + "17": "1", + "18": "1", + "19": "1", + "20": "1", + "21": "1", + "22": "1", + "23": "1", + "24": "1", + "25": "1", + "26": "1", + "27": "1", + "28": "1", + "29": "1", + "30": "1", + "31": "1", + "32": "1", + "33": "1", + "34": "1", + "35": "1", + "36": "1", + "37": "1", + "38": "1", + "39": "1", + "40": "1", + "41": "1", + "42": "1", + "43": "1", + "44": "1", + "45": "1", + "46": "5", + "47": "1", + "48": "6", + "49": "1", + "50": "1", + "51": "1", + "52": "1", + "53": "1", + "54": "1", + "55": "1", + "56": "1", + "57": "1", + "58": "1", + "59": "1", + "60": "1", + "61": "1", + "62": "1", + "63": "1" + } + }, + "SCHEDULER": { + "scheduler.0": { + "type" : "DWRR", + "weight": "14" + }, + "scheduler.1": { + "type" : "DWRR", + "weight": "15" + } + }, +{% if asic_type in pfc_to_pg_map_supported_asics %} + "PFC_PRIORITY_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "3": "3", + "4": "4" + } + }, +{% endif %} + "PORT_QOS_MAP": { +{% for port in PORT_ACTIVE %} + "{{ port }}": { + "dscp_to_tc_map" : "[DSCP_TO_TC_MAP|AZURE]", + "tc_to_queue_map" : "[TC_TO_QUEUE_MAP|AZURE]", + "tc_to_pg_map" : "[TC_TO_PRIORITY_GROUP_MAP|AZURE]", + "pfc_to_queue_map": "[MAP_PFC_PRIORITY_TO_QUEUE|AZURE]", +{% if asic_type in pfc_to_pg_map_supported_asics %} + "pfc_to_pg_map" : "[PFC_PRIORITY_TO_PRIORITY_GROUP_MAP|AZURE]", +{% endif %} + "pfc_enable" : "3,4" + }{% if not loop.last %},{% endif %} +{% endfor %} + } +} diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/sai.profile b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/sai.profile new file mode 100644 index 000000000000..cee88bc7e762 --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td3-x5-n3248pxe-48x10GCU+4x25G-2x100G.config.bcm diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/sai_preinit_cmd.soc b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/sai_preinit_cmd.soc new file mode 100644 index 000000000000..4d62900f898f --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/sai_preinit_cmd.soc @@ -0,0 +1,2 @@ +m0 load 0 0x0 /usr/share/sonic/hwsku/linkscan_led_fw.bin +m0 load 0 0x3800 /usr/share/sonic/hwsku/custom_led.bin diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/td3-x5-n3248pxe-48x10GCU+4x25G-2x100G.config.bcm b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/td3-x5-n3248pxe-48x10GCU+4x25G-2x100G.config.bcm new file mode 100644 index 000000000000..b6a424f55eda --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/td3-x5-n3248pxe-48x10GCU+4x25G-2x100G.config.bcm @@ -0,0 +1,364 @@ +pbmp_xport_xe=0x1FFFFFFFFFFFFFFE + +# PM 4x25: CLP0 +portmap_1=1:10 +portmap_2=2:10 +portmap_3=3:10 +portmap_4=4:10 + +phy_chain_tx_polarity_flip_physical{1}=0x1 +phy_chain_tx_polarity_flip_physical{2}=0x0 +phy_chain_tx_polarity_flip_physical{3}=0x1 +phy_chain_tx_polarity_flip_physical{4}=0x0 + +phy_chain_rx_polarity_flip_physical{1}=0x0 +phy_chain_rx_polarity_flip_physical{2}=0x1 +phy_chain_rx_polarity_flip_physical{3}=0x0 +phy_chain_rx_polarity_flip_physical{4}=0x1 + +# PM 4x25: CLP1 +portmap_5=5:10 +portmap_6=6:10 +portmap_7=7:10 +portmap_8=8:10 + +phy_chain_tx_polarity_flip_physical{5}=0x0 +phy_chain_tx_polarity_flip_physical{6}=0x1 +phy_chain_tx_polarity_flip_physical{7}=0x0 +phy_chain_tx_polarity_flip_physical{8}=0x1 + +phy_chain_rx_polarity_flip_physical{5}=0x1 +phy_chain_rx_polarity_flip_physical{6}=0x0 +phy_chain_rx_polarity_flip_physical{7}=0x1 +phy_chain_rx_polarity_flip_physical{8}=0x0 + + +# PM 4x25: CLP2 +portmap_9=9:10 +portmap_10=10:10 +portmap_11=11:10 +portmap_12=12:10 + +phy_chain_tx_polarity_flip_physical{9}=0x1 +phy_chain_tx_polarity_flip_physical{10}=0x0 +phy_chain_tx_polarity_flip_physical{11}=0x1 +phy_chain_tx_polarity_flip_physical{12}=0x0 + +phy_chain_rx_polarity_flip_physical{9}=0x1 +phy_chain_rx_polarity_flip_physical{10}=0x0 +phy_chain_rx_polarity_flip_physical{11}=0x1 +phy_chain_rx_polarity_flip_physical{12}=0x0 + + + +# PM 4x25: CLP3 +portmap_13=13:10 +portmap_14=14:10 +portmap_15=15:10 +portmap_16=16:10 + +phy_chain_tx_polarity_flip_physical{13}=0x0 +phy_chain_tx_polarity_flip_physical{14}=0x1 +phy_chain_tx_polarity_flip_physical{15}=0x0 +phy_chain_tx_polarity_flip_physical{16}=0x1 + +phy_chain_rx_polarity_flip_physical{13}=0x1 +phy_chain_rx_polarity_flip_physical{14}=0x0 +phy_chain_rx_polarity_flip_physical{15}=0x1 +phy_chain_rx_polarity_flip_physical{16}=0x0 + + +# PM 4x25: CLP4 +portmap_17=17:10 +portmap_18=18:10 +portmap_19=19:10 +portmap_20=20:10 + +phy_chain_tx_polarity_flip_physical{17}=0x1 +phy_chain_tx_polarity_flip_physical{18}=0x0 +phy_chain_tx_polarity_flip_physical{19}=0x1 +phy_chain_tx_polarity_flip_physical{20}=0x0 + +phy_chain_rx_polarity_flip_physical{17}=0x0 +phy_chain_rx_polarity_flip_physical{18}=0x1 +phy_chain_rx_polarity_flip_physical{19}=0x0 +phy_chain_rx_polarity_flip_physical{20}=0x1 + +# PM 4x25: CLP5 +portmap_21=21:10 +portmap_22=22:10 +portmap_23=23:10 +portmap_24=24:10 + +phy_chain_tx_polarity_flip_physical{21}=0x0 +phy_chain_tx_polarity_flip_physical{22}=0x1 +phy_chain_tx_polarity_flip_physical{23}=0x0 +phy_chain_tx_polarity_flip_physical{24}=0x1 + +phy_chain_rx_polarity_flip_physical{21}=0x1 +phy_chain_rx_polarity_flip_physical{22}=0x0 +phy_chain_rx_polarity_flip_physical{23}=0x1 +phy_chain_rx_polarity_flip_physical{24}=0x0 + + +# PM 4x25: CLP6 +portmap_25=25:10 +portmap_26=26:10 +portmap_27=27:10 +portmap_28=28:10 + +phy_chain_tx_polarity_flip_physical{25}=0x1 +phy_chain_tx_polarity_flip_physical{26}=0x0 +phy_chain_tx_polarity_flip_physical{27}=0x1 +phy_chain_tx_polarity_flip_physical{28}=0x0 + +phy_chain_rx_polarity_flip_physical{25}=0x1 +phy_chain_rx_polarity_flip_physical{26}=0x0 +phy_chain_rx_polarity_flip_physical{27}=0x1 +phy_chain_rx_polarity_flip_physical{28}=0x0 + + + + +# PM 4x25: CLP9 4x25G ports +portmap_29=37:25 +portmap_30=38:25 +portmap_31=39:25 +portmap_32=40:25 + +phy_chain_tx_polarity_flip_physical{37}=0x1 +phy_chain_tx_polarity_flip_physical{38}=0x0 +phy_chain_tx_polarity_flip_physical{39}=0x1 +phy_chain_tx_polarity_flip_physical{40}=0x1 + +phy_chain_rx_polarity_flip_physical{37}=0x1 +phy_chain_rx_polarity_flip_physical{38}=0x0 +phy_chain_rx_polarity_flip_physical{39}=0x1 +phy_chain_rx_polarity_flip_physical{40}=0x1 + + + +# PM 4x25: CLP15 +portmap_33=61:10 +portmap_34=62:10 +portmap_35=63:10 +portmap_36=64:10 + +phy_chain_tx_polarity_flip_physical{61}=0x0 +phy_chain_tx_polarity_flip_physical{62}=0x1 +phy_chain_tx_polarity_flip_physical{63}=0x0 +phy_chain_tx_polarity_flip_physical{64}=0x1 + +phy_chain_rx_polarity_flip_physical{61}=0x0 +phy_chain_rx_polarity_flip_physical{62}=0x1 +phy_chain_rx_polarity_flip_physical{63}=0x0 +phy_chain_rx_polarity_flip_physical{64}=0x1 + +# PM 4x25: CLP16 +portmap_37=65:10 +portmap_38=66:10 +portmap_39=67:10 +portmap_40=68:10 + +phy_chain_tx_polarity_flip_physical{65}=0x1 +phy_chain_tx_polarity_flip_physical{66}=0x0 +phy_chain_tx_polarity_flip_physical{67}=0x1 +phy_chain_tx_polarity_flip_physical{68}=0x0 + +phy_chain_rx_polarity_flip_physical{65}=0x1 +phy_chain_rx_polarity_flip_physical{66}=0x0 +phy_chain_rx_polarity_flip_physical{67}=0x1 +phy_chain_rx_polarity_flip_physical{68}=0x0 + + +# PM 4x25: CLP17 +portmap_41=69:10 +portmap_42=70:10 +portmap_43=71:10 +portmap_44=72:10 + +phy_chain_tx_polarity_flip_physical{69}=0x0 +phy_chain_tx_polarity_flip_physical{70}=0x1 +phy_chain_tx_polarity_flip_physical{71}=0x0 +phy_chain_tx_polarity_flip_physical{72}=0x1 + +phy_chain_rx_polarity_flip_physical{69}=0x1 +phy_chain_rx_polarity_flip_physical{70}=0x0 +phy_chain_rx_polarity_flip_physical{71}=0x1 +phy_chain_rx_polarity_flip_physical{72}=0x0 + +# PM 4x25: CLP18 +portmap_45=73:10 +portmap_46=74:10 +portmap_47=75:10 +portmap_48=76:10 + +phy_chain_tx_polarity_flip_physical{73}=0x1 +phy_chain_tx_polarity_flip_physical{74}=0x0 +phy_chain_tx_polarity_flip_physical{75}=0x1 +phy_chain_tx_polarity_flip_physical{76}=0x0 + +phy_chain_rx_polarity_flip_physical{73}=0x1 +phy_chain_rx_polarity_flip_physical{74}=0x0 +phy_chain_rx_polarity_flip_physical{75}=0x1 +phy_chain_rx_polarity_flip_physical{76}=0x0 + + + +# PM 4x25: CLP19 +portmap_49=77:10 +portmap_50=78:10 +portmap_51=79:10 +portmap_52=80:10 + +phy_chain_tx_polarity_flip_physical{77}=0x0 +phy_chain_tx_polarity_flip_physical{78}=0x1 +phy_chain_tx_polarity_flip_physical{79}=0x0 +phy_chain_tx_polarity_flip_physical{80}=0x1 + +phy_chain_rx_polarity_flip_physical{77}=0x0 +phy_chain_rx_polarity_flip_physical{78}=0x1 +phy_chain_rx_polarity_flip_physical{79}=0x0 +phy_chain_rx_polarity_flip_physical{80}=0x1 + +portmap_53=41:100 +phy_chain_tx_lane_map_physical{41.0}=0x2130 +phy_chain_rx_lane_map_physical{41.0}=0x0312 + + +phy_chain_tx_polarity_flip_physical{41.0}=0x0 +phy_chain_tx_polarity_flip_physical{42.0}=0x1 +phy_chain_tx_polarity_flip_physical{43.0}=0x1 +phy_chain_tx_polarity_flip_physical{44.0}=0x0 + +phy_chain_rx_polarity_flip_physical{41.0}=0x0 +phy_chain_rx_polarity_flip_physical{42.0}=0x1 +phy_chain_rx_polarity_flip_physical{43.0}=0x1 +phy_chain_rx_polarity_flip_physical{44.0}=0x0 + +# PM 4x25: CLP11 +portmap_57=45:100 +phy_chain_tx_lane_map_physical{45.0}=0x2130 +phy_chain_rx_lane_map_physical{45.0}=0x0312 + + +phy_chain_tx_polarity_flip_physical{45.0}=0x0 +phy_chain_tx_polarity_flip_physical{46.0}=0x1 +phy_chain_tx_polarity_flip_physical{47.0}=0x1 +phy_chain_tx_polarity_flip_physical{48.0}=0x0 + +phy_chain_rx_polarity_flip_physical{45.0}=0x0 +phy_chain_rx_polarity_flip_physical{46.0}=0x1 +phy_chain_rx_polarity_flip_physical{47.0}=0x1 +phy_chain_rx_polarity_flip_physical{48.0}=0x0 + + +dport_map_port_34=1 +dport_map_port_33=2 +dport_map_port_36=3 +dport_map_port_35=4 +dport_map_port_38=5 +dport_map_port_37=6 +dport_map_port_40=7 +dport_map_port_39=8 +dport_map_port_42=9 +dport_map_port_41=10 +dport_map_port_44=11 +dport_map_port_43=12 +dport_map_port_46=13 +dport_map_port_45=14 +dport_map_port_48=15 +dport_map_port_47=16 +dport_map_port_50=17 +dport_map_port_49=18 +dport_map_port_52=19 +dport_map_port_51=20 +dport_map_port_3=21 +dport_map_port_4=22 +dport_map_port_1=23 +dport_map_port_2=24 +dport_map_port_7=25 +dport_map_port_8=26 +dport_map_port_5=27 +dport_map_port_6=28 +dport_map_port_11=29 +dport_map_port_12=30 +dport_map_port_9=31 +dport_map_port_10=32 +dport_map_port_15=33 +dport_map_port_16=34 +dport_map_port_13=35 +dport_map_port_14=36 +dport_map_port_19=37 +dport_map_port_20=38 +dport_map_port_17=39 +dport_map_port_18=40 +dport_map_port_23=41 +dport_map_port_24=42 +dport_map_port_21=43 +dport_map_port_22=44 +dport_map_port_27=45 +dport_map_port_28=46 +dport_map_port_25=47 +dport_map_port_26=48 +dport_map_port_32=49 +dport_map_port_31=50 +dport_map_port_30=51 +dport_map_port_29=52 +dport_map_port_53=53 +dport_map_port_54=54 +dport_map_port_55=55 +dport_map_port_56=56 +dport_map_port_57=57 +dport_map_port_58=58 +dport_map_port_59=59 +dport_map_port_60=60 + + + +#pbmp_oversubscribe=0x7fff9fffffffffffffffe +#pbmp_xport_xe=0x7fff9fffffffffffffffe +port_flex_enable=1 +phy_an_c73=3 +oversubscribe_mode=1 +core_clock_frequency=1525 + +l2xmsg_mode=1 + +l2xmsg_hostbuf_size=16384 +module_64ports=0 + +#Interrupts and Parity +max_vp_lags=0 + +schan_intr_enable=0 +tdma_timeout_usec=5000000 + +stable_size=0x5500000 + +#Default L3 profile +l2_mem_entries=40960 +l3_alpm_enable=2 +l3_alpm_ipv6_128b_bkt_rsvd=1 +l3_mem_entries=40960 + +#Tunnels +use_all_splithorizon_groups=1 +sai_tunnel_support=1 +bcm_tunnel_term_compatible_mode=1 + +#RIOT Enable +riot_enable=1 +riot_overlay_l3_intf_mem_size=8192 +riot_overlay_l3_egress_mem_size=32768 +l3_ecmp_levels=2 +riot_overlay_ecmp_resilient_hash_size=16384 + +#sai_preinit_cmd_file=/usr/share/sonic/hwsku/sai_preinit_cmd.soc + +#New Additions +pfc_deadlock_seq_control=1 + +#Common configs from broadcom/x86_64-broadcom_common/x86_64-broadcom_b77/broadcom-sonic-td3.config.bcm (Lower version of Td3 (0xb771)) + +flow_init_mode=1 diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/default_sku b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/default_sku new file mode 100644 index 000000000000..1e0f4ccbc510 --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/default_sku @@ -0,0 +1 @@ +DELLEMC-N3248PXE t1 diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/installer.conf b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/installer.conf new file mode 100644 index 000000000000..924e0fb81963 --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/installer.conf @@ -0,0 +1,2 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/led_proc_init.soc b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/led_proc_init.soc new file mode 100644 index 000000000000..c909fe5e9fe5 --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/led_proc_init.soc @@ -0,0 +1,7 @@ +# LED microprocessor initialization for Dell N3248TE +# +# +#Led0 +#led auto on +m0 load 0 0x3800 /usr/share/sonic/hwsku/custom_led.bin +led start diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/eeprom.py b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/eeprom.py new file mode 100644 index 000000000000..bf4703f05d9f --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/eeprom.py @@ -0,0 +1,22 @@ +#!/usr/bin/python3 + +############################################################################# +# Dell S3000 +# +# 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 as 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-2/2-0050/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/fanutil.py b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/fanutil.py new file mode 100644 index 000000000000..5a3e882c3e44 --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/fanutil.py @@ -0,0 +1,73 @@ +# +# fanutil.py +# Platform-specific FAN status interface for SONiC +# + +import commands +import os +import sys + +SENSORS_CMD = "docker exec -i pmon /usr/bin/sensors" +DOCKER_SENSORS_CMD = "/usr/bin/sensors" + + +try: + from sonic_fan.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class FanUtil(FanBase): + """Platform-specific FanUtil class""" + _fan_mapping = { + 1 : '0', + 2 : '1', + 3 : '2' + } + + def __init__(self): + FanBase.__init__(self) + + def isDockerEnv(self): + num_docker = open('/proc/self/cgroup', 'r').read().count(":/docker") + if num_docker > 0: + return True + + def get_num_fans(self): + n3248pxe_MAX_FANTRAYS = 3 + return n3248pxe_MAX_FANTRAYS + + def get_presence(self, idx): + sysfs_path = "/sys/devices/platform/dell-n3248pxe-cpld.0/fan" + self._fan_mapping[idx] + "_prs" + return int(open(sysfs_path).read(), 16) + + def get_direction(self, idx): + sysfs_path = "/sys/devices/platform/dell-n3248pxe-cpld.0/fan" + self._fan_mapping[idx] + "_dir" + return open(sysfs_path).read() + + def get_speed(self, idx): + dockerenv = self.isDockerEnv() + if not dockerenv: + status, cmd_output = commands.getstatusoutput(SENSORS_CMD) + else : + status, cmd_output = commands.getstatusoutput(DOCKER_SENSORS_CMD) + + if status: + print('Failed to execute sensors command') + sys.exit(0) + fan_id = 'Fan ' + str(idx) + found = False + for line in cmd_output.splitlines(): + if line.startswith('emc2305-i2c-7-2c'): + found = True + if found and line.startswith(fan_id): + return line.split()[3] + return 0.0 + + def get_status(self, idx): + sysfs_path = "/sys/devices/platform/dell-n3248pxe-cpld.0/fan" + self._fan_mapping[idx] + "_prs" + return int(open(sysfs_path).read(), 16) + + + def set_speed(self, idx): + return False diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/psuutil.py b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/psuutil.py new file mode 100644 index 000000000000..71ab0e812e86 --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/psuutil.py @@ -0,0 +1,191 @@ +# +# psuutil.py +# Platform-specific PSU status interface for SONiC +# + +import commands +import os +import sys + +SENSORS_CMD = "docker exec -i pmon /usr/bin/sensors" +DOCKER_SENSORS_CMD = "/usr/bin/sensors" + +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""" + _psu_mapping = { + 1 : '0', + 2 : '1' + } + + def __init__(self): + PsuBase.__init__(self) + + def isDockerEnv(self): + num_docker = open('/proc/self/cgroup', 'r').read().count(":/docker") + if num_docker > 0: + return True + else: + return False + + def remove_nonnumeric(self, text): + digits='0123456789.' + return ''.join(c for c in text if c in digits) + + def get_cpld_register(self, reg_name): + cpld_dir = "/sys/devices/platform/dell-n3248pxe-cpld.0/" + retval = 'ERR' + reg_file = cpld_dir +'/' + reg_name + if (not os.path.isfile(reg_file)): + return retval + + try: + with open(reg_file, 'r') as fd: + retval = fd.read() + except Exception as error: + print("Unable to open ", reg_file, "file !") + + retval = retval.rstrip('\r\n') + return retval + + def get_num_psus(self): + """ + Retrieves the number of PSUs available on the device + :return: An integer, the number of PSUs available on the device + """ + N3248PXE_MAX_PSUS = 2 + return N3248PXE_MAX_PSUS + + def get_psu_status(self, index): + """ + Retrieves the oprational status of power supply unit (PSU) defined + by index + :param index: An integer, index of the PSU of which to query status + :return: Boolean, True if PSU is operating properly, False if PSU is\ + faulty + """ + status = 0 + psu_status = self.get_cpld_register('psu'+self._psu_mapping[index]+'_status') + if (psu_status != 'ERR'): + status = int(psu_status, 10) + + presence = self.get_psu_presence(index) + + return (status & presence) + + def get_psu_presence(self, index): + """ + Retrieves the presence status of power supply unit (PSU) defined + by index + :param index: An integer, index of the PSU of which to query status + :return: Boolean, True if PSU is plugged, False if not + """ + status = 0 + psu_presence = self.get_cpld_register('psu'+self._psu_mapping[index]+'_prs') + if (psu_presence != 'ERR'): + status = int(psu_presence, 10) + + return status + + def get_sensor(self): + dockerenv = self.isDockerEnv() + if not dockerenv: + status, cmd_output = commands.getstatusoutput(SENSORS_CMD) + else : + status, cmd_output = commands.getstatusoutput(DOCKER_SENSORS_CMD) + + if status: + print('Failed to execute sensors command') + sys.exit(0) + return cmd_output + + def get_output_current(self, index): + cmd_output= self.get_sensor() + sensor_name = 'dps460-i2c-10' if index == 1 else 'dps460-i2c-11' + found = False + for line in cmd_output.splitlines(): + if line.startswith(sensor_name): + found = True + if found: + if 'Output Current' in line : + return float(self.remove_nonnumeric(line.split()[2])) + return 0.0 + + def get_output_voltage(self, index): + cmd_output= self.get_sensor() + sensor_name = 'dps460-i2c-10' if index == 1 else 'dps460-i2c-11' + found = False + for line in cmd_output.splitlines(): + if line.startswith(sensor_name): + found = True + if found: + if 'Output Voltage' in line : + return float(self.remove_nonnumeric(line.split()[2])) + return 0.0 + + def get_fan_rpm(self, index, fan_index): + if fan_index > 1 : return 0.0 + cmd_output= self.get_sensor() + sensor_name = 'dps460-i2c-10' if index == 1 else 'dps460-i2c-11' + found = False + for line in cmd_output.splitlines(): + if line.startswith(sensor_name): + found = True + if found: + if 'Fan RPM' in line : + return self.remove_nonnumeric(line.split()[2]) + return 0.0 + + def get_output_power(self, index): + cmd_output= self.get_sensor() + sensor_name = 'dps460-i2c-10' if index == 1 else 'dps460-i2c-11' + found = False + for line in cmd_output.splitlines(): + if line.startswith(sensor_name): + found = True + if found: + if 'Output Power' in line : + return float(self.remove_nonnumeric(line.split()[2])) + return 0.0 + + def get_direction(self, index): + psuid = '0' if index == 1 else '1' + sysfs_path = '/sys/devices/platform/dell-n3248pxe-cpld.0/psu' + psuid + '_prs' + found_psu = int(open(sysfs_path).read()) + if not found_psu : return '' + bus_no = '10' if index == 1 else '11' + sysfs_path = "/sys/bus/i2c/devices/" + bus_no + "-0056/eeprom" + val = (open(sysfs_path, "rb").read())[0xe1:0xe8] + dir = 'F2B' if 'FORWARD' == val else 'B2F' + return dir + + def get_serial(self, index): + psuid = '0' if index == 1 else '1' + sysfs_path = '/sys/devices/platform/dell-n3248pxe-cpld.0/psu' + psuid + '_prs' + found_psu = int(open(sysfs_path).read()) + if not found_psu : return '' + bus_no = '10' if index == 1 else '11' + sysfs_path = "/sys/bus/i2c/devices/" + bus_no + "-0056/eeprom" + val = (open(sysfs_path, "rb").read())[0xc4:0xd9] + return val + + def get_model(self, index): + psuid = '0' if index == 1 else '1' + sysfs_path = '/sys/devices/platform/dell-n3248pxe-cpld.0/psu' + psuid + '_prs' + found_psu = int(open(sysfs_path).read()) + if not found_psu : return '' + bus_no = '10' if index == 1 else '11' + sysfs_path = "/sys/bus/i2c/devices/" + bus_no + "-0056/eeprom" + val = (open(sysfs_path, "rb").read())[0x50:0x62] + return val + + def get_mfr_id(self, index): + psuid = '0' if index == 1 else '1' + sysfs_path = '/sys/devices/platform/dell-n3248pxe-cpld.0/psu' + psuid + '_prs' + found_psu = int(open(sysfs_path).read()) + return 'DELTA' if found_psu else '' diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/sfputil.py new file mode 100644 index 000000000000..49c712b158be --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/sfputil.py @@ -0,0 +1,176 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import time + import datetime + import os + import struct + import traceback + from socket import * + from select import * + 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 = 52 + PORTS_IN_BLOCK = 52 + SFP_PORT_START = 49 + SFP_PORT_END = 52 + + EEPROM_OFFSET = 14 + + _port_to_eeprom_mapping = {} + _sfpp_port_i2c_mapping = { + 49 : 20, + 50 : 21, + 51 : 22, + 52 : 23 + } + port_dict = {} + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self) : + return range(self.SFP_PORT_END+1, self.SFP_PORT_END+1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + @property + def get_transceiver_status(self): + + try: + sfp_modprs_path = "/sys/devices/platform/dell-n3248pxe-cpld.0/sfp_modprs" + reg_file = open(sfp_modprs_path) + + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + + content = reg_file.readline().rstrip() + + reg_file.close() + + return int(content, 16) + + + def __init__(self): + + sfpplus_eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" + + for x in range(self.SFP_PORT_START, self.SFP_PORT_END + 1): + self.port_to_eeprom_mapping[x] = sfpplus_eeprom_path.format(self._sfpp_port_i2c_mapping[x]) + # Get Transceiver status + self.modprs_register = self.get_transceiver_status + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + if port_num < self.SFP_PORT_START : + return False + port_num -= self.SFP_PORT_START + try: + sfp_modprs_path = "/sys/devices/platform/dell-n3248pxe-cpld.0/sfp_modprs" + reg_file = open(sfp_modprs_path) + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + + content = reg_file.readline().rstrip() + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + + # ModPrsL is active low + if (reg_value & mask) == 0: + return True + + return False + + def get_low_power_mode(self, port_num): + return False + + def set_low_power_mode(self, port_num, lpmode): + return False + + def reset(self, port_num): + return False + + def get_transceiver_change_event(self, timeout=0): + + start_time = time.time() + port = self.SFP_PORT_START + forever = False + + if timeout == 0: + forever = True + elif timeout > 0: + timeout = timeout / float(1000) # Convert to secs + else: + print ('get_transceiver_change_event:Invalid timeout value', timeout) + return False, {} + + end_time = start_time + timeout + if start_time > end_time: + print ('get_transceiver_change_event:' \ + 'time wrap / invalid timeout value', timeout) + + return False, {} # Time wrap or possibly incorrect timeout + + while timeout >= 0: + # Check for OIR events and return updated port_dict + reg_value = self.get_transceiver_status + if reg_value != self.modprs_register: + changed_ports = self.modprs_register ^ reg_value + while port >= self.SFP_PORT_START and port <= self.SFP_PORT_END: + + # Mask off the bit corresponding to our port + mask = (1 << (port - self.SFP_PORT_START)) + + if changed_ports & mask: + # ModPrsL is active low + if reg_value & mask == 0: + self.port_dict[port] = '1' + else: + self.port_dict[port] = '0' + + port += 1 + + # Update reg value + self.modprs_register = reg_value + return True, self.port_dict + + if forever: + time.sleep(1) + else: + timeout = end_time - time.time() + if timeout >= 1: + time.sleep(1) # We poll at 1 second granularity + else: + if timeout > 0: + time.sleep(timeout) + return True, {} + print ("get_transceiver_change_event: Should not reach here.") + return False, {} diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/pmon_daemon_control.json b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..4f701c3b3400 --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/sensors.conf b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/sensors.conf new file mode 100644 index 000000000000..987b4ad73984 --- /dev/null +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/sensors.conf @@ -0,0 +1,58 @@ +# libsensors configuration file for Dell N3248TE +# The i2c bus portion is omit because adapter name +# changes every time when system boot up. + +bus "i2c-7" "i2c-0-mux (chan_id 5)" +bus "i2c-5" "i2c-0-mux (chan_id 3)" +bus "i2c-10" "i2c-5-mux (chan_id 0)" +bus "i2c-11" "i2c-5-mux (chan_id 1)" + +chip "tmp75-i2c-7-49" + label temp1 "Switch Near Temperature" +chip "tmp75-i2c-7-4a" + label temp1 "Switch Rear Temperature" +chip "tmp75-i2c-7-4b" + label temp1 "Front Panel PHY Temperature" +chip "tmp75-i2c-7-4c" + label temp1 "Near Front Panel Temperature" +chip "tmp75-i2c-7-4f" + label temp1 "Middle Fan Tray Temperature" + + +chip "emc2305-i2c-7-2c" + ignore fan4 + ignore fan5 + label fan1 "Fan 1 " + label fan2 "Fan 2 " + label fan3 "Fan 3 " + +chip "dps460-i2c-10-5e" + label power1 "Input Power" + label power2 "Output Power" + label curr1 "Input Current" + label curr2 "Output Current" + label in1 "Input Voltage" + ignore in2 + label in3 "Output Voltage" + label fan1 "Fan RPM" + ignore fan2 + ignore fan3 + ignore temp1 + label temp2 "FAN Airflow Temperature" + label temp3 "FAN Normal Temperature" + + +chip "dps460-i2c-11-5e" + label power1 "Input Power" + label power2 "Output Power" + label curr1 "Input Current" + label curr2 "Output Current" + label in1 "Input Voltage" + ignore in2 + label in3 "Output Voltage" + label fan1 "Fan RPM" + ignore fan2 + ignore fan3 + ignore temp1 + label temp2 "FAN Airflow Temperature" + label temp3 "FAN Normal Temperature" diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index 9509c1b0910e..540934a1a155 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -15,6 +15,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(DELL_S5296F_PLATFORM_MODULE) \ $(DELL_Z9100_PLATFORM_MODULE) \ $(DELL_S6100_PLATFORM_MODULE) \ + $(DELL_N3248PXE_PLATFORM_MODULE) \ $(INGRASYS_S8900_54XC_PLATFORM_MODULE) \ $(INGRASYS_S8900_64XC_PLATFORM_MODULE) \ $(INGRASYS_S9100_PLATFORM_MODULE) \ diff --git a/platform/broadcom/platform-modules-dell.mk b/platform/broadcom/platform-modules-dell.mk index 90eb4fc20b5a..2f9c98b99431 100644 --- a/platform/broadcom/platform-modules-dell.mk +++ b/platform/broadcom/platform-modules-dell.mk @@ -8,6 +8,7 @@ DELL_S5232F_PLATFORM_MODULE_VERSION = 1.1 DELL_Z9332F_PLATFORM_MODULE_VERSION = 1.1 DELL_S5248F_PLATFORM_MODULE_VERSION = 1.1 DELL_S5296F_PLATFORM_MODULE_VERSION = 1.1 +DELL_N3248PXE_PLATFORM_MODULE_VERSION = 1.1 export DELL_S6000_PLATFORM_MODULE_VERSION export DELL_Z9100_PLATFORM_MODULE_VERSION @@ -17,6 +18,7 @@ export DELL_S5232F_PLATFORM_MODULE_VERSION export DELL_Z9332F_PLATFORM_MODULE_VERSION export DELL_S5248F_PLATFORM_MODULE_VERSION export DELL_S5296F_PLATFORM_MODULE_VERSION +export DELL_N3248PXE_PLATFORM_MODULE_VERSION DELL_Z9100_PLATFORM_MODULE = platform-modules-z9100_$(DELL_Z9100_PLATFORM_MODULE_VERSION)_amd64.deb $(DELL_Z9100_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-dell @@ -52,3 +54,7 @@ $(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5248F_PLAT DELL_S5296F_PLATFORM_MODULE = platform-modules-s5296f_$(DELL_S5296F_PLATFORM_MODULE_VERSION)_amd64.deb $(DELL_S5296F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5296f_c3538-r0 $(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5296F_PLATFORM_MODULE))) + +DELL_N3248PXE_PLATFORM_MODULE = platform-modules-n3248pxe_$(DELL_N3248PXE_PLATFORM_MODULE_VERSION)_amd64.deb +$(DELL_N3248PXE_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_n3248pxe_c3338-r0 +$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_N3248PXE_PLATFORM_MODULE))) diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/control b/platform/broadcom/sonic-platform-modules-dell/debian/control index 2920602fcd60..b07e53b97f71 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/control +++ b/platform/broadcom/sonic-platform-modules-dell/debian/control @@ -40,6 +40,11 @@ Architecture: amd64 Depends: linux-image-4.19.0-12-2-amd64-unsigned Description: kernel modules for platform devices such as fan, led, sfp +Package: platform-modules-n3248pxe +Architecture: amd64 +Depends: linux-image-4.19.0-12-2-amd64-unsigned +Description: kernel modules for platform devices such as fan, led, sfp + Package: platform-modules-s5296f Architecture: amd64 Depends: linux-image-4.9.0-9-2-amd64 diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-n3248pxe.init b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-n3248pxe.init new file mode 100755 index 000000000000..83970d734e6c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-n3248pxe.init @@ -0,0 +1,39 @@ +#!/bin/bash + +### BEGIN INIT INFO +# Provides: setup-board +# Required-Start: +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Setup N32xx board. +### END INIT INFO + +case "$1" in +start) + echo -n "Setting up board... " + + /usr/local/bin/n3248pxe_platform.sh init + + echo "done." + ;; + +stop) + /usr/local/bin/n3248pxe_platform.sh deinit + echo "done." + + ;; + +force-reload|restart) + echo "Not supported" + ;; + +*) + echo "Usage: /etc/init.d/platform-modules-n3248pxe.init {start|stop}" + exit 1 + ;; +esac + +exit 0 diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-n3248pxe.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-n3248pxe.install new file mode 100644 index 000000000000..2cc759fa9fc9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-n3248pxe.install @@ -0,0 +1,12 @@ +n3248pxe/scripts/n3248pxe_platform.sh usr/local/bin +n3248pxe/scripts/platform_sensors.py usr/local/bin +n3248pxe/scripts/sensors usr/bin +n3248pxe/scripts//portiocfg.py usr/local/bin +n3248pxe/scripts//ports_xcvrd_notify.py usr/local/bin +n3248pxe/systemd/platform-modules-n3248pxe.service etc/systemd/system +n3248pxe/cfg/n3248pxe-modules.conf etc/modules-load.d +common/dell_i2c_utils.sh usr/local/bin +n3248pxe/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-dellemc_n3248pxe_c3338-r0 +common/platform_reboot usr/share/sonic/device/x86_64-dellemc_n3248pxe_c3338-r0 +common/fw-updater usr/local/bin +common/onie_mode_set usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-n3248pxe.postinst b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-n3248pxe.postinst new file mode 100644 index 000000000000..cbf0c4f46c0a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-n3248pxe.postinst @@ -0,0 +1,7 @@ +# postinst script for n3248pxe + +# Enable Dell-n3248pxe-platform-service +depmod -a +systemctl enable platform-modules-n3248pxe.service +systemctl start platform-modules-n3248pxe.service +#DEBHELPER# diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/rules b/platform/broadcom/sonic-platform-modules-dell/debian/rules index 520331ed16d3..0fd5d793492b 100755 --- a/platform/broadcom/sonic-platform-modules-dell/debian/rules +++ b/platform/broadcom/sonic-platform-modules-dell/debian/rules @@ -5,7 +5,7 @@ export INSTALL_MOD_DIR:=extra KVERSION ?= $(shell uname -r) KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) -MODULE_DIRS:= s6000 z9100 s6100 z9264f s5232f s5248f z9332f s5296f +MODULE_DIRS:= s6000 z9100 s6100 z9264f s5232f s5248f z9332f s5296f n3248pxe COMMON_DIR := common %: @@ -56,6 +56,12 @@ override_dh_auto_build: python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ cd $(MOD_SRC_DIR); \ + elif [ $$mod = "n3248pxe" ]; then \ + cp $(COMMON_DIR)/ipmihelper.py $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \ + cd $(MOD_SRC_DIR)/$${mod}; \ + python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ + python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ + cd $(MOD_SRC_DIR); \ fi; \ echo "making man page alias $$mod -> $$mod APIs";\ make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ @@ -118,6 +124,11 @@ override_dh_clean: rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \ rm -rf $(MOD_SRC_DIR)/$${mod}/build; \ rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \ + elif [ $$mod = "n3248pxe" ]; then \ + rm -f $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \ + rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/build; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \ fi; \ make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules clean; \ done); \ diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/cfg/n3248pxe-modules.conf b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/cfg/n3248pxe-modules.conf new file mode 100644 index 000000000000..f3cbdc1ce259 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/cfg/n3248pxe-modules.conf @@ -0,0 +1,14 @@ +# /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-isch +i2c-ismt +i2c-dev +i2c-mux +i2c-smbus + +i2c-mux-pca954x +dell_n3248pxe_platform + diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/Makefile b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/Makefile new file mode 100644 index 000000000000..3b07288f938a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/Makefile @@ -0,0 +1,2 @@ +obj-m := dell_n3248pxe_platform.o emc2305.o + diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/dell_n3248pxe_platform.c b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/dell_n3248pxe_platform.c new file mode 100644 index 000000000000..34f62a39e45b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/dell_n3248pxe_platform.c @@ -0,0 +1,1207 @@ +/* Copyright (c) 2020 Dell Inc. + * dell_n3248pxe_platform.c - Driver for n3248pxe switches + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #define PSU_MODULE_BASE_NR 10 + #define FANTRAY_MODULE_BASE_NR 15 + #define SFP_MODULE_BASE_NR 20 + #define SFP_MUX_BASE_NR 8 + #define FANTRAY_MUX_BASE_NR 4 + #define PSU_MUX_BASE_NR 5 + + #define PHY_RESET_REG 0x40 + #define RESET_ALL_PHY 0x7F + #define SYS_CTRL_REG 0x15 + #define POWER_CYCLE_SYS 0x1 + #define CPLD_DEVICE_NUM 2 + #define PF_MUX_DEVICES 3 + + #define FAN_0 0 + #define FAN_1 1 + #define FAN_2 2 + + static void device_release(struct device *dev) + { + return; + } + + /* + * n3248pxe CPLD + */ + + enum cpld_type { + cpu_cpld, + sys_cpld, + }; + + struct cpld_platform_data { + int reg_addr; + struct i2c_client *client; + }; + + static struct cpld_platform_data n3248pxe_cpld_platform_data[] = { + [cpu_cpld] = { + .reg_addr = 0x31, + }, + + [sys_cpld] = { + .reg_addr = 0x32, + }, + }; + + static struct platform_device n3248pxe_cpld = { + .name = "dell-n3248pxe-cpld", + .id = 0, + .dev = { + .platform_data = n3248pxe_cpld_platform_data, + .release = device_release + }, + }; + + /* + * n3248pxe MUX + */ + + struct mux_platform_data { + int parent; + int base_nr; + int reg_addr; + struct i2c_client *cpld; + int no_of_buses; + int mux_offset; + }; + + struct pf_mux { + struct mux_platform_data data; + }; + + static struct mux_platform_data n3248pxe_mux_platform_data[] = { + { + .parent = SFP_MUX_BASE_NR, + .base_nr = SFP_MODULE_BASE_NR, + .cpld = NULL, + .reg_addr = 0x11, + .no_of_buses = 6, + .mux_offset = 1, + }, + { + .parent = FANTRAY_MUX_BASE_NR, + .base_nr = FANTRAY_MODULE_BASE_NR, + .cpld = NULL, + .reg_addr = 0x13, + .no_of_buses = 3, + .mux_offset = 1, + }, + { + .parent = PSU_MUX_BASE_NR, + .base_nr = PSU_MODULE_BASE_NR, + .cpld = NULL, + .reg_addr = 0x12, + .no_of_buses = 2, + .mux_offset = 1, + }, + }; + + static struct platform_device n3248pxe_mux[] = { + { + .name = "dell-n3248pxe-mux", + .id = 0, + .dev = { + .platform_data = &n3248pxe_mux_platform_data[0], + .release = device_release, + }, + }, + { + .name = "dell-n3248pxe-mux", + .id = 1, + .dev = { + .platform_data = &n3248pxe_mux_platform_data[1], + .release = device_release, + }, + }, + { + .name = "dell-n3248pxe-mux", + .id = 2, + .dev = { + .platform_data = &n3248pxe_mux_platform_data[2], + .release = device_release, + }, + }, + }; + + static int cpld_reg_write_byte(struct i2c_client *client, u8 regaddr, u8 val) + { + union i2c_smbus_data data; + + data.byte = val; + return client->adapter->algo->smbus_xfer(client->adapter, client->addr, + client->flags, + I2C_SMBUS_WRITE, + regaddr, I2C_SMBUS_BYTE_DATA, &data); + } + + static int mux_select(struct i2c_mux_core *muxc, u32 chan) + { + struct pf_mux *mux = i2c_mux_priv(muxc); + u8 chan_data = chan + mux->data.mux_offset; + + return cpld_reg_write_byte(mux->data.cpld, mux->data.reg_addr, chan_data); + } + + static int __init mux_probe(struct platform_device *pdev) + { + struct i2c_mux_core *muxc; + struct pf_mux *mux; + struct mux_platform_data *pdata; + struct i2c_adapter *parent; + int i, ret; + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "Missing platform data\n"); + return -ENODEV; + } + + mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); + if (!mux) { + return -ENOMEM; + } + + mux->data = *pdata; + + parent = i2c_get_adapter(pdata->parent); + if (!parent) { + dev_err(&pdev->dev, "Parent adapter (%d) not found\n", + pdata->parent); + return -EPROBE_DEFER; + } + + muxc = i2c_mux_alloc(parent, &pdev->dev, pdata->no_of_buses, 0, 0, + mux_select, NULL); + if (!muxc) { + ret = -ENOMEM; + goto alloc_failed; + } + muxc->priv = mux; + + platform_set_drvdata(pdev, muxc); + + for (i = 0; i < pdata->no_of_buses; i++) { + int nr = pdata->base_nr + i; + unsigned int class = 0; + + ret = i2c_mux_add_adapter(muxc, nr, i, class); + if (ret) { + dev_err(&pdev->dev, "Failed to add adapter %d\n", i); + goto add_adapter_failed; + } + } + + return 0; + + add_adapter_failed: + i2c_mux_del_adapters(muxc); + alloc_failed: + i2c_put_adapter(parent); + + return ret; + } + + static int mux_remove(struct platform_device *pdev) + { + struct i2c_mux_core *muxc = platform_get_drvdata(pdev); + + i2c_mux_del_adapters(muxc); + + i2c_put_adapter(muxc->parent); + + return 0; + } + + static struct platform_driver mux_driver = { + .probe = mux_probe, + .remove = mux_remove, + .driver = { + .owner = THIS_MODULE, + .name = "dell-n3248pxe-mux", + }, + }; + + static ssize_t sfp_txdis_show (struct device *dev, struct device_attribute *devattr, char *buf) + { + s32 ret = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x31); + if (ret < 0) + return sprintf(buf, "read error"); + + return sprintf(buf, "0x%x\n", (u8)ret); + } + + static ssize_t sfp_txdis_store (struct device *dev, struct device_attribute *devattr, const char *buf, size_t size) + { + long value; + struct cpld_platform_data *pdata = dev->platform_data; + s32 ret; + u8 data; + ssize_t status; + + status = kstrtol(buf, 0, &value); + if (status == 0) { + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x31); + if (ret < 0) + return ret; + data = (u8)ret & ~(0x0F); + data = data | (value & 0x0F); + + ret = i2c_smbus_write_byte_data(pdata[sys_cpld].client, 0x31, data); + if (ret < 0) + return ret; + + status = size; + } + + return status; + } + + static ssize_t sfp_rxlos_show (struct device *dev, struct device_attribute *devattr, char *buf) + { + s32 ret = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x32); + if (ret < 0) + return sprintf(buf, "read error"); + + return sprintf(buf, "0x%x\n", (u8)ret); + } + + static ssize_t sfp_txfault_show (struct device *dev, struct device_attribute *devattr, char *buf) + { + s32 ret = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x33); + if (ret < 0) + return sprintf(buf, "read error"); + + return sprintf(buf, "0x%x\n", (u8)ret); + } + + static ssize_t sfp_modprs_show (struct device *dev, struct device_attribute *devattr, char *buf) + { + s32 ret = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x30); + if (ret < 0) + return sprintf(buf, "read error"); + + return sprintf(buf, "0x%x\n", (u8)ret); + } + + static ssize_t reboot_cause_show (struct device *dev, struct device_attribute *devattr, char *buf) + { + s32 ret = 0; + u8 data; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x10); + if (ret < 0) + return sprintf(buf, "read error"); + + data = (u8)ret; + return sprintf(buf, "0x%x\n", data); + } + + + static ssize_t power_reset_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) + { + unsigned long data; + s32 err; + struct cpld_platform_data *pdata = dev->platform_data; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + if (data) + { + i2c_smbus_write_byte_data(pdata[sys_cpld].client, SYS_CTRL_REG, (u8)(POWER_CYCLE_SYS)); + } + + return count; + } + + static ssize_t power_reset_show(struct device *dev, struct device_attribute *devattr, char *buf) + { + s32 ret = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, SYS_CTRL_REG); + if (ret < 0) + return sprintf(buf, "read error"); + + return sprintf(buf, "0x%x\n", ret); + } + + static ssize_t fan_dir_show(struct device *dev, struct device_attribute *devattr, char *buf) + { + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + struct sensor_device_attribute *sa = to_sensor_dev_attr(devattr); + int index = sa->index; + u8 mask = 1 << (index+4); + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0xA); + if (ret < 0) + return sprintf(buf, "read error"); + data = (u8)((ret & mask) >> (index+4)); + + return sprintf(buf, "%s\n", data? "B2F" : "F2B"); +} + +static ssize_t fan_prs_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + struct sensor_device_attribute *sa = to_sensor_dev_attr(devattr); + int index = sa->index; + uint8_t mask = 1 << index; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0xA); + if (ret < 0) + return sprintf(buf, "read error"); + data = (u32)((ret & mask) >> index); + + data = ~data & 0x1; + + return sprintf(buf, "0x%x\n", data); +} + +static ssize_t psu0_prs_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0xC); + if (ret < 0) + return sprintf(buf, "read error"); + + if (!(ret & 0x80)) + data = 1; + + return sprintf(buf, "%d\n", data); +} + +static ssize_t psu1_prs_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0xC); + if (ret < 0) + return sprintf(buf, "read error"); + + if (!(ret & 0x08)) + data = 1; + + return sprintf(buf, "%d\n", data); +} + +static ssize_t psu0_status_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0xC); + if (ret < 0) + return sprintf(buf, "read error"); + + if ((ret & 0x40)) + data = 1; + + return sprintf(buf, "%d\n", data); +} + +static ssize_t psu1_status_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0xC); + if (ret < 0) + return sprintf(buf, "read error"); + + if ((ret & 0x04)) + data = 1; + + return sprintf(buf, "%d\n", data); +} + +static ssize_t fani_led_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + struct sensor_device_attribute *sa = to_sensor_dev_attr(devattr); + int index = sa->index; + uint8_t mask = 3 << (index*2); + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x9); + if (ret < 0) + return sprintf(buf, "read error"); + + data = (u32)(ret & mask) >> (index*2); + + switch (data) + { + case 0: + ret = sprintf(buf, "off\n"); + break; + case 1: + ret = sprintf(buf, "green\n"); + break; + case 2: + ret = sprintf(buf, "yellow\n"); + break; + default: + ret = sprintf(buf, "unknown\n"); + } + + return ret; +} + +static ssize_t fani_led_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + s32 ret; + u8 mask, data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + struct sensor_device_attribute *sa = to_sensor_dev_attr(devattr); + int index = sa->index; + + if (!strncmp(buf, "off", 3)) + { + data = 0; + } + else if (!strncmp(buf, "yellow", 6)) + { + data = 2; + } + else if (!strncmp(buf, "green", 5)) + { + data = 1; + } + else + { + return -1; + } + + mask = ~((uint8_t)(3 << (index*2))); + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x9); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(pdata[sys_cpld].client, 0x9, (u8)((ret & mask) | (data << (index * 2)))); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t system_led_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x7); + if (ret < 0) + return sprintf(buf, "read error"); + + data = (u8)(ret & 0x30) >> 5; + + switch (data) + { + case 0: + ret = sprintf(buf, "blink_green\n"); + break; + case 1: + ret = sprintf(buf, "green\n"); + break; + case 2: + ret = sprintf(buf, "yellow\n"); + break; + default: + ret = sprintf(buf, "blink_yellow\n"); + } + + return ret; +} + +static ssize_t system_led_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + if (!strncmp(buf, "blink_green", 11)) + { + data = 0; + } + else if (!strncmp(buf, "green", 5)) + { + data = 1; + } + else if (!strncmp(buf, "yellow", 6)) + { + data = 2; + } + else if (!strncmp(buf, "blink_yellow", 12)) + { + data = 3; + } + else + { + return -1; + } + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x7); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(pdata[sys_cpld].client, 0x7, (u8)((ret & 0xCF) | (data << 4))); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t locator_led_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x7); + if (ret < 0) + return sprintf(buf, "read error"); + + data = (u32)(ret & 0x08) >> 3; + + switch (data) + { + case 0: + ret = sprintf(buf, "off\n"); + break; + case 1: + ret = sprintf(buf, "blink_blue\n"); + break; + default: + ret = sprintf(buf, "invalid\n"); + } + + return ret; +} + +static ssize_t locator_led_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + if (!strncmp(buf, "off", 3)) + { + data = 0; + } + else if (!strncmp(buf, "blink_blue", 10)) + { + data = 1; + } + else + { + return -1; + } + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x7); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(pdata[sys_cpld].client, 0x7, (u8)((ret & 0xF7) | (data << 3))); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t power_led_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x7); + if (ret < 0) + return sprintf(buf, "read error"); + + data = (u32)(ret & 0x06) >> 1; + + switch (data) + { + case 0: + ret = sprintf(buf, "off\n"); + break; + case 1: + ret = sprintf(buf, "yellow\n"); + break; + case 2: + ret = sprintf(buf, "green\n"); + break; + default: + ret = sprintf(buf, "blink_yellow\n"); + } + + return ret; +} + +static ssize_t power_led_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + if (!strncmp(buf, "off", 3)) + { + data = 0; + } + else if (!strncmp(buf, "yellow", 6)) + { + data = 1; + } + else if (!strncmp(buf, "green", 5)) + { + data = 2; + } + else if (!strncmp(buf, "blink_yellow", 12)) + { + data = 3; + } + else + { + return -1; + } + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x7); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(pdata[sys_cpld].client, 0x7, (u8)((ret & 0xF9) | (data << 1))); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t master_led_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x7); + if (ret < 0) + return sprintf(buf, "read error"); + + data = (u32)(ret & 0x1); + + switch (data) + { + case 0: + ret = sprintf(buf, "green\n"); + break; + default: + ret = sprintf(buf, "off\n"); + break; + } + + return ret; +} + +static ssize_t master_led_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + if (!strncmp(buf, "green", 5)) + { + data = 0; + } + else if (!strncmp(buf, "off", 3)) + { + data = 1; + } + else + { + return -1; + } + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x7); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(pdata[sys_cpld].client, 0x7, (u8)((ret & 0xFE) | data)); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t fan_led_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x7); + if (ret < 0) + return sprintf(buf, "read error"); + + data = (u8)(ret & 0xC0) >> 6; + + switch (data) + { + case 0: + ret = sprintf(buf, "off\n"); + break; + case 1: + ret = sprintf(buf, "yellow\n"); + break; + case 2: + ret = sprintf(buf, "green\n"); + break; + default: + ret = sprintf(buf, "blink_yellow\n"); + } + + return ret; +} + +static ssize_t fan_led_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + if (!strncmp(buf, "off", 3)) + { + data = 0; + } + else if (!strncmp(buf, "yellow", 6)) + { + data = 1; + } + else if (!strncmp(buf, "green", 5)) + { + data = 2; + } + else if (!strncmp(buf, "blink_yellow", 12)) + { + data = 3; + } + else + { + return -1; + } + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x7); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(pdata[sys_cpld].client, 0x7, (u8)((ret & 0x3F) | (data << 6))); + if (ret < 0) + return ret; + + return count; +} + + +static ssize_t power_good_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 pwr_good1 = 0; + u8 pwr_good2 = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[cpu_cpld].client, 0xc); + if (ret < 0) + return sprintf(buf, "read error"); + pwr_good1 = ret; + + ret = i2c_smbus_read_byte_data(pdata[cpu_cpld].client, 0xd); + if (ret < 0) + return sprintf(buf, "read error"); + pwr_good2 = ret; + + return sprintf(buf, "0x%x\n", (pwr_good1 == 0xFF && (pwr_good2 & 0x1F) == 0x1F)); +} + +static ssize_t sys_cpld_mjr_ver_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x1); + if (ret < 0) + return sprintf(buf, "read error"); + data = ret; + + return sprintf(buf, "0x%x\n", data); +} + +static ssize_t sys_cpld_mnr_ver_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[sys_cpld].client, 0x0); + if (ret < 0) + return sprintf(buf, "read error"); + data = ret; + + return sprintf(buf, "0x%x\n", data); +} + +static ssize_t cpu_cpld_mjr_ver_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[cpu_cpld].client, 0x1); + if (ret < 0) + return sprintf(buf, "read error"); + data = ret; + + return sprintf(buf, "0x%x\n", data); +} + +static ssize_t cpu_cpld_mnr_ver_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + s32 ret; + u8 data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + ret = i2c_smbus_read_byte_data(pdata[cpu_cpld].client, 0x0); + if (ret < 0) + return sprintf(buf, "read error"); + data = ret; + + return sprintf(buf, "0x%x\n", data); +} + + +static DEVICE_ATTR_RO(sfp_txfault); +static DEVICE_ATTR_RO(sfp_modprs); +static DEVICE_ATTR_RO(sfp_rxlos); +static DEVICE_ATTR_RW(sfp_txdis); +static DEVICE_ATTR_RO(reboot_cause); +static DEVICE_ATTR_RW(power_reset); +static DEVICE_ATTR_RO(psu0_prs); +static DEVICE_ATTR_RO(psu1_prs); +static DEVICE_ATTR_RO(psu0_status); +static DEVICE_ATTR_RO(psu1_status); +static DEVICE_ATTR_RW(system_led); +static DEVICE_ATTR_RW(locator_led); +static DEVICE_ATTR_RW(power_led); +static DEVICE_ATTR_RW(master_led); +static DEVICE_ATTR_RW(fan_led); +static DEVICE_ATTR_RO(power_good); +static DEVICE_ATTR_RO(sys_cpld_mjr_ver); +static DEVICE_ATTR_RO(sys_cpld_mnr_ver); +static DEVICE_ATTR_RO(cpu_cpld_mjr_ver); +static DEVICE_ATTR_RO(cpu_cpld_mnr_ver); + +static SENSOR_DEVICE_ATTR(fan0_dir, S_IRUGO, fan_dir_show, NULL, FAN_0); +static SENSOR_DEVICE_ATTR(fan1_dir, S_IRUGO, fan_dir_show, NULL, FAN_1); +static SENSOR_DEVICE_ATTR(fan2_dir, S_IRUGO, fan_dir_show, NULL, FAN_2); +static SENSOR_DEVICE_ATTR(fan0_prs, S_IRUGO, fan_prs_show, NULL, FAN_0); +static SENSOR_DEVICE_ATTR(fan1_prs, S_IRUGO, fan_prs_show, NULL, FAN_1); +static SENSOR_DEVICE_ATTR(fan2_prs, S_IRUGO, fan_prs_show, NULL, FAN_2); +static SENSOR_DEVICE_ATTR(fan0_led, S_IRUGO, fani_led_show, fani_led_store, FAN_0); +static SENSOR_DEVICE_ATTR(fan1_led, S_IRUGO, fani_led_show, fani_led_store, FAN_1); +static SENSOR_DEVICE_ATTR(fan2_led, S_IRUGO, fani_led_show, fani_led_store, FAN_2); + +static struct attribute *n3248pxe_cpld_attrs[] = { + &dev_attr_sfp_txdis.attr, + &dev_attr_sfp_rxlos.attr, + &dev_attr_sfp_txfault.attr, + &dev_attr_sfp_modprs.attr, + &dev_attr_reboot_cause.attr, + &dev_attr_power_reset.attr, + &sensor_dev_attr_fan0_dir.dev_attr.attr, + &sensor_dev_attr_fan1_dir.dev_attr.attr, + &sensor_dev_attr_fan2_dir.dev_attr.attr, + &sensor_dev_attr_fan0_prs.dev_attr.attr, + &sensor_dev_attr_fan1_prs.dev_attr.attr, + &sensor_dev_attr_fan2_prs.dev_attr.attr, + &sensor_dev_attr_fan0_led.dev_attr.attr, + &sensor_dev_attr_fan1_led.dev_attr.attr, + &sensor_dev_attr_fan2_led.dev_attr.attr, + &dev_attr_psu0_prs.attr, + &dev_attr_psu1_prs.attr, + &dev_attr_psu0_status.attr, + &dev_attr_psu1_status.attr, + &dev_attr_system_led.attr, + &dev_attr_locator_led.attr, + &dev_attr_power_led.attr, + &dev_attr_master_led.attr, + &dev_attr_fan_led.attr, + &dev_attr_power_good.attr, + &dev_attr_sys_cpld_mjr_ver.attr, + &dev_attr_sys_cpld_mnr_ver.attr, + &dev_attr_cpu_cpld_mjr_ver.attr, + &dev_attr_cpu_cpld_mnr_ver.attr, + NULL, +}; + +static struct attribute_group n3248pxe_cpld_attr_grp = { + .attrs = n3248pxe_cpld_attrs, +}; + +static int get_ismt_base_nr(void) +{ + struct i2c_adapter *ismt_adap; + static int ismt_base_nr = -1; + + if (ismt_base_nr != -1) { + return ismt_base_nr; + } + for (ismt_base_nr = 0; ismt_base_nr < 2; ismt_base_nr++) { + ismt_adap = i2c_get_adapter(ismt_base_nr); + if (!ismt_adap) { + printk(KERN_WARNING "iSMT adapter (%d) not found\n", ismt_base_nr); + return -ENODEV; + } + if (!strstr(ismt_adap->name, "iSMT adapter")) { + i2c_put_adapter(ismt_adap); + printk("I2C %d adapter is %s\n", ismt_base_nr, ismt_adap->name); + } else { + i2c_put_adapter(ismt_adap); + return ismt_base_nr; + } + } + return -ENODEV; +} + +static int __init cpld_probe(struct platform_device *pdev) +{ + struct cpld_platform_data *pdata; + struct i2c_adapter *parent; + int i, cpld_bus; + int ret; + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "Missing platform data\n"); + return -ENODEV; + } + + cpld_bus = get_ismt_base_nr(); + if (cpld_bus < 0) { + return -ENODEV; + } + parent = i2c_get_adapter(cpld_bus); + if (!parent) { + printk(KERN_WARNING "Parent adapter (%d) not found\n", cpld_bus); + return -ENODEV; + } + for (i = 0; i < CPLD_DEVICE_NUM; i++) { + pdata[i].client = i2c_new_dummy(parent, pdata[i].reg_addr); + if (!pdata[i].client) { + printk(KERN_WARNING "Fail to create dummy i2c client for addr %d\n", pdata[i].reg_addr); + goto error; + } + } + + ret = sysfs_create_group(&pdev->dev.kobj, &n3248pxe_cpld_attr_grp); + if (ret) + goto error; + + return 0; + +error: + i--; + for (; i >= 0; i--) { + if (pdata[i].client) { + i2c_unregister_device(pdata[i].client); + } + } + + i2c_put_adapter(parent); + + return -ENODEV; +} + +static int __exit cpld_remove(struct platform_device *pdev) +{ + int i; + struct i2c_adapter *parent = NULL; + struct cpld_platform_data *pdata = pdev->dev.platform_data; + + sysfs_remove_group(&pdev->dev.kobj, &n3248pxe_cpld_attr_grp); + + if (!pdata) { + dev_err(&pdev->dev, "Missing platform data\n"); + } else { + for (i = 0; i < CPLD_DEVICE_NUM; i++) { + if (pdata[i].client) { + if (!parent) { + parent = (pdata[i].client)->adapter; + } + i2c_unregister_device(pdata[i].client); + } + } + } + + i2c_put_adapter(parent); + + return 0; +} + +static struct platform_driver cpld_driver = { + .probe = cpld_probe, + .remove = __exit_p(cpld_remove), + .driver = { + .owner = THIS_MODULE, + .name = "dell-n3248pxe-cpld", + }, +}; + +static struct i2c_board_info sys_board_mux[] = { + { + I2C_BOARD_INFO("pca9548", 0x71) + } +}; + +static int __init dell_n3248pxe_platform_init(void) +{ + int ret = 0; + struct i2c_adapter *sys_i2c_adap; + struct i2c_client *mux_i2c_cli; + struct cpld_platform_data *cpld_pdata; + struct mux_platform_data *pdata; + int i, sys_i2c_bus; + + printk("dell_n3248pxe_platform module initialization\n"); + sys_i2c_bus = get_ismt_base_nr(); + if (sys_i2c_bus < 0) { + return -ENODEV; + } + + sys_i2c_adap = i2c_get_adapter(sys_i2c_bus); + mux_i2c_cli = i2c_new_device(sys_i2c_adap, sys_board_mux); + if (!mux_i2c_cli) + return PTR_ERR_OR_ZERO(mux_i2c_cli); + + ret = platform_driver_register(&cpld_driver); + if (ret) { + printk(KERN_WARNING "Fail to register cpld driver\n"); + goto error_cpld_driver; + } + + ret = platform_driver_register(&mux_driver); + if (ret) { + printk(KERN_WARNING "Fail to register mux driver\n"); + goto error_mux_driver; + } + + ret = platform_device_register(&n3248pxe_cpld); + if (ret) { + printk(KERN_WARNING "Fail to create cpld device\n"); + goto error_cpld; + } + + cpld_pdata = n3248pxe_cpld.dev.platform_data; + + for (i = 0; i < PF_MUX_DEVICES; i++) { + pdata = n3248pxe_mux[i].dev.platform_data; + pdata->cpld = cpld_pdata[sys_cpld].client; + ret = platform_device_register(&n3248pxe_mux[i]); + if (ret) { + printk(KERN_WARNING "fail to create mux %d\n", i); + goto error_mux; + } + } + ret = i2c_smbus_write_byte_data(cpld_pdata[sys_cpld].client, PHY_RESET_REG, RESET_ALL_PHY); + if (ret) + goto error_mux; + + return 0; + +error_mux: + i--; + for (; i >= 0; i--) { + platform_device_unregister(&n3248pxe_mux[i]); + } + platform_device_unregister(&n3248pxe_cpld); +error_cpld: + platform_driver_unregister(&mux_driver); +error_mux_driver: + platform_driver_unregister(&cpld_driver); +error_cpld_driver: + return ret; +} + +static void __exit dell_n3248pxe_platform_exit(void) +{ + int i; + + for (i = 0; i < PF_MUX_DEVICES; i++) + platform_device_unregister(&n3248pxe_mux[i]); + platform_device_unregister(&n3248pxe_cpld); + platform_driver_unregister(&cpld_driver); + platform_driver_unregister(&mux_driver); +} + +module_init(dell_n3248pxe_platform_init); +module_exit(dell_n3248pxe_platform_exit); + +MODULE_DESCRIPTION("DELL n3248pxe Platform Support"); +MODULE_AUTHOR("Dhanakumar Subramanian "); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/emc2305.c b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/emc2305.c new file mode 100644 index 000000000000..f08033e080ce --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/emc2305.c @@ -0,0 +1,877 @@ +/* + * emc2305.c - hwmon driver for SMSC EMC2305 fan controller + * (C) Copyright 2013 + * Reinhard Pfau, Guntermann & Drunck GmbH + * + * Based on emc2103 driver by SMSC. + * + * Datasheet available at: + * http://www.smsc.com/Downloads/SMSC/Downloads_Public/Data_Sheets/2305.pdf + * + * Also supports the EMC2303 fan controller which has the same functionality + * and register layout as EMC2305, but supports only up to 3 fans instead of 5. + * + * Also supports EMC2302 (up to 2 fans) and EMC2301 (1 fan) fan controller. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * TODO / IDEAS: + * - expose more of the configuration and features + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Addresses scanned. + * Listed in the same order as they appear in the EMC2305, EMC2303 data sheets. + * + * Note: these are the I2C adresses which are possible for EMC2305 and EMC2303 + * chips. + * The EMC2302 supports only 0x2e (EMC2302-1) and 0x2f (EMC2302-2). + * The EMC2301 supports only 0x2f. + */ +static const unsigned short i2c_adresses[] = { + 0x2E, + 0x2F, + 0x2C, + 0x2D, + 0x4C, + 0x4D, + I2C_CLIENT_END +}; + +/* + * global registers + */ +enum { + REG_CONFIGURATION = 0x20, + REG_FAN_STATUS = 0x24, + REG_FAN_STALL_STATUS = 0x25, + REG_FAN_SPIN_STATUS = 0x26, + REG_DRIVE_FAIL_STATUS = 0x27, + REG_FAN_INTERRUPT_ENABLE = 0x29, + REG_PWM_POLARITY_CONFIG = 0x2a, + REG_PWM_OUTPUT_CONFIG = 0x2b, + REG_PWM_BASE_FREQ_1 = 0x2c, + REG_PWM_BASE_FREQ_2 = 0x2d, + REG_SOFTWARE_LOCK = 0xef, + REG_PRODUCT_FEATURES = 0xfc, + REG_PRODUCT_ID = 0xfd, + REG_MANUFACTURER_ID = 0xfe, + REG_REVISION = 0xff +}; + +/* + * fan specific registers + */ +enum { + REG_FAN_SETTING = 0x30, + REG_PWM_DIVIDE = 0x31, + REG_FAN_CONFIGURATION_1 = 0x32, + REG_FAN_CONFIGURATION_2 = 0x33, + REG_GAIN = 0x35, + REG_FAN_SPIN_UP_CONFIG = 0x36, + REG_FAN_MAX_STEP = 0x37, + REG_FAN_MINIMUM_DRIVE = 0x38, + REG_FAN_VALID_TACH_COUNT = 0x39, + REG_FAN_DRIVE_FAIL_BAND_LOW = 0x3a, + REG_FAN_DRIVE_FAIL_BAND_HIGH = 0x3b, + REG_TACH_TARGET_LOW = 0x3c, + REG_TACH_TARGET_HIGH = 0x3d, + REG_TACH_READ_HIGH = 0x3e, + REG_TACH_READ_LOW = 0x3f, +}; + +#define SEL_FAN(fan, reg) (reg + fan * 0x10) + +/* + * Factor by equations [2] and [3] from data sheet; valid for fans where the + * number of edges equals (poles * 2 + 1). + */ +#define FAN_RPM_FACTOR 3932160 + + +struct emc2305_fan_data { + bool enabled; + bool valid; + unsigned long last_updated; + bool rpm_control; + u8 multiplier; + u8 poles; + u16 target; + u16 tach; + u16 rpm_factor; + u8 pwm; +}; + +struct emc2305_data { + struct device *hwmon_dev; + struct mutex update_lock; + int fans; + struct emc2305_fan_data fan[5]; +}; + +static int read_u8_from_i2c(struct i2c_client *client, u8 i2c_reg, u8 *output) +{ + int status = i2c_smbus_read_byte_data(client, i2c_reg); + if (status < 0) { + dev_warn(&client->dev, "reg 0x%02x, err %d\n", + i2c_reg, status); + } else { + *output = status; + } + return status; +} + +static void read_fan_from_i2c(struct i2c_client *client, u16 *output, + u8 hi_addr, u8 lo_addr) +{ + u8 high_byte, lo_byte; + + if (read_u8_from_i2c(client, hi_addr, &high_byte) < 0) + return; + + if (read_u8_from_i2c(client, lo_addr, &lo_byte) < 0) + return; + + *output = ((u16)high_byte << 5) | (lo_byte >> 3); +} + +static void write_fan_target_to_i2c(struct i2c_client *client, int fan, + u16 new_target) +{ + const u8 lo_reg = SEL_FAN(fan, REG_TACH_TARGET_LOW); + const u8 hi_reg = SEL_FAN(fan, REG_TACH_TARGET_HIGH); + u8 high_byte = (new_target & 0x1fe0) >> 5; + u8 low_byte = (new_target & 0x001f) << 3; + i2c_smbus_write_byte_data(client, lo_reg, low_byte); + i2c_smbus_write_byte_data(client, hi_reg, high_byte); +} + +static void read_fan_config_from_i2c(struct i2c_client *client, int fan) + +{ + struct emc2305_data *data = i2c_get_clientdata(client); + u8 conf1; + + if (read_u8_from_i2c(client, SEL_FAN(fan, REG_FAN_CONFIGURATION_1), + &conf1) < 0) + return; + + data->fan[fan].rpm_control = (conf1 & 0x80) != 0; + data->fan[fan].multiplier = 1 << ((conf1 & 0x60) >> 5); + data->fan[fan].poles = ((conf1 & 0x18) >> 3) + 1; +} + +static void read_fan_setting(struct i2c_client *client, int fan) +{ + struct emc2305_data *data = i2c_get_clientdata(client); + u8 setting; + + if (read_u8_from_i2c(client, SEL_FAN(fan, REG_FAN_SETTING), + &setting) < 0) + return; + + data->fan[fan].pwm = setting; +} + +static void read_fan_data(struct i2c_client *client, int fan_idx) +{ + struct emc2305_data *data = i2c_get_clientdata(client); + + read_fan_from_i2c(client, &data->fan[fan_idx].target, + SEL_FAN(fan_idx, REG_TACH_TARGET_HIGH), + SEL_FAN(fan_idx, REG_TACH_TARGET_LOW)); + read_fan_from_i2c(client, &data->fan[fan_idx].tach, + SEL_FAN(fan_idx, REG_TACH_READ_HIGH), + SEL_FAN(fan_idx, REG_TACH_READ_LOW)); +} + +static struct emc2305_fan_data * +emc2305_update_fan(struct i2c_client *client, int fan_idx) +{ + struct emc2305_data *data = i2c_get_clientdata(client); + struct emc2305_fan_data *fan_data = &data->fan[fan_idx]; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, fan_data->last_updated + HZ + HZ / 2) + || !fan_data->valid) { + read_fan_config_from_i2c(client, fan_idx); + read_fan_data(client, fan_idx); + read_fan_setting(client, fan_idx); + fan_data->valid = true; + fan_data->last_updated = jiffies; + } + + mutex_unlock(&data->update_lock); + return fan_data; +} + +static struct emc2305_fan_data * +emc2305_update_device_fan(struct device *dev, struct device_attribute *da) +{ + struct i2c_client *client = to_i2c_client(dev); + int fan_idx = to_sensor_dev_attr(da)->index; + + return emc2305_update_fan(client, fan_idx); +} + +/* + * set/ config functions + */ + +/* + * Note: we also update the fan target here, because its value is + * determined in part by the fan clock divider. This follows the principle + * of least surprise; the user doesn't expect the fan target to change just + * because the divider changed. + */ +static int +emc2305_set_fan_div(struct i2c_client *client, int fan_idx, long new_div) +{ + struct emc2305_data *data = i2c_get_clientdata(client); + struct emc2305_fan_data *fan = emc2305_update_fan(client, fan_idx); + const u8 reg_conf1 = SEL_FAN(fan_idx, REG_FAN_CONFIGURATION_1); + int new_range_bits, old_div = 8 / fan->multiplier; + int status = 0; + + if (new_div == old_div) /* No change */ + return 0; + + switch (new_div) { + case 1: + new_range_bits = 3; + break; + case 2: + new_range_bits = 2; + break; + case 4: + new_range_bits = 1; + break; + case 8: + new_range_bits = 0; + break; + default: + return -EINVAL; + } + + mutex_lock(&data->update_lock); + + status = i2c_smbus_read_byte_data(client, reg_conf1); + if (status < 0) { + dev_dbg(&client->dev, "reg 0x%02x, err %d\n", + reg_conf1, status); + status = -EIO; + goto exit_unlock; + } + status &= 0x9F; + status |= (new_range_bits << 5); + status = i2c_smbus_write_byte_data(client, reg_conf1, status); + if (status < 0) { + status = -EIO; + goto exit_invalidate; + } + + fan->multiplier = 8 / new_div; + + /* update fan target if high byte is not disabled */ + if ((fan->target & 0x1fe0) != 0x1fe0) { + u16 new_target = (fan->target * old_div) / new_div; + fan->target = min_t(u16, new_target, 0x1fff); + write_fan_target_to_i2c(client, fan_idx, fan->target); + } + +exit_invalidate: + /* invalidate fan data to force re-read from hardware */ + fan->valid = false; +exit_unlock: + mutex_unlock(&data->update_lock); + return status; +} + +static int +emc2305_set_fan_target(struct i2c_client *client, int fan_idx, long rpm_target) +{ + struct emc2305_data *data = i2c_get_clientdata(client); + struct emc2305_fan_data *fan = emc2305_update_fan(client, fan_idx); + + /* + * Datasheet states 16000 as maximum RPM target + * (table 2.2 and section 4.3) + */ + if ((rpm_target < 0) || (rpm_target > 16000)) + return -EINVAL; + + mutex_lock(&data->update_lock); + + if (rpm_target == 0) + fan->target = 0x1fff; + else + fan->target = clamp_val( + (FAN_RPM_FACTOR * fan->multiplier) / rpm_target, + 0, 0x1fff); + + write_fan_target_to_i2c(client, fan_idx, fan->target); + + mutex_unlock(&data->update_lock); + return 0; +} + +static int +emc2305_set_pwm_enable(struct i2c_client *client, int fan_idx, long enable) +{ + struct emc2305_data *data = i2c_get_clientdata(client); + struct emc2305_fan_data *fan = emc2305_update_fan(client, fan_idx); + const u8 reg_fan_conf1 = SEL_FAN(fan_idx, REG_FAN_CONFIGURATION_1); + int status = 0; + u8 conf_reg; + + mutex_lock(&data->update_lock); + switch (enable) { + case 0: + fan->rpm_control = false; + break; + case 3: + fan->rpm_control = true; + break; + default: + status = -EINVAL; + goto exit_unlock; + } + + status = read_u8_from_i2c(client, reg_fan_conf1, &conf_reg); + if (status < 0) { + status = -EIO; + goto exit_unlock; + } + + if (fan->rpm_control) + conf_reg |= 0x80; + else + conf_reg &= ~0x80; + + status = i2c_smbus_write_byte_data(client, reg_fan_conf1, conf_reg); + if (status < 0) + status = -EIO; + +exit_unlock: + mutex_unlock(&data->update_lock); + return status; +} + +static int +emc2305_set_pwm(struct i2c_client *client, int fan_idx, long pwm) +{ + struct emc2305_data *data = i2c_get_clientdata(client); + struct emc2305_fan_data *fan = emc2305_update_fan(client, fan_idx); + const u8 reg_fan_setting = SEL_FAN(fan_idx, REG_FAN_SETTING); + int status = 0; + + /* + * Datasheet states 255 as maximum PWM + * (section 5.7) + */ + if ((pwm < 0) || (pwm > 255)) + return -EINVAL; + + fan->pwm = pwm; + + mutex_lock(&data->update_lock); + + status = i2c_smbus_write_byte_data(client, reg_fan_setting, fan->pwm); + + mutex_unlock(&data->update_lock); + return status; +} +/* + * sysfs callback functions + * + * Note: + * Naming of the funcs is modelled after the naming scheme described in + * Documentation/hwmon/sysfs-interface: + * + * For a sysfs file _ the functions are named like this: + * the show function: show__ + * the store function: set__ + * For read only (RO) attributes of course only the show func is required. + * + * This convention allows us to define the sysfs attributes by using macros. + */ + +static ssize_t +show_fan_input(struct device *dev, struct device_attribute *da, char *buf) +{ + struct emc2305_fan_data *fan = emc2305_update_device_fan(dev, da); + int rpm = 0; + if (fan->tach != 0) + rpm = (FAN_RPM_FACTOR * fan->multiplier) / fan->tach; + return sprintf(buf, "%d\n", rpm); +} + +static ssize_t +show_fan_fault(struct device *dev, struct device_attribute *da, char *buf) +{ + struct emc2305_fan_data *fan = emc2305_update_device_fan(dev, da); + bool fault = ((fan->tach & 0x1fe0) == 0x1fe0); + return sprintf(buf, "%d\n", fault ? 1 : 0); +} + +static ssize_t +show_fan_div(struct device *dev, struct device_attribute *da, char *buf) +{ + struct emc2305_fan_data *fan = emc2305_update_device_fan(dev, da); + int fan_div = 8 / fan->multiplier; + return sprintf(buf, "%d\n", fan_div); +} + +static ssize_t +set_fan_div(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + int fan_idx = to_sensor_dev_attr(da)->index; + long new_div; + int status; + + status = kstrtol(buf, 10, &new_div); + if (status < 0) + return -EINVAL; + + status = emc2305_set_fan_div(client, fan_idx, new_div); + if (status < 0) + return status; + + return count; +} + +static ssize_t +show_fan_target(struct device *dev, struct device_attribute *da, char *buf) +{ + struct emc2305_fan_data *fan = emc2305_update_device_fan(dev, da); + int rpm = 0; + + /* high byte of 0xff indicates disabled so return 0 */ + if ((fan->target != 0) && ((fan->target & 0x1fe0) != 0x1fe0)) + rpm = (FAN_RPM_FACTOR * fan->multiplier) + / fan->target; + + return sprintf(buf, "%d\n", rpm); +} + +static ssize_t set_fan_target(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + int fan_idx = to_sensor_dev_attr(da)->index; + long rpm_target; + int status; + + status = kstrtol(buf, 10, &rpm_target); + if (status < 0) + return -EINVAL; + + status = emc2305_set_fan_target(client, fan_idx, rpm_target); + if (status < 0) + return status; + + return count; +} + +static ssize_t +show_pwm_enable(struct device *dev, struct device_attribute *da, char *buf) +{ + struct emc2305_fan_data *fan = emc2305_update_device_fan(dev, da); + return sprintf(buf, "%d\n", fan->rpm_control ? 3 : 0); +} + +static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + int fan_idx = to_sensor_dev_attr(da)->index; + long new_value; + int status; + + status = kstrtol(buf, 10, &new_value); + if (status < 0) + return -EINVAL; + status = emc2305_set_pwm_enable(client, fan_idx, new_value); + return count; +} + +static ssize_t show_pwm(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct emc2305_fan_data *fan = emc2305_update_device_fan(dev, da); + return sprintf(buf, "%d\n", fan->pwm); +} + +static ssize_t set_pwm(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + int fan_idx = to_sensor_dev_attr(da)->index; + unsigned long val; + int ret; + int status; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 255) + return -EINVAL; + + status = emc2305_set_pwm(client, fan_idx, val); + return count; +} + +/* define a read only attribute */ +#define EMC2305_ATTR_RO(_type, _item, _num) \ + SENSOR_ATTR(_type ## _num ## _ ## _item, S_IRUGO, \ + show_## _type ## _ ## _item, NULL, _num - 1) + +/* define a read/write attribute */ +#define EMC2305_ATTR_RW(_type, _item, _num) \ + SENSOR_ATTR(_type ## _num ## _ ## _item, S_IRUGO | S_IWUSR, \ + show_## _type ##_ ## _item, \ + set_## _type ## _ ## _item, _num - 1) + +/* + * TODO: Ugly hack, but temporary as this whole logic needs + * to be rewritten as per standard HWMON sysfs registration + */ + +/* define a read/write attribute */ +#define EMC2305_ATTR_RW2(_type, _num) \ + SENSOR_ATTR(_type ## _num, S_IRUGO | S_IWUSR, \ + show_## _type, set_## _type, _num - 1) + +/* defines the attributes for a single fan */ +#define EMC2305_DEFINE_FAN_ATTRS(_num) \ + static const \ + struct sensor_device_attribute emc2305_attr_fan ## _num[] = { \ + EMC2305_ATTR_RO(fan, input, _num), \ + EMC2305_ATTR_RO(fan, fault, _num), \ + EMC2305_ATTR_RW(fan, div, _num), \ + EMC2305_ATTR_RW(fan, target, _num), \ + EMC2305_ATTR_RW(pwm, enable, _num), \ + EMC2305_ATTR_RW2(pwm, _num) \ + } + +#define EMC2305_NUM_FAN_ATTRS ARRAY_SIZE(emc2305_attr_fan1) + +/* common attributes for EMC2303 and EMC2305 */ +static const struct sensor_device_attribute emc2305_attr_common[] = { +}; + +/* fan attributes for the single fans */ +EMC2305_DEFINE_FAN_ATTRS(1); +EMC2305_DEFINE_FAN_ATTRS(2); +EMC2305_DEFINE_FAN_ATTRS(3); +EMC2305_DEFINE_FAN_ATTRS(4); +EMC2305_DEFINE_FAN_ATTRS(5); +EMC2305_DEFINE_FAN_ATTRS(6); + +/* fan attributes */ +static const struct sensor_device_attribute *emc2305_fan_attrs[] = { + emc2305_attr_fan1, + emc2305_attr_fan2, + emc2305_attr_fan3, + emc2305_attr_fan4, + emc2305_attr_fan5, +}; + +/* + * driver interface + */ + +static int emc2305_remove(struct i2c_client *client) +{ + struct emc2305_data *data = i2c_get_clientdata(client); + int fan_idx, i; + + hwmon_device_unregister(data->hwmon_dev); + + for (fan_idx = 0; fan_idx < data->fans; ++fan_idx) + for (i = 0; i < EMC2305_NUM_FAN_ATTRS; ++i) + device_remove_file( + &client->dev, + &emc2305_fan_attrs[fan_idx][i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(emc2305_attr_common); ++i) + device_remove_file(&client->dev, + &emc2305_attr_common[i].dev_attr); + + kfree(data); + return 0; +} + + +#ifdef CONFIG_OF +/* + * device tree support + */ + +struct of_fan_attribute { + const char *name; + int (*set)(struct i2c_client*, int, long); +}; + +struct of_fan_attribute of_fan_attributes[] = { + {"fan-div", emc2305_set_fan_div}, + {"fan-target", emc2305_set_fan_target}, + {"pwm-enable", emc2305_set_pwm_enable}, + {NULL, NULL} +}; + +static int emc2305_config_of(struct i2c_client *client) +{ + struct emc2305_data *data = i2c_get_clientdata(client); + struct device_node *node; + unsigned int fan_idx; + + if (!client->dev.of_node) + return -EINVAL; + if (!of_get_next_child(client->dev.of_node, NULL)) + return 0; + + for (fan_idx = 0; fan_idx < data->fans; ++fan_idx) + data->fan[fan_idx].enabled = false; + + for_each_child_of_node(client->dev.of_node, node) { + const __be32 *property; + int len; + struct of_fan_attribute *attr; + + property = of_get_property(node, "reg", &len); + if (!property || len != sizeof(int)) { + dev_err(&client->dev, "invalid reg on %s\n", + node->full_name); + continue; + } + + fan_idx = be32_to_cpup(property); + if (fan_idx >= data->fans) { + dev_err(&client->dev, + "invalid fan index %d on %s\n", + fan_idx, node->full_name); + continue; + } + + data->fan[fan_idx].enabled = true; + + for (attr = of_fan_attributes; attr->name; ++attr) { + int status = 0; + long value; + property = of_get_property(node, attr->name, &len); + if (!property) + continue; + if (len != sizeof(int)) { + dev_err(&client->dev, "invalid %s on %s\n", + attr->name, node->full_name); + continue; + } + value = be32_to_cpup(property); + status = attr->set(client, fan_idx, value); + if (status == -EINVAL) { + dev_err(&client->dev, + "invalid value for %s on %s\n", + attr->name, node->full_name); + } + } + } + + return 0; +} + +#endif + +static void emc2305_get_config(struct i2c_client *client) +{ + int i; + struct emc2305_data *data = i2c_get_clientdata(client); + + for (i = 0; i < data->fans; ++i) { + data->fan[i].enabled = true; + emc2305_update_fan(client, i); + } + +#ifdef CONFIG_OF + emc2305_config_of(client); +#endif + +} + +static int +emc2305_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct emc2305_data *data; + int status; + int i; + int fan_idx; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + data = kzalloc(sizeof(struct emc2305_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + status = i2c_smbus_read_byte_data(client, REG_PRODUCT_ID); + switch (status) { + case 0x34: /* EMC2305 */ + data->fans = 5; + break; + case 0x35: /* EMC2303 */ + data->fans = 3; + break; + case 0x36: /* EMC2302 */ + data->fans = 2; + break; + case 0x37: /* EMC2301 */ + data->fans = 1; + break; + default: + if (status >= 0) + status = -EINVAL; + goto exit_free; + } + + emc2305_get_config(client); + + for (i = 0; i < ARRAY_SIZE(emc2305_attr_common); ++i) { + status = device_create_file(&client->dev, + &emc2305_attr_common[i].dev_attr); + if (status) + goto exit_remove; + } + for (fan_idx = 0; fan_idx < data->fans; ++fan_idx) + for (i = 0; i < EMC2305_NUM_FAN_ATTRS; ++i) { + if (!data->fan[fan_idx].enabled) + continue; + status = device_create_file( + &client->dev, + &emc2305_fan_attrs[fan_idx][i].dev_attr); + if (status) + goto exit_remove_fans; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove_fans; + } + + dev_info(&client->dev, "%s: sensor '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove_fans: + for (fan_idx = 0; fan_idx < data->fans; ++fan_idx) + for (i = 0; i < EMC2305_NUM_FAN_ATTRS; ++i) + device_remove_file( + &client->dev, + &emc2305_fan_attrs[fan_idx][i].dev_attr); + +exit_remove: + for (i = 0; i < ARRAY_SIZE(emc2305_attr_common); ++i) + device_remove_file(&client->dev, + &emc2305_attr_common[i].dev_attr); +exit_free: + kfree(data); + return status; +} + +static const struct i2c_device_id emc2305_id[] = { + { "emc2305", 0 }, + { "emc2303", 0 }, + { "emc2302", 0 }, + { "emc2301", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, emc2305_id); + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int +emc2305_detect(struct i2c_client *new_client, struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = new_client->adapter; + int manufacturer, product; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + manufacturer = + i2c_smbus_read_byte_data(new_client, REG_MANUFACTURER_ID); + if (manufacturer != 0x5D) + return -ENODEV; + + product = i2c_smbus_read_byte_data(new_client, REG_PRODUCT_ID); + + switch (product) { + case 0x34: + strlcpy(info->type, "emc2305", I2C_NAME_SIZE); + break; + case 0x35: + strlcpy(info->type, "emc2303", I2C_NAME_SIZE); + break; + case 0x36: + strlcpy(info->type, "emc2302", I2C_NAME_SIZE); + break; + case 0x37: + strlcpy(info->type, "emc2301", I2C_NAME_SIZE); + break; + default: + return -ENODEV; + } + + return 0; +} + +static struct i2c_driver emc2305_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "emc2305", + }, + .probe = emc2305_probe, + .remove = emc2305_remove, + .id_table = emc2305_id, +/* + .detect = emc2305_detect, + .address_list = i2c_adresses, +*/ +}; + +module_i2c_driver(emc2305_driver); + +MODULE_AUTHOR("Reinhard Pfau "); +MODULE_DESCRIPTION("SMSC EMC2305 hwmon driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/pmbus.h b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/pmbus.h new file mode 100644 index 000000000000..521baf6da49a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/pmbus.h @@ -0,0 +1,425 @@ +/* + * pmbus.h - Common defines and structures for PMBus devices + * + * Copyright (c) 2010, 2011 Ericsson AB. + * Copyright (c) 2012 Guenter Roeck + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef PMBUS_H +#define PMBUS_H + +#include +#include + +/* + * Registers + */ +enum pmbus_regs { + PMBUS_PAGE = 0x00, + PMBUS_OPERATION = 0x01, + PMBUS_ON_OFF_CONFIG = 0x02, + PMBUS_CLEAR_FAULTS = 0x03, + PMBUS_PHASE = 0x04, + + PMBUS_CAPABILITY = 0x19, + PMBUS_QUERY = 0x1A, + + PMBUS_VOUT_MODE = 0x20, + PMBUS_VOUT_COMMAND = 0x21, + PMBUS_VOUT_TRIM = 0x22, + PMBUS_VOUT_CAL_OFFSET = 0x23, + PMBUS_VOUT_MAX = 0x24, + PMBUS_VOUT_MARGIN_HIGH = 0x25, + PMBUS_VOUT_MARGIN_LOW = 0x26, + PMBUS_VOUT_TRANSITION_RATE = 0x27, + PMBUS_VOUT_DROOP = 0x28, + PMBUS_VOUT_SCALE_LOOP = 0x29, + PMBUS_VOUT_SCALE_MONITOR = 0x2A, + + PMBUS_COEFFICIENTS = 0x30, + PMBUS_POUT_MAX = 0x31, + + PMBUS_FAN_CONFIG_12 = 0x3A, + PMBUS_FAN_COMMAND_1 = 0x3B, + PMBUS_FAN_COMMAND_2 = 0x3C, + PMBUS_FAN_CONFIG_34 = 0x3D, + PMBUS_FAN_COMMAND_3 = 0x3E, + PMBUS_FAN_COMMAND_4 = 0x3F, + + PMBUS_VOUT_OV_FAULT_LIMIT = 0x40, + PMBUS_VOUT_OV_FAULT_RESPONSE = 0x41, + PMBUS_VOUT_OV_WARN_LIMIT = 0x42, + PMBUS_VOUT_UV_WARN_LIMIT = 0x43, + PMBUS_VOUT_UV_FAULT_LIMIT = 0x44, + PMBUS_VOUT_UV_FAULT_RESPONSE = 0x45, + PMBUS_IOUT_OC_FAULT_LIMIT = 0x46, + PMBUS_IOUT_OC_FAULT_RESPONSE = 0x47, + PMBUS_IOUT_OC_LV_FAULT_LIMIT = 0x48, + PMBUS_IOUT_OC_LV_FAULT_RESPONSE = 0x49, + PMBUS_IOUT_OC_WARN_LIMIT = 0x4A, + PMBUS_IOUT_UC_FAULT_LIMIT = 0x4B, + PMBUS_IOUT_UC_FAULT_RESPONSE = 0x4C, + + PMBUS_OT_FAULT_LIMIT = 0x4F, + PMBUS_OT_FAULT_RESPONSE = 0x50, + PMBUS_OT_WARN_LIMIT = 0x51, + PMBUS_UT_WARN_LIMIT = 0x52, + PMBUS_UT_FAULT_LIMIT = 0x53, + PMBUS_UT_FAULT_RESPONSE = 0x54, + PMBUS_VIN_OV_FAULT_LIMIT = 0x55, + PMBUS_VIN_OV_FAULT_RESPONSE = 0x56, + PMBUS_VIN_OV_WARN_LIMIT = 0x57, + PMBUS_VIN_UV_WARN_LIMIT = 0x58, + PMBUS_VIN_UV_FAULT_LIMIT = 0x59, + + PMBUS_IIN_OC_FAULT_LIMIT = 0x5B, + PMBUS_IIN_OC_WARN_LIMIT = 0x5D, + + PMBUS_POUT_OP_FAULT_LIMIT = 0x68, + PMBUS_POUT_OP_WARN_LIMIT = 0x6A, + PMBUS_PIN_OP_WARN_LIMIT = 0x6B, + + PMBUS_STATUS_BYTE = 0x78, + PMBUS_STATUS_WORD = 0x79, + PMBUS_STATUS_VOUT = 0x7A, + PMBUS_STATUS_IOUT = 0x7B, + PMBUS_STATUS_INPUT = 0x7C, + PMBUS_STATUS_TEMPERATURE = 0x7D, + PMBUS_STATUS_CML = 0x7E, + PMBUS_STATUS_OTHER = 0x7F, + PMBUS_STATUS_MFR_SPECIFIC = 0x80, + PMBUS_STATUS_FAN_12 = 0x81, + PMBUS_STATUS_FAN_34 = 0x82, + + PMBUS_READ_VIN = 0x88, + PMBUS_READ_IIN = 0x89, + PMBUS_READ_VCAP = 0x8A, + PMBUS_READ_VOUT = 0x8B, + PMBUS_READ_IOUT = 0x8C, + PMBUS_READ_TEMPERATURE_1 = 0x8D, + PMBUS_READ_TEMPERATURE_2 = 0x8E, + PMBUS_READ_TEMPERATURE_3 = 0x8F, + PMBUS_READ_FAN_SPEED_1 = 0x90, + PMBUS_READ_FAN_SPEED_2 = 0x91, + PMBUS_READ_FAN_SPEED_3 = 0x92, + PMBUS_READ_FAN_SPEED_4 = 0x93, + PMBUS_READ_DUTY_CYCLE = 0x94, + PMBUS_READ_FREQUENCY = 0x95, + PMBUS_READ_POUT = 0x96, + PMBUS_READ_PIN = 0x97, + + PMBUS_REVISION = 0x98, + PMBUS_MFR_ID = 0x99, + PMBUS_MFR_MODEL = 0x9A, + PMBUS_MFR_REVISION = 0x9B, + PMBUS_MFR_LOCATION = 0x9C, + PMBUS_MFR_DATE = 0x9D, + PMBUS_MFR_SERIAL = 0x9E, + +/* + * Virtual registers. + * Useful to support attributes which are not supported by standard PMBus + * registers but exist as manufacturer specific registers on individual chips. + * Must be mapped to real registers in device specific code. + * + * Semantics: + * Virtual registers are all word size. + * READ registers are read-only; writes are either ignored or return an error. + * RESET registers are read/write. Reading reset registers returns zero + * (used for detection), writing any value causes the associated history to be + * reset. + * Virtual registers have to be handled in device specific driver code. Chip + * driver code returns non-negative register values if a virtual register is + * supported, or a negative error code if not. The chip driver may return + * -ENODATA or any other error code in this case, though an error code other + * than -ENODATA is handled more efficiently and thus preferred. Either case, + * the calling PMBus core code will abort if the chip driver returns an error + * code when reading or writing virtual registers. + */ + PMBUS_VIRT_BASE = 0x100, + PMBUS_VIRT_READ_TEMP_AVG, + PMBUS_VIRT_READ_TEMP_MIN, + PMBUS_VIRT_READ_TEMP_MAX, + PMBUS_VIRT_RESET_TEMP_HISTORY, + PMBUS_VIRT_READ_VIN_AVG, + PMBUS_VIRT_READ_VIN_MIN, + PMBUS_VIRT_READ_VIN_MAX, + PMBUS_VIRT_RESET_VIN_HISTORY, + PMBUS_VIRT_READ_IIN_AVG, + PMBUS_VIRT_READ_IIN_MIN, + PMBUS_VIRT_READ_IIN_MAX, + PMBUS_VIRT_RESET_IIN_HISTORY, + PMBUS_VIRT_READ_PIN_AVG, + PMBUS_VIRT_READ_PIN_MIN, + PMBUS_VIRT_READ_PIN_MAX, + PMBUS_VIRT_RESET_PIN_HISTORY, + PMBUS_VIRT_READ_POUT_AVG, + PMBUS_VIRT_READ_POUT_MIN, + PMBUS_VIRT_READ_POUT_MAX, + PMBUS_VIRT_RESET_POUT_HISTORY, + PMBUS_VIRT_READ_VOUT_AVG, + PMBUS_VIRT_READ_VOUT_MIN, + PMBUS_VIRT_READ_VOUT_MAX, + PMBUS_VIRT_RESET_VOUT_HISTORY, + PMBUS_VIRT_READ_IOUT_AVG, + PMBUS_VIRT_READ_IOUT_MIN, + PMBUS_VIRT_READ_IOUT_MAX, + PMBUS_VIRT_RESET_IOUT_HISTORY, + PMBUS_VIRT_READ_TEMP2_AVG, + PMBUS_VIRT_READ_TEMP2_MIN, + PMBUS_VIRT_READ_TEMP2_MAX, + PMBUS_VIRT_RESET_TEMP2_HISTORY, + + PMBUS_VIRT_READ_VMON, + PMBUS_VIRT_VMON_UV_WARN_LIMIT, + PMBUS_VIRT_VMON_OV_WARN_LIMIT, + PMBUS_VIRT_VMON_UV_FAULT_LIMIT, + PMBUS_VIRT_VMON_OV_FAULT_LIMIT, + PMBUS_VIRT_STATUS_VMON, +}; + +/* + * OPERATION + */ +#define PB_OPERATION_CONTROL_ON BIT(7) + +/* + * CAPABILITY + */ +#define PB_CAPABILITY_SMBALERT BIT(4) +#define PB_CAPABILITY_ERROR_CHECK BIT(7) + +/* + * VOUT_MODE + */ +#define PB_VOUT_MODE_MODE_MASK 0xe0 +#define PB_VOUT_MODE_PARAM_MASK 0x1f + +#define PB_VOUT_MODE_LINEAR 0x00 +#define PB_VOUT_MODE_VID 0x20 +#define PB_VOUT_MODE_DIRECT 0x40 + +/* + * Fan configuration + */ +#define PB_FAN_2_PULSE_MASK (BIT(0) | BIT(1)) +#define PB_FAN_2_RPM BIT(2) +#define PB_FAN_2_INSTALLED BIT(3) +#define PB_FAN_1_PULSE_MASK (BIT(4) | BIT(5)) +#define PB_FAN_1_RPM BIT(6) +#define PB_FAN_1_INSTALLED BIT(7) + +/* + * STATUS_BYTE, STATUS_WORD (lower) + */ +#define PB_STATUS_NONE_ABOVE BIT(0) +#define PB_STATUS_CML BIT(1) +#define PB_STATUS_TEMPERATURE BIT(2) +#define PB_STATUS_VIN_UV BIT(3) +#define PB_STATUS_IOUT_OC BIT(4) +#define PB_STATUS_VOUT_OV BIT(5) +#define PB_STATUS_OFF BIT(6) +#define PB_STATUS_BUSY BIT(7) + +/* + * STATUS_WORD (upper) + */ +#define PB_STATUS_UNKNOWN BIT(8) +#define PB_STATUS_OTHER BIT(9) +#define PB_STATUS_FANS BIT(10) +#define PB_STATUS_POWER_GOOD_N BIT(11) +#define PB_STATUS_WORD_MFR BIT(12) +#define PB_STATUS_INPUT BIT(13) +#define PB_STATUS_IOUT_POUT BIT(14) +#define PB_STATUS_VOUT BIT(15) + +/* + * STATUS_IOUT + */ +#define PB_POUT_OP_WARNING BIT(0) +#define PB_POUT_OP_FAULT BIT(1) +#define PB_POWER_LIMITING BIT(2) +#define PB_CURRENT_SHARE_FAULT BIT(3) +#define PB_IOUT_UC_FAULT BIT(4) +#define PB_IOUT_OC_WARNING BIT(5) +#define PB_IOUT_OC_LV_FAULT BIT(6) +#define PB_IOUT_OC_FAULT BIT(7) + +/* + * STATUS_VOUT, STATUS_INPUT + */ +#define PB_VOLTAGE_UV_FAULT BIT(4) +#define PB_VOLTAGE_UV_WARNING BIT(5) +#define PB_VOLTAGE_OV_WARNING BIT(6) +#define PB_VOLTAGE_OV_FAULT BIT(7) + +/* + * STATUS_INPUT + */ +#define PB_PIN_OP_WARNING BIT(0) +#define PB_IIN_OC_WARNING BIT(1) +#define PB_IIN_OC_FAULT BIT(2) + +/* + * STATUS_TEMPERATURE + */ +#define PB_TEMP_UT_FAULT BIT(4) +#define PB_TEMP_UT_WARNING BIT(5) +#define PB_TEMP_OT_WARNING BIT(6) +#define PB_TEMP_OT_FAULT BIT(7) + +/* + * STATUS_FAN + */ +#define PB_FAN_AIRFLOW_WARNING BIT(0) +#define PB_FAN_AIRFLOW_FAULT BIT(1) +#define PB_FAN_FAN2_SPEED_OVERRIDE BIT(2) +#define PB_FAN_FAN1_SPEED_OVERRIDE BIT(3) +#define PB_FAN_FAN2_WARNING BIT(4) +#define PB_FAN_FAN1_WARNING BIT(5) +#define PB_FAN_FAN2_FAULT BIT(6) +#define PB_FAN_FAN1_FAULT BIT(7) + +/* + * CML_FAULT_STATUS + */ +#define PB_CML_FAULT_OTHER_MEM_LOGIC BIT(0) +#define PB_CML_FAULT_OTHER_COMM BIT(1) +#define PB_CML_FAULT_PROCESSOR BIT(3) +#define PB_CML_FAULT_MEMORY BIT(4) +#define PB_CML_FAULT_PACKET_ERROR BIT(5) +#define PB_CML_FAULT_INVALID_DATA BIT(6) +#define PB_CML_FAULT_INVALID_COMMAND BIT(7) + +enum pmbus_sensor_classes { + PSC_VOLTAGE_IN = 0, + PSC_VOLTAGE_OUT, + PSC_CURRENT_IN, + PSC_CURRENT_OUT, + PSC_POWER, + PSC_TEMPERATURE, + PSC_FAN, + PSC_NUM_CLASSES /* Number of power sensor classes */ +}; + +#define PMBUS_PAGES 32 /* Per PMBus specification */ + +/* Functionality bit mask */ +#define PMBUS_HAVE_VIN BIT(0) +#define PMBUS_HAVE_VCAP BIT(1) +#define PMBUS_HAVE_VOUT BIT(2) +#define PMBUS_HAVE_IIN BIT(3) +#define PMBUS_HAVE_IOUT BIT(4) +#define PMBUS_HAVE_PIN BIT(5) +#define PMBUS_HAVE_POUT BIT(6) +#define PMBUS_HAVE_FAN12 BIT(7) +#define PMBUS_HAVE_FAN34 BIT(8) +#define PMBUS_HAVE_TEMP BIT(9) +#define PMBUS_HAVE_TEMP2 BIT(10) +#define PMBUS_HAVE_TEMP3 BIT(11) +#define PMBUS_HAVE_STATUS_VOUT BIT(12) +#define PMBUS_HAVE_STATUS_IOUT BIT(13) +#define PMBUS_HAVE_STATUS_INPUT BIT(14) +#define PMBUS_HAVE_STATUS_TEMP BIT(15) +#define PMBUS_HAVE_STATUS_FAN12 BIT(16) +#define PMBUS_HAVE_STATUS_FAN34 BIT(17) +#define PMBUS_HAVE_VMON BIT(18) +#define PMBUS_HAVE_STATUS_VMON BIT(19) + +enum pmbus_data_format { linear = 0, direct, vid }; +enum vrm_version { vr11 = 0, vr12 }; + +struct pmbus_driver_info { + int pages; /* Total number of pages */ + enum pmbus_data_format format[PSC_NUM_CLASSES]; + enum vrm_version vrm_version; + /* + * Support one set of coefficients for each sensor type + * Used for chips providing data in direct mode. + */ + int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */ + int b[PSC_NUM_CLASSES]; /* offset */ + int R[PSC_NUM_CLASSES]; /* exponent */ + + u32 func[PMBUS_PAGES]; /* Functionality, per page */ + /* + * The following functions map manufacturing specific register values + * to PMBus standard register values. Specify only if mapping is + * necessary. + * Functions return the register value (read) or zero (write) if + * successful. A return value of -ENODATA indicates that there is no + * manufacturer specific register, but that a standard PMBus register + * may exist. Any other negative return value indicates that the + * register does not exist, and that no attempt should be made to read + * the standard register. + */ + int (*read_byte_data)(struct i2c_client *client, int page, int reg); + int (*read_word_data)(struct i2c_client *client, int page, int reg); + int (*write_word_data)(struct i2c_client *client, int page, int reg, + u16 word); + int (*write_byte)(struct i2c_client *client, int page, u8 value); + /* + * The identify function determines supported PMBus functionality. + * This function is only necessary if a chip driver supports multiple + * chips, and the chip functionality is not pre-determined. + */ + int (*identify)(struct i2c_client *client, + struct pmbus_driver_info *info); + + /* Regulator functionality, if supported by this chip driver. */ + int num_regulators; + const struct regulator_desc *reg_desc; +}; + +/* Regulator ops */ + +extern const struct regulator_ops pmbus_regulator_ops; + +/* Macro for filling in array of struct regulator_desc */ +#define PMBUS_REGULATOR(_name, _id) \ + [_id] = { \ + .name = (_name # _id), \ + .id = (_id), \ + .of_match = of_match_ptr(_name # _id), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &pmbus_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + } + +/* Function declarations */ + +void pmbus_clear_cache(struct i2c_client *client); +int pmbus_set_page(struct i2c_client *client, u8 page); +int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg); +int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word); +int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg); +int pmbus_write_byte(struct i2c_client *client, int page, u8 value); +int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, + u8 value); +int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, + u8 mask, u8 value); +void pmbus_clear_faults(struct i2c_client *client); +bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); +bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); +int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, + struct pmbus_driver_info *info); +int pmbus_do_remove(struct i2c_client *client); +const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client + *client); + +#endif /* PMBUS_H */ \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/fancontrol.sh b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/fancontrol.sh new file mode 100755 index 000000000000..448ec5acb38c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/fancontrol.sh @@ -0,0 +1,78 @@ +#! /bin/sh + +### BEGIN INIT INFO +# Provides: fancontrol +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: +# Short-Description: fancontrol +# Description: fan speed regulator +### END INIT INFO + +. /lib/lsb/init-functions + +[ -f /etc/default/rcS ] && . /etc/default/rcS +PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin +DAEMON=/usr/local/bin/fancontrol +DESC="fan speed regulator" +NAME="fancontrol" +PIDFILE=/var/run/fancontrol.pid +PLATFORMPATH=/sys/devices/platform/LPC +MAIN_CONF=/usr/share/sonic/device/x86_64-dell_s3000_c2338-r0/fancontrol +DEVPATH=/sys/devices/pci0000:00/0000:00:13.0/i2c-0/i2c-8/i2c-23/23-004d + +test -x $DAEMON || exit 0 + +for i in 1 2 3 +do + j=$i + [ $i -eq 3 ] && j=4 + FANFAULT=$(cat ${DEVPATH}/fan${j}_fault) + [ $FANFAULT = 1 ] && continue + FANDIR=$(cat ${PLATFORMPATH}/fan${i}_dir) +done +CONF=${MAIN_CONF}-${FANDIR} + +case "$1" in + start) + if [ -f $CONF ] ; then + if $DAEMON --check $CONF 1>/dev/null 2>/dev/null ; then + log_daemon_msg "Starting $DESC" "$NAME\n" + start-stop-daemon --start --quiet --pidfile $PIDFILE --startas $DAEMON $CONF + log_end_msg $? + else + log_failure_msg "Not starting fancontrol, broken configuration file; please re-run pwmconfig." + fi + else + if [ "$VERBOSE" != no ]; then + log_warning_msg "Not starting fancontrol; run pwmconfig first." + fi + fi + ;; + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + start-stop-daemon --stop --quiet --pidfile $PIDFILE --oknodo --startas $DAEMON $CONF + rm -f $PIDFILE + log_end_msg $? + ;; + restart) + $0 stop + sleep 3 + $0 start + ;; + force-reload) + if start-stop-daemon --stop --test --quiet --pidfile $PIDFILE --startas $DAEMON $CONF ; then + $0 restart + fi + ;; + status) + status_of_proc $DAEMON $NAME $CONF && exit 0 || exit $? + ;; + *) + log_success_msg "Usage: /etc/init.d/fancontrol {start|stop|restart|force-reload|status}" + exit 1 + ;; +esac + +exit 0 diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/n3248pxe_platform.sh b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/n3248pxe_platform.sh new file mode 100755 index 000000000000..c049826608b1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/n3248pxe_platform.sh @@ -0,0 +1,141 @@ +#!/bin/bash + +#platform init script for Dell n3248pxe + +source dell_i2c_utils.sh + +#Attach/Detach the system devices +sys_devices() { + case $1 in + "new_device") #syseeprom + i2c_config "echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-2/$1" + #Attach Fan Controller + i2c_config "echo emc2305 0x2c > /sys/bus/i2c/devices/i2c-7/$1" + #Attach temperature monitor + i2c_config "echo tmp75 0x49 > /sys/bus/i2c/devices/i2c-7/$1" + i2c_config "echo tmp75 0x4a > /sys/bus/i2c/devices/i2c-7/$1" + i2c_config "echo tmp75 0x4b > /sys/bus/i2c/devices/i2c-7/$1" + i2c_config "echo tmp75 0x4c > /sys/bus/i2c/devices/i2c-7/$1" + i2c_config "echo tmp75 0x4f > /sys/bus/i2c/devices/i2c-7/$1" + #Attach PSU Controller + i2c_config "echo dps460 0x5e > /sys/bus/i2c/devices/i2c-10/$1" + i2c_config "echo dps460 0x5e > /sys/bus/i2c/devices/i2c-11/$1" + #Attach PSU EEPROM + i2c_config "echo 24c02 0x56 > /sys/bus/i2c/devices/i2c-10/$1" + i2c_config "echo 24c02 0x56 > /sys/bus/i2c/devices/i2c-11/$1" + #Attach Fan EEPROM + i2c_config "echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-15/$1" + i2c_config "echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-16/$1" + i2c_config "echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-17/$1" + ;; + "delete_device") i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-2/$1" + i2c_config "echo 0x2c > /sys/bus/i2c/devices/i2c-7/$1" + i2c_config "echo 0x49 > /sys/bus/i2c/devices/i2c-7/$1" + i2c_config "echo 0x4a > /sys/bus/i2c/devices/i2c-7/$1" + i2c_config "echo 0x4b > /sys/bus/i2c/devices/i2c-7/$1" + i2c_config "echo 0x4c > /sys/bus/i2c/devices/i2c-7/$1" + i2c_config "echo 0x4f > /sys/bus/i2c/devices/i2c-7/$1" + i2c_config "echo 0x5e > /sys/bus/i2c/devices/i2c-10/$1" + i2c_config "echo 0x5e > /sys/bus/i2c/devices/i2c-11/$1" + i2c_config "echo 0x56 > /sys/bus/i2c/devices/i2c-10/$1" + i2c_config "echo 0x56 > /sys/bus/i2c/devices/i2c-11/$1" + i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-15/$1" + i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-16/$1" + i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-17/$1" + ;; + *) echo "n3248pxe_platform: main_board_mux : invalid command !" + ;; + esac +} + +#Attach/Detach the SFP modules on PCA9548_2 +switch_board_sfp() { + case $1 in + "new_device") i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-20/$1" + i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-21/$1" + i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-22/$1" + i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-23/$1" + ;; + "delete_device") i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-20/$1" + i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-21/$1" + i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-22/$1" + i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-23/$1" + ;; + *) echo "n3248pxe_platform: switch_board_sfp: invalid command !" + ;; + esac +} + +#Forcibly bring quad-port phy out of reset for 48-1G port functionality + +platform_firmware_versions() { + +FIRMWARE_VERSION_FILE=/var/log/firmware_versions +rm -rf ${FIRMWARE_VERSION_FILE} +# Get BIOS version +echo "BIOS: `dmidecode -s system-version `" > $FIRMWARE_VERSION_FILE +# Get CPU CPLD version +echo "CPU CPLD: $((`cat /sys/devices/platform/dell-n3248pxe-cpld.0/cpu_cpld_mjr_ver`)).$((`cat /sys/devices/platform/dell-n3248pxe-cpld.0/cpu_cpld_mnr_ver`))" >> $FIRMWARE_VERSION_FILE +# Get SYS CPLD version +echo "SYS CPLD: $((`cat /sys/devices/platform/dell-n3248pxe-cpld.0/sys_cpld_mjr_ver`)).$((`cat /sys/devices/platform/dell-n3248pxe-cpld.0/sys_cpld_mnr_ver`))" >> $FIRMWARE_VERSION_FILE + +} + +install_python_api_package() { + device="/usr/share/sonic/device" + platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform) + + rv=$(pip3 install $device/$platform/sonic_platform-1.0-py3-none-any.whl) +} + +remove_python_api_package() { + rv=$(pip show sonic-platform > /dev/null 2>/dev/null) + + rv=$(pip3 show sonic-platform > /dev/null 2>/dev/null) + if [ $? -eq 0 ]; then + rv=$(pip3 uninstall -y sonic-platform > /dev/null 2>/dev/null) + fi +} + +get_reboot_cause() { + REBOOT_REASON_FILE="/host/reboot-cause/platform/reboot_reason" + mkdir -p $(dirname $REBOOT_REASON_FILE) + + # Handle First Boot into software version with reboot cause determination support + if [[ ! -e $REBOOT_REASON_FILE ]]; then + echo "0x0" > $REBOOT_REASON_FILE + else + cat /sys/devices/platform/dell-n3248pxe-cpld.0/reboot_cause > $REBOOT_REASON_FILE + fi +} + + +if [[ "$1" == "init" ]]; then + modprobe i2c-dev + modprobe i2c-mux-pca954x force_deselect_on_exit=1 + modprobe pmbus + modprobe emc2305 + modprobe dps200 + modprobe dell_n3248pxe_platform + + sys_devices "new_device" + get_reboot_cause + switch_board_sfp "new_device" + echo 0xf0 > /sys/devices/platform/dell-n3248pxe-cpld.0/sfp_txdis + install_python_api_package + platform_firmware_versions +elif [[ "$1" == "deinit" ]]; then + switch_board_sfp "delete_device" + sysdevices "delete_device" + + modprobe -r dell_n3248pxe_platform + + modprobe -r dps200 + modprobe -r emc2305 + modprobe -r pmbus + modprobe -r i2c-mux-pca954x + modprobe -r i2c-dev + remove_python_api_package +else + echo "n3248pxe_platform : Invalid option !" +fi diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/platform_sensors.py new file mode 100755 index 000000000000..9640f16750e6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/platform_sensors.py @@ -0,0 +1,139 @@ +#!/usr/bin/python +# This provies support for the following objects: +# * Onboard temperature sensors +# * FAN trays +# * PSU + + +import os +import sys +import logging +import subprocess + +output = "" +try: + rc = 0 + output = subprocess.check_output('/usr/bin/sensors').splitlines() + + valid = False + for line in output: + if line.startswith(b'acpitz') or line.startswith(b'coretemp'): + valid = True + if valid: + print (line) + if line == '': valid = False + + print ("Onboard Temperature Sensors:") + idx = 0 + for line in output: + if line.startswith(b'tmp75'): + print ('\t' + output[idx+2].split('(')[0]) + idx += 1 + + print ("\nFanTrays:") + idx = 0 + found_emc = False + for line in output: + if line.startswith(b'emc'): + found_emc = True + with open('/sys/devices/platform/dell-n3248pxe-cpld.0/fan0_prs') as f: + line = f.readline() + present = int(line, 0) + if present : + print ('\t' + 'FanTray1:') + print ('\t\t' + 'Fan Speed:' + (output[idx+2].split('(')[0]).split(':')[1]) + with open('/sys/devices/platform/dell-n3248pxe-cpld.0/fan0_dir') as f: + line = f.readline() + dir = 'Intake' if line[:-1] == 'B2F' else 'Exhaust' + print ('\t\t' + 'Airflow:\t' + dir) + else : print ('\t' + 'FanTray1:\tNot Present') + + with open('/sys/devices/platform/dell-n3248pxe-cpld.0/fan1_prs') as f: + line = f.readline() + present = int(line, 0) + if present : + print ('\t' + 'FanTray2:') + print ('\t\t' + 'Fan Speed:' + (output[idx+3].split('(')[0]).split(':')[1]) + with open('/sys/devices/platform/dell-n3248pxe-cpld.0/fan1_dir') as f: + line = f.readline() + dir = 'Intake' if line[:-1] == 'B2F' else 'Exhaust' + print ('\t\t' + 'Airflow:\t' + dir) + else : print ('\t' + 'FanTray2:\tNot Present') + + with open('/sys/devices/platform/dell-n3248pxe-cpld.0/fan2_prs') as f: + line = f.readline() + present = int(line, 0) + if present : + print ('\t' + 'FanTray3:') + print ('\t\t' + 'Fan Speed:' + (output[idx+4].split('(')[0]).split(':')[1]) + with open('/sys/devices/platform/dell-n3248pxe-cpld.0/fan2_dir') as f: + line = f.readline() + dir = 'Intake' if line[:-1] == 'B2F' else 'Exhaust' + print ('\t\t' + 'Airflow:\t' + dir) + else : print ('\t' + 'FanTray3:\tNot Present') + idx += 1 + if not found_emc : + print ('\t' + 'FanTray1:\tNot Present') + print ('\t' + 'FanTray2:\tNot Present') + print ('\t' + 'FanTray3:\tNot Present') + + print ('\nPSUs:') + idx = 0 + with open('/sys/devices/platform/dell-n3248pxe-cpld.0/psu0_prs') as f: + line = f.readline() + found_psu1 = int(line, 0) + if not found_psu1 : + print ('\tPSU1:\tNot Present') + with open('/sys/devices/platform/dell-n3248pxe-cpld.0/psu1_prs') as f: + line = f.readline() + found_psu2 = int(line, 0) + for line in output: + if line.startswith(b'dps460-i2c-10'): + with open('/sys/devices/platform/dell-n3248pxe-cpld.0/psu0_status') as f: + line = f.readline() + status = int(line, 0) + if not status : + print ('\tPSU1:\tNot OK') + break + with open('/sys/bus/i2c/devices/10-0056/eeprom') as f: + line = f.readline() + dir = 'Exhaust' if 'FORWARD' in line else 'Intake' + print ('\tPSU1:') + print ('\t\t' + output[idx+2].split('(')[0]) + print ('\t\t' + output[idx+4].split('(')[0]) + print ('\t\t' + output[idx+6].split('(')[0]) + print ('\t\t' + output[idx+7].split('(')[0]) + print ('\t\t' + output[idx+9].split('(')[0]) + print ('\t\t' + output[idx+11].split('(')[0]) + print ('\t\t' + output[idx+12].split('(')[0]) + print ('\t\t' + output[idx+14].split('(')[0]) + print ('\t\t' + output[idx+15].split('(')[0]) + print ('\t\t' + 'Airflow:\t\t ' + dir) + if line.startswith(b'dps460-i2c-11'): + with open('/sys/devices/platform/dell-n3248pxe-cpld.0/psu1_status') as f: + line = f.readline() + status = int(line, 0) + if not status : + print ('\tPSU2:\tNot OK') + break + print ('\tPSU2:') + with open('/sys/bus/i2c/devices/11-0056/eeprom') as f: + line = f.readline() + dir = 'Exhaust' if 'FORWARD' in line else 'Intake' + print ('\t\t' + output[idx+2].split('(')[0]) + print ('\t\t' + output[idx+4].split('(')[0]) + print ('\t\t' + output[idx+6].split('(')[0]) + print ('\t\t' + output[idx+7].split('(')[0]) + print ('\t\t' + output[idx+9].split('(')[0]) + print ('\t\t' + output[idx+11].split('(')[0]) + print ('\t\t' + output[idx+12].split('(')[0]) + print ('\t\t' + output[idx+14].split('(')[0]) + print ('\t\t' + output[idx+15].split('(')[0]) + print ('\t\t' + 'Airflow:\t\t ' + dir) + idx += 1 + if not found_psu2 : + print ('\tPSU2:\tNot Present') + +except subprocess.CalledProcessError as err: + print ("Exception when calling get_sonic_error -> %s\n" %(err)) + rc = err.returncode diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/portiocfg.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/portiocfg.py new file mode 100755 index 000000000000..51cc9ab27db3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/portiocfg.py @@ -0,0 +1,106 @@ +#!/usr/bin/python +# Copyright (c) 2015 Dell Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +#Script to read/write the portio based registers + +import sys +import os +import getopt +import struct + +resource='/dev/port' + +def usage(): + ''' This is the Usage Method ''' + + print ('\t\t portiocfg.py --default') + print ('\t\t portiocfg.py --get --offset ') + print ('\t\t portiocfg.py --set --val --offset ') + sys.exit(1) + +def portio_reg_read(resource,offset): + fd=os.open(resource, os.O_RDONLY) + if(fd<0): + print ('file open failed %s"%resource') + return + if(os.lseek(fd, offset, os.SEEK_SET) != offset): + print ('lseek failed on %s'%resource) + return + buf=os.read(fd,1) + reg_val1=ord(buf) + print ('reg value %x'%reg_val1) + os.close(fd) + +def portio_reg_write(resource,offset,val): + fd=os.open(resource,os.O_RDWR) + if(fd<0): + print ('file open failed %s"%resource') + return + if(os.lseek(fd, offset, os.SEEK_SET) != offset): + print ('lseek failed on %s'%resource) + return + ret=os.write(fd,struct.pack('B',val)) + if(ret != 1): + print ('write failed %d'%ret) + return + os.close(fd) + +def main(argv): + + ''' The main function will read the user input from the + command line argument and process the request ''' + + opts = '' + val = '' + choice = '' + resouce = '' + offset = '' + + try: + opts, args = getopt.getopt(argv, "hgs:" , \ + ["val=","offset=","help", "get", "set"]) + + except getopt.GetoptError: + usage() + + for opt,arg in opts: + + if opt in ('-h','--help'): + choice = 'help' + + elif opt in ('-g', '--get'): + choice = 'get' + + elif opt in ('-s', '--set'): + choice = 'set' + + elif opt == '--offset': + offset = int(arg,16) + + elif opt == '--val': + val = int(arg,16) + + if choice == 'get' and offset != '': + portio_reg_read(resource,offset) + + elif choice == 'set' and offset != '' and val != '': + portio_reg_write(resource,offset,val) + + else: + usage() + +#Calling the main method +if __name__ == "__main__": + main(sys.argv[1:]) + diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/ports_xcvrd_notify.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/ports_xcvrd_notify.py new file mode 100755 index 000000000000..be44d58343cb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/ports_xcvrd_notify.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python2 + +""" + port_notify + port notify status change for SONiC +""" + +try: + import os + import sys + import time + from datetime import datetime + from swsscommon import swsscommon + from sonic_py_common import daemon_base, logger +except ImportError as e: + raise ImportError (str(e) + " - required module not found") + +# +# Constants ==================================================================== +# + +SYSLOG_IDENTIFIER = "port_notify" + + +STATE_PORT_TABLE = 'PORT_TABLE' + + +RJ45_PORT_START = 0; +RJ45_PORT_END = 47; + +# Global logger class instance +helper_logger = logger.Logger(SYSLOG_IDENTIFIER) + +XCVR_STATE_EMPTY = 0 +XCVR_STATE_ERROR = 1 +XCVR_STATE_INCOMP = 2 +XCVR_STATE_CONFIG = 3 +XCVR_STATE_READY = 4 +XCVR_STATE_TIMEOUT = 5 + +xcvr_state_tbl = { + XCVR_STATE_EMPTY: { "xcvr_state": "N/A", "xcvr_app_status": "down" }, + XCVR_STATE_ERROR: { "xcvr_state": "Error", "xcvr_app_status": "down" }, + XCVR_STATE_INCOMP: { "xcvr_state": "Incompatible", "xcvr_app_status": "up" }, + XCVR_STATE_CONFIG: { "xcvr_state": "Config", "xcvr_app_status": "down" }, + XCVR_STATE_TIMEOUT: { "xcvr_state": "Timeout", "xcvr_app_status": "up" }, + XCVR_STATE_READY: { "xcvr_state": "Ready", "xcvr_app_status": "up" } +} + +# Wait for port init is done +def wait_for_port_init_done(): + # Connect to APPL_DB and subscribe to PORT table notifications + appl_db = daemon_base.db_connect("APPL_DB") + + sel = swsscommon.Select() + sst = swsscommon.SubscriberStateTable(appl_db, swsscommon.APP_PORT_TABLE_NAME) + sel.addSelectable(sst) + + # Make sure this daemon started after all port configured + while True: + (state, c) = sel.select(1000) + if state == swsscommon.Select.TIMEOUT: + continue + if state != swsscommon.Select.OBJECT: + helper_logger.log_warning("sel.select() did not return swsscommon.Select.OBJECT") + continue + + (key, op, fvp) = sst.pop() + + # Wait until PortInitDone + if key in ["PortInitDone"]: + break + +def notify_port_xcvr_status(port_name, app_status_port_tbl, state_port_tbl, flag): + + fvs = swsscommon.FieldValuePairs([("xcvr_status", xcvr_state_tbl[flag]["xcvr_app_status"])]) + tm = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + state_fvs = swsscommon.FieldValuePairs([("xcvr_status", xcvr_state_tbl[flag]["xcvr_state"]), ("xcvr_time", tm)]) + + state_port_tbl.set(port_name, state_fvs) + + app_status_port_tbl.set(port_name, fvs) + + helper_logger.log_notice("Port {} xcvr_app_status change to {}".format(port_name, xcvr_state_tbl[flag]["xcvr_app_status"])) + return True + + +def main(): + helper_logger.log_notice("Start port_notify") + # Connect to APP_DB and create transceiver dom info table + appl_db = daemon_base.db_connect("APPL_DB") + cst = swsscommon.SubscriberStateTable(appl_db, swsscommon.APP_PORT_TABLE_NAME) + + app_port_tbl = swsscommon.ProducerStateTable(appl_db, swsscommon.APP_PORT_TABLE_NAME) + + app_status_port_tbl = swsscommon.ProducerStateTable(appl_db, + swsscommon.APP_PORT_APP_STATUS_TABLE_NAME) + + state_db = daemon_base.db_connect("STATE_DB") + state_port_tbl = swsscommon.Table(state_db, STATE_PORT_TABLE) + + # Wait for PortInitDone + wait_for_port_init_done() + + for port in range(RJ45_PORT_START, RJ45_PORT_END+1): + #print "Ethernet{}".format(port) + notify_port_xcvr_status("Ethernet{}".format(port), app_status_port_tbl, state_port_tbl, XCVR_STATE_READY) + + helper_logger.log_notice("End port_notify") + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/sensors b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/sensors new file mode 100755 index 000000000000..572b9d45e9e3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/sensors @@ -0,0 +1,8 @@ +#!/bin/bash +#docker exec -i pmon sensors "$@" +docker exec -i pmon /usr/bin/platform_sensors.py "$@" + +#To probe sensors not part of lm-sensors +#if [ -r /usr/local/bin/platform_sensors.py ]; then +# python /usr/local/bin/platform_sensors.py +#fi diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/setup.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/setup.py new file mode 120000 index 000000000000..4f6de9941d96 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/setup.py @@ -0,0 +1 @@ +../s6100/setup.py \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/__init__.py new file mode 100644 index 000000000000..3e1260e6b854 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/__init__.py @@ -0,0 +1,8 @@ +""" +Module sonic_platform provides the platform dependent population of +platform.py, chassis.py, component.py, sfp.py, thermal.py, psu.py, +fan.py and watchdog.py +""" +__all__ = ["platform", "chassis", "sfp", "eeprom", "component", "thermal", "psu", "fan", "fan_drawer", "watchdog"] +from sonic_platform import * + diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/chassis.py new file mode 100644 index 000000000000..3dd887eae28a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/chassis.py @@ -0,0 +1,344 @@ +#!/usr/bin/env python + +############################################################################# +# DELLEMC N3248TE +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + import os + import select + import sys + import time + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.sfp import Sfp + from sonic_platform.eeprom import Eeprom + from sonic_platform.component import Component + from sonic_platform.psu import Psu + from sonic_platform.thermal import Thermal + from sonic_platform.watchdog import Watchdog + from sonic_platform.fan import Fan + from sonic_platform.fan_drawer import FanDrawer +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +MAX_N3248TE_FANTRAY = 3 +MAX_N3248TE_FAN = 1 +MAX_N3248TE_PSU = 2 +MAX_N3248TE_THERMAL = 5 +MAX_N3248TE_COMPONENT = 3 # BIOS, CPU CPLD and SYS CPLD + +media_part_num_list = set([ \ +"8T47V","XTY28","MHVPK","GF76J","J6FGD","F1KMV","9DN5J","H4DHD","6MCNV","0WRX0","X7F70","5R2PT","WTRD1","WTRD1","WTRD1","WTRD1","5250G","WTRD1","C5RNH","C5RNH","FTLX8571D3BCL-FC", +"C5RNH","5250G","N8TDR","7D64H","7D64H","RN84N","RN84N","HMTNW","6K3Y6","6K3Y6","TY5FM","50M0R","PGYJT","WP2PP","85Y13","1HCGH","FP9R1","FYD0M","C6Y7M","C6Y7M","V250M","V250M", +"5CWK6","5CWK6","53HVN","53HVN","358VV","358VV","MV799","MV799","YJF03","P9GND","T1KCN","1DXKP","MT7R2","K0T7R","W5G04","7TCDN","7TCDN","7TCDN","7TCDN","7TCDN","V3XJK","0MV31", +"5FVP7","N6KM9","C41MF","77KC3","XW7J0","V4NJV","2XJHY","H93DH","H93DH","F8CG0","F8CG0","F8CG0","119N6","WFMF5","794RX","288F6","1M31V","1M31V","5NP8R","5NP8R","4TC09","4TC09", +"FC6KV","FC6KV","J90VN","J90VN","05RH0","05RH0","YDN52","0C2YV","YDN52","0C2YV","9JT65","D7M6H","6GW14","FYVFW","0VF5H","P4YPY","P4YPY","TCPM2","TCPM2","JNPF8","JNPF8","27GG5", +"27GG5","P8T4W","P8T4W","JR54Y","M6N0J","XJYD0","K44H9","035KG","P7C7N","76V43","3CC35","FN4FC","26FN3","YFNDD","YFNDD","7R9N9","035KG","P7C7N","76V43","3CC35","PLRXPLSCS43811", +"FN4FC","26FN3","YFNDD","YFNDD","7R9N9","G86YJ","V407F","V407F","9KH6T","G86YJ","V407F","9KH6T","2JVDD","D0R73","VXFJY","9X8JP","2JVDD","D0R73","VXFJY","9X8JP","2JVDD","D0R73","VXFJY", +"9X8JP","GMFC5","GMFC5","GMFC5","D7P80","3MFXG","3MFXG","0GWXJ","THPF3","THPF3","THPF3","THPF3","THPF3","PJ62G","3XCX1","JJYKG","RRRTK","16K56","86JM2","K5R6C","7MG2C","WTPPN","9HTT2", +"NKM4F","VXGGG","JC9W6","6MR8M","RP3GV","M5PPJ","XKY55","TKCXT","05J8P","5WGKD","XFDRT","NW8DM","YPKH3","5WGKD","XFDRT","NW8DM","YPKH3","71XXK","MVCX6","0XYP6","HPPVW","3GHRT","71XXK", +"MVCX6","0XYP6","HPPVW","3GHRT","2X5T6","135V2","KD5MV","2X5T6","KD5MV","HHFK0","3YWG7","5CMT2","RCVP5","X5DH4","HHFK0","3YWG7","5CMT2","RCVP5","X5DH4","3YWG7","5CMT2","RCVP5","X5DH4", +"4WJ41","4WJ41","14NV5","14NV5","14NV5","4WGYD","YKMH7","X7CCC","X7CCC","0X9CT","0CY8V","P7D7R","W4GPP","W4GPP","W4GPP","HHHCHC","07RN7","07RN7","0YR96","0YR96","JCYM9","FTLX8571D3BCL", +"DDW0X","VPFDJ","229KM","9FC7D","DDW0X","VPFDJ","6FMR5","J7K20","N3K9W","6FMR5","8R4VM","7VN5T","D9YM8","8R4VM","VYXPW","87TPX","WY6FK","VYXPW","87TPX","WY6FK","WG8C4","N8K82","2DV6Y", +"77C3C","RC0HM","77C3C","RC0HM","JHXTN","3P3PG","92YVM","4VX5M","4VX5M","6RRGD","W4JWV","22V6R","XR11M","9GMDY","JMCWK","TP2F0","6MGDY","78RHK", "C0TP5","0WDNV","FCLF8522P2BTL"\ +]) +class Chassis(ChassisBase): + """ + DELLEMC Platform-specific Chassis class + """ + CPLD_DIR = '/sys/devices/platform/dell-n3248pxe-cpld.0/' + + _global_port_pres_dict = {} + + _sfpp_port_to_i2c_mapping = { + 49: 20, + 50: 21, + 51: 22, + 52: 23, + } + + def __init__(self): + ChassisBase.__init__(self) + # sfp.py will read eeprom contents and retrive the eeprom data. + # We pass the eeprom path from chassis.py + self.PORT_START = 1 + self.PORT_END = 52 + self.PORTS_IN_BLOCK = (self.PORT_END + 1) + self.SFP_PORT_START = 49 + self._sfp_port = range(self.SFP_PORT_START, self.PORTS_IN_BLOCK) + eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" + for index in range(self.PORT_START, self.PORTS_IN_BLOCK): + eeprom_path = '' + if index in self._sfp_port: + eeprom_path = eeprom_base.format(self._sfpp_port_to_i2c_mapping[index]) + sfp_node = Sfp(index, 'SFP', eeprom_path) + self._sfp_list.append(sfp_node) + + self._eeprom = Eeprom() + self._watchdog = Watchdog() + self._num_sfps = 52 + self._num_fans = MAX_N3248TE_FANTRAY * MAX_N3248TE_FAN + self._fan_list = [Fan(i, j) for i in range(MAX_N3248TE_FANTRAY) \ + for j in range(MAX_N3248TE_FAN)] + for k in range(MAX_N3248TE_FANTRAY): + fandrawer = FanDrawer(k) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + self._psu_list = [Psu(i) for i in range(MAX_N3248TE_PSU)] + self._thermal_list = [Thermal(i) for i in range(MAX_N3248TE_THERMAL)] + self._component_list = [Component(i) for i in range(MAX_N3248TE_COMPONENT)] + for port_num in self._sfp_port: + # sfp get uses zero-indexing, but port numbers start from 1 + presence = self.get_sfp(port_num-1).get_presence() + self._global_port_pres_dict[port_num] = '1' if presence else '0' + + self._watchdog = Watchdog() + self.locator_led_reg = "locator_led" + self.LOCATOR_LED_ON = "blink_blue" + self.LOCATOR_LED_OFF = self.STATUS_LED_COLOR_OFF + + def _get_cpld_register(self, reg_name): + # On successful read, returns the value read from given + # reg name and on failure rethrns 'ERR' + cpld_reg_file = self.CPLD_DIR + '/' + reg_name + try: + rv = open(cpld_reg_file, 'r').read() + except IOError : return 'ERR' + return rv.strip('\r\n').lstrip(' ') + + def _set_cpld_register(self, reg_name, value): + # On successful write, returns the value will be written on + # reg_name and on failure returns 'ERR' + rv = 'ERR' + cpld_reg_file = self.CPLD_DIR + '/' + reg_name + + if (not os.path.isfile(cpld_reg_file)): + #print "open error" + return rv + + try: + with open(cpld_reg_file, 'w') as fd: + rv = fd.write(str(value)) + except: + rv = 'ERR' + + return rv + +# check for this event change for sfp / do we need to handle timeout/sleep + + def get_change_event(self, timeout=0): + """ + Returns a nested dictionary containing all devices which have + experienced a change at chassis level + """ + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + while True: + for port_num in self._sfp_port: + # sfp get uses zero-indexing, but port numbers start from 1 + presence = self.get_sfp(port_num-1).get_presence() + if(presence and self._global_port_pres_dict[port_num] == '0'): + self._global_port_pres_dict[port_num] = '1' + port_dict[port_num] = '1' + elif(not presence and self._global_port_pres_dict[port_num] == '1'): + self._global_port_pres_dict[port_num] = '0' + port_dict[port_num] = '0' + + if(len(port_dict) > 0): + return True, change_dict + + time.sleep(0.5) + + + + def get_sfp(self, index): + """ + Retrieves sfp represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 0. + For example, 0 for Ethernet0, 1 for Ethernet4 and so on. + + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + + try: + # The index will start from 0 + sfp = self._sfp_list[index] + except IndexError: + sys.stderr.write("SFP index {} out of range (0-{})\n".format( + index, len(self._sfp_list)-1)) + return sfp + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self._eeprom.modelstr().decode() + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self._eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis (Service tag) + Returns: + string: Serial number of chassis + """ + return self._eeprom.serial_str() + + def get_status(self): + """ + Retrieves the operational status of the chassis + Returns: + bool: A boolean value, True if chassis is operating properly + False if not + """ + return True + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self._eeprom.base_mac_addr('') + + def get_serial_number(self): + """ + Retrieves the hardware serial number for the chassis + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.serial_number_str() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + """ + return self._eeprom.system_eeprom_info() + + def get_reboot_cause(self): + """ + Retrieves the cause of the previous reboot + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + one of the predefined strings in this class. If the first string + is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used + to pass a description of the reboot cause. + """ + + reset_reason = int(self._get_cpld_register('reboot_cause'), 16) + + if (reset_reason & 0x02) : + return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Shutdown by CPU') + elif (reset_reason & 0x04) : + return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, "Failed to boot from configured boot device") + elif (reset_reason & 0x8) : + return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, "Booted from Backup BIOS") + elif (reset_reason & 0x10) : + return(ChassisBase.REBOOT_CAUSE_WATCHDOG, None) + elif (reset_reason & 0x20): + return(ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU) + elif (reset_reason & 0x40) : + return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Warm Reset') + elif (reset_reason & 0x80) : + return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Cold Reset') + elif (reset_reason & 0x01) : + return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) + + def get_eeprom(self): + """ + Retrieves the Sys Eeprom instance for the chassis. + Returns : + The instance of the Sys Eeprom + """ + return self._eeprom + + def get_num_fans(self): + """ + Retrives the number of Fans on the chassis. + Returns : + An integer represents the number of Fans on the chassis. + """ + return self._num_fans + + def get_num_sfps(self): + """ + Retrives the numnber of Media on the chassis. + Returns: + An integer represences the number of SFPs on the chassis. + """ + return self._num_sfps + + def get_qualified_media_list(self): + return media_part_num_list + + def set_locator_led(self, color): + """ + Sets the state of the Chassis Locator LED + + Args: + color: A string representing the color with which to set the Chassis Locator LED + + Returns: + bool: True if the Chassis Locator LED state is set successfully, False if not + + """ + if color == self.LOCATOR_LED_ON or color == self.LOCATOR_LED_OFF: + rv = self._set_cpld_register(self.locator_led_reg, color) + if (rv != 'ERR'): + return True + else: + return False + + def get_locator_led(self): + """ + Gets the state of the Chassis Locator LED + + Returns: + LOCATOR_LED_ON or LOCATOR_LED_OFF + """ + loc_led = self._get_cpld_register(self.locator_led_reg) + if (loc_led != 'ERR'): + # Actually driver returns the color code 'blink_blue' + # Returning "blue_blink" to make it common to all platforms output + if (loc_led == self.LOCATOR_LED_ON): + self.LOCATOR_LED_ON = self.STATUS_LED_COLOR_BLUE_BLINK + return self.LOCATOR_LED_ON + else: + return self.LOCATOR_LED_OFF + else: + return self.LOCATOR_LED_OFF diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/component.py new file mode 100644 index 000000000000..3e1254b99cf1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/component.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +######################################################################## +# DELLEMC N3248TE +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Components' (e.g., BIOS, CPLD, FPGA, BMC etc.) available in +# the platform +# +######################################################################## + +try: + import os + import re + import subprocess + from sonic_platform_base.component_base import ComponentBase + +except ImportError as e: + raise ImportError(str(e) + "- required module not found") +def get_bios_version(): + return subprocess.check_output(['dmidecode', '-s', 'system-version']).strip().decode() + +def get_cpld_version(cpld): + mjr_ver=subprocess.check_output('cat /sys/devices/platform/dell-n3248pxe-cpld.0/' + cpld + '_mjr_ver', shell=True).strip()[2:].decode() + mnr_ver=subprocess.check_output('cat /sys/devices/platform/dell-n3248pxe-cpld.0/' + cpld + '_mnr_ver', shell=True).strip()[2:].decode() + return (str(mjr_ver) + '.' + str(mnr_ver)) + +class Component(ComponentBase): + """DellEMC Platform-specific Component class""" + + CHASSIS_COMPONENTS = [ + ['BIOS', + 'Performs initialization of hardware components during booting', + get_bios_version() + ], + ['CPU CPLD', + 'Used for managing the CPU power sequence and CPU states', + get_cpld_version('cpu_cpld') + ], + ['SYS CPLD', + 'Used for managing FAN, PSU, SFP modules (1-48) SFP Plus modules (49-62)', + get_cpld_version('sys_cpld') + ] + ] + + def __init__(self, component_index=0): + self.index = component_index + self.name = self.CHASSIS_COMPONENTS[self.index][0] + self.description = self.CHASSIS_COMPONENTS[self.index][1] + self.version = self.CHASSIS_COMPONENTS[self.index][2] + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return self.name + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return self.description + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + Returns: + A string containing the firmware version of the component + """ + return self.version + + def install_firmware(self, image_path): + """ + Installs firmware to the component + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install was successful, False if not + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/eeprom.py new file mode 100644 index 000000000000..df33c78d13e7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/eeprom.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python + +############################################################################# +# DellEmc Z9332F +# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# +try: + import os.path + from sonic_eeprom import eeprom_tlvinfo + import binascii +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self): + self.eeprom_path = None + f = '/sys/class/i2c-adapter/i2c-2/2-0050/eeprom' + if not os.path.exists(f): + return + self.eeprom_path = f + super(Eeprom, self).__init__(self.eeprom_path, 0, '', True) + self.eeprom_tlv_dict = dict() + try: + self.eeprom_data = self.read_eeprom() + except: + self.eeprom_data = "N/A" + raise RuntimeError("Eeprom is not Programmed") + + eeprom = self.eeprom_data + + if not self.is_valid_tlvinfo_header(eeprom): + return + + total_length = ((eeprom[9]) << 8) | (eeprom[10]) + tlv_index = self._TLV_INFO_HDR_LEN + tlv_end = self._TLV_INFO_HDR_LEN + total_length + + while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end: + if not self.is_valid_tlv(eeprom[tlv_index:]): + break + + tlv = eeprom[tlv_index:tlv_index + 2 + + (eeprom[tlv_index + 1])] + code = "0x%02X" % ((tlv[0])) + + + name, value = self.decoder(None, tlv) + + self.eeprom_tlv_dict[code] = value + if (eeprom[tlv_index]) == self._TLV_CODE_CRC_32: + break + + tlv_index += (eeprom[tlv_index+1]) + 2 + + def serial_number_str(self): + """ + Returns the serial number + """ + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_SERIAL_NUMBER) + if not is_valid: + return "N/A" + return results[2] + + def base_mac_addr(self, e): + """ + Returns the base mac address found in the system EEPROM + """ + (is_valid, t) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_MAC_BASE) + if not is_valid or t[1] != 6: + return super(eeprom_tlvinfo.TlvInfoDecoder, self).switchaddrstr(t) + + return ":".join([binascii.b2a_hex(T) for T in t[2]]) + + def modelstr(self): + """ + Returns the Model name + """ + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if not is_valid: + return "N/A" + + return results[2] + + def part_number_str(self): + """ + Returns the part number + """ + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return "N/A" + + return results[2] + + def serial_str(self): + """ + Returns the servicetag number + """ + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_SERVICE_TAG) + if not is_valid: + return "N/A" + + return results[2] + + def revision_str(self): + """ + Returns the device revision + """ + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return results[2] + + def system_eeprom_info(self): + """ + Returns a dictionary, where keys are the type code defined in + ONIE EEPROM format and values are their corresponding values + found in the system EEPROM. + """ + return self.eeprom_tlv_dict + + diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan.py new file mode 100644 index 000000000000..bd525bf6fe5c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python + +######################################################################## +# DellEMC Z9332F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fans' information which are available in the platform. +# +######################################################################## +try: + import os + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Fan(FanBase): + """DellEMC Platform-specific Fan class""" + + def __init__(self, fantray_index=0, fan_index=0, psu_fan=False, dependency=None): + self.is_psu_fan = psu_fan + + if not self.is_psu_fan: + # API index is starting from 0, DellEMC platform index is + # starting from 1 + self.presence_reg = "fan{}_prs".format(fantray_index) + self.dir_reg = "fan{}_dir".format(fantray_index) + self.rpm_file = "/sys/bus/i2c/devices/7-002c/fan{}_input".format(fantray_index+1) + self.eeprom = "/sys/bus/i2c/devices/{}-0050/eeprom".format(15 + fantray_index) + self.fantray_index = fantray_index + else: + self.psu_index = fantray_index + self.dependancy = dependency + self.dir_reg = "" + self.dps_hwmon = "/sys/bus/i2c/devices/{}-005e/hwmon/".format(fantray_index+10) + self.eeprom = "/sys/bus/i2c/devices/{}-0056/eeprom".format(10 + fantray_index) + self.max_speed = 0 + + def _get_cpld_register(self, reg_name): + # On successful read, returns the value read from given + # reg name and on failure rethrns 'ERR' + cpld_dir = "/sys/devices/platform/dell-n3248pxe-cpld.0/" + cpld_reg_file = cpld_dir + '/' + reg_name + try: + buf = open(cpld_reg_file, 'r').read() + except (IOError, AttributeError): + return 'ERR' + return buf.strip('\r\n').lstrip(' ') + + def get_name(self): + """ + Retrieves the name of the device + Returns: + String: The name of the device + """ + if self.is_psu_fan: + return "PSU{} Fan".format(self.psu_index) + else: + return "Fan{}".format(self.fantray_index+1) + + def get_model(self): + """ + Retrieves the part number of the FAN + Returns: + String: Part number of FAN + """ + try: + val = open(self.eeprom, "rb").read()[13:19] + except: + val = None + return val.decode() + + def get_serial(self): + """ + Retrieves the serial number of the FAN + Returns: + String: Serial number of FAN + """ + try: + val = open(self.eeprom, "rb").read()[21:41] + except: + val = None + return val.decode() + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if fan is present, False if not + """ + + if self.is_psu_fan: + return False #--- TBD --- # + + presence = self._get_cpld_register(self.presence_reg) + if presence == 'ERR': + return False + if int(presence,0) == 1: + return True + + def get_status(self): + """ + Retrieves the operational status of the FAN + Returns: + bool: True if FAN is operating properly, False if not + """ + return True + + def get_direction(self): + """ + Retrieves the fan airfow direction + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + + Notes: + In DellEMC platforms, + - Forward/Exhaust : Air flows from Port side to Fan side. + - Reverse/Intake : Air flows from Fan side to Port side. + """ + if not self.is_psu_fan: + val = self._get_cpld_register(self.dir_reg) + direction = 'Exhaust' if val == 'F2B' else 'Intake' + if direction == 'ERR': + return None + else: + try: + val = open(self.eeprom, "rb").read()[0xe1:0xe8] + except: + return None + direction = 'Exhaust' if val == 'FORWARD' else 'Intake' + return direction + + def get_speed(self): + """ + Retrieves the speed of the fan + Returns: + int: percentage of the max fan speed + """ + if self.max_speed == 0: + self.max_speed = 23500 + fan_speed = 0 + try: + if not self.is_psu_fan: + rpm_file = self.rpm_file + else: + dps_dir = self.dps_hwmon + '/' + os.listdir(self.dps_hwmon)[0] + rpm_file = dps_dir + '/' + 'fan1_input' + fan_speed = int(open(rpm_file, "rb").read()) + except: + return None + speed = (100 * fan_speed)//self.max_speed + return speed + + def get_speed_rpm(self): + """ + Retrieves the speed of the fan + Returns: + int: percentage of the max fan speed + """ + fan_speed = 0 + try: + if not self.is_psu_fan: + rpm_file = self.rpm_file + else: + dps_dir = self.dps_hwmon + '/' + os.listdir(self.dps_hwmon)[0] + rpm_file = dps_dir + '/' + 'fan1_input' + fan_speed = int(open(rpm_file, "rb").read()) + except: + return None + return fan_speed diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan_drawer.py new file mode 100644 index 000000000000..5142827554db --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan_drawer.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +######################################################################## +# DellEMC N3248TE +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fan-Drawers' information available in the platform. +# +######################################################################## + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +N3248TE_FANS_PER_FANTRAY = 2 + + +class FanDrawer(FanDrawerBase): + """DellEMC Platform-specific Fan class""" + + def __init__(self, fantray_index): + + FanDrawerBase.__init__(self) + # FanTray is 1-based in DellEMC platforms + self.fantrayindex = fantray_index + 1 + for i in range(N3248TE_FANS_PER_FANTRAY): + self._fan_list.append(Fan(fantray_index, i)) + + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray{}".format(self.fantrayindex) diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/ipmihelper.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/ipmihelper.py new file mode 100644 index 000000000000..d95329c40de2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/ipmihelper.py @@ -0,0 +1,269 @@ +#!/usr/bin/python3 + +######################################################################## +# DellEMC +# +# Module contains implementation of IpmiSensor and IpmiFru classes that +# provide Sensor's and FRU's information respectively. +# +######################################################################## + +import subprocess +import re + +# IPMI Request Network Function Codes +NetFn_SensorEvent = 0x04 +NetFn_Storage = 0x0A + +# IPMI Sensor Device Commands +Cmd_GetSensorReadingFactors = 0x23 +Cmd_GetSensorThreshold = 0x27 +Cmd_GetSensorReading = 0x2D + +# IPMI FRU Device Commands +Cmd_ReadFRUData = 0x11 + +def get_ipmitool_raw_output(args): + """ + Returns a list the elements of which are the individual bytes of + ipmitool raw command output. + """ + result_bytes = list() + result = "" + command = "ipmitool raw {}".format(args) + try: + proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE, + universal_newlines=True, stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + if not proc.returncode: + result = stdout.rstrip('\n') + except EnvironmentError: + pass + + for i in result.split(): + result_bytes.append(int(i, 16)) + + return result_bytes + +class IpmiSensor(object): + + # Sensor Threshold types and their respective bit masks + THRESHOLD_BIT_MASK = { + "LowerNonCritical" : 0, + "LowerCritical" : 1, + "LowerNonRecoverable" : 2, + "UpperNonCritical" : 3, + "UpperCritical" : 4, + "UpperNonRecoverable" : 5 + } + + def __init__(self, sensor_id, is_discrete=False): + self.id = sensor_id + self.is_discrete = is_discrete + + def _get_converted_sensor_reading(self, raw_value): + """ + Returns a 2 element tuple(bool, int) in which first element + provides the validity of the reading and the second element is + the converted sensor reading + """ + # Get Sensor Reading Factors + cmd_args = "{} {} {} {}".format(NetFn_SensorEvent, + Cmd_GetSensorReadingFactors, + self.id, raw_value) + factors = get_ipmitool_raw_output(cmd_args) + + if len(factors) != 7: + return False, 0 + + # Compute Twos complement + def get_twos_complement(val, bits): + if val & (1 << (bits - 1)): + val = val - (1 << bits) + return val + + # Calculate actual sensor value from the raw sensor value + # using the sensor reading factors. + M = get_twos_complement(((factors[2] & 0xC0) << 8) | factors[1], 10) + B = get_twos_complement(((factors[4] & 0xC0) << 8) | factors[3], 10) + R_exp = get_twos_complement((factors[6] & 0xF0) >> 4, 4) + B_exp = get_twos_complement(factors[6] & 0x0F, 4) + + converted_reading = ((M * raw_value) + (B * 10**B_exp)) * 10**R_exp + + return True, converted_reading + + def get_reading(self): + """ + For Threshold sensors, returns the sensor reading. + For Discrete sensors, returns the state value. + + Returns: + A tuple (bool, int) where the first element provides the + validity of the reading and the second element provides the + sensor reading/state value. + """ + # Get Sensor Reading + cmd_args = "{} {} {}".format(NetFn_SensorEvent, Cmd_GetSensorReading, + self.id) + output = get_ipmitool_raw_output(cmd_args) + if len(output) != 4: + return False, 0 + + # Check reading/state unavailable + if output[1] & 0x20: + return False, 0 + + if self.is_discrete: + state = ((output[3] & 0x7F) << 8) | output[2] + return True, state + else: + return self._get_converted_sensor_reading(output[0]) + + def get_threshold(self, threshold_type): + """ + Returns the sensor's threshold value for a given threshold type. + + Args: + threshold_type (str) - one of the below mentioned + threshold type strings + + "LowerNonCritical" + "LowerCritical" + "LowerNonRecoverable" + "UpperNonCritical" + "UpperCritical" + "UpperNonRecoverable" + Returns: + A tuple (bool, int) where the first element provides the + validity of that threshold and second element provides the + threshold value. + """ + # Thresholds are not valid for discrete sensors + if self.is_discrete: + raise TypeError("Threshold is not applicable for Discrete Sensor") + + if threshold_type not in list(self.THRESHOLD_BIT_MASK.keys()): + raise ValueError("Invalid threshold type {} provided. Valid types " + "are {}".format(threshold_type, + list(self.THRESHOLD_BIT_MASK.keys()))) + + bit_mask = self.THRESHOLD_BIT_MASK[threshold_type] + + # Get Sensor Threshold + cmd_args = "{} {} {}".format(NetFn_SensorEvent, Cmd_GetSensorThreshold, + self.id) + thresholds = get_ipmitool_raw_output(cmd_args) + if len(thresholds) != 7: + return False, 0 + + valid_thresholds = thresholds.pop(0) + # Check whether particular threshold is readable + if valid_thresholds & (1 << bit_mask): + return self._get_converted_sensor_reading(thresholds[bit_mask]) + else: + return False, 0 + +class IpmiFru(object): + + def __init__(self, fru_id): + self.id = fru_id + + def _get_ipmitool_fru_print(self): + result = "" + command = "ipmitool fru print {}".format(self.id) + try: + proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE, + universal_newlines=True, stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + if not proc.returncode: + result = stdout.rstrip('\n') + except EnvironmentError: + pass + + return result + + def _get_from_fru(self, info): + """ + Returns a string containing the info from FRU + """ + fru_output = self._get_ipmitool_fru_print() + if not fru_output: + return "NA" + + info_req = re.search(r"%s\s*:(.*)" % info, fru_output) + if not info_req: + return "NA" + + return info_req.group(1).strip() + + def get_board_serial(self): + """ + Returns a string containing the Serial Number of the device. + """ + return self._get_from_fru('Board Serial') + + def get_board_part_number(self): + """ + Returns a string containing the Part Number of the device. + """ + return self._get_from_fru('Board Part Number') + + def get_board_mfr_id(self): + """ + Returns a string containing the manufacturer id of the FRU. + """ + return self._get_from_fru('Board Mfg') + + def get_board_product(self): + """ + Returns a string containing the manufacturer id of the FRU. + """ + return self._get_from_fru('Board Product') + + def get_fru_data(self, offset, count=1): + """ + Reads and returns the FRU data at the provided offset. + + Args: + offset (int) - FRU offset to read + count (int) - Number of bytes to read [optional, default = 1] + Returns: + A tuple (bool, list(int)) where the first element provides + the validity of the data read and the second element is a + list, the elements of which are the individual bytes of the + FRU data read. + """ + result_bytes = list() + is_valid = True + result = "" + + offset_LSB = offset & 0xFF + offset_MSB = offset & 0xFF00 + command = "ipmitool raw {} {} {} {} {} {}".format(NetFn_Storage, + Cmd_ReadFRUData, + self.id, offset_LSB, + offset_MSB, count) + try: + proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE, + universal_newlines=True, stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + if not proc.returncode: + result = stdout.rstrip('\n') + except EnvironmentError: + is_valid = False + + if (not result) or (not is_valid): + return False, result_bytes + + for i in result.split(): + result_bytes.append(int(i, 16)) + + read_count = result_bytes.pop(0) + if read_count != count: + return False, result_bytes + else: + return True, result_bytes diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/platform.py new file mode 100644 index 000000000000..996d94cf5a6e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/platform.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +############################################################################# +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + """ + DELLEMC Platform-specific class + """ + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/psu.py new file mode 100644 index 000000000000..b10505900afb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/psu.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python + +######################################################################## +# DellEMC Z9332F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs' information which are available in the platform +# +######################################################################## + +try: + import os + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Psu(PsuBase): + """DellEMC Platform-specific PSU class""" + + def __init__(self, psu_index): + PsuBase.__init__(self) + self.index = psu_index + 1 # PSU is 1-based in DellEMC platforms + self.psu_presence_reg = "psu{}_prs".format(psu_index) + self.psu_status = "psu{}_status".format(psu_index) + self.eeprom = "/sys/bus/i2c/devices/{}-0056/eeprom".format(10+psu_index) + self.psu_voltage_reg = 'in3_input' + self.psu_current_reg = 'curr2_input' + self.psu_power_reg = 'power2_input' + self.dps_hwmon = "/sys/bus/i2c/devices/{}-005e/hwmon/".format(10 + psu_index) + self.dps_hwmon_exist = os.path.exists(self.dps_hwmon) + self._fan_list.append(Fan(fan_index=self.index, psu_fan=True, dependency=self)) + + def _get_cpld_register(self, reg_name): + # On successful read, returns the value read from given + # reg name and on failure rethrns 'ERR' + cpld_dir = "/sys/devices/platform/dell-n3248pxe-cpld.0/" + cpld_reg_file = cpld_dir + '/' + reg_name + try: + rv = open(cpld_reg_file, 'r').read() + except IOError : return 'ERR' + return rv.strip('\r\n').lstrip(' ') + + def _get_dps_register(self, reg_name): + try : + dps_dir = self.dps_hwmon + '/' + os.listdir(self.dps_hwmon)[0] + dps_reg_file = dps_dir + '/' + reg_name + rv = open(dps_reg_file, 'r').read() + except (IOError, OSError) : return 'ERR' + return rv + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return "PSU{}".format(self.index) + + def _reload_dps_module(self): + try: + del_cmd = "echo 0x56 > /sys/bus/i2c/devices/i2c-{}/delete_device".format(10 + self.index - 1) + os.system(del_cmd) + except (IOError, OSError): + pass + try: + del_cmd = "echo 0x5e > /sys/bus/i2c/devices/i2c-{}/delete_device".format(10 + self.index - 1) + os.system(del_cmd) + except (IOError, OSError): + pass + try: + ins_cmd = "echo '24c02 0x56' > /sys/bus/i2c/devices/i2c-{}/new_device".format(10 + self.index - 1) + os.system(ins_cmd) + ins_cmd = "echo 'dps460 0x5e' > /sys/bus/i2c/devices/i2c-{}/new_device".format(10 + self.index - 1) + os.system(ins_cmd) + except (IOError, OSError): + pass + + def get_presence(self): + """ + Retrieves the presence of the Power Supply Unit (PSU) + + Returns: + bool: True if PSU is present, False if not + """ + presence = self._get_cpld_register(self.psu_presence_reg).strip() + if presence == 'ERR' : return False + if not self.dps_hwmon_exist and int(presence, 0): + self.dps_hwmon_exist = os.path.exists(self.dps_hwmon) + if not self.dps_hwmon_exist: + self._reload_dps_module() + return int(presence, 0) + + def get_model(self): + """ + Retrieves the part number of the PSU + + Returns: + string: Part number of PSU + """ + try: val = open(self.eeprom, "rb").read()[0x50:0x62] + except: val = None + return val.decode() + + def get_serial(self): + """ + Retrieves the serial number of the PSU + + Returns: + string: Serial number of PSU + """ + try: val = open(self.eeprom, "rb").read()[0xc4:0xd9] + except: val = None + return val.decode() + + def get_status(self): + """ + Retrieves the operational status of the PSU + + Returns: + bool: True if PSU is operating properly, False if not + """ + status = self._get_cpld_register(self.psu_status).strip() + if status == 'ERR' : return False + return int(status, 0) + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage = 0.0 + volt_reading = self._get_dps_register(self.psu_voltage_reg) + try: + voltage = int(volt_reading)/1000 + except : return None + return "{:.1f}".format(voltage) + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, electric current in amperes, + e.g. 15.4 + """ + current = 0.0 + curr_reading = self._get_dps_register(self.psu_current_reg) + try: + current = int(curr_reading)/1000 + except : return None + return "{:.1f}".format(current) + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, + e.g. 302.6 + """ + power = 0.0 + power_reading = self._get_dps_register(self.psu_power_reg) + try: + power = int(power_reading)/1000 + except : return None + return "{:.1f}".format(power) + + def get_powergood_status(self): + """ + Retrieves the powergood status of PSU + + Returns: + A boolean, True if PSU has stablized its output voltages and + passed all its internal self-tests, False if not. + """ + power_good = self._get_cpld_register(self.psu_status).strip() + if power_good == 'ERR' : return False + return int(power_good, 0) + + def get_mfr_id(self): + """ + Retrives the Manufacturer Id of PSU + + Returns: + A string, the manunfacturer id. + """ + return 'DELTA' + + def get_type(self): + """ + Retrives the Power Type of PSU + + Returns : + A string, PSU power type + """ + try: val = open(self.eeprom, "rb").read()[0xe8:0xea] + except: return None + return val diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/sfp.py new file mode 100644 index 000000000000..04d30490ddd6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/sfp.py @@ -0,0 +1,785 @@ +#!/usr/bin/env python + +############################################################################# +# DELLEMC S5248F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + import os + import time + import struct + import sys + import getopt + import select + import mmap + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8472 import sffbase + +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PAGE_OFFSET = 0 +KEY_OFFSET = 1 +KEY_WIDTH = 2 +FUNC_NAME = 3 + +QSFP_INFO_OFFSET = 128 +QSFP_DOM_OFFSET = 0 +QSFP_DOM_OFFSET1 = 384 + +SFP_PORT_START = 49 +SFP_PORT_END = 52 + +SFP_INFO_OFFSET = 0 +SFP_DOM_OFFSET = 256 + +SFP_STATUS_CONTROL_OFFSET = 110 +SFP_STATUS_CONTROL_WIDTH = 7 +SFP_TX_DISABLE_HARD_BIT = 7 +SFP_TX_DISABLE_SOFT_BIT = 6 + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', 'Length OM2(m)', + 'Length OM1(m)', 'Length Cable Assembly(m)') + +qsfp_compliance_code_tup = ( + '10/40G Ethernet Compliance Code', + 'SONET Compliance codes', + 'SAS/SATA compliance codes', + 'Gigabit Ethernet Compliant codes', + 'Fibre Channel link length/Transmitter Technology', + 'Fibre Channel transmission media', + 'Fibre Channel Speed') + +sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthOM3(UnitsOf10m)', 'LengthCable(UnitsOfm)') + +sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes', 'FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia', 'FibreChannelSpeed') + +info_dict_keys = ['type', 'hardwarerev', 'serialnum', + 'manufacturename', 'modelname', 'Connector', + 'encoding', 'ext_identifier', 'ext_rateselect_compliance', + 'cable_type', 'cable_length', 'nominal_bit_rate', + 'specification_compliance', 'type_abbrv_name','vendor_date', 'vendor_oui'] + +dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', + 'power_lpmode', 'tx_disable', 'tx_disable_channel', + 'temperature', 'voltage', 'rx1power', + 'rx2power', 'rx3power', 'rx4power', + 'tx1bias', 'tx2bias', 'tx3bias', + 'tx4bias', 'tx1power', 'tx2power', + 'tx3power', 'tx4power'] + +threshold_dict_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning'] + +sff8436_parser = { + 'reset_status': [QSFP_DOM_OFFSET, 2, 1, 'parse_dom_status_indicator'], + 'rx_los': [QSFP_DOM_OFFSET, 3, 1, 'parse_dom_tx_rx_los'], + 'tx_fault': [QSFP_DOM_OFFSET, 4, 1, 'parse_dom_tx_fault'], + 'tx_disable': [QSFP_DOM_OFFSET, 86, 1, 'parse_dom_tx_disable'], + 'power_lpmode': [QSFP_DOM_OFFSET, 93, 1, 'parse_dom_power_control'], + 'power_override': [QSFP_DOM_OFFSET, 93, 1, 'parse_dom_power_control'], + 'Temperature': [QSFP_DOM_OFFSET, 22, 2, 'parse_temperature'], + 'Voltage': [QSFP_DOM_OFFSET, 26, 2, 'parse_voltage'], + 'ChannelMonitor': [QSFP_DOM_OFFSET, 34, 16, 'parse_channel_monitor_params'], + 'ChannelMonitor_TxPower': + [QSFP_DOM_OFFSET, 34, 24, 'parse_channel_monitor_params_with_tx_power'], + + 'cable_type': [QSFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'], + 'cable_length': [QSFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'], + 'Connector': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'type': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'encoding': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'ext_identifier': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'ext_rateselect_compliance': + [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'nominal_bit_rate': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'specification_compliance': + [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'type_abbrv_name': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'manufacturename': [QSFP_INFO_OFFSET, 20, 16, 'parse_vendor_name'], + 'vendor_oui': [QSFP_INFO_OFFSET, 37, 3, 'parse_vendor_oui'], + 'modelname': [QSFP_INFO_OFFSET, 40, 16, 'parse_vendor_pn'], + 'hardwarerev': [QSFP_INFO_OFFSET, 56, 2, 'parse_vendor_rev'], + 'serialnum': [QSFP_INFO_OFFSET, 68, 16, 'parse_vendor_sn'], + 'vendor_date': [QSFP_INFO_OFFSET, 84, 8, 'parse_vendor_date'], + 'dom_capability': [QSFP_INFO_OFFSET, 92, 1, 'parse_qsfp_dom_capability'], + 'dom_rev': [QSFP_DOM_OFFSET, 1, 1, 'parse_sfp_dom_rev'], + 'ModuleThreshold': [QSFP_DOM_OFFSET1, 128, 24, 'parse_module_threshold_values'], + 'ChannelThreshold': [QSFP_DOM_OFFSET1, 176, 16, 'parse_channel_threshold_values'], +} + +sff8472_parser = { + 'Temperature': [SFP_DOM_OFFSET, 96, 2, 'parse_temperature'], + 'Voltage': [SFP_DOM_OFFSET, 98, 2, 'parse_voltage'], + 'ChannelMonitor': [SFP_DOM_OFFSET, 100, 6, 'parse_channel_monitor_params'], + + 'cable_type': [SFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'], + 'cable_length': [SFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'], + 'Connector': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], + 'type': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], + 'encoding': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], + 'ext_identifier': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], + 'ext_rateselect_compliance': + [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], + 'nominal_bit_rate': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], + 'specification_compliance': + [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], + 'type_abbrv_name': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], + 'manufacturename': [SFP_INFO_OFFSET, 20, 16, 'parse_vendor_name'], + 'vendor_oui': [SFP_INFO_OFFSET, 37, 3, 'parse_vendor_oui'], + 'modelname': [SFP_INFO_OFFSET, 40, 16, 'parse_vendor_pn'], + 'hardwarerev': [SFP_INFO_OFFSET, 56, 4, 'parse_vendor_rev'], + 'serialnum': [SFP_INFO_OFFSET, 68, 16, 'parse_vendor_sn'], + 'vendor_date': [SFP_INFO_OFFSET, 84, 8, 'parse_vendor_date'], + 'ModuleThreshold': [SFP_DOM_OFFSET, 0, 56, 'parse_alarm_warning_threshold'], +} + + +class Sfp(SfpBase): + """ + DELLEMC Platform-specific Sfp class + """ + + def __init__(self, index, sfp_type, eeprom_path): + SfpBase.__init__(self) + self.sfp_type = sfp_type + self.index = index + self.eeprom_path = eeprom_path + self.qsfpInfo = sff8436InterfaceId() + self.qsfpDomInfo = sff8436Dom() + self.sfpInfo = sff8472InterfaceId() + self.sfpDomInfo = sff8472Dom(None,1) + + def get_eeprom_sysfs_path(self): + return self.eeprom_path + + def pci_mem_read(self, mm, offset): + mm.seek(offset) + read_data_stream = mm.read(4) + reg_val = struct.unpack('I', read_data_stream) + mem_val = str(reg_val)[1:-2] + # print "reg_val read:%x"%reg_val + return mem_val + + def pci_mem_write(self, mm, offset, data): + mm.seek(offset) + # print "data to write:%x"%data + mm.write(struct.pack('I', data)) + + def pci_set_value(self, resource, val, offset): + fd = os.open(resource, os.O_RDWR) + mm = mmap.mmap(fd, 0) + val = self.pci_mem_write(mm, offset, val) + mm.close() + os.close(fd) + return val + + def pci_get_value(self, resource, offset): + fd = os.open(resource, os.O_RDWR) + mm = mmap.mmap(fd, 0) + val = self.pci_mem_read(mm, offset) + mm.close() + os.close(fd) + return val + + def _read_eeprom_bytes(self, eeprom_path, offset, num_bytes): + eeprom_raw = [] + try: + eeprom = open(eeprom_path, mode="rb", buffering=0) + except IOError: + return None + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + try: + eeprom.seek(offset) + raw = eeprom.read(num_bytes) + except IOError: + eeprom.close() + return None + + try: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except BaseException: + eeprom.close() + return None + + eeprom.close() + return eeprom_raw + + def _get_eeprom_data(self, eeprom_key): + eeprom_data = None + page_offset = None + + if(self.sfp_type == 'QSFP'): + page_offset = sff8436_parser[eeprom_key][PAGE_OFFSET] + eeprom_data_raw = self._read_eeprom_bytes( + self.eeprom_path, + (sff8436_parser[eeprom_key][PAGE_OFFSET] + + sff8436_parser[eeprom_key][KEY_OFFSET]), + sff8436_parser[eeprom_key][KEY_WIDTH]) + if (eeprom_data_raw is not None): + # Offset 128 is used to retrieve sff8436InterfaceId Info + # Offset 0 is used to retrieve sff8436Dom Info + if (page_offset == 128): + if ( self.qsfpInfo is None): + return None + eeprom_data = getattr( + self.qsfpInfo, sff8436_parser[eeprom_key][FUNC_NAME])( + eeprom_data_raw, 0) + else: + if ( self.qsfpDomInfo is None): + return None + eeprom_data = getattr( + self.qsfpDomInfo, sff8436_parser[eeprom_key][FUNC_NAME])( + eeprom_data_raw, 0) + else: + page_offset = sff8472_parser[eeprom_key][PAGE_OFFSET] + eeprom_data_raw = self._read_eeprom_bytes( + self.eeprom_path, + (sff8472_parser[eeprom_key][PAGE_OFFSET] + + sff8472_parser[eeprom_key][KEY_OFFSET]), + sff8472_parser[eeprom_key][KEY_WIDTH]) + if (eeprom_data_raw is not None): + # Offset 0 is used to retrieve sff8472InterfaceId Info + # Offset 256 is used to retrieve sff8472Dom Info + if (page_offset == 0): + if ( self.sfpInfo is None): + return None + eeprom_data = getattr( + self.sfpInfo, sff8472_parser[eeprom_key][FUNC_NAME])( + eeprom_data_raw, 0) + else: + if ( self.sfpDomInfo is None): + return None + eeprom_data = getattr( + self.sfpDomInfo, sff8472_parser[eeprom_key][FUNC_NAME])( + eeprom_data_raw, 0) + + return eeprom_data + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + """ + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys(info_dict_keys, 'N/A') + # BaseInformation + try: + iface_data = self._get_eeprom_data('type') + connector = iface_data['data']['Connector']['value'] + encoding = iface_data['data']['EncodingCodes']['value'] + ext_id = iface_data['data']['Extended Identifier']['value'] + rate_identifier = iface_data['data']['RateIdentifier']['value'] + identifier = iface_data['data']['type']['value'] + type_abbrv_name=iface_data['data']['type_abbrv_name']['value'] + if(self.sfp_type == 'QSFP'): + bit_rate = str( + iface_data['data']['Nominal Bit Rate(100Mbs)']['value']) + for key in qsfp_compliance_code_tup: + if key in iface_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = iface_data['data']['Specification compliance']['value'][key]['value'] + for key in qsfp_cable_length_tup: + if key in iface_data['data']: + cable_type = key + cable_length = str(iface_data['data'][key]['value']) + else: + bit_rate = str( + iface_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + for key in sfp_compliance_code_tup: + if key in iface_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = iface_data['data']['Specification compliance']['value'][key]['value'] + for key in sfp_cable_length_tup: + if key in iface_data['data']: + cable_type = key + cable_length = str(iface_data['data'][key]['value']) + + transceiver_info_dict['type_abbrv_name']=type_abbrv_name + transceiver_info_dict['type'] = identifier + transceiver_info_dict['Connector'] = connector + transceiver_info_dict['encoding'] = encoding + transceiver_info_dict['ext_identifier'] = ext_id + transceiver_info_dict['ext_rateselect_compliance'] = rate_identifier + transceiver_info_dict['cable_type'] = cable_type + transceiver_info_dict['cable_length'] = cable_length + transceiver_info_dict['nominal_bit_rate'] = bit_rate + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + except (ValueError, TypeError) : pass + + # Vendor Date + try: + vendor_date_data = self._get_eeprom_data('vendor_date') + vendor_date = vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['vendor_date'] = vendor_date + except (ValueError, TypeError) : pass + + # Vendor Name + try: + vendor_name_data = self._get_eeprom_data('manufacturename') + vendor_name = vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['manufacturename'] = vendor_name + except (ValueError, TypeError) : pass + + # Vendor OUI + try: + vendor_oui_data = self._get_eeprom_data('vendor_oui') + vendor_oui = vendor_oui_data['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_oui'] = vendor_oui + except (ValueError, TypeError) : pass + + # Vendor PN + try: + vendor_pn_data = self._get_eeprom_data('modelname') + vendor_pn = vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['modelname'] = vendor_pn + except (ValueError, TypeError) : pass + + # Vendor Revision + try: + vendor_rev_data = self._get_eeprom_data('hardwarerev') + vendor_rev = vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['hardwarerev'] = vendor_rev + except (ValueError, TypeError) : pass + + # Vendor Serial Number + try: + vendor_sn_data = self._get_eeprom_data('serialnum') + vendor_sn = vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['serialnum'] = vendor_sn + except (ValueError, TypeError) : pass + + return transceiver_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + """ + transceiver_dom_threshold_dict = {} + transceiver_dom_threshold_dict = dict.fromkeys( + threshold_dict_keys, 'N/A') + + try: + # Module Threshold + module_threshold_data = self._get_eeprom_data('ModuleThreshold') + if (self.sfp_type == 'QSFP'): + transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['data']['VccLowWarning']['value'] + else: #SFP + transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_dict['txbiashighalarm'] = module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_dict['txbiaslowalarm'] = module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_dict['txbiashighwarning'] = module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_dict['txbiaslowwarning'] = module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_dict['txpowerhighalarm'] = module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_dict['txpowerlowalarm'] = module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_dict['txpowerhighwarning'] = module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_dict['txpowerlowwarning'] = module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_dict['rxpowerhighalarm'] = module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerlowalarm'] = module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerhighwarning'] = module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_dict['rxpowerlowwarning'] = module_threshold_data['data']['RXPowerLowWarning']['value'] + except (ValueError, TypeError) : pass + + try: + if (self.sfp_type == 'QSFP'): + channel_threshold_data = self._get_eeprom_data('ChannelThreshold') + transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['data']['TxBiasLowWarning']['value'] + + except (ValueError, TypeError) : pass + return transceiver_dom_threshold_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + """ + tx_bias_list = [] + rx_power_list = [] + transceiver_dom_dict = {} + transceiver_dom_dict = dict.fromkeys(dom_dict_keys, 'N/A') + + # RxLos + rx_los = self.get_rx_los() + + # TxFault + tx_fault = self.get_tx_fault() + + # ResetStatus + reset_state = self.get_reset_status() + + # LowPower Mode + lp_mode = self.get_lpmode() + + # TxDisable + tx_disable = self.get_tx_disable() + + # TxDisable Channel + tx_disable_channel = self.get_tx_disable_channel() + + # Temperature + temperature = self.get_temperature() + + # Voltage + voltage = self.get_voltage() + + # Channel Monitor + tx_power_list = self.get_tx_power() + + # tx bias + tx_bias_list = self.get_tx_bias() + + # rx power + rx_power_list = self.get_rx_power() + + if tx_bias_list is not None: + transceiver_dom_dict['tx1bias'] = tx_bias_list[0] + transceiver_dom_dict['tx2bias'] = tx_bias_list[1] + transceiver_dom_dict['tx3bias'] = tx_bias_list[2] + transceiver_dom_dict['tx4bias'] = tx_bias_list[3] + + if rx_power_list is not None: + transceiver_dom_dict['rx1power'] = rx_power_list[0] + transceiver_dom_dict['rx2power'] = rx_power_list[1] + transceiver_dom_dict['rx3power'] = rx_power_list[2] + transceiver_dom_dict['rx4power'] = rx_power_list[3] + + if tx_power_list is not None: + transceiver_dom_dict['tx1power'] = tx_power_list[0] + transceiver_dom_dict['tx2power'] = tx_power_list[1] + transceiver_dom_dict['tx3power'] = tx_power_list[2] + transceiver_dom_dict['tx4power'] = tx_power_list[3] + + transceiver_dom_dict['rx_los'] = rx_los + transceiver_dom_dict['tx_fault'] = tx_fault + transceiver_dom_dict['reset_status'] = reset_state + transceiver_dom_dict['power_lpmode'] = lp_mode + transceiver_dom_dict['tx_disable'] = tx_disable + transceiver_dom_dict['tx_disable_channel'] = tx_disable_channel + transceiver_dom_dict['temperature'] = temperature + transceiver_dom_dict['voltage'] = voltage + + return transceiver_dom_dict + + def get_name(self): + """ + Retrieves the name of the sfp + Returns : QSFP or QSFP+ or QSFP28 + """ + try: + iface_data = self._get_eeprom_data('type') + identifier = iface_data['data']['type']['value'] + except (TypeError, ValueError): + return 'N/A' + return identifier + + def _get_cpld_register(self, reg): + reg_file = '/sys/devices/platform/dell-n3248pxe-cpld.0/' + reg + try: + rv = open(reg_file, 'r').read() + except IOError : return 'ERR' + return rv.strip('\r\n').lstrip(' ') + + def get_presence(self): + """ + Retrieves the presence of the sfp + Returns : True if sfp is present and false if it is absent + """ + # Check for invalid port_num + presence = False + if not (self.index >= SFP_PORT_START and self.index <= SFP_PORT_END): return presence + bit_mask = 1 << (self.index - SFP_PORT_START) + try: + sfp_mod_prs = self._get_cpld_register('sfp_modprs') + if sfp_mod_prs == 'ERR' : return presence + presence = ((int(sfp_mod_prs, 16) & bit_mask) == 0) + except: pass + return presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the sfp + """ + try: + vendor_pn_data = self._get_eeprom_data('modelname') + vendor_pn = vendor_pn_data['data']['Vendor PN']['value'] + except (TypeError, ValueError): + return 'N/A' + + return vendor_pn + + def get_serial(self): + """ + Retrieves the serial number of the sfp + """ + try: + vendor_sn_data = self._get_eeprom_data('serialnum') + vendor_sn = vendor_sn_data['data']['Vendor SN']['value'] + except (TypeError, ValueError): + return 'N/A' + + return vendor_sn + + def get_reset_status(self): + """ + Retrives the reset status of SFP + """ + reset_status = False + return reset_status + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + """ + rx_los = False + if not (self.index >= SFP_PORT_START and self.index <= SFP_PORT_END): return rx_los + bit_mask = 1 << (self.index - SFP_PORT_START) + try: + sfp_rxlos = self._get_cpld_register('sfp_rxlos') + if sfp_rxlos == 'ERR' : return rx_los + rx_los = ((int(sfp_rxlos, 16) & bit_mask) != 0) + except: pass + return rx_los + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + """ + tx_fault = False + if not (self.index >= SFP_PORT_START and self.index <= SFP_PORT_END): return tx_fault + bit_mask = 1 << (self.index - SFP_PORT_START) + try: + sfp_txfault = self._get_cpld_register('sfp_txfault') + if sfp_txfault == 'ERR' : return tx_fault + tx_fault = ((int(sfp_txfault, 16) & bit_mask) != 0) + except: pass + return tx_fault + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + """ + tx_disable = False + if not (self.index >= SFP_PORT_START and self.index <= SFP_PORT_END): return tx_disable + bit_mask = 1 << (self.index - SFP_PORT_START) + try: + sfp_txdisable = self._get_cpld_register('sfp_txdis') + if sfp_txdisable == 'ERR' : return tx_disable + tx_disable = ((int(sfp_txdisable, 16) & bit_mask) != 0) + except: pass + return tx_disable + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + """ + tx_disable_channel = 0 + try: + if (self.sfp_type == 'QSFP'): + tx_disable_data = self._get_eeprom_data('tx_disable') + for tx_disable_id in ('Tx1Disable', 'Tx2Disable', 'Tx3Disable', 'Tx4Disable'): + tx_disable_channel <<= 1 + tx_disable_channel |= (tx_disable_data['data']['Tx1Disable']['value'] is 'On') + except (TypeError, ValueError): + return 'N/A' + return tx_disable_channel + + def get_lpmode(self): + """ + Retrieves the lpmode(low power mode) of this SFP + """ + lpmode_state = False + return lpmode_state + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + """ + power_override_state = False + + try: + if (self.sfp_type == 'QSFP'): + power_override_data = self._get_eeprom_data('power_override') + power_override = power_override_data['data']['PowerOverRide']['value'] + power_override_state = (power_override is 'On') + except (TypeError, ValueError): pass + return power_override_state + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + """ + temperature = 'N/A' + try : + temperature_data = self._get_eeprom_data('Temperature') + temperature = temperature_data['data']['Temperature']['value'] + except (TypeError, ValueError): + return 'N/A' + return temperature + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + """ + voltage = 'N/A' + try: + voltage_data = self._get_eeprom_data('Voltage') + voltage = voltage_data['data']['Vcc']['value'] + except (TypeError, ValueError): + return 'N/A' + return voltage + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + """ + tx_bias_list = [] + try: + tx_bias_data = self._get_eeprom_data('ChannelMonitor') + if (self.sfp_type == 'QSFP'): + for tx_bias_id in ('TX1Bias', 'TX2Bias', 'TX3Bias', 'TX4Bias') : + tx_bias = tx_bias_data['data'][tx_bias_id]['value'] + tx_bias_list.append(tx_bias) + else: + tx1_bias = tx_bias_data['data']['TXBias']['value'] + tx_bias_list = [tx1_bias, "N/A", "N/A", "N/A"] + except (TypeError, ValueError): + return None + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + """ + rx_power_list = [] + try: + rx_power_data = self._get_eeprom_data('ChannelMonitor') + if (self.sfp_type == 'QSFP'): + for rx_power_id in ('RX1Power', 'RX2Power', 'RX3Power', 'RX4Power'): + rx_power = rx_power_data['data'][rx_power_id]['value'] + rx_power_list.append(rx_power) + else: + rx1_pw = rx_power_data['data']['RXPower']['value'] + rx_power_list = [rx1_pw, "N/A", "N/A", "N/A"] + except (TypeError, ValueError): + return None + return rx_power_list + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + """ + tx_power_list = [] + try: + if(self.sfp_type == 'QSFP'): + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qspf_dom_capability_data = self._get_eeprom_data('dom_capability') + qsfp_dom_rev_data = self._get_eeprom_data('dom_rev') + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value'] + + # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 + # and claimed that it support tx_power with one indicator bit. + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + return None + channel_monitor_data = self._get_eeprom_data('ChannelMonitor_TxPower') + for tx_power_id in ('TX1Power', 'TX2Power', 'TX3Power', 'TX4Power'): + tx_pw = channel_monitor_data['data'][tx_power_id]['value'] + tx_power_list.append(tx_pw) + else: + channel_monitor_data = self._get_eeprom_data('ChannelMonitor') + tx1_pw = channel_monitor_data['data']['TXPower']['value'] + tx_power_list = [tx1_pw, 'N/A', 'N/A', 'N/A'] + except (TypeError, ValueError): + return None + return tx_power_list + + def reset(self): + """ + Reset the SFP and returns all user settings to their default state + """ + return True + + def set_lpmode(self, lpmode): + """ + Sets the lpmode(low power mode) of this SFP + """ + return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + """ + return False + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + """ + return False + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + """ + return False + + def get_status(self): + """ + Retrieves the operational status of the device + """ + reset = self.get_reset_status() + return (not reset) + + def get_max_port_power(self): + """ + Retrieves the maximumum power allowed on the port in watts + """ + return 2.5 diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/thermal.py new file mode 100644 index 000000000000..cdbd74562392 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/thermal.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python + +######################################################################## +# DellEMC Z9332F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermals' information which are available in the platform +# +######################################################################## + + +try: + import os + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Thermal(ThermalBase): + """DellEMC Platform-specific Thermal class""" + + # [ Sensor-Name, Sensor-ID ] + SENSOR_MAPPING = [ + ['Switch Near Temperature', '7-0049'], + ['Switch Rear Temperature', '7-004a'], + ['Front Panel PHY Temperature', '7-004b'], + ['Near Front Panel Temperature', '7-004c'], + ['Middle Fan Tray Temperature', '7-004f'], + ] + + def __init__(self, thermal_index): + ThermalBase.__init__(self) + self.index = thermal_index + 1 + temp_hwmon = '/sys/bus/i2c/devices/' + self.SENSOR_MAPPING[thermal_index][1] + '/hwmon' + self.temp_file = temp_hwmon + '/' + os.listdir(temp_hwmon)[0] + '/' + 'temp1_input' + + def get_name(self): + """ + Retrieves the name of the thermal + + Returns: + string: The name of the thermal + """ + return self.SENSOR_MAPPING[self.index - 1][0] + + def get_presence(self): + """ + Retrieves the presence of the thermal + + Returns: + bool: True if thermal is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the Thermal + + Returns: + string: Model/part number of Thermal + """ + return 'NA' + + def get_serial(self): + """ + Retrieves the serial number of the Thermal + + Returns: + string: Serial number of Thermal + """ + return 'NA' + + def get_status(self): + """ + Retrieves the operational status of the thermal + + Returns: + A boolean value, True if thermal is operating properly, + False if not + """ + return True + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + + Returns: + A float number of current temperature in Celsius up to + nearest thousandth of one degree Celsius, e.g. 30.125 + """ + temperature = 0.0 + try : + temperature = float(open(self.temp_file).read()) / 1000.0 + except : pass + return float(temperature) + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of thermal + + Returns: + A float number, the high threshold temperature of thermal in + Celsius up to nearest thousandth of one degree Celsius, + e.g. 30.125 + """ + return 75.0 + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature of thermal + + Returns: + A float number, the low threshold temperature of thermal in + Celsius up to nearest thousandth of one degree Celsius, + e.g. 30.125 + """ + return 0.0 + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + + Args : + temperature: A float number up to nearest thousandth of one + degree Celsius, e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if + not + """ + # Thermal threshold values are pre-defined based on HW. + return False + + def set_low_threshold(self, temperature): + """ + Sets the low threshold temperature of thermal + + Args : + temperature: A float number up to nearest thousandth of one + degree Celsius, e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if + not + """ + # Thermal threshold values are pre-defined based on HW. + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/watchdog.py new file mode 100644 index 000000000000..90a6c7f6eef4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/watchdog.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python + +######################################################################## +# +# DELLEMC Z9332F +# +# Abstract base class for implementing a platform-specific class with +# which to interact with a hardware watchdog module in SONiC +# +######################################################################## + +try: + import sys + import struct + import ctypes + import subprocess + from sonic_platform_base.watchdog_base import WatchdogBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class _timespec(ctypes.Structure): + _fields_ = [ + ('tv_sec', ctypes.c_long), + ('tv_nsec', ctypes.c_long) + ] + + +class Watchdog(WatchdogBase): + """ + Abstract base class for interfacing with a hardware watchdog module + """ + + TIMERS = [15,20,30,40,50,60,65,70] + + armed_time = 0 + timeout = 0 + CLOCK_MONOTONIC = 1 + + def __init__(self): + self._librt = ctypes.CDLL('librt.so.1', use_errno=True) + self._clock_gettime = self._librt.clock_gettime + self._clock_gettime.argtypes=[ctypes.c_int, ctypes.POINTER(_timespec)] + + def _get_command_result(self, cmdline): + try: + proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + result = stdout.rstrip('\n') + except OSError: + result = None + + return result + + def _get_reg_val(self): + # 0x31 = CPLD I2C Base Address + # 0x07 = Watchdog Function Register + value = self._get_command_result("/usr/sbin/i2cget -y 601 0x31 0x07") + if not value: + return None + else: + return int(value, 16) + + def _set_reg_val(self,val): + # 0x31 = CPLD I2C Base Address + # 0x07 = Watchdog Function Register + value = self._get_command_result("/usr/sbin/i2cset -y 601 0x31 0x07 %s" + % (val)) + return value + + def _get_time(self): + """ + To get clock monotonic time + """ + ts = _timespec() + if self._clock_gettime(self.CLOCK_MONOTONIC, ctypes.pointer(ts)) != 0: + self._errno = ctypes.get_errno() + return 0 + return ts.tv_sec + ts.tv_nsec * 1e-9 + + def arm(self, seconds): + """ + Arm the hardware watchdog with a timeout of seconds. + If the watchdog is currently armed, calling this function will + simply reset the timer to the provided value. If the underlying + hardware does not support the value provided in , this + method should arm the watchdog with the *next greater* + available value. + + Returns: + An integer specifying the *actual* number of seconds the + watchdog was armed with. On failure returns -1. + """ + timer_offset = -1 + for key,timer_seconds in enumerate(self.TIMERS): + if seconds <= timer_seconds: + timer_offset = key + seconds = timer_seconds + break + + if timer_offset == -1: + return -1 + + # Extracting 5th to 7th bits for WD timer values + # 000 - 15 sec + # 001 - 20 sec + # 010 - 30 sec + # 011 - 40 sec + # 100 - 50 sec + # 101 - 60 sec + # 110 - 65 sec + # 111 - 70 sec + reg_val = self._get_reg_val() + wd_timer_offset = (reg_val >> 4) & 0x7 + + if wd_timer_offset != timer_offset: + # Setting 5th to 7th bits + # value from timer_offset + self.disarm() + self._set_reg_val(reg_val | (timer_offset << 4)) + + if self.is_armed(): + # Setting last bit to WD Timer punch + # Last bit = WD Timer punch + self._set_reg_val(reg_val & 0xFE) + + self.armed_time = self._get_time() + self.timeout = seconds + return seconds + else: + # Setting 4th bit to enable WD + # 4th bit = Enable WD + reg_val = self._get_reg_val() + self._set_reg_val(reg_val | 0x8) + + self.armed_time = self._get_time() + self.timeout = seconds + return seconds + + return -1 + + def disarm(self): + """ + Disarm the hardware watchdog + + Returns: + A boolean, True if watchdog is disarmed successfully, False + if not + """ + if self.is_armed(): + # Setting 4th bit to disable WD + # 4th bit = Disable WD + reg_val = self._get_reg_val() + self._set_reg_val(reg_val & 0xF7) + + self.armed_time = 0 + self.timeout = 0 + return True + + return False + + def is_armed(self): + """ + Retrieves the armed state of the hardware watchdog. + + Returns: + A boolean, True if watchdog is armed, False if not + """ + + # Extracting 4th bit to get WD Enable/Disable status + # 0 - Disabled WD + # 1 - Enabled WD + reg_val = self._get_reg_val() + wd_offset = (reg_val >> 3) & 1 + + return bool(wd_offset) + + def get_remaining_time(self): + """ + If the watchdog is armed, retrieve the number of seconds + remaining on the watchdog timer + + Returns: + An integer specifying the number of seconds remaining on + their watchdog timer. If the watchdog is not armed, returns + -1. + + S5232 doesnot have hardware support to show remaining time. + Due to this limitation, this API is implemented in software. + This API would return correct software time difference if it + is called from the process which armed the watchdog timer. + If this API called from any other process, it would return + 0. If the watchdog is not armed, this API would return -1. + """ + if not self.is_armed(): + return -1 + + if self.armed_time > 0 and self.timeout != 0: + cur_time = self._get_time() + + if cur_time <= 0: + return 0 + + diff_time = int(cur_time - self.armed_time) + + if diff_time > self.timeout: + return self.timeout + else: + return self.timeout - diff_time + + return 0 + diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/systemd/platform-modules-n3248pxe.service b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/systemd/platform-modules-n3248pxe.service new file mode 100644 index 000000000000..68c7ea36ed06 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/systemd/platform-modules-n3248pxe.service @@ -0,0 +1,13 @@ +[Unit] +Description=Dell N3248pxe Platform modules +Before=pmon.service +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/n3248pxe_platform.sh init +ExecStop=/usr/local/bin/n3248pxe_platform.sh deinit +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target From e9d09632203c3e99d45f3d66faf38b562be534fd Mon Sep 17 00:00:00 2001 From: Arun LK Date: Mon, 30 Aug 2021 17:47:40 +0530 Subject: [PATCH 2/4] DellEMC: N3248PXE Initial platform commit --- ...-n3248pxe-48x10GCU+4x25G-2x100G.config.bcm | 27 ++++++++- .../plugins/fanutil.py | 1 - .../plugins/psuutil.py | 2 +- .../plugins/sfputil.py | 4 -- .../n3248pxe/scripts/platform_sensors.py | 4 -- .../n3248pxe/scripts/portiocfg.py | 1 - .../n3248pxe/scripts/ports_xcvrd_notify.py | 6 -- .../n3248pxe/sonic_platform/chassis.py | 42 +++++++------- .../n3248pxe/sonic_platform/component.py | 4 +- .../n3248pxe/sonic_platform/eeprom.py | 2 +- .../n3248pxe/sonic_platform/fan.py | 12 ++-- .../n3248pxe/sonic_platform/fan_drawer.py | 6 +- .../n3248pxe/sonic_platform/psu.py | 25 +++++---- .../n3248pxe/sonic_platform/sfp.py | 56 ++++++++++--------- .../n3248pxe/sonic_platform/thermal.py | 5 +- .../n3248pxe/sonic_platform/watchdog.py | 10 +--- src/sonic-device-data/tests/permitted_list | 11 ++++ 17 files changed, 120 insertions(+), 98 deletions(-) diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/td3-x5-n3248pxe-48x10GCU+4x25G-2x100G.config.bcm b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/td3-x5-n3248pxe-48x10GCU+4x25G-2x100G.config.bcm index b6a424f55eda..8d3a064211c4 100644 --- a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/td3-x5-n3248pxe-48x10GCU+4x25G-2x100G.config.bcm +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/DELLEMC-N3248PXE/td3-x5-n3248pxe-48x10GCU+4x25G-2x100G.config.bcm @@ -323,6 +323,10 @@ phy_an_c73=3 oversubscribe_mode=1 core_clock_frequency=1525 +#25G,10G and 1G support +serdes_10g_at_25g_vco=1 +serdes_1000x_at_25g_vco=1 + l2xmsg_mode=1 l2xmsg_hostbuf_size=16384 @@ -360,5 +364,26 @@ riot_overlay_ecmp_resilient_hash_size=16384 pfc_deadlock_seq_control=1 #Common configs from broadcom/x86_64-broadcom_common/x86_64-broadcom_b77/broadcom-sonic-td3.config.bcm (Lower version of Td3 (0xb771)) - +mem_cache_enable=0 +ifp_inports_support_enable=1 +ipv6_lpm_128b_enable=0x1 +l3_max_ecmp_mode=1 +lpm_scaling_enable=0 +bcm_num_cos=10 +default_cpu_tx_queue=9 +mmu_lossless=0 +host_as_route_disable=1 +sai_eapp_config_file=/etc/broadcom/eapps_cfg.json +sai_fast_convergence_support=1 flow_init_mode=1 +sai_interface_type_auto_detect=0 +mpls_mem_entries=16384 +vlan_xlate_1_mem_entries=65536 +vlan_xlate_2_mem_entries=16384 +sai_load_hw_config=/usr/lib/cancun/ +sai_nbr_bcast_ifp_optimized=1 +sai_brcm_sonic_acl_enhancements=1 +# Reduced Trap Group QSET for BRCM Sonic +sai_brcm_sonic_trap_group=1 +l2_entry_used_as_my_station=1 +multi_hash_recurse_depth_l3=2 diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/fanutil.py b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/fanutil.py index 5a3e882c3e44..b70d58901330 100644 --- a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/fanutil.py +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/fanutil.py @@ -4,7 +4,6 @@ # import commands -import os import sys SENSORS_CMD = "docker exec -i pmon /usr/bin/sensors" diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/psuutil.py b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/psuutil.py index 71ab0e812e86..a9cfd00b9e2d 100644 --- a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/psuutil.py +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/psuutil.py @@ -47,7 +47,7 @@ def get_cpld_register(self, reg_name): try: with open(reg_file, 'r') as fd: retval = fd.read() - except Exception as error: + except Exception: print("Unable to open ", reg_file, "file !") retval = retval.rstrip('\r\n') diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/sfputil.py index 49c712b158be..3aedcca1851b 100644 --- a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/plugins/sfputil.py @@ -5,10 +5,6 @@ try: import time - import datetime - import os - import struct - import traceback from socket import * from select import * from sonic_sfp.sfputilbase import SfpUtilBase diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/platform_sensors.py index 9640f16750e6..e76fffa20cc2 100755 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/platform_sensors.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/platform_sensors.py @@ -4,10 +4,6 @@ # * FAN trays # * PSU - -import os -import sys -import logging import subprocess output = "" diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/portiocfg.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/portiocfg.py index 51cc9ab27db3..348ae9920164 100755 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/portiocfg.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/portiocfg.py @@ -64,7 +64,6 @@ def main(argv): opts = '' val = '' choice = '' - resouce = '' offset = '' try: diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/ports_xcvrd_notify.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/ports_xcvrd_notify.py index be44d58343cb..8e40ce4853ef 100755 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/ports_xcvrd_notify.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/scripts/ports_xcvrd_notify.py @@ -6,9 +6,6 @@ """ try: - import os - import sys - import time from datetime import datetime from swsscommon import swsscommon from sonic_py_common import daemon_base, logger @@ -89,9 +86,6 @@ def main(): helper_logger.log_notice("Start port_notify") # Connect to APP_DB and create transceiver dom info table appl_db = daemon_base.db_connect("APPL_DB") - cst = swsscommon.SubscriberStateTable(appl_db, swsscommon.APP_PORT_TABLE_NAME) - - app_port_tbl = swsscommon.ProducerStateTable(appl_db, swsscommon.APP_PORT_TABLE_NAME) app_status_port_tbl = swsscommon.ProducerStateTable(appl_db, swsscommon.APP_PORT_APP_STATUS_TABLE_NAME) diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/chassis.py index 3dd887eae28a..5576aaf039ce 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/chassis.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ############################################################################# -# DELLEMC N3248TE +# DELLEMC N3248PXE # # Module contains an implementation of SONiC Platform Base API and # provides the platform information @@ -10,7 +10,6 @@ try: import os - import select import sys import time from sonic_platform_base.chassis_base import ChassisBase @@ -26,11 +25,11 @@ raise ImportError(str(e) + "- required module not found") -MAX_N3248TE_FANTRAY = 3 -MAX_N3248TE_FAN = 1 -MAX_N3248TE_PSU = 2 -MAX_N3248TE_THERMAL = 5 -MAX_N3248TE_COMPONENT = 3 # BIOS, CPU CPLD and SYS CPLD +MAX_N3248PXE_FANTRAY = 3 +MAX_N3248PXE_FAN = 1 +MAX_N3248PXE_PSU = 2 +MAX_N3248PXE_THERMAL = 5 +MAX_N3248PXE_COMPONENT = 3 # BIOS, CPU CPLD and SYS CPLD media_part_num_list = set([ \ "8T47V","XTY28","MHVPK","GF76J","J6FGD","F1KMV","9DN5J","H4DHD","6MCNV","0WRX0","X7F70","5R2PT","WTRD1","WTRD1","WTRD1","WTRD1","5250G","WTRD1","C5RNH","C5RNH","FTLX8571D3BCL-FC", @@ -60,6 +59,8 @@ class Chassis(ChassisBase): 50: 21, 51: 22, 52: 23, + 53: 24, + 54: 25, } def __init__(self): @@ -67,7 +68,7 @@ def __init__(self): # sfp.py will read eeprom contents and retrive the eeprom data. # We pass the eeprom path from chassis.py self.PORT_START = 1 - self.PORT_END = 52 + self.PORT_END = 54 self.PORTS_IN_BLOCK = (self.PORT_END + 1) self.SFP_PORT_START = 49 self._sfp_port = range(self.SFP_PORT_START, self.PORTS_IN_BLOCK) @@ -81,21 +82,21 @@ def __init__(self): self._eeprom = Eeprom() self._watchdog = Watchdog() - self._num_sfps = 52 - self._num_fans = MAX_N3248TE_FANTRAY * MAX_N3248TE_FAN - self._fan_list = [Fan(i, j) for i in range(MAX_N3248TE_FANTRAY) \ - for j in range(MAX_N3248TE_FAN)] - for k in range(MAX_N3248TE_FANTRAY): + self._num_sfps = 54 + self._num_fans = MAX_N3248PXE_FANTRAY * MAX_N3248PXE_FAN + self._fan_list = [Fan(i, j) for i in range(MAX_N3248PXE_FANTRAY) \ + for j in range(MAX_N3248PXE_FAN)] + for k in range(MAX_N3248PXE_FANTRAY): fandrawer = FanDrawer(k) self._fan_drawer_list.append(fandrawer) self._fan_list.extend(fandrawer._fan_list) - self._psu_list = [Psu(i) for i in range(MAX_N3248TE_PSU)] - self._thermal_list = [Thermal(i) for i in range(MAX_N3248TE_THERMAL)] - self._component_list = [Component(i) for i in range(MAX_N3248TE_COMPONENT)] + self._psu_list = [Psu(i) for i in range(MAX_N3248PXE_PSU)] + self._thermal_list = [Thermal(i) for i in range(MAX_N3248PXE_THERMAL)] + self._component_list = [Component(i) for i in range(MAX_N3248PXE_COMPONENT)] for port_num in self._sfp_port: # sfp get uses zero-indexing, but port numbers start from 1 - presence = self.get_sfp(port_num-1).get_presence() + presence = self.get_sfp(port_num).get_presence() self._global_port_pres_dict[port_num] = '1' if presence else '0' self._watchdog = Watchdog() @@ -119,13 +120,12 @@ def _set_cpld_register(self, reg_name, value): cpld_reg_file = self.CPLD_DIR + '/' + reg_name if (not os.path.isfile(cpld_reg_file)): - #print "open error" return rv try: with open(cpld_reg_file, 'w') as fd: rv = fd.write(str(value)) - except: + except Exception: rv = 'ERR' return rv @@ -143,7 +143,7 @@ def get_change_event(self, timeout=0): while True: for port_num in self._sfp_port: # sfp get uses zero-indexing, but port numbers start from 1 - presence = self.get_sfp(port_num-1).get_presence() + presence = self.get_sfp(port_num).get_presence() if(presence and self._global_port_pres_dict[port_num] == '0'): self._global_port_pres_dict[port_num] = '1' port_dict[port_num] = '1' @@ -175,7 +175,7 @@ def get_sfp(self, index): try: # The index will start from 0 - sfp = self._sfp_list[index] + sfp = self._sfp_list[index-1] except IndexError: sys.stderr.write("SFP index {} out of range (0-{})\n".format( index, len(self._sfp_list)-1)) diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/component.py index 3e1254b99cf1..50b85cc179e4 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/component.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/component.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ######################################################################## -# DELLEMC N3248TE +# DELLEMC N3248PXE # # Module contains an implementation of SONiC Platform Base API and # provides the Components' (e.g., BIOS, CPLD, FPGA, BMC etc.) available in @@ -10,8 +10,6 @@ ######################################################################## try: - import os - import re import subprocess from sonic_platform_base.component_base import ComponentBase diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/eeprom.py index df33c78d13e7..1343265508e0 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/eeprom.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/eeprom.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ############################################################################# -# DellEmc Z9332F +# DellEmc N3248PXE # # Platform and model specific eeprom subclass, inherits from the base class, # and provides the followings: diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan.py index bd525bf6fe5c..85d262f1c049 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ######################################################################## -# DellEMC Z9332F +# DellEMC N3248PXE # # Module contains an implementation of SONiC Platform Base API and # provides the Fans' information which are available in the platform. @@ -66,7 +66,7 @@ def get_model(self): """ try: val = open(self.eeprom, "rb").read()[13:19] - except: + except Exception: val = None return val.decode() @@ -78,7 +78,7 @@ def get_serial(self): """ try: val = open(self.eeprom, "rb").read()[21:41] - except: + except Exception: val = None return val.decode() @@ -126,7 +126,7 @@ def get_direction(self): else: try: val = open(self.eeprom, "rb").read()[0xe1:0xe8] - except: + except Exception: return None direction = 'Exhaust' if val == 'FORWARD' else 'Intake' return direction @@ -147,7 +147,7 @@ def get_speed(self): dps_dir = self.dps_hwmon + '/' + os.listdir(self.dps_hwmon)[0] rpm_file = dps_dir + '/' + 'fan1_input' fan_speed = int(open(rpm_file, "rb").read()) - except: + except Exception: return None speed = (100 * fan_speed)//self.max_speed return speed @@ -166,6 +166,6 @@ def get_speed_rpm(self): dps_dir = self.dps_hwmon + '/' + os.listdir(self.dps_hwmon)[0] rpm_file = dps_dir + '/' + 'fan1_input' fan_speed = int(open(rpm_file, "rb").read()) - except: + except Exception: return None return fan_speed diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan_drawer.py index 5142827554db..45abfae3647a 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan_drawer.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/fan_drawer.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ######################################################################## -# DellEMC N3248TE +# DellEMC N3248PXE # # Module contains an implementation of SONiC Platform Base API and # provides the Fan-Drawers' information available in the platform. @@ -14,7 +14,7 @@ except ImportError as e: raise ImportError(str(e) + "- required module not found") -N3248TE_FANS_PER_FANTRAY = 2 +N3248PXE_FANS_PER_FANTRAY = 2 class FanDrawer(FanDrawerBase): @@ -25,7 +25,7 @@ def __init__(self, fantray_index): FanDrawerBase.__init__(self) # FanTray is 1-based in DellEMC platforms self.fantrayindex = fantray_index + 1 - for i in range(N3248TE_FANS_PER_FANTRAY): + for i in range(N3248PXE_FANS_PER_FANTRAY): self._fan_list.append(Fan(fantray_index, i)) def get_name(self): diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/psu.py index b10505900afb..74f8a766f6d8 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/psu.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/psu.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ######################################################################## -# DellEMC Z9332F +# DellEMC N3248PXE # # Module contains an implementation of SONiC Platform Base API and # provides the PSUs' information which are available in the platform @@ -101,7 +101,8 @@ def get_model(self): string: Part number of PSU """ try: val = open(self.eeprom, "rb").read()[0x50:0x62] - except: val = None + except Exception: + val = None return val.decode() def get_serial(self): @@ -112,7 +113,8 @@ def get_serial(self): string: Serial number of PSU """ try: val = open(self.eeprom, "rb").read()[0xc4:0xd9] - except: val = None + except Exception: + val = None return val.decode() def get_status(self): @@ -134,11 +136,11 @@ def get_voltage(self): A float number, the output voltage in volts, e.g. 12.1 """ - voltage = 0.0 volt_reading = self._get_dps_register(self.psu_voltage_reg) try: voltage = int(volt_reading)/1000 - except : return None + except Exception: + return None return "{:.1f}".format(voltage) def get_current(self): @@ -149,11 +151,11 @@ def get_current(self): A float number, electric current in amperes, e.g. 15.4 """ - current = 0.0 curr_reading = self._get_dps_register(self.psu_current_reg) try: current = int(curr_reading)/1000 - except : return None + except Exception: + return None return "{:.1f}".format(current) def get_power(self): @@ -164,11 +166,11 @@ def get_power(self): A float number, the power in watts, e.g. 302.6 """ - power = 0.0 power_reading = self._get_dps_register(self.psu_power_reg) try: power = int(power_reading)/1000 - except : return None + except Exception: + return None return "{:.1f}".format(power) def get_powergood_status(self): @@ -200,5 +202,6 @@ def get_type(self): A string, PSU power type """ try: val = open(self.eeprom, "rb").read()[0xe8:0xea] - except: return None - return val + except Exception: + return None + return val.decode() diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/sfp.py index 04d30490ddd6..1a56c036dc86 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/sfp.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ############################################################################# -# DELLEMC S5248F +# DELLEMC N3248PXE # # Module contains an implementation of SONiC Platform Base API and # provides the platform information @@ -37,7 +37,7 @@ QSFP_DOM_OFFSET1 = 384 SFP_PORT_START = 49 -SFP_PORT_END = 52 +SFP_PORT_END = 54 SFP_INFO_OFFSET = 0 SFP_DOM_OFFSET = 256 @@ -69,8 +69,8 @@ 'FibreChannelTechnology', 'SFP+CableTechnology', 'FibreChannelTransmissionMedia', 'FibreChannelSpeed') -info_dict_keys = ['type', 'hardwarerev', 'serialnum', - 'manufacturename', 'modelname', 'Connector', +info_dict_keys = ['type', 'hardware_rev', 'serial', + 'manufacturer', 'model', 'connector', 'encoding', 'ext_identifier', 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', 'specification_compliance', 'type_abbrv_name','vendor_date', 'vendor_oui'] @@ -109,7 +109,7 @@ 'cable_type': [QSFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'], 'cable_length': [QSFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'], - 'Connector': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'connector': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], 'type': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], 'encoding': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], 'ext_identifier': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], @@ -119,11 +119,11 @@ 'specification_compliance': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], 'type_abbrv_name': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], - 'manufacturename': [QSFP_INFO_OFFSET, 20, 16, 'parse_vendor_name'], + 'manufacturer': [QSFP_INFO_OFFSET, 20, 16, 'parse_vendor_name'], 'vendor_oui': [QSFP_INFO_OFFSET, 37, 3, 'parse_vendor_oui'], - 'modelname': [QSFP_INFO_OFFSET, 40, 16, 'parse_vendor_pn'], - 'hardwarerev': [QSFP_INFO_OFFSET, 56, 2, 'parse_vendor_rev'], - 'serialnum': [QSFP_INFO_OFFSET, 68, 16, 'parse_vendor_sn'], + 'model': [QSFP_INFO_OFFSET, 40, 16, 'parse_vendor_pn'], + 'hardware_rev': [QSFP_INFO_OFFSET, 56, 2, 'parse_vendor_rev'], + 'serial': [QSFP_INFO_OFFSET, 68, 16, 'parse_vendor_sn'], 'vendor_date': [QSFP_INFO_OFFSET, 84, 8, 'parse_vendor_date'], 'dom_capability': [QSFP_INFO_OFFSET, 92, 1, 'parse_qsfp_dom_capability'], 'dom_rev': [QSFP_DOM_OFFSET, 1, 1, 'parse_sfp_dom_rev'], @@ -138,7 +138,7 @@ 'cable_type': [SFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'], 'cable_length': [SFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'], - 'Connector': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], + 'connector': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], 'type': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], 'encoding': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], 'ext_identifier': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], @@ -148,11 +148,11 @@ 'specification_compliance': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], 'type_abbrv_name': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'], - 'manufacturename': [SFP_INFO_OFFSET, 20, 16, 'parse_vendor_name'], + 'manufacturer': [SFP_INFO_OFFSET, 20, 16, 'parse_vendor_name'], 'vendor_oui': [SFP_INFO_OFFSET, 37, 3, 'parse_vendor_oui'], - 'modelname': [SFP_INFO_OFFSET, 40, 16, 'parse_vendor_pn'], - 'hardwarerev': [SFP_INFO_OFFSET, 56, 4, 'parse_vendor_rev'], - 'serialnum': [SFP_INFO_OFFSET, 68, 16, 'parse_vendor_sn'], + 'model': [SFP_INFO_OFFSET, 40, 16, 'parse_vendor_pn'], + 'hardware_rev': [SFP_INFO_OFFSET, 56, 4, 'parse_vendor_rev'], + 'serial': [SFP_INFO_OFFSET, 68, 16, 'parse_vendor_sn'], 'vendor_date': [SFP_INFO_OFFSET, 84, 8, 'parse_vendor_date'], 'ModuleThreshold': [SFP_DOM_OFFSET, 0, 56, 'parse_alarm_warning_threshold'], } @@ -207,6 +207,7 @@ def pci_get_value(self, resource, offset): def _read_eeprom_bytes(self, eeprom_path, offset, num_bytes): eeprom_raw = [] + print(eeprom_path, num_bytes) try: eeprom = open(eeprom_path, mode="rb", buffering=0) except IOError: @@ -222,9 +223,11 @@ def _read_eeprom_bytes(self, eeprom_path, offset, num_bytes): eeprom.close() return None + raw = bytearray(raw) + try: for n in range(0, num_bytes): - eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + eeprom_raw[n] = hex((raw[n]))[2:].zfill(2) except BaseException: eeprom.close() return None @@ -322,7 +325,7 @@ def get_transceiver_info(self): transceiver_info_dict['type_abbrv_name']=type_abbrv_name transceiver_info_dict['type'] = identifier - transceiver_info_dict['Connector'] = connector + transceiver_info_dict['connector'] = connector transceiver_info_dict['encoding'] = encoding transceiver_info_dict['ext_identifier'] = ext_id transceiver_info_dict['ext_rateselect_compliance'] = rate_identifier @@ -341,9 +344,9 @@ def get_transceiver_info(self): # Vendor Name try: - vendor_name_data = self._get_eeprom_data('manufacturename') + vendor_name_data = self._get_eeprom_data('manufacturer') vendor_name = vendor_name_data['data']['Vendor Name']['value'] - transceiver_info_dict['manufacturename'] = vendor_name + transceiver_info_dict['manufacturer'] = vendor_name except (ValueError, TypeError) : pass # Vendor OUI @@ -355,23 +358,23 @@ def get_transceiver_info(self): # Vendor PN try: - vendor_pn_data = self._get_eeprom_data('modelname') + vendor_pn_data = self._get_eeprom_data('model') vendor_pn = vendor_pn_data['data']['Vendor PN']['value'] - transceiver_info_dict['modelname'] = vendor_pn + transceiver_info_dict['model'] = vendor_pn except (ValueError, TypeError) : pass # Vendor Revision try: - vendor_rev_data = self._get_eeprom_data('hardwarerev') + vendor_rev_data = self._get_eeprom_data('hardware_rev') vendor_rev = vendor_rev_data['data']['Vendor Rev']['value'] - transceiver_info_dict['hardwarerev'] = vendor_rev + transceiver_info_dict['hardware_rev'] = vendor_rev except (ValueError, TypeError) : pass # Vendor Serial Number try: - vendor_sn_data = self._get_eeprom_data('serialnum') + vendor_sn_data = self._get_eeprom_data('serial') vendor_sn = vendor_sn_data['data']['Vendor SN']['value'] - transceiver_info_dict['serialnum'] = vendor_sn + transceiver_info_dict['serial'] = vendor_sn except (ValueError, TypeError) : pass return transceiver_info_dict @@ -540,12 +543,13 @@ def get_presence(self): except: pass return presence + def get_model(self): """ Retrieves the model number (or part number) of the sfp """ try: - vendor_pn_data = self._get_eeprom_data('modelname') + vendor_pn_data = self._get_eeprom_data('model') vendor_pn = vendor_pn_data['data']['Vendor PN']['value'] except (TypeError, ValueError): return 'N/A' @@ -557,7 +561,7 @@ def get_serial(self): Retrieves the serial number of the sfp """ try: - vendor_sn_data = self._get_eeprom_data('serialnum') + vendor_sn_data = self._get_eeprom_data('serial') vendor_sn = vendor_sn_data['data']['Vendor SN']['value'] except (TypeError, ValueError): return 'N/A' diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/thermal.py index cdbd74562392..d89b50ababd0 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/thermal.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/thermal.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ######################################################################## -# DellEMC Z9332F +# DellEMC N3248PXE # # Module contains an implementation of SONiC Platform Base API and # provides the Thermals' information which are available in the platform @@ -91,7 +91,8 @@ def get_temperature(self): temperature = 0.0 try : temperature = float(open(self.temp_file).read()) / 1000.0 - except : pass + except Exception: + pass return float(temperature) def get_high_threshold(self): diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/watchdog.py index 90a6c7f6eef4..876aa4beda51 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/watchdog.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/watchdog.py @@ -2,7 +2,7 @@ ######################################################################## # -# DELLEMC Z9332F +# DELLEMC N3248PXE # # Abstract base class for implementing a platform-specific class with # which to interact with a hardware watchdog module in SONiC @@ -10,8 +10,6 @@ ######################################################################## try: - import sys - import struct import ctypes import subprocess from sonic_platform_base.watchdog_base import WatchdogBase @@ -128,7 +126,6 @@ def arm(self, seconds): self.armed_time = self._get_time() self.timeout = seconds - return seconds else: # Setting 4th bit to enable WD # 4th bit = Enable WD @@ -137,9 +134,8 @@ def arm(self, seconds): self.armed_time = self._get_time() self.timeout = seconds - return seconds - return -1 + return seconds def disarm(self): """ @@ -187,7 +183,7 @@ def get_remaining_time(self): their watchdog timer. If the watchdog is not armed, returns -1. - S5232 doesnot have hardware support to show remaining time. + N3248PXE doesnot have hardware support to show remaining time. Due to this limitation, this API is implemented in software. This API would return correct software time difference if it is called from the process which armed the watchdog timer. diff --git a/src/sonic-device-data/tests/permitted_list b/src/sonic-device-data/tests/permitted_list index f4f576b8dc31..fca54f6b4110 100644 --- a/src/sonic-device-data/tests/permitted_list +++ b/src/sonic-device-data/tests/permitted_list @@ -256,3 +256,14 @@ appl_param_module_id serdes_lane_config_cl72_auto_polarity_en serdes_lane_config_cl72_restart_timeout_en bist_enable +mpls_mem_entries +vlan_xlate_1_mem_entries +vlan_xlate_2_mem_entries +sai_nbr_bcast_ifp_optimized +sai_brcm_sonic_acl_enhancements +sai_brcm_sonic_trap_group +l2_entry_used_as_my_station +multi_hash_recurse_depth_l3 +serdes_10g_at_25g_vco +serdes_1000x_at_25g_vco +sai_interface_type_auto_detect From a39e2e056081c2d1ed25ae462f9f213ed553da86 Mon Sep 17 00:00:00 2001 From: Arun LK Date: Mon, 30 Aug 2021 18:44:42 +0530 Subject: [PATCH 3/4] DellEMC: N3248PXE Initial platform commit --- .../n3248pxe/sonic_platform/eeprom.py | 2 +- .../n3248pxe/sonic_platform/sfp.py | 20 ++++++++----------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/eeprom.py index 1343265508e0..59ca26a0e408 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/eeprom.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/eeprom.py @@ -28,7 +28,7 @@ def __init__(self): self.eeprom_tlv_dict = dict() try: self.eeprom_data = self.read_eeprom() - except: + except Exception: self.eeprom_data = "N/A" raise RuntimeError("Eeprom is not Programmed") diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/sfp.py index 1a56c036dc86..9674b6a7b1a4 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/sfp.py @@ -10,19 +10,13 @@ try: import os - import time import struct - import sys - import getopt - import select import mmap - from sonic_platform_base.chassis_base import ChassisBase from sonic_platform_base.sfp_base import SfpBase from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom - from sonic_platform_base.sonic_sfp.sff8472 import sffbase except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -540,7 +534,8 @@ def get_presence(self): sfp_mod_prs = self._get_cpld_register('sfp_modprs') if sfp_mod_prs == 'ERR' : return presence presence = ((int(sfp_mod_prs, 16) & bit_mask) == 0) - except: pass + except Exception: + pass return presence @@ -586,7 +581,8 @@ def get_rx_los(self): sfp_rxlos = self._get_cpld_register('sfp_rxlos') if sfp_rxlos == 'ERR' : return rx_los rx_los = ((int(sfp_rxlos, 16) & bit_mask) != 0) - except: pass + except Exception: + pass return rx_los def get_tx_fault(self): @@ -600,7 +596,8 @@ def get_tx_fault(self): sfp_txfault = self._get_cpld_register('sfp_txfault') if sfp_txfault == 'ERR' : return tx_fault tx_fault = ((int(sfp_txfault, 16) & bit_mask) != 0) - except: pass + except Exception: + pass return tx_fault def get_tx_disable(self): @@ -614,7 +611,8 @@ def get_tx_disable(self): sfp_txdisable = self._get_cpld_register('sfp_txdis') if sfp_txdisable == 'ERR' : return tx_disable tx_disable = ((int(sfp_txdisable, 16) & bit_mask) != 0) - except: pass + except Exception: + pass return tx_disable def get_tx_disable_channel(self): @@ -657,7 +655,6 @@ def get_temperature(self): """ Retrieves the temperature of this SFP """ - temperature = 'N/A' try : temperature_data = self._get_eeprom_data('Temperature') temperature = temperature_data['data']['Temperature']['value'] @@ -669,7 +666,6 @@ def get_voltage(self): """ Retrieves the supply voltage of this SFP """ - voltage = 'N/A' try: voltage_data = self._get_eeprom_data('Voltage') voltage = voltage_data['data']['Vcc']['value'] From 42f5b7256e1616b19bc4bdbf3cd8b5bd4e2f03c5 Mon Sep 17 00:00:00 2001 From: Arun LK Date: Tue, 14 Sep 2021 13:35:42 +0530 Subject: [PATCH 4/4] DellEMC: N3248PXE Initial platform commit --- device/dell/x86_64-dellemc_n3248pxe_c3338-r0/installer.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/installer.conf b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/installer.conf index 924e0fb81963..8e3add013c31 100644 --- a/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/installer.conf +++ b/device/dell/x86_64-dellemc_n3248pxe_c3338-r0/installer.conf @@ -1,2 +1,3 @@ CONSOLE_PORT=0x3f8 CONSOLE_DEV=0 +VAR_LOG_SIZE=512