From 16b7c2028f0f732f5bd53b59cfd9a41cd37008d6 Mon Sep 17 00:00:00 2001 From: Arun LK Date: Tue, 24 Aug 2021 15:29:33 +0530 Subject: [PATCH] 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