From 28ca0d7691f59f2befda97fc69a5908fe5e1d3a4 Mon Sep 17 00:00:00 2001 From: Arun LK Date: Thu, 9 Sep 2021 20:27:33 +0530 Subject: [PATCH 1/4] DellEMC: Initial commit for S5224F plaform support --- .../DellEMC-S5224f-P-25G/buffers.json.j2 | 2 + .../buffers_defaults_t0.j2 | 37 + .../buffers_defaults_t1.j2 | 37 + .../DellEMC-S5224f-P-25G/custom_led.bin | Bin 0 -> 340 bytes .../DellEMC-S5224f-P-25G/linkscan_led_fw.bin | Bin 0 -> 10524 bytes .../pg_profile_lookup.ini | 17 + .../DellEMC-S5224f-P-25G/port_config.ini | 29 + .../DellEMC-S5224f-P-25G/qos.json.j2 | 1 + .../DellEMC-S5224f-P-25G/sai.profile | 1 + .../DellEMC-S5224f-P-25G/sai_preinit_cmd.soc | 2 + .../td3-s5224f-25g.config.bcm | 251 +++ .../default_sku | 1 + .../installer.conf | 2 + .../led_proc_init.soc | 6 + .../media_settings.json | 446 +++++ .../plugins/eeprom.py | 32 + .../plugins/pcie.yaml | 21 + .../plugins/psuutil.py | 100 + .../plugins/sfputil.py | 547 ++++++ .../pmon_daemon_control.json | 4 + platform/broadcom/one-image.mk | 1 + platform/broadcom/platform-modules-dell.mk | 6 + .../debian/control | 5 + .../debian/platform-modules-s5224f.init | 40 + .../debian/platform-modules-s5224f.install | 13 + .../debian/platform-modules-s5224f.postinst | 10 + .../sonic-platform-modules-dell/debian/rules | 12 +- .../s5224f/cfg/s5224f-modules.conf | 19 + .../s5224f/cfg/s5224f-params.conf | 1 + .../s5224f/modules/Makefile | 2 + .../s5224f/modules/dell_s5224f_fpga_ocores.c | 1626 +++++++++++++++++ .../s5224f/scripts/check_qsfp.sh | 3 + .../s5224f/scripts/pcisysfs.py | 102 ++ .../s5224f/scripts/platform_sensors.py | 321 ++++ .../s5224f/scripts/qsfp_irq_enable.py | 3 + .../s5224f/scripts/s5224f_platform.sh | 202 ++ .../s5224f/scripts/sensors | 8 + .../s5224f/setup.py | 1 + .../s5224f/sonic_platform/__init__.py | 3 + .../s5224f/sonic_platform/chassis.py | 340 ++++ .../s5224f/sonic_platform/component.py | 113 ++ .../s5224f/sonic_platform/eeprom.py | 133 ++ .../s5224f/sonic_platform/fan.py | 185 ++ .../s5224f/sonic_platform/fan_drawer.py | 37 + .../s5224f/sonic_platform/hwaccess.py | 1 + .../s5224f/sonic_platform/ipmihelper.py | 269 +++ .../s5224f/sonic_platform/platform.py | 25 + .../s5224f/sonic_platform/psu.py | 230 +++ .../s5224f/sonic_platform/sfp.py | 1050 +++++++++++ .../s5224f/sonic_platform/thermal.py | 170 ++ .../s5224f/sonic_platform/watchdog.py | 212 +++ .../systemd/platform-modules-s5224f.service | 13 + 52 files changed, 6691 insertions(+), 1 deletion(-) create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/buffers.json.j2 create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/buffers_defaults_t0.j2 create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/buffers_defaults_t1.j2 create mode 100755 device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/custom_led.bin create mode 100755 device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/linkscan_led_fw.bin create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/pg_profile_lookup.ini create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/port_config.ini create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/qos.json.j2 create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/sai.profile create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/sai_preinit_cmd.soc create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/td3-s5224f-25g.config.bcm create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/default_sku create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/installer.conf create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/led_proc_init.soc create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/media_settings.json create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/eeprom.py create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/pcie.yaml create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/psuutil.py create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/sfputil.py create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/pmon_daemon_control.json create mode 100644 platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5224f.init create mode 100644 platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5224f.install create mode 100644 platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5224f.postinst create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/cfg/s5224f-modules.conf create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/cfg/s5224f-params.conf create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/modules/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/modules/dell_s5224f_fpga_ocores.c create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/check_qsfp.sh create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/pcisysfs.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/platform_sensors.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/qsfp_irq_enable.py create mode 100755 platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/s5224f_platform.sh create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/sensors create mode 120000 platform/broadcom/sonic-platform-modules-dell/s5224f/setup.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/__init__.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/chassis.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/component.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/eeprom.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan_drawer.py create mode 120000 platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/hwaccess.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/ipmihelper.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/platform.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/psu.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/sfp.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/thermal.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/watchdog.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5224f/systemd/platform-modules-s5224f.service diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/buffers.json.j2 b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/buffers.json.j2 new file mode 100644 index 000000000000..0b1cb2c541b6 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/buffers.json.j2 @@ -0,0 +1,2 @@ +{%- set default_topo = 't1' %} +{%- include 'buffers_config.j2' %} diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/buffers_defaults_t0.j2 b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/buffers_defaults_t0.j2 new file mode 100644 index 000000000000..12283a072c9a --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/buffers_defaults_t0.j2 @@ -0,0 +1,37 @@ + +{%- set default_cable = '5m' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "26531072", + "type": "ingress", + "mode": "dynamic", + "xoff": "6291456" + }, + "egress_lossless_pool": { + "size": "32822528", + "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", + "mode": "static", + "static_th":"32822528" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"0", + "mode": "dynamic", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/buffers_defaults_t1.j2 b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/buffers_defaults_t1.j2 new file mode 100644 index 000000000000..ca0528e61465 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/buffers_defaults_t1.j2 @@ -0,0 +1,37 @@ + +{%- set default_cable = '40m' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "26531072", + "type": "ingress", + "mode": "dynamic", + "xoff": "6291456" + }, + "egress_lossless_pool": { + "size": "32822528", + "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", + "mode": "static", + "static_th":"32822528" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"0", + "mode": "dynamic", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/custom_led.bin b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/custom_led.bin new file mode 100755 index 0000000000000000000000000000000000000000..632e7e106e1b14852b6488b2b35a0e47ff716305 GIT binary patch literal 340 zcmeyc^`2X}o1dGj+k>sm8yJ-sRBU}~T^MZ}lxMlsTF-G~vYzS2?J&d5!n@jqakAJ0 z#@TWi#d7l;%bdL3<~cK)O=fV<*zFeWBG!RfaCT$RzI=gM z?c#G8pqsLcnT z^Dr_n$N}*x1_p)&KwJRCNkAM0#3G_%;u4Zl(lWAg@&<-R#wMm_<`$M#)(VPB$||aA R>Kd9_+B&*=`aq>%002fiXKMfe literal 0 HcmV?d00001 diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/linkscan_led_fw.bin b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/linkscan_led_fw.bin new file mode 100755 index 0000000000000000000000000000000000000000..86cf30e80fbff201f7d4c8ab64da0fbf15a688ff GIT binary patch literal 10524 zcmdUVeSA}8mhibZ-)Y*Wr4DIH%T2#XD@ckc0Ufa~ zXaCsW`}@7^@ARJg+~+*!Jm=$io^zgp58!72@UIBJMfmT2qL+OfLHs@n;0!+h7QFpG z=<~P6xbnNg^#hJhY#jp^G<`#X3~(Nqc<$F2qL_#x(&<-GXCN^&WVz9wx57zj|zpaNoA9`?7HVUNCkJerCl z-x&U0fS51za0}Gj?Rm)kuI_wRflI zQu4gCYK4kR2w*jfP<4@C;2rS(xJ-jGJmR3w?kF4NA@-Uq#plsHl%n5}cQ(g8<{j`5 z3F4_^C_y4hW~An%~$e3 zdS3H<8Yevcg5E+W=ABQ40!CprhauPgc zu`G{mo>QJ={50xJD~c7P zz<(U!$)M~DUDzfiQ<*ZC|DvuJ82`nR-alO|@zWNqli;sj{LbS#MoPYtp%UISmDn#8 zEiYP8yt25(%2_zT`G9pSYT;~%TM)m9xE=9Xh+jZl=Yqslh{vN~(PI0)$=}Ce6T1IT z5JCWfZCRND+tD`}U(-J}7YkZe&-OT!;zNiNjEYkDg?#N=2BA{!doC&Ykpxylw3PcU z;{S=bI(omWluO&CoIm>U01#6$AvvB9DJNj=h}mD{#;tR$`&?;l!zabV2yDK|GtdpdVNps z$J_9F=I0sG18-uKdT9F?#luVPUzd!~V*61yaZCy~Tjx_Lm$Zj>au zWT)*Gp)f|iKP-PYh!)EZD%;~uNo8@L@X?zPG8vY@B;x^rFiz zNJ&eE%=yz$VtLPi71tn21SS(!S# zQxRvaz0bM6^@CEcX$4Oo*vSv^cX4?hsM_htTlc1?&Ae>gLXNKgaFjJeU$5hLBMjQ_ zsm$vwRLw!Ou~w`=8=rJj9E7R&UncB=tJ#>9)REu$9488c}5vr?c-uXfcR6=QMwZ}Pw zV@+1eDrX~7Et9E$AyiOTIQmRWhwz*uZ&)SM^tEIuSkr4AJsqT1Rwk%3jy@stFbu1z zX3_1=$Cp86#MD}~#>tv`I!<&LIbRd$>ubu&zrERSYOP#_Uvn)z(=Aq;uPGHOkRxkO z1_CgzP_%Jcn}++?OC?^Ibd+cP@>~Y2DztCJnUdv5h3yzYPvZAuTos4=nV^q72KR8k zTC*MATXl_>HM`B*91x|M-Htzx@Isx}j~+;mP>E|Nd(Au#!Moi`;coPhCnl*HT%|;^ zw&*i+Io7$N zf}`zQ;B;#}^6oJI6X9Kb+;MS)4*H?QMkSt})b^p}d7W5N=|$O9liDD?pAuBe+ogsW zjbpwQ|Ee);D1W3hEC0wuui3_{gW-58RKjUMC&FGWmybHjpvLki8_R()#EAY=;U$;J z(gTOve+YkW?M0a&SSR?Qp_R-p8LDaN87SmbU=-~*$|qio?!+G_9OVu2iZB~Bua-5h znw~QRsl?d{wj2UJ;g{S3)ISx_$9AIr)9u?~WYyKO{$d>>#@wL(Vjt|C0nl)VTcdcZqXOoRMU^p_ON+=UnAO%R@gCIp zE+|_?H10O{WV!7p_6DXOcXlP{#mw@Is}3Xl-~{m>2KTwoCdg^P7p~*R(BgZsT_LwW zkRffKW7{L7Z?ulPi1^m&?~`d?_yUeacCrU1D6XS|*KGx;BR&6!J-;*6Q?fm6qhkyw z*}iL&lAj{CPec0$%7S3MR*Wr&>W!S?C7xo~}mIXJMsa1w~ z?~ejA3$3I;>yO71xJNxY;KG&XTN5f+BG#3w5LZvsaYlU7_|!I#ePuEY48?8adVn>* z+-k6nk21ow++ZOKR3!ugFsHrEycr6evs;<=!9qj*=Oa*k5E@Hu?IjIV;=Oc-*)aFg z=wZ|i2)LGJl;}59BAsTqe3XT(R^zy`J+}-PGe>i_h23y_D{EedoW@3}SJ_Mk>jAx?{ZZat&rjTnc)mY)o0Kq=bGsYG9z!fy7~jgQ-e4(qJoHcQzpG~I1snC2f3R;MaF*L528lz?fk=cg5 zUQWY)ilLpbC;J{kAE6RI`O>IA9iKft>SOY#WtWZm^tf_r)WYdex23<(1mW@sj#?fg z=V@|=CFj@NxrLllw%!78E3P-K2$!E#Y-A0RB&i*rc%uH2OzX!xr)64-G9^Nf4*>J+ zl}au@U^uL_e4Vo+Uq`y&Fj%aJeLY68fS0Vqm+AHpBB*L z6O;J?uzoGNdc|t@7O*XTqy6*tPHwn8pDkh^bx_K|Bxfn-DKUoW$6Th?gL)5SO@!4IdcG4;ErP zWkL-r=P#!N)FC=3B{xqfq2MhlsOA8z`tBHIHHfrziKwuCT~u0GQBnQAlfwN#fgX|x zFXpOn)IVa*s){b=EQtR>&R-$1JB2=jhy4+z$H^{$DXsiy{Ox%5 z+kX6(^_J}WGvlE+$!DbG^BHX{i@lyvOkp44xX+6}ixc}1+a5zZ6CcRgKIaQ};I~BR z=nAMAsDd1Ui(2*KF-&Iz1a;@%F$n_h@Rq;EL#T21O7W7>gN#hw7C~+FMfOEJ5-FE3c*_SZga)kGo^x8O`CO_skdiQl|N^%7M|puaGsbs zT<{cEY`U6XUGyy6%cV_ix;Cn(Y?eSV0aoFlVuqL|rVx4Ve$ME$VkO~a$FJY*Fy{vk zI<}qzCLFhiNZ!U)%xhtFYLT**h<<=ltgZy?c$R>~eAJ3kq!6n|jEcta3vIzwk5R`M z7e32LU&=yb9&#O8%^sf7jFqJ-?Se9Q8P4`SJY(gJmb$QV)Cm+@DDp)Qx;5@X7rUEp z#l27C)(cRNoGW`+mq3$MVJhziFer+Qb{61$^mk}P%hJZV0LT46Yt2B@0Cd+v|8C6J zwgC;aeJ%@?MkzFk{%`9#+tNKS6IcCfM2t_2)B32b>x>&{hl%Pd;z!)N@+G5JLJ|)%Tz2ph>K(>ilYziaSN9sgll~y92xv7>NCjqyiXc@5rQO=?t{uR(OBVX@oCYcR zkVFS51I1FoUZ2RY*~vIm6?IsN zBbm{YvXt-3l%3O*IT=c(W%xEy$7E_+rnM6(`Y>*ET9!zmnwDa8WPMC|AaaB8YGG<_ zxBkVrU(BubOLNQrin%GL=GHhp(wFCU(_hT(NG3Zsr8PUZYo{sya&GglnA_>hU!R-O zIy!<@wEL{4;d1xaS)G9AUW}-Ehfb_AeG_)BHLd)GLo>YAymR$Fry>TGRi?FYx{Wn6 z)(=Ol+<^~@U6cTIYH@~3C$JSzrx3~RNvbQP&PsLzUlZ2Vvb6}}`}l=f0f0dV2Cyhx z_&ll0oxb*tLvis+)rK>A5TojN8l^tSDZjPT2qnK1C?vNU`z?zF+uh%QRmSId0?&mwCV1Nk;g0 z%+-~BHa1c>WB7(xC*R|L)G1; z4X}E(+sxE`FtR#6f67N}|Ba8-Ug0BBs9au;%cj?3DLINeAX$%RPOryTO|Qqre{((7 zf8}~CB_k5V0WSB;mMi@7_#6OxZPqWb7F@f?Z9kYv1}CBNy5*$KR?qvwA6huX*`E1&!|W&gelACaSBgtndEpz;K_+ClgwlkTt9DZ&c2<B4oOC#UF zeGO$54V(FU#r@#hiGL%bOAXAxH+ZbZBfaauetWReo*3cm1_xd5p}{7WGK$q6nL zz+XK_lG-lTP7}9Id+e-nQ1-AyzB$lO`K9FxxRbA#@)CO5)~6{MWgO@^$swUUMR4YV+9{85flS; z7J(M~S;|Sp`mruxL0yn@iE+Zt(S1_#kd(pfOo{TAEG*#28E`DkR%}1YVCD>oi|NSG z#n|@iF$<1(DUBH&wq>h7yCjm=5y}FjHDT{_X+no96OPb*bP3^}czFzI@OgHM>OQ2x z`U_WL%g6dRBu*d)NDPc+rFuPGhcZaXZ%RJQ>bDFif+aR3M+G2pB(35Yl;LptWUN|_hcA_q#A^!1}y=L&*hJPtus0kHuj=1q-wDwE0T>shEN zSw!w~zLs8ELG-lMvGjLYUfZ-k1?tH)F82CP4z-Qkl4(0?luCc2xw|ajxIrvBcdOe` z*6UaxD$nVySBo9i+Gu^O)nznYEv|GAIc7&y%#7Fym%gmqVHGv!T3lLFrPzXBigAZi z$C|Nch1iVm`e+_%%~Mt?QgyRLx^BLxsH=`HhymVnFfocr#A)V}xPtjOu4F!ptC{n0 z4f8=<$GjicGkDk3r_<|bWlXAszG8Z}6KKi_yRUZXr{wuZ_3bdxvvuY zD$f&oyyXP-AFzS}7TE2@wWV%S3C6b+wea*MC(P4}R-F0PaRor)g>j9>FtgZfxycEn zu92-OFPF1Na_`~8s?|cwBniGflfpccU{7Z*PGL^zlPTpF=E|us069HSm^s*8cy3@o zf%S2Q#lLwn4tT@*iL^thGqAVgT@=2>&CoGn58%^?025#Piid7-!CNn$(sGiI0Utp9_=2e#7Ycl`E=YKE_FvVI^nd? zh83kqA&peNrV_GGJrvPI3VlsQ?uc3^JmMv}Q>1`)K7#kz23H440FRL#B=2!oq@%tj zjoj+LqE*6Noal?_EfIRDd3Mby;mER=T7ImG3UE!Scv}}W=O*WEzHN_a9=SAYlld6; z8}F;C3U+h;P0o9`&8k}VRsBuQ-*`0NKjM_sn{@;~<;_ykS;}3SU0KS4&cCEASf_b3 zM_I7$RA-h_DN}BLO#Rravo@Q5$*t`CscJU6DSwgk+uSDA9QLRBMb4G$)Q`X9yrkZw zBlxL%vy@tyvT40~eU|d^ze4%=x^3%ol#j1FwH~gSiSsndlM;S_Pkf|myAF5bs9aZhk;$oYiwfGwv(+_S~U zwFRu5T!m<`97M^3V-PgRzDoXAg0vhMBQxm7b3r6i>GBBuO{B{7ZyCNzO8!`GRdac< zEcFA^)LGhp9OF@Tp69)&trS@Y@a7BUdv{Dqw%{qFNIqo@r8I7^x;#3(Y3=3>Qzr}> zPZ*OJf%0uM`Y@HkVxcA?kvq<%x3skXUk>1*3T(Fn++2xghfp3zbiv>~oi3KoonfDL zs7A`UeXM&{4gO_Iuj1M&VBV+aY+(hL=RBZMh`N~ejpEtbh_ZfsSP{$XQuxTtMq9<$ zu&-(OC>5j0dqo=Gpz;#d)Ms#5r{PL*rAo+h$+x+Tf`iyv^Air$@W*!y-NBSmQJ8xv zid-yE&Q>V8is>?^yJGANxu;Wbib|~y^n}a!856ds@s3ixLKXXipn3CZr{Tt6lX2lO zM{;B`xiQma1qdS8j{O7Pf7En!n1AGe;d1V-JJ-S=OtxQ|ngCFv)+!NCsFg6gR8Yja z9g4Gh&W(A~SQP5@;tXMH*;5W>6a~yH!xueW!x<#Sj0*RyV6%Mqb@qTsEv7hNTgTvGZ@o{Ww11p=<>#7Gk+1rX4~X3l4cLi~o{N9aWeA{;~*Ksb&tgdifs5Y8i{5a2rG zhhRdmBG?dE1Q$X(0*~NB=tAg42p}9p=tuZ}JwG1xljGTicuubY#B;jsM?9zB2;xHs zM8{_la(Yf6p3}7!^_J5&gSZue=-iHw(|ar8Io%70`w)o!{Rq7X0fZnz&JF{JA4iBF z3?YaJXAyYRcg{v#i0AASKs;xwe#CS3iXfh|*;&MMc1s|hvz-?0kh33yxD|oe(2kI^ zV=Ll0TMCH#5Qshf2)zgagdjrBt^S@Irve}l}%rI$0huK{pY^`BXts7 literal 0 HcmV?d00001 diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/pg_profile_lookup.ini b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/pg_profile_lookup.ini new file mode 100644 index 000000000000..a8cf083ec04d --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/pg_profile_lookup.ini @@ -0,0 +1,17 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold xon_offset + 10000 5m 1024 2048 46080 -3 2048 + 25000 5m 1024 2048 65024 -3 2048 + 40000 5m 1024 2048 77056 -3 2048 + 50000 5m 1024 2048 93440 -3 2048 + 100000 5m 1024 2048 162048 -3 2048 + 10000 40m 1024 2048 47360 -3 2048 + 25000 40m 1024 2048 67840 -3 2048 + 40000 40m 1024 2048 81664 -3 2048 + 50000 40m 1024 2048 99072 -3 2048 + 100000 40m 1024 2048 173568 -3 2048 + 10000 300m 1024 2048 57088 -3 2048 + 25000 300m 1024 2048 92672 -3 2048 + 40000 300m 1024 2048 121344 -3 2048 + 50000 300m 1024 2048 148736 -3 2048 + 100000 300m 1024 2048 272640 -3 2048 diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/port_config.ini b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/port_config.ini new file mode 100644 index 000000000000..b17acc6caf99 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/port_config.ini @@ -0,0 +1,29 @@ +# name lanes alias index speed +Ethernet0 21 twentyfiveGigE1/1 1 25000 +Ethernet1 22 twentyfiveGigE1/2 2 25000 +Ethernet2 23 twentyfiveGigE1/3 3 25000 +Ethernet3 24 twentyfiveGigE1/4 4 25000 +Ethernet4 25 twentyfiveGigE1/5 5 25000 +Ethernet5 26 twentyfiveGigE1/6 6 25000 +Ethernet6 27 twentyfiveGigE1/7 7 25000 +Ethernet7 28 twentyfiveGigE1/8 8 25000 +Ethernet8 29 twentyfiveGigE1/9 9 25000 +Ethernet9 30 twentyfiveGigE1/10 10 25000 +Ethernet10 31 twentyfiveGigE1/11 11 25000 +Ethernet11 32 twentyfiveGigE1/12 12 25000 +Ethernet12 49 twentyfiveGigE1/13 13 25000 +Ethernet13 50 twentyfiveGigE1/14 14 25000 +Ethernet14 51 twentyfiveGigE1/15 15 25000 +Ethernet15 52 twentyfiveGigE1/16 16 25000 +Ethernet16 53 twentyfiveGigE1/17 17 25000 +Ethernet17 54 twentyfiveGigE1/18 18 25000 +Ethernet18 55 twentyfiveGigE1/19 19 25000 +Ethernet19 56 twentyfiveGigE1/20 20 25000 +Ethernet20 57 twentyfiveGigE1/21 21 25000 +Ethernet21 58 twentyfiveGigE1/22 22 25000 +Ethernet22 59 twentyfiveGigE1/23 23 25000 +Ethernet23 60 twentyfiveGigE1/24 24 25000 +Ethernet24 33,34,35,36 hundredGigE1/25 25 100000 +Ethernet28 37,38,39,40 hundredGigE1/26 26 100000 +Ethernet32 41,42,43,44 hundredGigE1/27 27 100000 +Ethernet36 45,46,47,48 hundredGigE1/28 28 100000 diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/qos.json.j2 b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/qos.json.j2 new file mode 100644 index 000000000000..3e548325ea30 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/qos.json.j2 @@ -0,0 +1 @@ +{%- include 'qos_config.j2' %} diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/sai.profile b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/sai.profile new file mode 100644 index 000000000000..5b040308b2e1 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td3-s5224f-25g.config.bcm diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/sai_preinit_cmd.soc b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/sai_preinit_cmd.soc new file mode 100644 index 000000000000..4d62900f898f --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/sai_preinit_cmd.soc @@ -0,0 +1,2 @@ +m0 load 0 0x0 /usr/share/sonic/hwsku/linkscan_led_fw.bin +m0 load 0 0x3800 /usr/share/sonic/hwsku/custom_led.bin diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/td3-s5224f-25g.config.bcm b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/td3-s5224f-25g.config.bcm new file mode 100644 index 000000000000..f88ebcf3aa73 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/td3-s5224f-25g.config.bcm @@ -0,0 +1,251 @@ +os=unix +portmap_1.0=21:25 +portmap_2.0=22:25 +portmap_3.0=23:25 +portmap_4.0=24:25 +portmap_5.0=25:25 +portmap_6.0=26:25 +portmap_7.0=27:25 +portmap_8.0=28:25 +portmap_9.0=29:25 +portmap_10.0=30:25 +portmap_11.0=31:25 +portmap_12.0=32:25 +portmap_13.0=33:100 +portmap_17.0=37:100 +portmap_47.0=41:100 +portmap_51.0=45:100 +portmap_35.0=49:25 +portmap_36.0=50:25 +portmap_37.0=51:25 +portmap_38.0=52:25 +portmap_39.0=53:25 +portmap_40.0=54:25 +portmap_41.0=55:25 +portmap_42.0=56:25 +portmap_43.0=57:25 +portmap_44.0=58:25 +portmap_45.0=59:25 +portmap_46.0=60:25 +phy_chain_tx_lane_map_physical{21.0}=0x0123 +phy_chain_rx_lane_map_physical{21.0}=0x1032 +phy_chain_tx_lane_map_physical{25.0}=0x0123 +phy_chain_rx_lane_map_physical{25.0}=0x1032 +phy_chain_tx_lane_map_physical{29.0}=0x0123 +phy_chain_rx_lane_map_physical{29.0}=0x1032 +phy_chain_tx_lane_map_physical{33.0}=0x0132 +phy_chain_rx_lane_map_physical{33.0}=0x1302 +phy_chain_tx_lane_map_physical{37.0}=0x2310 +phy_chain_rx_lane_map_physical{37.0}=0x3201 +phy_chain_tx_lane_map_physical{41.0}=0x3210 +phy_chain_rx_lane_map_physical{41.0}=0x1032 +phy_chain_tx_lane_map_physical{45.0}=0x2031 +phy_chain_rx_lane_map_physical{45.0}=0x1320 +phy_chain_tx_lane_map_physical{49.0}=0x3210 +phy_chain_rx_lane_map_physical{49.0}=0x2301 +phy_chain_tx_lane_map_physical{53.0}=0x3210 +phy_chain_rx_lane_map_physical{53.0}=0x2301 +phy_chain_tx_lane_map_physical{57.0}=0x3210 +phy_chain_rx_lane_map_physical{57.0}=0x2301 +phy_chain_tx_polarity_flip_physical{21.0}=0x0 +phy_chain_rx_polarity_flip_physical{21.0}=0x1 +phy_chain_tx_polarity_flip_physical{22.0}=0x1 +phy_chain_rx_polarity_flip_physical{22.0}=0x0 +phy_chain_tx_polarity_flip_physical{23.0}=0x0 +phy_chain_rx_polarity_flip_physical{23.0}=0x1 +phy_chain_tx_polarity_flip_physical{24.0}=0x1 +phy_chain_rx_polarity_flip_physical{24.0}=0x0 +phy_chain_tx_polarity_flip_physical{25.0}=0x0 +phy_chain_rx_polarity_flip_physical{25.0}=0x1 +phy_chain_tx_polarity_flip_physical{26.0}=0x1 +phy_chain_rx_polarity_flip_physical{26.0}=0x0 +phy_chain_tx_polarity_flip_physical{27.0}=0x0 +phy_chain_rx_polarity_flip_physical{27.0}=0x1 +phy_chain_tx_polarity_flip_physical{28.0}=0x1 +phy_chain_rx_polarity_flip_physical{28.0}=0x0 +phy_chain_tx_polarity_flip_physical{29.0}=0x0 +phy_chain_rx_polarity_flip_physical{29.0}=0x1 +phy_chain_tx_polarity_flip_physical{30.0}=0x1 +phy_chain_rx_polarity_flip_physical{30.0}=0x0 +phy_chain_tx_polarity_flip_physical{31.0}=0x0 +phy_chain_rx_polarity_flip_physical{31.0}=0x1 +phy_chain_tx_polarity_flip_physical{32.0}=0x1 +phy_chain_rx_polarity_flip_physical{32.0}=0x0 +phy_chain_tx_polarity_flip_physical{33.0}=0x1 +phy_chain_rx_polarity_flip_physical{33.0}=0x0 +phy_chain_tx_polarity_flip_physical{34.0}=0x0 +phy_chain_rx_polarity_flip_physical{34.0}=0x1 +phy_chain_tx_polarity_flip_physical{35.0}=0x1 +phy_chain_rx_polarity_flip_physical{35.0}=0x1 +phy_chain_tx_polarity_flip_physical{36.0}=0x1 +phy_chain_rx_polarity_flip_physical{36.0}=0x1 +phy_chain_tx_polarity_flip_physical{37.0}=0x0 +phy_chain_rx_polarity_flip_physical{37.0}=0x1 +phy_chain_tx_polarity_flip_physical{38.0}=0x1 +phy_chain_rx_polarity_flip_physical{38.0}=0x0 +phy_chain_tx_polarity_flip_physical{39.0}=0x1 +phy_chain_rx_polarity_flip_physical{39.0}=0x0 +phy_chain_tx_polarity_flip_physical{40.0}=0x0 +phy_chain_rx_polarity_flip_physical{40.0}=0x0 +phy_chain_tx_polarity_flip_physical{41.0}=0x0 +phy_chain_rx_polarity_flip_physical{41.0}=0x0 +phy_chain_tx_polarity_flip_physical{42.0}=0x1 +phy_chain_rx_polarity_flip_physical{42.0}=0x1 +phy_chain_tx_polarity_flip_physical{43.0}=0x1 +phy_chain_rx_polarity_flip_physical{43.0}=0x0 +phy_chain_tx_polarity_flip_physical{44.0}=0x1 +phy_chain_rx_polarity_flip_physical{44.0}=0x1 +phy_chain_tx_polarity_flip_physical{45.0}=0x0 +phy_chain_rx_polarity_flip_physical{45.0}=0x0 +phy_chain_tx_polarity_flip_physical{46.0}=0x0 +phy_chain_rx_polarity_flip_physical{46.0}=0x1 +phy_chain_tx_polarity_flip_physical{47.0}=0x0 +phy_chain_rx_polarity_flip_physical{47.0}=0x1 +phy_chain_tx_polarity_flip_physical{48.0}=0x1 +phy_chain_rx_polarity_flip_physical{48.0}=0x1 +phy_chain_tx_polarity_flip_physical{49.0}=0x0 +phy_chain_rx_polarity_flip_physical{49.0}=0x1 +phy_chain_tx_polarity_flip_physical{50.0}=0x1 +phy_chain_rx_polarity_flip_physical{50.0}=0x0 +phy_chain_tx_polarity_flip_physical{51.0}=0x0 +phy_chain_rx_polarity_flip_physical{51.0}=0x1 +phy_chain_tx_polarity_flip_physical{52.0}=0x1 +phy_chain_rx_polarity_flip_physical{52.0}=0x0 +phy_chain_tx_polarity_flip_physical{53.0}=0x0 +phy_chain_rx_polarity_flip_physical{53.0}=0x1 +phy_chain_tx_polarity_flip_physical{54.0}=0x1 +phy_chain_rx_polarity_flip_physical{54.0}=0x0 +phy_chain_tx_polarity_flip_physical{55.0}=0x0 +phy_chain_rx_polarity_flip_physical{55.0}=0x1 +phy_chain_tx_polarity_flip_physical{56.0}=0x1 +phy_chain_rx_polarity_flip_physical{56.0}=0x0 +phy_chain_tx_polarity_flip_physical{57.0}=0x0 +phy_chain_rx_polarity_flip_physical{57.0}=0x1 +phy_chain_tx_polarity_flip_physical{58.0}=0x1 +phy_chain_rx_polarity_flip_physical{58.0}=0x0 +phy_chain_tx_polarity_flip_physical{59.0}=0x0 +phy_chain_rx_polarity_flip_physical{59.0}=0x1 +phy_chain_tx_polarity_flip_physical{60.0}=0x1 +phy_chain_rx_polarity_flip_physical{60.0}=0x0 +dport_map_port_1=1 +dport_map_port_2=2 +dport_map_port_3=3 +dport_map_port_4=4 +dport_map_port_5=5 +dport_map_port_6=6 +dport_map_port_7=7 +dport_map_port_8=8 +dport_map_port_9=9 +dport_map_port_10=10 +dport_map_port_11=11 +dport_map_port_12=12 +dport_map_port_35=13 +dport_map_port_36=14 +dport_map_port_37=15 +dport_map_port_38=16 +dport_map_port_39=17 +dport_map_port_40=18 +dport_map_port_41=19 +dport_map_port_42=20 +dport_map_port_43=21 +dport_map_port_44=22 +dport_map_port_45=23 +dport_map_port_46=24 +dport_map_port_13=25 +dport_map_port_14=26 +dport_map_port_15=27 +dport_map_port_16=28 +dport_map_port_17=29 +dport_map_port_18=30 +dport_map_port_19=31 +dport_map_port_20=32 +dport_map_port_47=33 +dport_map_port_48=34 +dport_map_port_49=35 +dport_map_port_50=36 +dport_map_port_51=37 +dport_map_port_52=38 +dport_map_port_53=39 +dport_map_port_54=40 + +dpp_clock_ratio=2:3 +oversubscribe_mode=1 +core_clock_frequency=1525 +pbmp_oversubscribe=0x7fff9fffffffffffffffe +pbmp_xport_xe=0x7fff9fffffffffffffffe +port_flex_enable=1 +phy_an_c73=3 + +#25G,10G,1G support +serdes_10g_at_25g_vco=1 +serdes_1000x_at_25g_vco=1 + +l2xmsg_mode=1 + +#Need for mac learn scale +l2xmsg_hostbuf_size=16384 +module_64ports=0 + +#Interrupts and Parity +max_vp_lags=0 + +schan_intr_enable=0 +tdma_timeout_usec=5000000 + +# Following added by BRCM +stable_size=0x5500000 + +#Default L3 profile +l2_mem_entries=32768 +l3_alpm_enable=2 +l3_alpm_ipv6_128b_bkt_rsvd=1 + +#check correct value +l2_mem_entries=40960 +l3_mem_entries=40960 + +#Tunnels +use_all_splithorizon_groups=1 +sai_tunnel_support=1 +bcm_tunnel_term_compatible_mode=1 + +ptp_ts_pll_fref=50000000 +ptp_bs_fref_0=50000000 +ptp_bs_fref_1=50000000 + +#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)) +mem_cache_enable=0 +ifp_inports_support_enable=1 +ipv6_lpm_128b_enable=0x1 +l3_max_ecmp_mode=1 +lpm_scaling_enable=0 +bcm_num_cos=10 +default_cpu_tx_queue=9 +mmu_lossless=0 +host_as_route_disable=1 +sai_eapp_config_file=/etc/broadcom/eapps_cfg.json +sai_fast_convergence_support=1 +flow_init_mode=1 +mpls_mem_entries=16384 +vlan_xlate_1_mem_entries=65536 +vlan_xlate_2_mem_entries=16384 +sai_load_hw_config=/usr/lib/cancun/ +sai_nbr_bcast_ifp_optimized=1 +sai_brcm_sonic_acl_enhancements=1 +# Reduced Trap Group QSET for BRCM Sonic +sai_brcm_sonic_trap_group=1 +l2_entry_used_as_my_station=1 +multi_hash_recurse_depth_l3=2 +sai_interface_type_auto_detect=0 diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/default_sku b/device/dell/x86_64-dellemc_s5224f_c3538-r0/default_sku new file mode 100644 index 000000000000..99d108897200 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/default_sku @@ -0,0 +1 @@ +DellEMC-S5224f-P-25G t1 diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/installer.conf b/device/dell/x86_64-dellemc_s5224f_c3538-r0/installer.conf new file mode 100644 index 000000000000..924e0fb81963 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/installer.conf @@ -0,0 +1,2 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/led_proc_init.soc b/device/dell/x86_64-dellemc_s5224f_c3538-r0/led_proc_init.soc new file mode 100644 index 000000000000..a00dfd181f4a --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/led_proc_init.soc @@ -0,0 +1,6 @@ +# LED microprocessor initialization for Dell S5224 +# +# +#Led0 +led auto on +led start diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/media_settings.json b/device/dell/x86_64-dellemc_s5224f_c3538-r0/media_settings.json new file mode 100644 index 000000000000..86050eb4a6f3 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/media_settings.json @@ -0,0 +1,446 @@ +{ + "GLOBAL_MEDIA_SETTINGS": { + "1-24": { + "(.*-C6Y7M)|(.*-V250M)|(.*-05CWK6)|(.*-53HVN)|(.*-358VV)|(.*-MV799)|(.*-59970000.)|(.*-P4YPY)|(.*-TCPM2)|(.*-JNPF8)|(.*-27GG5)|(.*-P8T4W)|(.*-JR54Y)|(.*-L56[SQ]F0..-SD-R)|(.*-61676000.)|(.*-74752.*)|(SFP\\+-CR-.*)": { + "preemphasis": { + "lane0": "0x19410a" + } + }, + "(.*-58KM3)|(.*-2JVDD)|(.*-26FN3)|(SFP28-CR-((0\\.5)|(1\\.0)|(0\\.0)|(N/A)))": { + "preemphasis": { + "lane0": "0x19410a" + } + }, + "(.*-D0R73)|(.*-YFNDD)|(SFP28-CR-2\\.0)": { + "preemphasis": { + "lane0": "0x19410a" + } + }, + "(.*-VXFJY)|(.*-9X8JP)|(.*-7R9N9)|(SFP28-CR-.*)": { + "preemphasis": { + "lane0": "0x19410a" + } + } + }, + "25-28": { + "QSFP\\+-CR-.*": { + "preemphasis": { + "lane0": "0x18420a", + "lane1": "0x18420a", + "lane2": "0x18420a", + "lane3": "0x18420a" + } + }, + "(.*-035KG)|(.*-P7C7N)|(QSFP28-CR-((0\\.5)|(1\\.0)|(0\\.0)|(N/A)))": { + "preemphasis": { + "lane0": "0x18420a", + "lane1": "0x18420a", + "lane2": "0x18420a", + "lane3": "0x18420a" + } + }, + "(.*-76V43)|(QSFP28-CR-2\\.0)": { + "preemphasis": { + "lane0": "0x18420a", + "lane1": "0x18420a", + "lane2": "0x18420a", + "lane3": "0x18420a" + } + }, + "(.*-3CC35)|(.*-FN4FC)|(QSFP28-CR-.*)": { + "preemphasis": { + "lane0": "0x18420a", + "lane1": "0x18420a", + "lane2": "0x18420a", + "lane3": "0x18420a" + } + } + } + }, + "PORT_MEDIA_SETTINGS": { + "1": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x0b3c02" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x14460a" + } + } + }, + "2": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x0b3c02" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x14460a" + } + } + }, + "3": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x0a3b02" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x14460a" + } + } + }, + "4": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x0a3b02" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x14460a" + } + } + }, + "5": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x0a3b02" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x14460a" + } + } + }, + "6": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x093a02" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "7": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x083902" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "8": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x083902" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "9": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073802" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "10": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073802" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "11": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073702" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x124909" + } + } + }, + "12": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073702" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x124909" + } + } + }, + "13": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x093a02" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "14": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x083902" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "15": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x083902" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "16": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x083902" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "17": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x083902" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "18": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073802" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "19": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x083902" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "20": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073802" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "21": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073802" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "22": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073802" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "23": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073802" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "24": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073802" + } + }, + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a" + } + } + }, + "25": { + "(.*-14NV5)|(.*-D7P80)|(.*-THPF3)|(.*-X7CCC)|(.*-YKMH7)|(.*-0X9CT)|(.*-05J8P)|(.*-5WGKD)|(.*-XFDRT)|(.*-1002971101)|(QSFP28-.*)": { + "preemphasis": { + "lane0": "0x114b08", + "lane1": "0x114b08", + "lane2": "0x114b08", + "lane3": "0x114b08" + } + }, + "QSFP\\+-.*": { + "preemphasis": { + "lane0": "0x114b08", + "lane1": "0x114b08", + "lane2": "0x114b08", + "lane3": "0x114b08" + } + } + }, + "26": { + "(.*-14NV5)|(.*-D7P80)|(.*-THPF3)|(.*-X7CCC)|(.*-YKMH7)|(.*-0X9CT)|(.*-05J8P)|(.*-5WGKD)|(.*-XFDRT)|(.*-1002971101)|(QSFP28-.*)": { + "preemphasis": { + "lane0": "0x0f4d08", + "lane1": "0x0f4d08", + "lane2": "0x0f4d08", + "lane3": "0x0f4d08" + } + }, + "QSFP\\+-.*": { + "preemphasis": { + "lane0": "0x0f4d08", + "lane1": "0x0f4d08", + "lane2": "0x0f4d08", + "lane3": "0x0f4d08" + } + } + }, + "27": { + "(.*-14NV5)|(.*-D7P80)|(.*-THPF3)|(.*-X7CCC)|(.*-YKMH7)|(.*-0X9CT)|(.*-05J8P)|(.*-5WGKD)|(.*-XFDRT)|(.*-1002971101)|(QSFP28-.*)": { + "preemphasis": { + "lane0": "0x0e4f07", + "lane1": "0x0e4f07", + "lane2": "0x0e4f07", + "lane3": "0x0e4f07" + } + }, + "QSFP\\+-.*": { + "preemphasis": { + "lane0": "0x0e4f07", + "lane1": "0x0e4f07", + "lane2": "0x0e4f07", + "lane3": "0x0e4f07" + } + } + }, + "28": { + "(.*-14NV5)|(.*-D7P80)|(.*-THPF3)|(.*-X7CCC)|(.*-YKMH7)|(.*-0X9CT)|(.*-05J8P)|(.*-5WGKD)|(.*-XFDRT)|(.*-1002971101)|(QSFP28-.*)": { + "preemphasis": { + "lane0": "0x0f4d08", + "lane1": "0x0f4d08", + "lane2": "0x0f4d08", + "lane3": "0x0f4d08" + } + }, + "QSFP\\+-.*": { + "preemphasis": { + "lane0": "0x0f4d08", + "lane1": "0x0f4d08", + "lane2": "0x0f4d08", + "lane3": "0x0f4d08" + } + } + } + } +} diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/eeprom.py b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/eeprom.py new file mode 100644 index 000000000000..7c137a808031 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/eeprom.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +############################################################################# +# DellEMC S5224f +# +# 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 +############################################################################# + +import os.path + +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 = None + for b in (0, 1): + f = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom'.format(b) + if os.path.exists(f): + self.eeprom_path = f + break + if self.eeprom_path is None: + return + + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/pcie.yaml b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/pcie.yaml new file mode 100644 index 000000000000..c9c41d889ebd --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/pcie.yaml @@ -0,0 +1,21 @@ +- bus: '03' + dev: '00' + fn: '0' + id: '1533' + name: 'Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev + 03)' +- bus: '02' + dev: '00' + fn: '0' + id: b771 + name: 'Ethernet controller: Broadcom Limited Device b771 (rev 01)' +- bus: '04' + dev: '00' + fn: '0' + id: '7021' + name: 'Non-VGA unclassified device: Xilinx Corporation Device 7021' +- bus: '00' + dev: '14' + fn: '0' + id: 19c2 + name: 'SATA controller: Intel Corporation DNV SATA Controller 1 (rev 11)' diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/psuutil.py b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/psuutil.py new file mode 100644 index 000000000000..1cacc0558c6d --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/psuutil.py @@ -0,0 +1,100 @@ +# +# psuutil.py +# Platform-specific PSU status interface for SONiC +# + + +import os.path +import logging +import sys +import subprocess + +S5224F_MAX_PSUS = 2 +IPMI_PSU_DATA = "docker exec -it pmon ipmitool sdr list" +IPMI_PSU_DATA_DOCKER = "ipmitool sdr list" +PSU_PRESENCE = "PSU{0}_stat" +# Use this for older firmware +# PSU_PRESENCE="PSU{0}_prsnt" +ipmi_sdr_list = "" + + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + PsuBase.__init__(self) + + def isDockerEnv(self): + num_docker = open('/proc/self/cgroup', 'r').read().count(":/docker") + if num_docker > 0: + return True + else: + return False + + # Fetch a BMC register + def get_pmc_register(self, reg_name): + + status = 1 + global ipmi_sdr_list + ipmi_dev_node = "/dev/pmi0" + ipmi_cmd = IPMI_PSU_DATA + dockerenv = self.isDockerEnv() + if dockerenv == True: + ipmi_cmd = IPMI_PSU_DATA_DOCKER + + status, ipmi_sdr_list = subprocess.getstatusoutput(ipmi_cmd) + + if status: + logging.error('Failed to execute:' + ipmi_sdr_list) + sys.exit(0) + + for item in ipmi_sdr_list.split("\n"): + if reg_name in item: + output = item.strip() + + if not output: + print('\nFailed to fetch: ' + reg_name + ' sensor ') + sys.exit(0) + + output = output.split('|')[1] + + logging.basicConfig(level=logging.DEBUG) + return output + + def get_num_psus(self): + """ + Retrieves the number of PSUs available on the device + :return: An integer, the number of PSUs available on the device + """ + S5224F_MAX_PSUS = 2 + return S5224F_MAX_PSUS + + def get_psu_status(self, index): + """ + Retrieves the oprational status of power supply unit (PSU) defined + by index + :param index: An integer, index of the PSU of which to query status + :return: Boolean, True if PSU is operating properly, False if PSU is\ + faulty + """ + # Until psu_status is implemented this is hardcoded temporarily + + status = 1 + return status + + def get_psu_presence(self, index): + """ + Retrieves the presence status of power supply unit (PSU) defined + by index + :param index: An integer, index of the PSU of which to query status + :return: Boolean, True if PSU is plugged, False if not + """ + cmd_status, psu_status = subprocess.getstatusoutput('ipmitool raw 0x04 0x2d ' + hex(0x30 + index) + " | awk '{print substr($0,9,1)}'") + return 1 if psu_status == '1' else 0 + diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/sfputil.py new file mode 100644 index 000000000000..2ee649d0dc22 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/sfputil.py @@ -0,0 +1,547 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# +# For S5224F-ON, hardware version X01 + +try: + import struct + import sys + import getopt + import time + from sonic_sfp.sfputilbase import SfpUtilBase + from os import * + from mmap import * + import io + from sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_sfp.sff8436 import sff8436Dom + from sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_sfp.sff8472 import sff8472Dom + +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + + +#definitions of the offset and width for values in DOM info eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VOLT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNL_THRESHOLD_OFFSET = 176 +QSFP_CHANNL_THRESHOLD_WIDTH = 16 +QSFP_CHANNL_MON_MASK_OFFSET = 242 +QSFP_CHANNL_MON_MASK_WIDTH = 4 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 56 + +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 1 + + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 28 + PORTS_IN_BLOCK = 28 + + BASE_RES_PATH = "/sys/bus/pci/devices/0000:04:00.0/resource0" + + _port_to_eeprom_mapping = {} + + + _global_port_pres_dict = {} + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(25, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def pci_mem_read(self, mm, offset): + mm.seek(offset) + read_data_stream=mm.read(4) + reg_val=struct.unpack('I',read_data_stream) + mem_val = str(reg_val)[1:-2] + # print "reg_val read:%x"%reg_val + return mem_val + + def pci_mem_write(self, mm, offset, data): + mm.seek(offset) + # print "data to write:%x"%data + mm.write(struct.pack('I',data)) + + def pci_set_value(self, resource, val, offset): + fd = open(resource, O_RDWR) + mm = mmap(fd, 0) + val = self.pci_mem_write(mm, offset, val) + mm.close() + close(fd) + return val + + def pci_get_value(self, resource, offset): + fd = open(resource, O_RDWR) + mm = mmap(fd, 0) + val = self.pci_mem_read(mm, offset) + mm.close() + close(fd) + return val + + def init_global_port_presence(self): + for port_num in range(self.port_start, (self.port_end + 1)): + presence = self.get_presence(port_num) + if(presence): + self._global_port_pres_dict[port_num] = '1' + else: + self._global_port_pres_dict[port_num] = '0' + + def __init__(self): + eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" + + for x in range(self.port_start, self.port_end + 1): + self.port_to_eeprom_mapping[x] = eeprom_path.format(x + 1) + self.init_global_port_presence() + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # Port offset starts with 0x4004 + port_offset = 16388 + ((port_num-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == "" ): + return False + + # Mask off bit for presence + mask = (1 << 0) + if (port_num > 24): + mask = (1 << 4) + + # ModPrsL is active low + if reg_value & mask == 0: + return True + + return False + + def get_low_power_mode(self, port_num): + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == "" ): + return False + + # Mask off 4th bit for presence + mask = (1 << 6) + + # LPMode is active high + if reg_value & mask == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == "" ): + return False + + # Mask off 4th bit for presence + mask = (1 << 6) + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = reg_value | mask + else: + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + return True + + def reset(self, port_num): + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == "" ): + return False + + # Mask off 4th bit for presence + mask = (1 << 6) + + # ResetL is active low + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + # Sleep 1 second to allow it to settle + time.sleep(1) + + reg_value = reg_value | mask + + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + return True + + def get_transceiver_change_event(self, timeout=0): + port_dict = {} + while True: + for port_num in range(self.port_start, (self.port_end + 1)): + presence = self.get_presence(port_num) + if(presence and self._global_port_pres_dict[port_num] == '0'): + self._global_port_pres_dict[port_num] = '1' + port_dict[port_num] = '1' + elif(not presence and + self._global_port_pres_dict[port_num] == '1'): + self._global_port_pres_dict[port_num] = '0' + port_dict[port_num] = '0' + + if(len(port_dict) > 0): + return True, port_dict + + time.sleep(0.5) + + def get_transceiver_dom_info_dict(self, port_num): + transceiver_dom_info_dict = {} + + dom_info_dict_keys = ['temperature', 'voltage', 'rx1power', + 'rx2power', 'rx3power', 'rx4power', + 'tx1bias', 'tx2bias', 'tx3bias', + 'tx4bias', 'tx1power', 'tx2power', + 'tx3power', 'tx4power', + ] + transceiver_dom_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') + + if port_num in self.qsfp_ports: + offset = 0 + offset_xcvr = 128 + file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + return None + + try: + sysfsfile_eeprom = io.open(file_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + return transceiver_dom_info_dict + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qspf_dom_capability_data = sfpi_obj.parse_qsfp_dom_capability(qsfp_dom_capability_raw, 0) + else: + return transceiver_dom_info_dict + + dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + else: + return transceiver_dom_info_dict + + dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + else: + return transceiver_dom_info_dict + + qsfp_dom_rev_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) + if qsfp_dom_rev_raw is not None: + qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) + else: + return transceiver_dom_info_dict + + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 + # and claimed that it support tx_power with one indicator bit. + dom_channel_monitor_data = {} + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value'] + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + else: + return transceiver_dom_info_dict + + transceiver_dom_info_dict['tx1power'] = 'N/A' + transceiver_dom_info_dict['tx2power'] = 'N/A' + transceiver_dom_info_dict['tx3power'] = 'N/A' + transceiver_dom_info_dict['tx4power'] = 'N/A' + try: + sysfsfile_eeprom.close() + except IOError: + print("Error: closing sysfs file %s" % file_path) + return None + + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + + else: + offset = 256 + file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + return None + + try: + sysfsfile_eeprom = io.open(file_path,"rb",0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8472Dom(None,1) + if sfpd_obj is None: + return None + dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_TEMPE_OFFSET), + SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + else: + return transceiver_dom_info_dict + + dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_VOLT_OFFSET), + SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + else: + return transceiver_dom_info_dict + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_MODULE_THRESHOLD_OFFSET), + SFP_MODULE_THRESHOLD_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + else: + return transceiver_dom_info_dict + + try: + sysfsfile_eeprom.close() + except IOError: + print("Error: closing sysfs file %s" % file_path) + return None + + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RXPower']['value'] + transceiver_dom_info_dict['rx2power'] = 'N/A' + transceiver_dom_info_dict['rx3power'] = 'N/A' + transceiver_dom_info_dict['rx4power'] = 'N/A' + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value'] + transceiver_dom_info_dict['tx2bias'] = 'N/A' + transceiver_dom_info_dict['tx3bias'] = 'N/A' + transceiver_dom_info_dict['tx4bias'] = 'N/A' + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value'] + transceiver_dom_info_dict['tx2power'] = 'N/A' + transceiver_dom_info_dict['tx3power'] = 'N/A' + transceiver_dom_info_dict['tx4power'] = 'N/A' + + return transceiver_dom_info_dict + + def get_transceiver_dom_threshold_info_dict(self, port_num): + transceiver_dom_threshold_info_dict = {} + dom_info_dict_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning' + ] + transceiver_dom_threshold_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') + + if port_num in self.qsfp_ports: + file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + return None + + try: + sysfsfile_eeprom = io.open(file_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + # Dom Threshold data starts from offset 384 + # Revert offset back to 0 once data is retrieved + offset = 384 + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + sysfsfile_eeprom, + (offset + QSFP_MODULE_THRESHOLD_OFFSET), + QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + else: + return transceiver_dom_threshold_info_dict + + dom_channel_threshold_raw = self._read_eeprom_specific_bytes( + sysfsfile_eeprom, + (offset + QSFP_CHANNL_THRESHOLD_OFFSET), + QSFP_CHANNL_THRESHOLD_WIDTH) + if dom_channel_threshold_raw is not None: + dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values(dom_channel_threshold_raw, 0) + else: + return transceiver_dom_threshold_info_dict + + try: + sysfsfile_eeprom.close() + except IOError: + print("Error: closing sysfs file %s" % file_path) + return None + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] + + else: + offset = 256 + file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + return None + + try: + sysfsfile_eeprom = io.open(file_path,"rb",0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8472Dom(None,1) + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, + (offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) + + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(dom_module_threshold_raw, 0) + else: + return transceiver_dom_threshold_info_dict + + try: + sysfsfile_eeprom.close() + except IOError: + print("Error: closing sysfs file %s" % file_path) + return None + + #Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + return transceiver_dom_threshold_info_dict + diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/pmon_daemon_control.json b/device/dell/x86_64-dellemc_s5224f_c3538-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..0c42f485acab --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/pmon_daemon_control.json @@ -0,0 +1,4 @@ +{ + "skip_ledd": true, + "start_ipmievd": true +} diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index d11f82bde341..f348ce274e22 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -9,6 +9,7 @@ $(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR) $(SONIC_ONE_IMAGE)_INSTALLS += $(FLASHROM) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(DELL_Z9264F_PLATFORM_MODULE) \ + $(DELL_S5224F_PLATFORM_MODULE) \ $(DELL_S5232F_PLATFORM_MODULE) \ $(DELL_S5248F_PLATFORM_MODULE) \ $(DELL_Z9332F_PLATFORM_MODULE) \ diff --git a/platform/broadcom/platform-modules-dell.mk b/platform/broadcom/platform-modules-dell.mk index 90eb4fc20b5a..7e1571116477 100644 --- a/platform/broadcom/platform-modules-dell.mk +++ b/platform/broadcom/platform-modules-dell.mk @@ -4,6 +4,7 @@ DELL_S6000_PLATFORM_MODULE_VERSION = 1.1 DELL_Z9100_PLATFORM_MODULE_VERSION = 1.1 DELL_S6100_PLATFORM_MODULE_VERSION = 1.1 DELL_Z9264F_PLATFORM_MODULE_VERSION = 1.1 +DELL_S5224F_PLATFORM_MODULE_VERSION = 1.1 DELL_S5232F_PLATFORM_MODULE_VERSION = 1.1 DELL_Z9332F_PLATFORM_MODULE_VERSION = 1.1 DELL_S5248F_PLATFORM_MODULE_VERSION = 1.1 @@ -13,6 +14,7 @@ export DELL_S6000_PLATFORM_MODULE_VERSION export DELL_Z9100_PLATFORM_MODULE_VERSION export DELL_S6100_PLATFORM_MODULE_VERSION export DELL_Z9264F_PLATFORM_MODULE_VERSION +export DELL_S5224F_PLATFORM_MODULE_VERSION export DELL_S5232F_PLATFORM_MODULE_VERSION export DELL_Z9332F_PLATFORM_MODULE_VERSION export DELL_S5248F_PLATFORM_MODULE_VERSION @@ -37,6 +39,10 @@ DELL_S6000_PLATFORM_MODULE = platform-modules-s6000_$(DELL_S6000_PLATFORM_MODULE $(DELL_S6000_PLATFORM_MODULE)_PLATFORM = x86_64-dell_s6000_s1220-r0 $(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S6000_PLATFORM_MODULE))) +DELL_S5224F_PLATFORM_MODULE = platform-modules-s5224f_$(DELL_S5224F_PLATFORM_MODULE_VERSION)_amd64.deb +$(DELL_S5224F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5224f_c3538-r0 +$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5224F_PLATFORM_MODULE))) + DELL_S5232F_PLATFORM_MODULE = platform-modules-s5232f_$(DELL_S5232F_PLATFORM_MODULE_VERSION)_amd64.deb $(DELL_S5232F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5232f_c3538-r0 $(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5232F_PLATFORM_MODULE))) diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/control b/platform/broadcom/sonic-platform-modules-dell/debian/control index 2920602fcd60..972802a9aa6e 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/control +++ b/platform/broadcom/sonic-platform-modules-dell/debian/control @@ -25,6 +25,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-s5224f +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-s5232f Architecture: amd64 Depends: linux-image-4.19.0-12-2-amd64-unsigned diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5224f.init b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5224f.init new file mode 100644 index 000000000000..acd238c7f1e9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5224f.init @@ -0,0 +1,40 @@ +#!/bin/bash + +### BEGIN INIT INFO +# Provides: setup-board +# Required-Start: +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Setup S5224f board. +### END INIT INFO + +case "$1" in +start) + echo -n "Setting up board... " + + # /usr/local/bin/iom_power_on.sh + /usr/local/bin/s5224f_platform.sh init + + echo "done." + ;; + +stop) + /usr/local/bin/s5224f_platform.sh deinit + echo "done." + + ;; + +force-reload|restart) + echo "Not supported" + ;; + +*) + echo "Usage: /etc/init.d/platform-modules-s5224f.init {start|stop}" + exit 1 + ;; +esac + +exit 0 diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5224f.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5224f.install new file mode 100644 index 000000000000..af81c9ba644d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5224f.install @@ -0,0 +1,13 @@ +s5224f/scripts/s5224f_platform.sh usr/local/bin +s5224f/scripts/check_qsfp.sh usr/local/bin +s5224f/scripts/platform_sensors.py usr/local/bin +s5224f/scripts/sensors usr/bin +s5224f/scripts/pcisysfs.py usr/bin +s5224f/scripts/qsfp_irq_enable.py usr/bin +s5224f/cfg/s5224f-modules.conf etc/modules-load.d +s5224f/cfg/s5224f-params.conf etc/modprobe.d +s5224f/systemd/platform-modules-s5224f.service etc/systemd/system +s5224f/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-dellemc_s5224f_c3538-r0 +common/platform_reboot usr/share/sonic/device/x86_64-dellemc_s5224f_c3538-r0 +common/fw-updater usr/local/bin +common/onie_mode_set usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5224f.postinst b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5224f.postinst new file mode 100644 index 000000000000..0c1f9e2c5e81 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5224f.postinst @@ -0,0 +1,10 @@ +# postinst script for S5224f + +# Enable Dell-S5224f-platform-service +depmod -a +systemctl enable platform-modules-s5224f.service +systemctl start platform-modules-s5224f.service + + +#DEBHELPER# + diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/rules b/platform/broadcom/sonic-platform-modules-dell/debian/rules index 520331ed16d3..22efd08ca65f 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 s5224f s5232f s5248f z9332f s5296f COMMON_DIR := common %: @@ -39,6 +39,11 @@ 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 = "s5224f" ]; then \ + cp $(COMMON_DIR)/ipmihelper.py $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \ + cd $(MOD_SRC_DIR)/$${mod}; \ + python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ + cd $(MOD_SRC_DIR); \ elif [ $$mod = "s5232f" ]; then \ cp $(COMMON_DIR)/ipmihelper.py $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \ cd $(MOD_SRC_DIR)/$${mod}; \ @@ -103,6 +108,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 = "s5224f" ]; 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; \ elif [ $$mod = "s5232f" ]; then \ rm -f $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \ rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \ diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/cfg/s5224f-modules.conf b/platform/broadcom/sonic-platform-modules-dell/s5224f/cfg/s5224f-modules.conf new file mode 100644 index 000000000000..fded7d25e40b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/cfg/s5224f-modules.conf @@ -0,0 +1,19 @@ +# /etc/modules: kernel modules to load at boot time. +# +# This file contains the names of kernel modules that should be loaded +# at boot time, one per line. Lines beginning with "#" are ignored. + +i2c-i801 +i2c-isch +i2c-ismt +i2c-dev +i2c-mux +i2c-smbus + +i2c-mux-gpio +i2c-mux-pca954x + +ipmi_devintf +ipmi_si +dell_s5224f_fpga_ocores +i2c_ocores diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/cfg/s5224f-params.conf b/platform/broadcom/sonic-platform-modules-dell/s5224f/cfg/s5224f-params.conf new file mode 100644 index 000000000000..dca013f105db --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/cfg/s5224f-params.conf @@ -0,0 +1 @@ +options ipmi_si kipmid_max_busy_us=1000 diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/modules/Makefile b/platform/broadcom/sonic-platform-modules-dell/s5224f/modules/Makefile new file mode 100644 index 000000000000..fdc2016fee24 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/modules/Makefile @@ -0,0 +1,2 @@ +obj-m := dell_s5224f_fpga_ocores.o + diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/modules/dell_s5224f_fpga_ocores.c b/platform/broadcom/sonic-platform-modules-dell/s5224f/modules/dell_s5224f_fpga_ocores.c new file mode 100644 index 000000000000..c0923719c527 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/modules/dell_s5224f_fpga_ocores.c @@ -0,0 +1,1626 @@ +/* +* Copyright (C) 2018 Dell Inc +* +* Licensed under the GNU General Public License Version 2 +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +/** +* @file fpga_i2ccore.c +* @brief This is a driver to interface with Linux Open Cores drivber for FPGA i2c access +* +************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include //siginfo +#include //rcu_read_lock +#include //kernel_version +#include +#include +#include +#include +#include + + +void __iomem * fpga_base_addr = NULL; +void __iomem * fpga_ctl_addr = NULL; + +#define DRIVER_NAME "fpgapci" +#define PCI_NUM_BARS 4 + +#ifdef DEBUG +# define PRINT(fmt, ...) printk(fmt, ##__VA_ARGS__) +#else +# define PRINT(fmt, ...) +#endif + +/* Maximum size of driver buffer (allocated with kalloc()). + * Needed to copy data from user to kernel space, among other + * things. */ +static const size_t BUF_SIZE = PAGE_SIZE; + +/* Device data used by this driver. */ +struct fpgapci_dev { + /* the kernel pci device data structure */ + struct pci_dev *pci_dev; + + /* upstream root node */ + struct pci_dev *upstream; + + /* kernels virtual addr. for the mapped BARs */ + void * __iomem bar[PCI_NUM_BARS]; + + /* length of each memory region. Used for error checking. */ + size_t bar_length[PCI_NUM_BARS]; + + /* Debug data */ + /* number of hw interrupts handled. */ + int num_handled_interrupts; + int num_undelivered_signals; + int pci_gen; + int pci_num_lanes; + + unsigned int irq_first; + unsigned int irq_length; + unsigned int irq_assigned; + unsigned int xcvr_intr_count; +}; + +static int use_irq = 0; +module_param(use_irq, int, 0644); +MODULE_PARM_DESC(use_irq, "Get an use_irq value from user...\n"); + +static uint32_t num_bus = 0; +module_param(num_bus, int, 0); +MODULE_PARM_DESC(num_bus, + "Number of i2c busses supported by the FPGA on this platform."); + + +/* Xilinx FPGA PCIE info: */ +/* Non-VGA unclassified device: Xilinx Corporation Device 7021*/ +/* Subsystem: Xilinx Corporation Device 0007 */ +//#define VENDOR 0x10EE +#define DEVICE 0x7021 +static phys_addr_t fpga_phys_addr; + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + + +/* struct to hold data related to the pcie device */ +struct pci_data_struct{ + struct pci_dev* dev; + unsigned long long phy_addr_bar0; + unsigned long long phy_len_bar0; + unsigned long long phy_flags_bar0; + unsigned int irq_first; + unsigned int irq_length; + unsigned int irq_assigned; + void * kvirt_addr_bar0; +}; + +/* global variable declarations */ + +/* Static function declarations */ +static int fpgapci_probe(struct pci_dev *dev, const struct pci_device_id *id); +static void fpgapci_remove(struct pci_dev *dev); + +static int scan_bars(struct fpgapci_dev *fpgapci, struct pci_dev *dev); +static int map_bars(struct fpgapci_dev *fpgapci, struct pci_dev *dev); +static void free_bars(struct fpgapci_dev *fpgapci, struct pci_dev *dev); + + +struct fpgalogic_i2c { + void __iomem *base; + u32 reg_shift; + u32 reg_io_width; + wait_queue_head_t wait; + struct i2c_msg *msg; + int pos; + int nmsgs; + int state; /* see STATE_ */ + int ip_clock_khz; + int bus_clock_khz; + void (*reg_set)(struct fpgalogic_i2c *i2c, int reg, u8 value); + u8 (*reg_get)(struct fpgalogic_i2c *i2c, int reg); + u32 timeout; + struct mutex lock; +}; +/* registers */ +#define FPGAI2C_REG_PRELOW 0 +#define FPGAI2C_REG_PREHIGH 1 +#define FPGAI2C_REG_CONTROL 2 +#define FPGAI2C_REG_DATA 3 +#define FPGAI2C_REG_CMD 4 /* write only */ +#define FPGAI2C_REG_STATUS 4 /* read only, same address as FPGAI2C_REG_CMD */ +#define FPGAI2C_REG_VER 5 + + + +#define FPGAI2C_REG_CTRL_IEN 0x40 +#define FPGAI2C_REG_CTRL_EN 0x80 + +#define FPGAI2C_REG_CMD_START 0x91 +#define FPGAI2C_REG_CMD_STOP 0x41 +#define FPGAI2C_REG_CMD_READ 0x21 +#define FPGAI2C_REG_CMD_WRITE 0x11 +#define FPGAI2C_REG_CMD_READ_ACK 0x21 +#define FPGAI2C_REG_CMD_READ_NACK 0x29 +#define FPGAI2C_REG_CMD_IACK 0x01 + +#define FPGAI2C_REG_STAT_IF 0x01 +#define FPGAI2C_REG_STAT_TIP 0x02 +#define FPGAI2C_REG_STAT_ARBLOST 0x20 +#define FPGAI2C_REG_STAT_BUSY 0x40 +#define FPGAI2C_REG_STAT_NACK 0x80 + +/* SR[7:0] - Status register */ +#define FPGAI2C_REG_SR_RXACK (1 << 7) /* Receive acknowledge from slave .1. = No acknowledge received*/ +#define FPGAI2C_REG_SR_BUSY (1 << 6) /* Busy, I2C bus busy (as defined by start / stop bits) */ +#define FPGAI2C_REG_SR_AL (1 << 5) /* Arbitration lost - fpga i2c logic lost arbitration */ +#define FPGAI2C_REG_SR_TIP (1 << 1) /* Transfer in progress */ +#define FPGAI2C_REG_SR_IF (1 << 0) /* Interrupt flag */ + +enum { + STATE_DONE = 0, + STATE_INIT, + STATE_ADDR, + STATE_ADDR10, + STATE_START, + STATE_WRITE, + STATE_READ, + STATE_STOP, + STATE_ERROR, +}; + +#define TYPE_FPGALOGIC 0 +#define TYPE_GRLIB 1 + +/*I2C_CH1 Offset address from PCIE BAR 0*/ +#define FPGALOGIC_I2C_BASE 0x00006000 +#define FPGALOGIC_CH_OFFSET 0x10 + +#define i2c_bus_controller_numb 1 +#define I2C_PCI_MAX_BUS (16) +#define I2C_PCI_MAX_BUS_REV00 (7) +#define DELL_I2C_CLOCK_LEGACY 0 +#define DELL_I2C_CLOCK_PRESERVE (~0U) +#define I2C_PCI_BUS_NUM_5 5 +#define I2C_PCI_BUS_NUM_7 7 +#define I2C_PCI_BUS_NUM_8 8 +#define I2C_PCI_BUS_NUM_10 10 +#define I2C_PCI_BUS_NUM_12 12 +#define I2C_PCI_BUS_NUM_16 16 + +#define IRQ_LTCH_STS 0x20 +#define PRSNT_LTCH_STS 0x10 + +#define PORT_CTRL_OFFSET 0x4000 +#define PORT_STS_OFFSET 0x4004 +#define PORT_IRQ_STS_OFFSET 0x4008 +#define PORT_IRQ_EN_OFFSET 0x400C +#define MB_BRD_REV_TYPE 0x0008 +#define MB_BRD_REV_MASK 0x00f0 +#define MB_BRD_REV_00 0x0000 +#define MB_BRD_REV_01 0x0010 +#define MB_BRD_REV_02 0x0020 +#define MB_BRD_REV_03 0x0030 +#define MB_BRD_TYPE_MASK 0x000f +#define BRD_TYPE_Z9232_NON_NEBS 0x0 +#define BRD_TYPE_Z9232_NEBS 0x1 +#define BRD_TYPE_Z9264_NON_NEBS 0x2 +#define BRD_TYPE_Z9264_NEBS 0x3 +#define BRD_TYPE_S5212_NON_NEBS 0x4 +#define BRD_TYPE_S5212_NEBS 0x5 +#define BRD_TYPE_S5224_NON_NEBS 0x6 +#define BRD_TYPE_S5224_NEBS 0x7 +#define BRD_TYPE_S5248_NON_NEBS 0x8 +#define BRD_TYPE_S5248_NEBS 0x9 +#define BRD_TYPE_S5296_NON_NEBS 0xa +#define BRD_TYPE_S5296_NEBS 0xb +#define BRD_TYPE_S5232_NON_NEBS 0xc +#define BRD_TYPE_S5232_NEBS 0xd + +#define FPGA_CTL_REG_SIZE 0x6000 +#define MSI_VECTOR_MAP_MASK 0x1f +#define MSI_VECTOR_MAP1 0x58 +#define I2C_CH1_MSI_MAP_VECT_8 0x00000008 +#define I2C_CH2_MSI_MAP_VECT_9 0x00000120 +#define I2C_CH3_MSI_MAP_VECT_10 0x00002800 +#define I2C_CH4_MSI_MAP_VECT_11 0x00058000 +#define I2C_CH5_MSI_MAP_VECT_12 0x00c00000 +#define I2C_CH6_MSI_MAP_VECT_13 0x15000000 +#define MSI_VECTOR_MAP2 0x5c +#define I2C_CH7_MSI_MAP_VECT_14 0x0000000e +#define MSI_VECTOR_MAP3 0x9c +#define I2C_CH8_MSI_MAP_VECT_8 0x00800000 +#define I2C_CH8_MSI_MAP_VECT_16 0x01100000 +#define I2C_CH9_MSI_MAP_VECT_9 0x12000000 +#define I2C_CH9_MSI_MAP_VECT_17 0x24000000 +#define MSI_VECTOR_MAP4 0xa0 +#define I2C_CH10_MSI_MAP_VECT_10 0x0000000a +#define I2C_CH10_MSI_MAP_VECT_18 0x00000012 +#define I2C_CH11_MSI_MAP_VECT_11 0x00000120 +#define I2C_CH11_MSI_MAP_VECT_19 0x00000260 +#define I2C_CH12_MSI_MAP_VECT_12 0x00002800 +#define I2C_CH12_MSI_MAP_VECT_20 0x00005000 +#define I2C_CH13_MSI_MAP_VECT_13 0x00058000 +#define I2C_CH13_MSI_MAP_VECT_21 0x000a8000 +#define I2C_CH14_MSI_MAP_VECT_14 0x00c00000 +#define I2C_CH14_MSI_MAP_VECT_22 0x01600000 +#define I2C_CH15_MSI_MAP_VECT_8 0x10000000 +#define I2C_CH15_MSI_MAP_VECT_23 0x2e000000 +#define MSI_VECTOR_MAP5 0xa4 +#define I2C_CH16_MSI_MAP_VECT_9 0x00000009 +#define I2C_CH16_MSI_MAP_VECT_24 0x00000018 + +#define MSI_VECTOR_REV_00 16 +#define MSI_VECTOR_REV_01 32 + +#define FPGA_MSI_VECTOR_ID_4 4 +#define FPGA_MSI_VECTOR_ID_5 5 +#define FPGA_MSI_VECTOR_ID_8 8 +#define FPGA_MSI_VECTOR_ID_9 9 +#define FPGA_MSI_VECTOR_ID_10 10 +#define FPGA_MSI_VECTOR_ID_11 11 +#define FPGA_MSI_VECTOR_ID_12 12 +#define FPGA_MSI_VECTOR_ID_13 13 +#define FPGA_MSI_VECTOR_ID_14 14 +#define FPGA_MSI_VECTOR_ID_15 15 /*Note: this is external MSI vector id */ +#define FPGA_MSI_VECTOR_ID_16 16 +#define FPGA_MSI_VECTOR_ID_17 17 +#define FPGA_MSI_VECTOR_ID_18 18 +#define FPGA_MSI_VECTOR_ID_19 19 +#define FPGA_MSI_VECTOR_ID_20 20 +#define FPGA_MSI_VECTOR_ID_21 21 +#define FPGA_MSI_VECTOR_ID_22 22 +#define FPGA_MSI_VECTOR_ID_23 23 +#define FPGA_MSI_VECTOR_ID_24 24 + + + +static int total_i2c_pci_bus = 0; +static uint32_t board_rev_type = 0; +static struct fpgalogic_i2c fpgalogic_i2c[I2C_PCI_MAX_BUS]; +static struct i2c_adapter i2c_pci_adap[I2C_PCI_MAX_BUS]; +static struct mutex i2c_xfer_lock[I2C_PCI_MAX_BUS]; + +static void fpgai2c_reg_set_8(struct fpgalogic_i2c *i2c, int reg, u8 value) +{ + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void fpgai2c_reg_set_16(struct fpgalogic_i2c *i2c, int reg, u8 value) +{ + iowrite16(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void fpgai2c_reg_set_32(struct fpgalogic_i2c *i2c, int reg, u8 value) +{ + iowrite32(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void fpgai2c_reg_set_16be(struct fpgalogic_i2c *i2c, int reg, u8 value) +{ + iowrite16be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void fpgai2c_reg_set_32be(struct fpgalogic_i2c *i2c, int reg, u8 value) +{ + iowrite32be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 fpgai2c_reg_get_8(struct fpgalogic_i2c *i2c, int reg) +{ + return ioread8(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 fpgai2c_reg_get_16(struct fpgalogic_i2c *i2c, int reg) +{ + return ioread16(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 fpgai2c_reg_get_32(struct fpgalogic_i2c *i2c, int reg) +{ + return ioread32(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 fpgai2c_reg_get_16be(struct fpgalogic_i2c *i2c, int reg) +{ + return ioread16be(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 fpgai2c_reg_get_32be(struct fpgalogic_i2c *i2c, int reg) +{ + return ioread32be(i2c->base + (reg << i2c->reg_shift)); +} + +static inline void fpgai2c_reg_set(struct fpgalogic_i2c *i2c, int reg, u8 value) +{ + i2c->reg_set(i2c, reg, value); + udelay(100); +} + +static inline u8 fpgai2c_reg_get(struct fpgalogic_i2c *i2c, int reg) +{ + udelay(100); + return i2c->reg_get(i2c, reg); +} + +static void fpgai2c_dump(struct fpgalogic_i2c *i2c) +{ + u8 tmp; + + PRINT("Logic register dump:\n"); + + tmp = fpgai2c_reg_get(i2c, FPGAI2C_REG_PRELOW); + PRINT("FPGAI2C_REG_PRELOW (%d) = 0x%x\n",FPGAI2C_REG_PRELOW,tmp); + + tmp = fpgai2c_reg_get(i2c, FPGAI2C_REG_PREHIGH); + PRINT("FPGAI2C_REG_PREHIGH(%d) = 0x%x\n",FPGAI2C_REG_PREHIGH,tmp); + + tmp = fpgai2c_reg_get(i2c, FPGAI2C_REG_CONTROL); + PRINT("FPGAI2C_REG_CONTROL(%d) = 0x%x\n",FPGAI2C_REG_CONTROL,tmp); + + tmp = fpgai2c_reg_get(i2c, FPGAI2C_REG_DATA); + PRINT("FPGAI2C_REG_DATA (%d) = 0x%x\n",FPGAI2C_REG_DATA,tmp); + + tmp = fpgai2c_reg_get(i2c, FPGAI2C_REG_CMD); + PRINT("FPGAI2C_REG_CMD (%d) = 0x%x\n",FPGAI2C_REG_CMD,tmp); +} + +static void fpgai2c_stop(struct fpgalogic_i2c *i2c) +{ + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_STOP); +} + +/* + * dell_get_mutex must be called prior to calling this function. + */ +static int fpgai2c_poll(struct fpgalogic_i2c *i2c) +{ + u8 stat = fpgai2c_reg_get(i2c, FPGAI2C_REG_STATUS); + struct i2c_msg *msg = i2c->msg; + u8 addr; + + /* Ready? */ + if (stat & FPGAI2C_REG_STAT_TIP) + return -EBUSY; + + if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) { + /* Stop has been sent */ + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK); + if (i2c->state == STATE_ERROR) + return -EIO; + return 0; + } + + /* Error? */ + if (stat & FPGAI2C_REG_STAT_ARBLOST) { + i2c->state = STATE_ERROR; + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_STOP); + return -EAGAIN; + } + + if (i2c->state == STATE_INIT) { + if (stat & FPGAI2C_REG_STAT_BUSY) + return -EBUSY; + + i2c->state = STATE_ADDR; + } + + if (i2c->state == STATE_ADDR) { + /* 10 bit address? */ + if (i2c->msg->flags & I2C_M_TEN) { + addr = 0xf0 | ((i2c->msg->addr >> 7) & 0x6); + i2c->state = STATE_ADDR10; + } else { + addr = (i2c->msg->addr << 1); + i2c->state = STATE_START; + } + + /* Set read bit if necessary */ + addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0; + + fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, addr); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_START); + + return 0; + } + + /* Second part of 10 bit addressing */ + if (i2c->state == STATE_ADDR10) { + fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, i2c->msg->addr & 0xff); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_WRITE); + + i2c->state = STATE_START; + return 0; + } + + if (i2c->state == STATE_START || i2c->state == STATE_WRITE) { + i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; + + if (stat & FPGAI2C_REG_STAT_NACK) { + i2c->state = STATE_ERROR; + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_STOP); + return -ENXIO; + } + } else { + msg->buf[i2c->pos++] = fpgai2c_reg_get(i2c, FPGAI2C_REG_DATA); + } + + if (i2c->pos >= msg->len) { + i2c->nmsgs--; + i2c->msg++; + i2c->pos = 0; + msg = i2c->msg; + + if (i2c->nmsgs) { + if (!(msg->flags & I2C_M_NOSTART)) { + i2c->state = STATE_ADDR; + return 0; + } else { + i2c->state = (msg->flags & I2C_M_RD) + ? STATE_READ : STATE_WRITE; + } + } else { + i2c->state = STATE_DONE; + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_STOP); + return 0; + } + } + + if (i2c->state == STATE_READ) { + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, i2c->pos == (msg->len - 1) ? + FPGAI2C_REG_CMD_READ_NACK : FPGAI2C_REG_CMD_READ_ACK); + } else { + fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, msg->buf[i2c->pos++]); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_WRITE); + } + + return 0; +} + +static ssize_t get_mod_msi(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ind = 0, port_status=0, port_irq_status=0; + struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(dev); + PRINT("%s:xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count); + for(ind=0;ind<64;ind++) + { + port_status = ioread32(fpga_ctl_addr + PORT_STS_OFFSET + (ind*16)); + port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status); + } + return sprintf(buf,"0x%04x\n",fpgapci->xcvr_intr_count); +} +static DEVICE_ATTR(port_msi, S_IRUGO, get_mod_msi, NULL); + +static struct attribute *port_attrs[] = { + &dev_attr_port_msi.attr, + NULL, +}; + +static struct attribute_group port_attr_grp = { + .attrs = port_attrs, +}; + + +static irqreturn_t fpgaport_1_32_isr(int irq, void *dev) +{ + struct pci_dev *pdev = dev; + struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&pdev->dev); + int ind = 0, port_status=0, port_irq_status=0; + for(ind=0;ind<32;ind++) + { + port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + if(port_irq_status&(IRQ_LTCH_STS|PRSNT_LTCH_STS)) + { + PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status); + //write on clear + iowrite32( IRQ_LTCH_STS|PRSNT_LTCH_STS,fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + } + } + fpgapci->xcvr_intr_count++; + PRINT("%s: xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count); + sysfs_notify(&pdev->dev.kobj, NULL, "port_msi"); + return IRQ_HANDLED; +} + +static irqreturn_t fpgaport_33_64_isr(int irq, void *dev) +{ + struct pci_dev *pdev = dev; + struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&pdev->dev); + int ind = 0, port_status=0, port_irq_status=0; + for(ind=32;ind<64;ind++) + { + port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + if(port_irq_status| (IRQ_LTCH_STS|PRSNT_LTCH_STS)) + { + PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status); + iowrite32( IRQ_LTCH_STS|PRSNT_LTCH_STS,fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + } + } + fpgapci->xcvr_intr_count++; + PRINT("%s: xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count); + sysfs_notify(&pdev->dev.kobj, NULL, "port_msi"); + return IRQ_HANDLED; +} + +static void fpgai2c_process(struct fpgalogic_i2c *i2c) +{ + struct i2c_msg *msg = i2c->msg; + u8 stat = fpgai2c_reg_get(i2c, FPGAI2C_REG_STATUS); + + PRINT("fpgai2c_process in. status reg :0x%x\n", stat); + + if ((i2c->state == STATE_STOP) || (i2c->state == STATE_ERROR)) { + /* stop has been sent */ + PRINT("fpgai2c_process FPGAI2C_REG_CMD_IACK stat = 0x%x Set FPGAI2C_REG_CMD(0%x) FPGAI2C_REG_CMD_IACK = 0x%x\n" \ + ,stat, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK); + if(i2c->state == STATE_STOP) { + i2c->state = STATE_DONE; + } + wake_up(&i2c->wait); + return; + } + + + /* error? */ + if (stat & FPGAI2C_REG_STAT_ARBLOST) { + i2c->state = STATE_ERROR; + PRINT("fpgai2c_process FPGAI2C_REG_STAT_ARBLOST FPGAI2C_REG_CMD_STOP\n"); + fpgai2c_stop(i2c); + return; + } + + if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { + i2c->state = + (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; + + if (stat & FPGAI2C_REG_STAT_NACK) { + i2c->state = STATE_ERROR; + fpgai2c_stop(i2c); + return; + } + } else + { + msg->buf[i2c->pos++] = fpgai2c_reg_get(i2c, FPGAI2C_REG_DATA); + } + + /* end of msg? */ + if (i2c->pos == msg->len) { + i2c->nmsgs--; + i2c->msg++; + i2c->pos = 0; + msg = i2c->msg; + + if (i2c->nmsgs) { /* end? */ + /* send start? */ + if (!(msg->flags & I2C_M_NOSTART)) { + + u8 addr = (msg->addr << 1); + + if (msg->flags & I2C_M_RD) + addr |= 1; + + i2c->state = STATE_START; + fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, addr); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_START); + return; + } else + { + i2c->state = (msg->flags & I2C_M_RD) + ? STATE_READ : STATE_WRITE; + } + } else { + i2c->state = STATE_STOP; + fpgai2c_stop(i2c); + return; + } + } + + if (i2c->state == STATE_READ) { + PRINT("fpgai2c_poll STATE_READ i2c->pos=%d msg->len-1 = 0x%x set FPGAI2C_REG_CMD = 0x%x\n",i2c->pos, msg->len-1, + i2c->pos == (msg->len-1) ? FPGAI2C_REG_CMD_READ_NACK : FPGAI2C_REG_CMD_READ_ACK); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, i2c->pos == (msg->len-1) ? + FPGAI2C_REG_CMD_READ_NACK : FPGAI2C_REG_CMD_READ_ACK); + } else { + PRINT("fpgai2c_process set FPGAI2C_REG_DATA(0x%x)\n",FPGAI2C_REG_DATA); + fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, msg->buf[i2c->pos++]); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_WRITE); + } +} + +static irqreturn_t fpgai2c_isr(int irq, void *dev_id) +{ + struct fpgalogic_i2c *i2c = dev_id; + fpgai2c_process(i2c); + + return IRQ_HANDLED; +} +void dell_get_mutex(struct fpgalogic_i2c *i2c) +{ + mutex_lock(&i2c->lock); +} + +/** + * dell_release_mutex - release mutex + */ +void dell_release_mutex(struct fpgalogic_i2c *i2c) +{ + mutex_unlock(&i2c->lock); +} + +static int fpgai2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct fpgalogic_i2c *i2c = i2c_get_adapdata(adap); + int ret; + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + i2c->msg = msgs; + i2c->pos = 0; + i2c->nmsgs = num; + i2c->state = (use_irq == 1) ? STATE_START : STATE_INIT; + + PRINT("i2c->msg->addr = 0x%x i2c->msg->flags = 0x%x\n",i2c->msg->addr,i2c->msg->flags); + PRINT("I2C_M_RD = 0x%x i2c->msg->addr << 1 = 0x%x\n",I2C_M_RD,i2c->msg->addr << 1); + + if (!use_irq) { + /* Handle the transfer */ + while (time_before(jiffies, timeout)) { + dell_get_mutex(i2c); + ret = fpgai2c_poll(i2c); + dell_release_mutex(i2c); + + if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) + return (i2c->state == STATE_DONE) ? num : ret; + + if (ret == 0) + timeout = jiffies + HZ; + + usleep_range(5, 15); + } + + i2c->state = STATE_ERROR; + + return -ETIMEDOUT; + + + } else { + ret = -ETIMEDOUT; + PRINT("Set FPGAI2C_REG_DATA(0%x) val = 0x%x\n",FPGAI2C_REG_DATA, + (i2c->msg->addr << 1) | ((i2c->msg->flags & I2C_M_RD) ? 1:0)); + + fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, + (i2c->msg->addr << 1) | + ((i2c->msg->flags & I2C_M_RD) ? 1:0)); + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_START); + + /* Interrupt mode */ + if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || + (i2c->state == STATE_DONE), HZ)) + ret = (i2c->state == STATE_DONE) ? num : -EIO; + return ret; + } +} + +static int fpgai2c_init(struct fpgalogic_i2c *i2c) +{ + int prescale; + int diff; + u8 ctrl; + + if (i2c->reg_io_width == 0) + i2c->reg_io_width = 1; /* Set to default value */ + + if (!i2c->reg_set || !i2c->reg_get) { + bool be = 0; //1:big_endian 0:little_endian + + switch (i2c->reg_io_width) { + case 1: + i2c->reg_set = fpgai2c_reg_set_8; + i2c->reg_get = fpgai2c_reg_get_8; + break; + + case 2: + i2c->reg_set = be ? fpgai2c_reg_set_16be : fpgai2c_reg_set_16; + i2c->reg_get = be ? fpgai2c_reg_get_16be : fpgai2c_reg_get_16; + break; + + case 4: + i2c->reg_set = be ? fpgai2c_reg_set_32be : fpgai2c_reg_set_32; + i2c->reg_get = be ? fpgai2c_reg_get_32be : fpgai2c_reg_get_32; + break; + + default: + PRINT("Unsupported I/O width (%d)\n", + i2c->reg_io_width); + return -EINVAL; + } + } + + ctrl = fpgai2c_reg_get(i2c, FPGAI2C_REG_CONTROL); + + PRINT("%s(), line:%d\n", __func__, __LINE__); + PRINT("i2c->base = 0x%p\n",i2c->base); + + PRINT("ctrl = 0x%x\n",ctrl); + PRINT("set ctrl = 0x%x\n",ctrl & ~(FPGAI2C_REG_CTRL_EN|FPGAI2C_REG_CTRL_IEN)); + + /* make sure the device is disabled */ + fpgai2c_reg_set(i2c, FPGAI2C_REG_CONTROL, ctrl & ~(FPGAI2C_REG_CTRL_EN|FPGAI2C_REG_CTRL_IEN)); + + /* + * I2C Frequency depends on host clock + * input clock of 100MHz + * prescale to 100MHz / ( 5*100kHz) -1 = 199 = 0x4F 100000/(5*100)-1=199=0xc7 + */ + prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1; + prescale = clamp(prescale, 0, 0xffff); + + diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz; + if (abs(diff) > i2c->bus_clock_khz / 10) { + PRINT("Unsupported clock settings: core: %d KHz, bus: %d KHz\n", + i2c->ip_clock_khz, i2c->bus_clock_khz); + return -EINVAL; + } + + fpgai2c_reg_set(i2c, FPGAI2C_REG_PRELOW, prescale & 0xff); + fpgai2c_reg_set(i2c, FPGAI2C_REG_PREHIGH, prescale >> 8); + + /* Init the device */ + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK); + if (!use_irq) + fpgai2c_reg_set(i2c, FPGAI2C_REG_CONTROL, ctrl | FPGAI2C_REG_CTRL_EN); + else + fpgai2c_reg_set(i2c, FPGAI2C_REG_CONTROL, ctrl | FPGAI2C_REG_CTRL_IEN | FPGAI2C_REG_CTRL_EN); + + fpgai2c_dump(i2c); + + /* Initialize interrupt handlers if not already done */ + init_waitqueue_head(&i2c->wait); + + return 0; +} + + +static u32 fpgai2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm fpgai2c_algorithm = { + .master_xfer = fpgai2c_xfer, + .functionality = fpgai2c_func, +}; + +static int i2c_pci_add_bus (struct i2c_adapter *adap) +{ + int ret = 0; + /* Register new adapter */ + adap->algo = &fpgai2c_algorithm; + ret = i2c_add_numbered_adapter(adap); + return ret; +} + +static int i2c_init_internal_data(void) +{ + int i; + PRINT("%s(), line:%d\n", __func__, __LINE__); + + for( i = 0; i < total_i2c_pci_bus; i++ ) + { + fpgalogic_i2c[i].reg_shift = 0; /* 8 bit registers */ + fpgalogic_i2c[i].reg_io_width = 1; /* 8 bit read/write */ + fpgalogic_i2c[i].timeout = 500;//1000;//1ms + fpgalogic_i2c[i].ip_clock_khz = 100000;//100000;/* input clock of 100MHz */ + fpgalogic_i2c[i].bus_clock_khz = 100; + fpgalogic_i2c[i].base = fpga_base_addr + i*FPGALOGIC_CH_OFFSET; + mutex_init(&fpgalogic_i2c[i].lock); + fpgai2c_init(&fpgalogic_i2c[i]); + } + + return 0; +} + + +static int i2c_pci_init (void) +{ + int i; + + if (num_bus == 0) { + board_rev_type = ioread32(fpga_ctl_addr + MB_BRD_REV_TYPE); + + if ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_00) { + num_bus = I2C_PCI_MAX_BUS_REV00; + } else if (((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_01) || + ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_02) || + ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_03)) { + switch (board_rev_type & MB_BRD_TYPE_MASK){ + case BRD_TYPE_S5212_NON_NEBS: + case BRD_TYPE_S5212_NEBS: + num_bus = I2C_PCI_BUS_NUM_5; + break; + case BRD_TYPE_S5224_NON_NEBS: + case BRD_TYPE_S5224_NEBS: + num_bus = I2C_PCI_BUS_NUM_7; + break; + case BRD_TYPE_Z9232_NON_NEBS: + case BRD_TYPE_Z9232_NEBS: + case BRD_TYPE_S5232_NON_NEBS: + case BRD_TYPE_S5232_NEBS: + num_bus = I2C_PCI_BUS_NUM_8; + break; + case BRD_TYPE_S5248_NON_NEBS: + case BRD_TYPE_S5248_NEBS: + num_bus = I2C_PCI_BUS_NUM_10; + break; + case BRD_TYPE_Z9264_NON_NEBS: + case BRD_TYPE_Z9264_NEBS: + num_bus = I2C_PCI_BUS_NUM_12; + break; + case BRD_TYPE_S5296_NON_NEBS: + case BRD_TYPE_S5296_NEBS: + num_bus = I2C_PCI_BUS_NUM_16; + break; + default: + num_bus = I2C_PCI_BUS_NUM_16; + printk("Wrong BRD_TYPE: 0x%x\n", board_rev_type); + break; + } + } else { + printk("unknown board_rev_type 0x%x\n", board_rev_type); + num_bus = I2C_PCI_BUS_NUM_8; + } + } + + printk("board_rev_type 0x%x, num_bus 0x%x\n", board_rev_type, num_bus); + total_i2c_pci_bus = num_bus; + + memset (&i2c_pci_adap, 0, sizeof(i2c_pci_adap)); + memset (&fpgalogic_i2c, 0, sizeof(fpgalogic_i2c)); + for(i=0; i < i2c_bus_controller_numb; i++) + mutex_init(&i2c_xfer_lock[i]); + + /* Initialize driver's itnernal data structures */ + i2c_init_internal_data(); + + for (i = 0 ; i < total_i2c_pci_bus; i ++) { + + i2c_pci_adap[i].owner = THIS_MODULE; + i2c_pci_adap[i].class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + + i2c_pci_adap[i].algo_data = &fpgalogic_i2c[i]; + /* /dev/i2c-600 ~ /dev/i2c-615 for FPGA LOGIC I2C channel controller 1-7 */ + i2c_pci_adap[i].nr = i+600; + sprintf( i2c_pci_adap[ i ].name, "i2c-pci-%d", i ); + /* Add the bus via the algorithm code */ + if( i2c_pci_add_bus( &i2c_pci_adap[ i ] ) != 0 ) + { + PRINT("Cannot add bus %d to algorithm layer\n", i ); + return( -ENODEV ); + } + i2c_set_adapdata(&i2c_pci_adap[i], &fpgalogic_i2c[i]); + + PRINT( "Registered bus id: %s\n", kobject_name(&i2c_pci_adap[ i ].dev.kobj)); + } + + return 0; +} + +static void i2c_pci_deinit(void) +{ + int i; + for( i = 0; i < total_i2c_pci_bus; i++ ){ + i2c_del_adapter(&i2c_pci_adap[i]); + } + +} + +/* Find upstream PCIe root node. + * Used for re-training and disabling AER. */ +static struct pci_dev* find_upstream_dev (struct pci_dev *dev) +{ + struct pci_bus *bus = 0; + struct pci_dev *bridge = 0; + struct pci_dev *cur = 0; + int found_dev = 0; + + bus = dev->bus; + if (bus == 0) { + PRINT ( "Device doesn't have an associated bus!\n"); + return 0; + } + + bridge = bus->self; + if (bridge == 0) { + PRINT ( "Can't get the bridge for the bus!\n"); + return 0; + } + + PRINT ( "Upstream device %x/%x, bus:slot.func %02x:%02x.%02x\n", + bridge->vendor, bridge->device, + bridge->bus->number, PCI_SLOT(bridge->devfn), PCI_FUNC(bridge->devfn)); + + PRINT ( "List of downstream devices:"); + list_for_each_entry (cur, &bus->devices, bus_list) { + if (cur != 0) { + PRINT ( " %x/%x", cur->vendor, cur->device); + if (cur == dev) { + found_dev = 1; + } + } + } + PRINT ( "\n"); + if (found_dev) { + return bridge; + } else { + PRINT ( "Couldn't find upstream device!\n"); + return 0; + } +} + + +static int scan_bars(struct fpgapci_dev *fpgapci, struct pci_dev *dev) +{ + int i; + + for (i = 0; i < PCI_NUM_BARS; i++) { + unsigned long bar_start = pci_resource_start(dev, i); + if (bar_start) { + unsigned long bar_end = pci_resource_end(dev, i); + unsigned long bar_flags = pci_resource_flags(dev, i); + PRINT ( "BAR[%d] 0x%08lx-0x%08lx flags 0x%08lx", + i, bar_start, bar_end, bar_flags); + } + } + + return 0; +} + + +/** + * Map the device memory regions into kernel virtual address space + * after verifying their sizes respect the minimum sizes needed, given + * by the bar_min_len[] array. + */ +static int map_bars(struct fpgapci_dev *fpgapci, struct pci_dev *dev) +{ + int i; + + for (i = 0; i < PCI_NUM_BARS; i++){ + phys_addr_t bar_start = pci_resource_start(dev, i); + phys_addr_t bar_end = pci_resource_end(dev, i); + unsigned long bar_length = bar_end - bar_start + 1; + fpgapci->bar_length[i] = bar_length; + + + if (!bar_start || !bar_end) { + fpgapci->bar_length[i] = 0; + continue; + } + + if (bar_length < 1) { + PRINT ( "BAR #%d length is less than 1 byte\n", i); + continue; + } + + PRINT ( "bar_start=%llx, bar_end=%llx, bar_length=%lx, flag=%lx\n", bar_start, + bar_end, bar_length, pci_resource_flags(dev, i)); + + /* map the device memory or IO region into kernel virtual + * address space */ + fpgapci->bar[i] = ioremap_nocache (bar_start + FPGALOGIC_I2C_BASE, I2C_PCI_MAX_BUS * FPGALOGIC_CH_OFFSET); + + if (!fpgapci->bar[i]) { + PRINT ( "Could not map BAR #%d.\n", i); + return -1; + } + + PRINT ( "BAR[%d] mapped at 0x%p with length %lu.", i, + fpgapci->bar[i], bar_length); + + if(i == 0) //FPGA register is in the BAR[0] + { + + fpga_phys_addr = bar_start; + fpga_ctl_addr = ioremap_nocache (bar_start, FPGA_CTL_REG_SIZE); + fpga_base_addr = fpgapci->bar[i]; + } + + PRINT ( "BAR[%d] mapped at 0x%p with length %lu.\n", i, + fpgapci->bar[i], bar_length); + } + return 0; +} + +static void free_bars(struct fpgapci_dev *fpgapci, struct pci_dev *dev) +{ + int i; + + for (i = 0; i < PCI_NUM_BARS; i++) { + if (fpgapci->bar[i]) { + pci_iounmap(dev, fpgapci->bar[i]); + fpgapci->bar[i] = NULL; + } + } +} + +#define FPGA_PCI_NAME "FPGA_PCI" + +/** + * @brief Register specific function with msi interrupt line + * @param dev Pointer to pci-device, which should be allocated + * @param int interrupt number relative to global interrupt number + * @return Returns error code or zero if success + * */ +static int register_intr_handler(struct pci_dev *dev, int irq_num_id) +{ + int err = 0; + struct fpgapci_dev *fpgapci = 0; + + fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&dev->dev); + if (fpgapci == 0) { + PRINT ( ": fpgapci_dev is 0\n"); + return err; + } + + if ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_00) { + /* Request interrupt line for unique function + * alternatively function will be called from free_irq as well + * with flag IRQF_SHARED */ + switch(irq_num_id) { + /* Currently we only support test vector 2 for FPGA Logic I2C channel + * controller 1-7 interrupt*/ + case FPGA_MSI_VECTOR_ID_4: + err = request_irq(dev->irq + irq_num_id, fpgaport_1_32_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, dev); + PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_5: + err = request_irq(dev->irq + irq_num_id, fpgaport_33_64_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, dev); + PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_8: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[0]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_9: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[1]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_10: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[2]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_11: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[3]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_12: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[4]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_13: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[5]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_14: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[6]); + fpgapci->irq_assigned++; + break; + + default: + PRINT("No more interrupt handler for number (%d)\n", + dev->irq + irq_num_id); + break; + } + } else if (((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_01) || + ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_02) || + ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_03)) { + /* FPGA SPEC 4.3.1.34, First i2c channel mapped to vector 8 */ + switch (irq_num_id) { + case FPGA_MSI_VECTOR_ID_4: + err = request_irq(dev->irq + irq_num_id, fpgaport_1_32_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, dev); + PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_5: + err = request_irq(dev->irq + irq_num_id, fpgaport_33_64_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, dev); + PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_8: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[0]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_9: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[1]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_10: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[2]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_11: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[3]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_12: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[4]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_13: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_5) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[5]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_14: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_5) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[6]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_15: + /*it is an external interrupt number. Ignore this case */ + break; + case FPGA_MSI_VECTOR_ID_16: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_7) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[7]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_17: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_8) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[8]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_18: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_8) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[9]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_19: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_10) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[10]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_20: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_10) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[11]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_21: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[12]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_22: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[13]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_23: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[14]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_24: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[15]); + fpgapci->irq_assigned++; + } + break; + + default: + PRINT("No more interrupt handler for number (%d)\n", + dev->irq + irq_num_id); + break; + } + } + + return err; +} +/* Mask for MSI Multi message enable bits */ +#define MSI_MME 0x70 +/** + * These enums define the type of interrupt scheme that the overall + * system uses. + */ +enum fpga_irq_type { + INT_MSI_SINGLE, + INT_MSI_MULTI, + INT_MSIX, + INT_NONE, + INT_FENCE /* Last item to guard from loop run-overs */ +}; +/** + * @def PCI_DEVICE_STATUS + * define the offset for STS register + * from the start of PCI config space as specified in the + * NVME_Comliance 1.0b. offset 06h:STS - Device status. + * This register has error status for NVME PCI Exress + * Card. After reading data from this reagister, the driver + * will identify if any error is set during the operation and + * report as kernel alert message. + */ +#define PCI_DEVICE_STATUS 0x6 +/** + * @def NEXT_MASK + * This indicates the location of the next capability item + * in the list. + */ +#define NEXT_MASK 0xFF00 +/** + * @def MSIXCAP_ID + * This bit indicates if the pointer leading to this position + * is a capability. + */ +#define MSIXCAP_ID 0x11 +/** + * @def MSICAP_ID + * This bit indicates if the pointer leading to this position + * is a capability. + */ +#define MSICAP_ID 0x5 + +/** + * @def CL_MASK + * This bit position indicates Capabilities List of the controller + * The controller should support the PCI Power Management cap as a + * minimum. + */ +#define CL_MASK 0x0010 + +/** + * @def CAP_REG + * Set to offset defined in NVME Spec 1.0b. + */ +#define CAP_REG 0x34 +static void msi_set_enable(struct pci_dev *dev, int enable) +{ + int pos,maxvec; + u16 control; + int request_private_bits = 4; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + + if (pos) { + pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); + maxvec = 1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1); + PRINT("control = 0x%x maxvec = 0x%x\n", control, maxvec); + control &= ~PCI_MSI_FLAGS_ENABLE; + + + /* + * The PCI 2.3 spec mandates that there are at most 32 + * interrupts. If this device asks for more, only give it one. + */ + if (request_private_bits > 5) { + request_private_bits = 0; + } + + /* Update the number of IRQs the device has available to it */ + control &= ~PCI_MSI_FLAGS_QSIZE; + control |= (request_private_bits << 4); + + pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); + } +} +/** + * @brief Enables pcie-device and claims/remaps neccessary bar resources + * @param dev Pointer to pci-device, which should be allocated + * @return Returns error code or zero if success + * */ +static int fpgapci_setup_device(struct fpgapci_dev *fpgapci,struct pci_dev *dev) +{ + int err = 0; + + /* wake up the pci device */ + err = pci_enable_device(dev); + if(err) { + PRINT("failed to enable pci device %d\n", err); + goto error_pci_en; + } + + /* on platforms with buggy ACPI, pdev->msi_enabled may be set to + * allow pci_enable_device to work. This indicates INTx was not routed + * and only MSI should be used + */ + + pci_set_master(dev); + + /* Setup the BAR memory regions */ + err = pci_request_regions(dev, DRIVER_NAME); + if (err) { + PRINT("failed to enable pci device %d\n", err); + goto error_pci_req; + } + + scan_bars(fpgapci, dev); + + if (map_bars(fpgapci, dev)) { + goto fail_map_bars; + } + + i2c_pci_init(); + + return 0; + /* ERROR HANDLING */ +fail_map_bars: + pci_release_regions(dev); +error_pci_req: + pci_disable_device(dev); +error_pci_en: + return -ENODEV; +} + +static int fpgapci_configure_msi(struct fpgapci_dev *fpgapci,struct pci_dev *dev) +{ + int err = 0, i; + int request_vec; + + msi_set_enable(dev,1); + PRINT("Check MSI capability after msi_set_enable\n"); + + + /*Above 4.1.12*/ + request_vec = total_i2c_pci_bus; + err = pci_alloc_irq_vectors(dev, request_vec, pci_msi_vec_count(dev), + PCI_IRQ_MSI);//PCI_IRQ_AFFINITY | PCI_IRQ_MSI); + + if (err <= 0) { + PRINT("Cannot set MSI vector (%d)\n", err); + goto error_no_msi; + } else { + PRINT("Got %d MSI vectors starting at %d\n", err, dev->irq); + if ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_00) { + if (err < MSI_VECTOR_REV_00) { + goto error_disable_msi; + } + } else if (((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_01) || + ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_02) || + ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_03)) { + if (err < MSI_VECTOR_REV_01) { + goto error_disable_msi; + } + } + } + fpgapci->irq_first = dev->irq; + fpgapci->irq_length = err; + fpgapci->irq_assigned = 0; + + + for(i = 0; i < fpgapci->irq_length; i++) { + err = register_intr_handler(dev, i); + if (err) { + PRINT("Cannot request Interrupt number %d\n", i); + goto error_pci_req_irq; + } + } + + return 0; + +error_pci_req_irq: + for(i = 0; i < fpgapci->irq_assigned; i++) + { + PRINT("free_irq %d i =%d\n",fpgapci->irq_first + i,i); + if (i < 7) + free_irq(fpgapci->irq_first + 8 + i, &fpgalogic_i2c[i]); + else + free_irq(fpgapci->irq_first + 8 + i + 1, &fpgalogic_i2c[i]); + } +error_disable_msi: + pci_disable_msi(fpgapci->pci_dev); +error_no_msi: + return -ENOSPC; +} + +static int fpgapci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct fpgapci_dev *fpgapci = 0; + +#ifdef TEST + PRINT ( " vendor = 0x%x, device = 0x%x, class = 0x%x, bus:slot.func = %02x:%02x.%02x\n", + dev->vendor, dev->device, dev->class, + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); +#endif + fpgapci = kzalloc(sizeof(struct fpgapci_dev), GFP_KERNEL); + + if (!fpgapci) { + PRINT( "Couldn't allocate memory!\n"); + goto fail_kzalloc; + } + + fpgapci->pci_dev = dev; + dev_set_drvdata(&dev->dev, (void*)fpgapci); + + + fpgapci->upstream = find_upstream_dev (dev); + + if(fpgapci_setup_device(fpgapci,dev)) { + goto error_no_device; + } + + printk("%s:MSI-irq disabled \n", __FUNCTION__); + + if (use_irq) { + printk("%s:MSI-irq enabled\n", __FUNCTION__); + if(fpgapci_configure_msi(fpgapci,dev)) { + goto error_cannot_configure; + } + } + + + return 0; + /* ERROR HANDLING */ +error_cannot_configure: + printk("error_cannot_configure\n"); + free_bars (fpgapci, dev); + pci_release_regions(dev); + pci_disable_device(dev); +error_no_device: + i2c_pci_deinit(); + printk("error_no_device\n"); +fail_kzalloc: + return -1; + + +} + +static void fpgapci_remove(struct pci_dev *dev) +{ + struct fpgapci_dev *fpgapci = 0; + int i; + PRINT (": dev is %p\n", dev); + + if (dev == 0) { + PRINT ( ": dev is 0\n"); + return; + } + + fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&dev->dev); + if (fpgapci == 0) { + PRINT ( ": fpgapci_dev is 0\n"); + return; + } + i2c_pci_deinit(); + // + if (use_irq) + { + for(i = 0; i < fpgapci->irq_assigned; i++) + { + PRINT("free_irq %d i =%d\n",fpgapci->irq_first + i,i); + if (i < 7) + free_irq(fpgapci->irq_first + 8 + i, &fpgalogic_i2c[i]); + else + free_irq(fpgapci->irq_first + 8 + i + 1, &fpgalogic_i2c[i]); + } + } + pci_disable_msi(fpgapci->pci_dev); + free_bars (fpgapci, dev); + pci_disable_device(dev); + pci_release_regions(dev); + + kfree (fpgapci); +} + +static const struct pci_device_id fpgapci_ids[] = { + {PCI_DEVICE(PCI_VENDOR_ID_XILINX, DEVICE)}, + {0, }, +}; + +MODULE_DEVICE_TABLE(pci, fpgapci_ids); + +static struct pci_driver fpgapci_driver = { + .name = DRIVER_NAME, + .id_table = fpgapci_ids, + .probe = fpgapci_probe, + .remove = fpgapci_remove, + /* resume, suspend are optional */ +}; + +/* Initialize the driver module (but not any device) and register + * the module with the kernel PCI subsystem. */ +static int __init fpgapci_init(void) +{ + + if (pci_register_driver(&fpgapci_driver)) { + PRINT("pci_unregister_driver\n"); + pci_unregister_driver(&fpgapci_driver); + return -ENODEV; + } + + return 0; +} + +static void __exit fpgapci_exit(void) +{ + PRINT ("fpgapci_exit"); + + /* unregister this driver from the PCI bus driver */ + pci_unregister_driver(&fpgapci_driver); + +} + + +module_init (fpgapci_init); +module_exit (fpgapci_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("joyce_yu@dell.com"); +MODULE_DESCRIPTION ("Driver for FPGA Logic I2C bus"); +MODULE_SUPPORTED_DEVICE ("FPGA Logic I2C bus"); + diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/check_qsfp.sh b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/check_qsfp.sh new file mode 100644 index 000000000000..a781b1b5599f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/check_qsfp.sh @@ -0,0 +1,3 @@ +# Temporary dummy file for s5224f. +# Will be updated soon. + diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/pcisysfs.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/pcisysfs.py new file mode 100644 index 000000000000..347d1bd7fb33 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/pcisysfs.py @@ -0,0 +1,102 @@ +#!/usr/bin/python +# Copyright (c) 2015 Dell Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. + +import struct +import sys +import getopt +from os import * +from mmap import * + +def usage(): + ''' This is the Usage Method ''' + + print '\t\t pcisysfs.py --get --offset --res ' + print '\t\t pcisysfs.py --set --val --offset --res ' + sys.exit(1) + +def pci_mem_read(mm,offset): + mm.seek(offset) + read_data_stream=mm.read(4) + print "" + reg_val=struct.unpack('I',read_data_stream) + print "reg_val read:%x"%reg_val + return reg_val + +def pci_mem_write(mm,offset,data): + mm.seek(offset) + print "data to write:%x"%data + mm.write(struct.pack('I',data)) + +def pci_set_value(resource,val,offset): + fd=open(resource,O_RDWR) + mm=mmap(fd,0) + pci_mem_write(mm,offset,val) + +def pci_get_value(resource,offset): + fd=open(resource,O_RDWR) + mm=mmap(fd,0) + pci_mem_read(mm,offset) + +def main(argv): + + ''' The main function will read the user input from the + command line argument and process the request ''' + + opts = '' + val = '' + choice = '' + resource = '' + offset = '' + + try: + opts, args = getopt.getopt(argv, "hgsv:" , \ + ["val=","res=","offset=","help", "get", "set"]) + + except getopt.GetoptError: + usage() + + for opt,arg in opts: + + if opt in ('-h','--help'): + choice = 'help' + + elif opt in ('-g', '--get'): + choice = 'get' + + elif opt in ('-s', '--set'): + choice = 'set' + + elif opt == '--res': + resource = arg + + elif opt == '--val': + val = int(arg,16) + + elif opt == '--offset': + offset = int(arg,16) + + if choice == 'set' and val != '' and offset !='' and resource !='': + pci_set_value(resource,val,offset) + + elif choice == 'get' and offset != '' and resource !='': + pci_get_value(resource,offset) + + else: + usage() + +#Calling the main method +if __name__ == "__main__": + main(sys.argv[1:]) + diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/platform_sensors.py new file mode 100644 index 000000000000..b1e3776d17fe --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/platform_sensors.py @@ -0,0 +1,321 @@ +#!/usr/bin/python +# On S5224F, the BaseBoard Management Controller is an +# autonomous subsystem provides monitoring and management +# facility independent of the host CPU. IPMI standard +# protocol is used with ipmitool to fetch sensor details. +# Current script support X00 board only. X01 support will +# be added soon. This provies support for the +# following objects: +# * Onboard temperature sensors +# * FAN trays +# * PSU + + +import os +import sys +import logging +import subprocess +import commands + +S5224F_MAX_FAN_TRAYS = 4 +S5224F_MAX_PSUS = 2 +IPMI_SENSOR_DATA = "ipmitool sdr list" +IPMI_SENSOR_DUMP = "/tmp/sdr" + +PSU_PRESENCE = "PSU{0}_stat" +# Use this for older firmware +# PSU_PRESENCE="PSU{0}_prsnt" + +IPMI_FAN_PRESENCE = "ipmitool sensor get FAN{0}_prsnt" +IPMI_PSU1_DATA_DOCKER = "ipmitool raw 0x04 0x2d 0x31 | awk '{print substr($0,9,1)}'" +IPMI_PSU2_DATA_DOCKER = "ipmitool raw 0x04 0x2d 0x32 | awk '{print substr($0,9,1)}'" +IPMI_RAW_STORAGE_READ = "ipmitool raw 0x0a 0x11 {0} 0 0 0xa0" +IPMI_FRU = "ipmitool fru" +ipmi_sdr_list = "" + +# Dump sensor registers + + +def ipmi_sensor_dump(): + + status = 1 + global ipmi_sdr_list + ipmi_cmd = IPMI_SENSOR_DATA + status, ipmi_sdr_list = commands.getstatusoutput(ipmi_cmd) + + if status: + logging.error('Failed to execute:' + ipmi_sdr_list) + sys.exit(0) + +# Fetch a Fan Status + +def get_fan_status(fan_id): + ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_FAN_PRESENCE.format(fan_id)) + if ret_status: + logging.error('Failed to execute : %s'%IPMI_FAN_PRESENCE.format(fan_id)) + sys.exit(0) + return(' ' + ipmi_cmd_ret.splitlines()[5].strip(' ').strip('[]')) + +# Fetch a BMC register + + +def get_pmc_register(reg_name): + + output = None + for item in ipmi_sdr_list.split("\n"): + if reg_name in item: + output = item.strip() + + if output is None: + print('\nFailed to fetch: ' + reg_name + ' sensor ') + sys.exit(0) + + output = output.split('|')[1] + + logging.basicConfig(level=logging.DEBUG) + return output + +#Fetch FRU Data for given fruid +def get_psu_airflow(psu_id): + fru_id = 'PSU' + str(psu_id) + '_fru' + ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_FRU) + if ret_status: + logging.error('Failed to execute ipmitool: '+ IPMI_FRU) + sys.exit(0) + found_fru = False + for line in ipmi_cmd_ret.splitlines(): + if line.startswith('FRU Device Description') and fru_id in line.split(':')[1] : + found_fru = True + if found_fru and line.startswith(' Board Product '): + return 'Intake' if 'PS/IO' in line else 'Exhaust' + return '' + +# Fetch FRU on given offset +def fetch_raw_fru(dev_id, offset): + ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_RAW_STORAGE_READ.format(dev_id)) + if ret_status: + logging.error('Failed to execute ipmitool :' + IPMI_RAW_STORAGE_READ.format(dev_id)) + sys.exit(0) + return int((ipmi_cmd_ret.splitlines()[offset/16]).split(' ')[(offset%16+1)]) + +def get_fan_airflow(fan_id): + Airflow_Direction = ['Exhaust', 'Intake'] + return Airflow_Direction[fetch_raw_fru(fan_id+2, 0x46)] + +# Print the information for temperature sensors + + +def print_temperature_sensors(): + + print("\nOnboard Temperature Sensors:") + + print (' PT_Left_temp: ',\ + (get_pmc_register('PT_Left_temp'))) + print (' PT_Mid_temp: ',\ + (get_pmc_register('PT_Mid_temp'))) + print (' PT_Right_temp: ',\ + (get_pmc_register('PT_Right_temp'))) + print (' Broadcom Temp: ',\ + (get_pmc_register('NPU_Near_temp'))) + print (' Inlet Airflow Temp: ',\ + (get_pmc_register('ILET_AF_temp'))) + print (' CPU Temp: ',\ + (get_pmc_register('CPU_temp'))) + +ret_status, ipmi_cmd_ret = commands.getstatusoutput('echo 0 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us') +ipmi_sensor_dump() + +print_temperature_sensors() + +# Print the information for 1 Fan Tray + + +def print_fan_tray(tray): + + Fan_Status = [' Normal', ' Abnormal'] + print (' Fan Tray ' + str(tray) + ':') + + if (tray == 1): + + fan1_status = int(get_pmc_register('FAN1_Front_stat'), 16) + fan2_status = int(get_pmc_register('FAN1_Rear_stat'), 16) + + print (' Fan1 Speed: ',\ + get_pmc_register('FAN1_Front_rpm')) + print (' Fan2 Speed: ',\ + get_pmc_register('FAN1_Rear_rpm')) + print (' Fan1 State: ',\ + Fan_Status[fan1_status]) + print (' Fan2 State: ',\ + Fan_Status[fan2_status]) + + elif (tray == 2): + + fan1_status = int(get_pmc_register('FAN2_Front_stat'), 16) + fan2_status = int(get_pmc_register('FAN2_Rear_stat'), 16) + + print (' Fan1 Speed: ',\ + get_pmc_register('FAN2_Front_rpm')) + print (' Fan2 Speed: ',\ + get_pmc_register('FAN2_Rear_rpm')) + print (' Fan1 State: ',\ + Fan_Status[fan1_status]) + print (' Fan2 State: ',\ + Fan_Status[fan2_status]) + + elif (tray == 3): + + fan1_status = int(get_pmc_register('FAN3_Front_stat'), 16) + fan2_status = int(get_pmc_register('FAN3_Rear_stat'), 16) + + print (' Fan1 Speed: ',\ + get_pmc_register('FAN3_Front_rpm')) + print (' Fan2 Speed: ',\ + get_pmc_register('FAN3_Rear_rpm')) + print (' Fan1 State: ',\ + Fan_Status[fan1_status]) + print (' Fan2 State: ',\ + Fan_Status[fan2_status]) + + elif (tray == 4): + + fan1_status = int(get_pmc_register('FAN4_Front_stat'), 16) + fan2_status = int(get_pmc_register('FAN4_Rear_stat'), 16) + + print (' Fan1 Speed: ',\ + get_pmc_register('FAN4_Front_rpm')) + print (' Fan2 Speed: ',\ + get_pmc_register('FAN4_Rear_rpm')) + print (' Fan1 State: ',\ + Fan_Status[fan1_status]) + print (' Fan2 State: ',\ + Fan_Status[fan2_status]) + print (' Airflow: ',\ + get_fan_airflow(tray)) + + +print('\nFan Trays:') + +for tray in range(1, S5224F_MAX_FAN_TRAYS + 1): + if (get_fan_status(tray) == ' Present'): + print_fan_tray(tray) + else: + print (' Fan Tray %d:' % (tray)) + print (' Fan State: Not present') + +def get_psu_presence(index): + """ + Retrieves the presence status of power supply unit (PSU) defined + by index + :param index: An integer, index of the PSU of which to query status + :return: Boolean, True if PSU is plugged, False if not + """ + ret_status = 1 + + if index == 1: + ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_PSU1_DATA_DOCKER) + elif index == 2: + ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_PSU2_DATA_DOCKER) + + if ret_status: + logging.error('Failed to execute ipmitool :' + IPMI_PSU1_DATA_DOCKER) + sys.exit(0) + + psu_status = ipmi_cmd_ret + return (int(psu_status, 16) & 1) + +def get_psu_status(index): + """ + Retrieves the presence status of power supply unit (PSU) defined + by index + :param index: An integer, index of the PSU of which to query status + :return: Boolean, True if PSU is plugged, False if not + """ + status = 0 + ret_status = 1 + ipmi_cmd_ret = 'f' + + if index == 1: + ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_PSU1_DATA_DOCKER) + elif index == 2: + ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_PSU2_DATA_DOCKER) + + if ret_status: + logging.error('Failed to execute ipmitool : ' + IPMI_PSU2_DATA_DOCKER) + sys.exit(0) + + psu_status = ipmi_cmd_ret + + return (not int(psu_status, 16) > 1) + + +# Print the information for PSU1, PSU2 +def print_psu(psu): + + # PSU FAN details + if (psu == 1): + + print (' PSU1:') + print (' FAN Normal Temperature: ',\ + get_pmc_register('PSU1_temp')) + print (' FAN AirFlow Temperature: ',\ + get_pmc_register('PSU1_AF_temp')) + print (' FAN RPM: ',\ + get_pmc_register('PSU1_rpm')) + + # PSU input & output monitors + print (' Input Voltage: ',\ + get_pmc_register('PSU1_In_volt')) + print (' Output Voltage: ',\ + get_pmc_register('PSU1_Out_volt')) + print (' Input Power: ',\ + get_pmc_register('PSU1_In_watt')) + print (' Output Power: ',\ + get_pmc_register('PSU1_Out_watt')) + print (' Input Current: ',\ + get_pmc_register('PSU1_In_amp')) + print (' Output Current: ',\ + get_pmc_register('PSU1_Out_amp')) + + else: + + print (' PSU2:') + print (' FAN Normal Temperature: ',\ + get_pmc_register('PSU2_temp')) + print (' FAN AirFlow Temperature: ',\ + get_pmc_register('PSU2_AF_temp')) + print (' FAN RPM: ',\ + get_pmc_register('PSU2_rpm')) + + # PSU input & output monitors + print (' Input Voltage: ',\ + get_pmc_register('PSU2_In_volt')) + print (' Output Voltage: ',\ + get_pmc_register('PSU2_Out_volt')) + print (' Input Power: ',\ + get_pmc_register('PSU2_In_watt')) + print (' Output Power: ',\ + get_pmc_register('PSU2_Out_watt')) + print (' Input Current: ',\ + get_pmc_register('PSU2_In_amp')) + print (' Output Current: ',\ + get_pmc_register('PSU2_Out_amp')) + print (' Airflow: ',\ + get_psu_airflow(psu)) + + +print('\nPSUs:') +for psu in range(1, S5224F_MAX_PSUS + 1): + if not get_psu_presence(psu): + print (' PSU%d:' % (psu)) + print (' Status: Not present') + elif not get_psu_status(psu) : + print (' PSU%d:' % (psu)) + print (' Status: Not OK') + else: + print_psu(psu) + +print ('\n Total Power: ',\ + get_pmc_register('PSU_Total_watt')) + +ret_status, ipmi_cmd_ret = commands.getstatusoutput('echo 1000 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us') diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/qsfp_irq_enable.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/qsfp_irq_enable.py new file mode 100644 index 000000000000..a61577fdb0d4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/qsfp_irq_enable.py @@ -0,0 +1,3 @@ +#!/usr/bin/python + +# No IRQ support for S5224F \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/s5224f_platform.sh b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/s5224f_platform.sh new file mode 100755 index 000000000000..bbb0a49ba842 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/s5224f_platform.sh @@ -0,0 +1,202 @@ +#!/bin/bash + +init_devnum() { + found=0 + for devnum in 0 1; do + devname=`cat /sys/bus/i2c/devices/i2c-${devnum}/name` + # iSMT adapter can be at either dffd0000 or dfff0000 + if [[ $devname == 'SMBus iSMT adapter at '* ]]; then + found=1 + break + fi + done + + [ $found -eq 0 ] && echo "cannot find iSMT" && exit 1 +} + +# Attach/Detach syseeprom on CPU board +sys_eeprom() { + b='' + for bb in 0 1; do + if [ "$(cat /sys/bus/i2c/devices/i2c-${bb}/name)" = 'SMBus iSMT adapter at dff9f000' ]; then + b=$bb + break + fi + done + if [ "$b" = '' ]; then + echo "s5224f_platform: sys_eeprom : cannot find I2C bus!" + return + fi + + case $1 in + "new_device") echo 24c16 0x50 > /sys/bus/i2c/devices/i2c-${b}/$1 + ;; + "delete_device") echo 0x50 > /sys/bus/i2c/devices/i2c-${b}/$1 + ;; + *) echo "s5224f_platform: sys_eeprom : invalid command !" + ;; + esac +} + +#Attach/Detach the MUX connecting all SFP28s/QSFP28s +switch_board_qsfp_mux() { + case $1 in + "new_device") + for ((i=603;i<=606;i++)); + do + echo "Attaching PCA9548 @ 0x74" + echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-$i/$1 + done + + ;; + "delete_device") + for ((i=603;i<=606;i++)); + do + echo "Detaching PCA9548 @ 0x74" + echo 0x74 > /sys/bus/i2c/devices/i2c-$i/$1 + done + + ;; + *) echo "s5224f_platform: switch_board_qsfp_mux: invalid command !" + ;; + esac + sleep 2 +} + +#Attach/Detach 24 instances of EEPROM driver SFP28 ports. Use optoe2 (for dual address devices) +#Attach/Detach 4 instances of EEPROM driver QSFP28 ports. Use optoe1 (for single address devices) +#eeprom can dump data using below command +switch_board_qsfp() { + case $1 in + "new_device") + for ((i=2;i<=25;i++)); + do + echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + done + for ((i=26;i<=29;i++)); + do + echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + done + ;; + + "delete_device") + for ((i=2;i<=29;i++)); + do + echo 0x50 > /sys/bus/i2c/devices/i2c-$i/$1 + done + ;; + + *) echo "s5224f_platform: switch_board_qsfp: invalid command !" + ;; + esac +} + +#Modsel 4 ports to applicable QSFP28 type modules +#This enables the adapter to respond for i2c commands +switch_board_modsel() { + resource="/sys/bus/pci/devices/0000:04:00.0/resource0" + for ((i=1;i<=28;i++)); + do + port_addr=$(( 16384 + ((i - 1) * 16))) + hex=$( printf "0x%x" $port_addr ) + python /usr/bin/pcisysfs.py --set --offset $hex --val 0x10 --res $resource > /dev/null 2>&1 + done +} + +platform_firmware_versions() { + FIRMWARE_VERSION_FILE=/var/log/firmware_versions + rm -rf ${FIRMWARE_VERSION_FILE} + echo "BIOS: `dmidecode -s system-version `" > $FIRMWARE_VERSION_FILE + ## Get FPGA version + r=`/usr/bin/pcisysfs.py --get --offset 0x00 --res /sys/bus/pci/devices/0000\:04\:00.0/resource0 | sed '1d; s/.*\(....\)$/\1/; s/\(..\{1\}\)/\1./'` + r_min=$(echo $r | sed 's/.*\(..\)$/0x\1/') + r_maj=$(echo $r | sed 's/^\(..\).*/0x\1/') + echo "FPGA: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE + + ## Get BMC Firmware Revision + r=`cat /sys/class/ipmi/ipmi0/device/bmc/firmware_revision` + echo "BMC: $r" >> $FIRMWARE_VERSION_FILE + + #System CPLD 0x31 on i2c bus 601 ( physical FPGA I2C-2) + r_min=`/usr/sbin/i2cget -y 601 0x31 0x0 | sed ' s/.*\(0x..\)$/\1/'` + r_maj=`/usr/sbin/i2cget -y 601 0x31 0x1 | sed ' s/.*\(0x..\)$/\1/'` + echo "System CPLD: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE + + #Slave CPLD 1 0x30 on i2c bus 600 ( physical FPGA I2C-1) + r_min=`/usr/sbin/i2cget -y 600 0x30 0x0 | sed ' s/.*\(0x..\)$/\1/'` + r_maj=`/usr/sbin/i2cget -y 600 0x30 0x1 | sed ' s/.*\(0x..\)$/\1/'` + echo "Slave CPLD 1: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE + + #Slave CPLD 2 0x31 on i2c bus 600 ( physical FPGA I2C-1) + r_min=`/usr/sbin/i2cget -y 600 0x31 0x0 | sed ' s/.*\(0x..\)$/\1/'` + r_maj=`/usr/sbin/i2cget -y 600 0x31 0x1 | sed ' s/.*\(0x..\)$/\1/'` + echo "Slave CPLD 2: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE + +} + +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=$(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" + resource="/sys/bus/pci/devices/0000:04:00.0/resource0" + + mkdir -p $(dirname $REBOOT_REASON_FILE) + + # Handle First Boot into software version with reboot cause determination support + if [[ ! -e $REBOOT_REASON_FILE ]]; then + echo "0" > $REBOOT_REASON_FILE + else + /usr/bin/pcisysfs.py --get --offset 0x18 --res $resource | sed '1d; s/.*:\(.*\)$/\1/;' > $REBOOT_REASON_FILE + fi + /usr/bin/pcisysfs.py --set --val 0x0 --offset 0x18 --res $resource +} + +#This enables the led control for CPU and default states +switch_board_led_default() { + resource="/sys/bus/pci/devices/0000:04:00.0/resource0" + python /usr/bin/pcisysfs.py --set --offset 0x24 --val 0x194 --res $resource > /dev/null 2>&1 +} +init_devnum + +if [ "$1" == "init" ]; then + modprobe i2c-dev + modprobe i2c-mux-pca954x force_deselect_on_exit=1 + modprobe ipmi_devintf + modprobe ipmi_si kipmid_max_busy_us=1000 + modprobe i2c_ocores + modprobe dell_s5224f_fpga_ocores + sys_eeprom "new_device" + get_reboot_cause + switch_board_qsfp_mux "new_device" + switch_board_qsfp "new_device" + switch_board_modsel + switch_board_led_default + install_python_api_package + #python /usr/bin/qsfp_irq_enable.py + platform_firmware_versions + +elif [ "$1" == "deinit" ]; then + sys_eeprom "delete_device" + switch_board_qsfp "delete_device" + switch_board_qsfp_mux "delete_device" + + modprobe -r i2c-mux-pca954x + modprobe -r i2c-dev + remove_python_api_package + modprobe -r ipmi_devintf + modprobe -r ipmi_si +else + echo "s5224f_platform : Invalid option !" +fi diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/sensors b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/sensors new file mode 100644 index 000000000000..ee53f2b0f325 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/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/s5224f/setup.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/setup.py new file mode 120000 index 000000000000..4f6de9941d96 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/setup.py @@ -0,0 +1 @@ +../s6100/setup.py \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/__init__.py new file mode 100644 index 000000000000..929d4eac3de4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +__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/s5224f/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/chassis.py new file mode 100644 index 000000000000..1b241512ecdb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/chassis.py @@ -0,0 +1,340 @@ +#!/usr/bin/env python + +############################################################################# +# DELLEMC S5224F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + import time + import sys + 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 + from sonic_platform.hwaccess import pci_get_value, pci_set_value +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +MAX_S5224F_COMPONENT = 5 +MAX_S5224F_FANTRAY =4 +MAX_S5224F_FAN = 2 +MAX_S5224F_PSU = 2 +MAX_S5224F_THERMAL = 8 +SYSTEM_LED_REG = 0x24 +SYSTEM_BEACON_LED_SET = 0x8 +SYSTEM_BEACON_LED_CLEAR = 0xFFFFFFF7 + +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 + """ + + REBOOT_CAUSE_PATH = "/host/reboot-cause/platform/reboot_reason" + OIR_FD_PATH = "/sys/bus/pci/devices/0000:04:00.0/port_msi" + + _global_port_pres_dict = {} + + 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 = 28 + self.SFP28_PORT_END = 24 + + PORTS_IN_BLOCK = (self.PORT_END + 1) + _sfp_port = range(1, self.SFP28_PORT_END + 1) + eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" + + for index in range(self.PORT_START, PORTS_IN_BLOCK): + port_num = index + 1 + eeprom_path = eeprom_base.format(port_num) + if index not in _sfp_port: + sfp_node = Sfp(index, 'QSFP', eeprom_path) + else: + sfp_node = Sfp(index, 'SFP', eeprom_path) + self._sfp_list.append(sfp_node) + + self._eeprom = Eeprom() + self._watchdog = Watchdog() + self._num_sfps = self.PORT_END + self._num_fans = MAX_S5224F_FAN * MAX_S5224F_FANTRAY + + for i in range(MAX_S5224F_THERMAL): + thermal = Thermal(i) + self._thermal_list.append(thermal) + + for i in range(MAX_S5224F_COMPONENT): + component = Component(i) + self._component_list.append(component) + + for i in range(MAX_S5224F_PSU): + psu = Psu(i) + self._psu_list.append(psu) + + for i in range(MAX_S5224F_FANTRAY): + for j in range(MAX_S5224F_FAN): + fan = Fan(i,j) + self._fan_list.append(fan) + + for i in range(MAX_S5224F_FANTRAY): + fandrawer = FanDrawer(i) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + for port_num in range(self.PORT_START, (self.PORT_END + 1)): + # sfp get uses zero-indexing, but port numbers start from 1 + presence = self.get_sfp(port_num-1).get_presence() + if presence: + self._global_port_pres_dict[port_num] = '1' + else: + self._global_port_pres_dict[port_num] = '0' + +# 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 + """ + start_ms = time.time() * 1000 + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + while True: + time.sleep(0.5) + for port_num in range(self.PORT_START, (self.PORT_END + 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 + + if timeout: + now_ms = time.time() * 1000 + if (now_ms - start_ms >= timeout): + return True, change_dict + + + 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-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self._eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self._eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis (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_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_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. + """ + try: + with open(self.REBOOT_CAUSE_PATH) as fd: + reboot_cause = int(fd.read(), 16) + except EnvironmentError: + return (self.REBOOT_CAUSE_NON_HARDWARE, None) + + if reboot_cause & 0x1: + return (self.REBOOT_CAUSE_POWER_LOSS, None) + elif reboot_cause & 0x2: + return (self.REBOOT_CAUSE_NON_HARDWARE, None) + elif reboot_cause & 0x4: + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "PSU Shutdown") + elif reboot_cause & 0x8: + return (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, None) + elif reboot_cause & 0x10: + return (self.REBOOT_CAUSE_WATCHDOG, None) + elif reboot_cause & 0x20: + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "BMC Shutdown") + elif reboot_cause & 0x40: + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Hot-Swap Shutdown") + elif reboot_cause & 0x80: + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Shutdown") + elif reboot_cause & 0x100: + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Cold Reboot") + else: + return (self.REBOOT_CAUSE_NON_HARDWARE, None) + + 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 + + """ + resource = "/sys/bus/pci/devices/0000:04:00.0/resource0" + val = pci_get_value(resource, SYSTEM_LED_REG) + if self.LOCATOR_LED_ON == color: + val = int(val) | SYSTEM_BEACON_LED_SET + elif self.LOCATOR_LED_OFF == color: + val = int(val) & SYSTEM_BEACON_LED_CLEAR + else: + return False + pci_set_value(resource, val, SYSTEM_LED_REG) + return True + + def get_locator_led(self): + """ + Gets the state of the Chassis Locator LED + + Returns: + LOCATOR_LED_ON or LOCATOR_LED_OFF + """ + resource = "/sys/bus/pci/devices/0000:04:00.0/resource0" + val = pci_get_value(resource, SYSTEM_LED_REG) + val = int(val) & SYSTEM_BEACON_LED_SET + if not val: + return self.LOCATOR_LED_OFF + else: + return self.LOCATOR_LED_ON + diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/component.py new file mode 100644 index 000000000000..282a323f2583 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/component.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python + +######################################################################## +# DELLEMC S5224F +# +# 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 subprocess + from sonic_platform_base.component_base import ComponentBase + import sonic_platform.hwaccess as hwaccess + +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() + +def get_fpga_version(): + val = hwaccess.pci_get_value('/sys/bus/pci/devices/0000:03:00.0/resource0', 0) + return '{}.{}'.format((val >> 8) & 0xff, val & 0xff) + +def get_bmc_version(): + return subprocess.check_output( + ['cat', '/sys/class/ipmi/ipmi0/device/bmc/firmware_revision'] + ).strip() + +def get_cpld_version(bus, i2caddr): + return '{}.{}'.format(hwaccess.i2c_get(bus, i2caddr, 1), + hwaccess.i2c_get(bus, i2caddr, 0) + ) + +def get_cpld0_version(): + return get_cpld_version(601, 0x31) + +def get_cpld1_version(): + return get_cpld_version(600, 0x30) + + +class Component(ComponentBase): + """DellEMC Platform-specific Component class""" + + CHASSIS_COMPONENTS = [ + ['BIOS', + 'Performs initialization of hardware components during booting', + get_bios_version + ], + + ['FPGA', + 'Used for managing the system LEDs', + get_fpga_version + ], + + ['BMC', + 'Platform management controller for on-board temperature monitoring, in-chassis power, Fan and LED control', + get_bmc_version + ], + + ['System CPLD', + 'Used for managing the CPU power sequence and CPU states', + get_cpld0_version + ], + + ['Slave CPLD 1', + 'Used for managing SFP28/QSFP28 port transceivers (SFP28 1-24, QSFP28 1-4)', + get_cpld1_version + ] + ] + + 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/s5224f/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/eeprom.py new file mode 100644 index 000000000000..953423bbb64e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/eeprom.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python + +############################################################################# +# DellEmc S5224F +# +# 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 +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self): + self.eeprom_path = None + for b in (0, 1): + f = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom'.format(b) + if os.path.exists(f): + self.eeprom_path = f + break + if self.eeprom_path is None: + return + super(Eeprom, self).__init__(self.eeprom_path, 0, '', True) + self.eeprom_tlv_dict = dict() + try: + self.eeprom_data = self.read_eeprom() + except Exception: + 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].decode('ascii') + + 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(["{:02x}".format(T) for T in t[2]]).upper() + + 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].decode('ascii') + + 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].decode('ascii') + + 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].decode('ascii') + + 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].decode('ascii') + + 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/s5224f/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan.py new file mode 100644 index 000000000000..bf248a03846f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python + +######################################################################## +# DellEMC S5224F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fans' information which are available in the platform. +# +######################################################################## + +try: + from sonic_platform_base.fan_base import FanBase + from sonic_platform.ipmihelper import IpmiSensor, IpmiFru +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FAN1_MAX_SPEED_OFFSET = 71 +FAN2_MAX_SPEED_OFFSET = 73 +PSU_FAN_MAX_SPEED_OFFSET = 50 +FAN_DIRECTION_OFFSET = 69 +PSU_FAN_DIRECTION_OFFSET = 47 + + +class Fan(FanBase): + """DellEMC Platform-specific Fan class""" + # { FAN-ID: { Sensor-Name: Sensor-ID } } + # System rev X01, BMC firmware rev 1.02 + FAN_SENSOR_MAPPING = { 1: {"Prsnt": 0x53, "State": 0x57, "Speed": 0x24}, + 2: {"Prsnt": 0x53, "State": 0x5b, "Speed": 0x20}, + 3: {"Prsnt": 0x54, "State": 0x58, "Speed": 0x25}, + 4: {"Prsnt": 0x54, "State": 0x5c, "Speed": 0x21}, + 5: {"Prsnt": 0x55, "State": 0x59, "Speed": 0x26}, + 6: {"Prsnt": 0x55, "State": 0x5d, "Speed": 0x22}, + 7: {"Prsnt": 0x56, "State": 0x5a, "Speed": 0x27}, + 8: {"Prsnt": 0x56, "State": 0x5e, "Speed": 0x23} + } + PSU_FAN_SENSOR_MAPPING = { 1: {"State": 0x31, "Speed": 0x28}, + 2: {"State": 0x32, "Speed": 0x29} } + + # { FANTRAY-ID: FRU-ID } + FAN_FRU_MAPPING = { 1: 3, 2: 4, 3: 5, 4: 6 } + PSU_FRU_MAPPING = { 1: 1, 2: 2 } + + def __init__(self, fantray_index=1, fan_index=1, psu_fan=False, + dependency=None): + FanBase.__init__(self) + 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.fantrayindex = fantray_index + 1 + self.fanindex = fan_index + 1 + if (self.fanindex == 1): + self.max_speed_offset = FAN1_MAX_SPEED_OFFSET + else: + self.max_speed_offset = FAN2_MAX_SPEED_OFFSET + self.fan_direction_offset = FAN_DIRECTION_OFFSET + self.index = (self.fantrayindex - 1) * 2 + self.fanindex + self.prsnt_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Prsnt"], + is_discrete=True) + self.state_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["State"], + is_discrete=True) + self.speed_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Speed"]) + self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex]) + else: + self.dependency = dependency + self.fanindex = fan_index + self.state_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"], + is_discrete=True) + self.speed_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"]) + self.fru = IpmiFru(self.PSU_FRU_MAPPING[self.fanindex]) + self.max_speed_offset = PSU_FAN_MAX_SPEED_OFFSET + self.fan_direction_offset = PSU_FAN_DIRECTION_OFFSET + self.max_speed = self.fru.get_fru_data(self.max_speed_offset,2)[1] + self.max_speed = self.max_speed[1] << 8 | self.max_speed[0] + + 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.fanindex) + else: + return "FanTray{}-Fan{}".format(self.fantrayindex, self.fanindex) + + def get_model(self): + """ + Retrieves the part number of the FAN + Returns: + String: Part number of FAN + """ + if self.is_psu_fan: + return None + else: + return self.fru.get_board_part_number() + + def get_serial(self): + """ + Retrieves the serial number of the FAN + Returns: + String: Serial number of FAN + """ + if self.is_psu_fan: + return None + else: + return self.fru.get_board_serial() + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if fan is present, False if not + """ + presence = False + if self.is_psu_fan: + return self.dependency.get_presence() + else: + is_valid, state = self.prsnt_sensor.get_reading() + if is_valid: + if (state & 0b1): + presence = True + return presence + + def get_status(self): + """ + Retrieves the operational status of the FAN + Returns: + bool: True if FAN is operating properly, False if not + """ + status = False + is_valid, state = self.state_sensor.get_reading() + if is_valid: + if not state > 1: + status = True + return status + + 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. + """ + direction = [self.FAN_DIRECTION_EXHAUST, self.FAN_DIRECTION_INTAKE] + fan_status = self.get_presence() + if not fan_status: + return None + is_valid, fan_direction = self.fru.get_fru_data(self.fan_direction_offset) + if is_valid and fan_direction[0] < len(direction): + return direction[fan_direction[0]] + else: + return None + + 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 = self.fru.get_fru_data(self.max_speed_offset,2)[1] + self.max_speed = self.max_speed[1] << 8 | self.max_speed[0] + is_valid, fan_speed = self.speed_sensor.get_reading() + if not is_valid or self.max_speed == 0: + return None + else: + 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 + is_valid, fan_speed = self.speed_sensor.get_reading() + return fan_speed if is_valid else None diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan_drawer.py new file mode 100644 index 000000000000..2233a9c73a81 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan_drawer.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +######################################################################## +# DellEMC S5224F +# +# 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") + +S5224F_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(S5224F_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/s5224f/sonic_platform/hwaccess.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/hwaccess.py new file mode 120000 index 000000000000..e8fa340a444d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/hwaccess.py @@ -0,0 +1 @@ +../../common/sonic_platform/hwaccess.py \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/ipmihelper.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/ipmihelper.py new file mode 100644 index 000000000000..d95329c40de2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/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/s5224f/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/platform.py new file mode 100644 index 000000000000..5c91dbb683bc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/platform.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +############################################################################# +# DellEMC S5224F +# +# 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/s5224f/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/psu.py new file mode 100644 index 000000000000..5e4dafc9b931 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/psu.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python + +######################################################################## +# DellEMC S5224F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs' information which are available in the platform +# +######################################################################## + + +try: + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.ipmihelper import IpmiSensor, IpmiFru + 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""" + + # { PSU-ID: { Sensor-Name: Sensor-ID } } + SENSOR_MAPPING = { 1: { "State": 0x31, "Current": 0x39, + "Power": 0x37, "Voltage": 0x38, + "InCurrent": 0x36, "InPower": 0x34, + "InVoltage": 0x35 }, + 2: { "State": 0x32, "Current": 0x3F, + "Power": 0x3D, "Voltage": 0x3E, + "InCurrent": 0x3C, "InPower": 0x3A, + "InVoltage": 0x3B } } + # ( PSU-ID: FRU-ID } + FRU_MAPPING = { 1: 1, 2: 2 } + + def __init__(self, psu_index): + PsuBase.__init__(self) + # PSU is 1-based in DellEMC platforms + self.index = psu_index + 1 + self.state_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["State"], + is_discrete=True) + self.voltage_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Voltage"]) + self.current_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Current"]) + self.power_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Power"]) + self.input_voltage_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InVoltage"]) + self.input_current_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InCurrent"]) + self.input_power_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InPower"]) + self.fru = IpmiFru(self.FRU_MAPPING[self.index]) + + self._fan_list.append(Fan(fan_index=self.index, psu_fan=True, + dependency=self)) + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return "PSU{}".format(self.index) + + def get_presence(self): + """ + Retrieves the presence of the Power Supply Unit (PSU) + + Returns: + bool: True if PSU is present, False if not + """ + presence = False + is_valid, state = self.state_sensor.get_reading() + if is_valid: + if (state & 0b1): + presence = True + + return presence + + def get_model(self): + """ + Retrieves the part number of the PSU + + Returns: + string: Part number of PSU + """ + return self.fru.get_board_part_number() + + def get_serial(self): + """ + Retrieves the serial number of the PSU + + Returns: + string: Serial number of PSU + """ + return self.fru.get_board_serial() + + def get_status(self): + """ + Retrieves the operational status of the PSU + + Returns: + bool: True if PSU is operating properly, False if not + """ + status = False + is_valid, state = self.state_sensor.get_reading() + if is_valid: + if (state == 0x01): + status = True + + return status + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + is_valid, voltage = self.voltage_sensor.get_reading() + if not is_valid: + 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 + """ + is_valid, current = self.current_sensor.get_reading() + if not is_valid: + 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 + """ + is_valid, power = self.power_sensor.get_reading() + if not is_valid: + return None + + return "{:.1f}".format(power) + + def get_input_voltage(self): + """ + Retrieves current PSU voltage input + + Returns: + A float number, the input voltage in volts, + e.g. 12.1 + """ + is_valid, input_voltage = self.input_voltage_sensor.get_reading() + if not is_valid: + return None + + return "{:.1f}".format(input_voltage) + + def get_input_current(self): + """ + Retrieves present electric current supplied to PSU + + Returns: + A float number, electric current in amperes, + e.g. 15.4 + """ + is_valid, input_current = self.input_current_sensor.get_reading() + if not is_valid: + return None + + return "{:.1f}".format(input_current) + + def get_input_power(self): + """ + Retrieves current energy supplied to PSU + + Returns: + A float number, the power in watts, + e.g. 302.6 + """ + is_valid, input_power = self.input_power_sensor.get_reading() + if not is_valid: + return None + + return "{:.1f}".format(input_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. + """ + status = False + is_valid, state = self.state_sensor.get_reading() + if is_valid: + if (state == 0x01): + status = True + + return status + + def get_mfr_id(self): + """ + Retrives the Manufacturer Id of PSU + + Returns: + A string, the manunfacturer id. + """ + return self.fru.get_board_mfr_id() + + def get_type(self): + """ + Retrives the Power Type of PSU + + Returns : + A string, PSU power type + """ + board_product = self.fru.get_board_product() + if board_product is not None : + info = board_product.split(',') + if 'AC' in info : return 'AC' + if 'DC' in info : return 'DC' + return None diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/sfp.py new file mode 100644 index 000000000000..e56ab85b3f01 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/sfp.py @@ -0,0 +1,1050 @@ +#!/usr/bin/env python + +############################################################################# +# DELLEMC +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + import os + import time + import struct + import mmap + 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_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', 'hardware_rev', 'serial', + 'manufacturer', 'model', 'connector', + 'encoding', 'ext_identifier', 'ext_rateselect_compliance', + 'cable_type', 'cable_length', 'nominal_bit_rate', + 'specification_compliance', 'type_abbrv_name','vendor_date', 'vendor_oui'] + +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'], + 'manufacturer': [QSFP_INFO_OFFSET, 20, 16, 'parse_vendor_name'], + 'vendor_oui': [QSFP_INFO_OFFSET, 37, 3, 'parse_vendor_oui'], + 'model': [QSFP_INFO_OFFSET, 40, 16, 'parse_vendor_pn'], + 'hardware_rev': [QSFP_INFO_OFFSET, 56, 2, 'parse_vendor_rev'], + 'serial': [QSFP_INFO_OFFSET, 68, 16, 'parse_vendor_sn'], + 'vendor_date': [QSFP_INFO_OFFSET, 84, 8, 'parse_vendor_date'], + 'dom_capability': [QSFP_INFO_OFFSET, 92, 1, 'parse_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'], + 'manufacturer': [SFP_INFO_OFFSET, 20, 16, 'parse_vendor_name'], + 'vendor_oui': [SFP_INFO_OFFSET, 37, 3, 'parse_vendor_oui'], + 'model': [SFP_INFO_OFFSET, 40, 16, 'parse_vendor_pn'], + 'hardware_rev': [SFP_INFO_OFFSET, 56, 4, 'parse_vendor_rev'], + 'serial': [SFP_INFO_OFFSET, 68, 16, 'parse_vendor_sn'], + 'vendor_date': [SFP_INFO_OFFSET, 84, 8, 'parse_vendor_date'], + 'ModuleThreshold': [SFP_DOM_OFFSET, 0, 56, 'parse_alarm_warning_threshold'], +} + + +class Sfp(SfpBase): + """ + DELLEMC Platform-specific Sfp class + """ + BASE_RES_PATH = "/sys/bus/pci/devices/0000:04:00.0/resource0" + + def __init__(self, index=0, sfp_type=0, 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 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: + if isinstance(raw , str): + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + else: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(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 + iface_data = self._get_eeprom_data('type') + if (iface_data is not None): + 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']) + else: + return transceiver_info_dict + + # Vendor Date + vendor_date_data = self._get_eeprom_data('vendor_date') + if (vendor_date_data is not None): + vendor_date = vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + else: + return transceiver_info_dict + + # Vendor Name + vendor_name_data = self._get_eeprom_data('manufacturer') + if (vendor_name_data is not None): + vendor_name = vendor_name_data['data']['Vendor Name']['value'] + else: + return transceiver_info_dict + + # Vendor OUI + vendor_oui_data = self._get_eeprom_data('vendor_oui') + if (vendor_oui_data is not None): + vendor_oui = vendor_oui_data['data']['Vendor OUI']['value'] + else: + return transceiver_info_dict + + # Vendor PN + vendor_pn_data = self._get_eeprom_data('model') + if (vendor_pn_data is not None): + vendor_pn = vendor_pn_data['data']['Vendor PN']['value'] + else: + return transceiver_info_dict + + # Vendor Revision + vendor_rev_data = self._get_eeprom_data('hardware_rev') + if (vendor_rev_data is not None): + vendor_rev = vendor_rev_data['data']['Vendor Rev']['value'] + else: + return transceiver_info_dict + + # Vendor Serial Number + vendor_sn_data = self._get_eeprom_data('serial') + if (vendor_sn_data is not None): + vendor_sn = vendor_sn_data['data']['Vendor SN']['value'] + else: + return transceiver_info_dict + + # Fill The Dictionary and return + transceiver_info_dict['type'] = identifier + transceiver_info_dict['hardware_rev'] = vendor_rev + transceiver_info_dict['serial'] = vendor_sn + transceiver_info_dict['manufacturer'] = vendor_name + transceiver_info_dict['model'] = vendor_pn + 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) + transceiver_info_dict['vendor_date'] = vendor_date + transceiver_info_dict['vendor_oui'] = vendor_oui + transceiver_info_dict['type_abbrv_name']=type_abbrv_name + + return transceiver_info_dict + + 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') + + # Module Threshold + module_threshold_data = self._get_eeprom_data('ModuleThreshold') + if (self.sfp_type == 'QSFP'): + # Channel Threshold + channel_threshold_data = self._get_eeprom_data('ChannelThreshold') + + if (channel_threshold_data is not None and module_threshold_data is not None): + 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'] + 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'] + + else: + return transceiver_dom_threshold_dict + else: + #SFP + if (module_threshold_data is not None): + #Threshold Data + 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'] + else: + return transceiver_dom_threshold_dict + + 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 (len(tx_bias_list) != 0): + 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 (len(rx_power_list) != 0): + 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 (len(tx_power_list) != 0): + 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 + """ + + iface_data = self._get_eeprom_data('type') + if (iface_data is not None): + identifier = iface_data['data']['type']['value'] + else: + return None + + return identifier + + 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 + + # Port offset starts with 0x4004 + port_offset = 16388 + ((self.index-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == ""): + return False + + # Mask off 4th bit for presence + if(self.sfp_type == 'QSFP'): + mask = (1 << 4) + + # Mask off 1st bit for presence 65,66 + if (self.sfp_type == 'SFP'): + mask = (1 << 0) + # ModPrsL is active low + if reg_value & mask == 0: + return True + + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the sfp + """ + vendor_pn_data = self._get_eeprom_data('model') + if (vendor_pn_data is not None): + vendor_pn = vendor_pn_data['data']['Vendor PN']['value'] + else: + return None + + return vendor_pn + + def get_serial(self): + """ + Retrieves the serial number of the sfp + """ + vendor_sn_data = self._get_eeprom_data('serial') + if (vendor_sn_data is not None): + vendor_sn = vendor_sn_data['data']['Vendor SN']['value'] + else: + return None + + return vendor_sn + + def get_reset_status(self): + """ + Retrives the reset status of SFP + """ + reset_status = False + if (self.sfp_type == 'QSFP'): + # Port offset starts with 0x4000 + port_offset = 16384 + ((self.index-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == ""): + return reset_status + + # Mask off 4th bit for reset status + mask = (1 << 4) + + if ((reg_value & mask) == 0): + reset_status = True + else: + reset_status = False + + return reset_status + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + """ + rx_los = None + rx_los_list = [] + if (self.sfp_type == 'QSFP'): + rx_los_data = self._get_eeprom_data('rx_los') + if (rx_los_data is not None): + rx_los = rx_los_data['data']['Rx1LOS']['value'] + if (rx_los is 'On'): + rx_los_list.append(True) + else: + rx_los_list.append(False) + rx_los = rx_los_data['data']['Rx2LOS']['value'] + if (rx_los is 'On'): + rx_los_list.append(True) + else: + rx_los_list.append(False) + rx_los = rx_los_data['data']['Rx3LOS']['value'] + if (rx_los is 'On'): + rx_los_list.append(True) + else: + rx_los_list.append(False) + rx_los = rx_los_data['data']['Rx4LOS']['value'] + if (rx_los is 'On'): + rx_los_list.append(True) + else: + rx_los_list.append(False) + + if (rx_los_list[0] and rx_los_list[1] + and rx_los_list[2] and rx_los_list[3]): + rx_los = True + else: + rx_los = False + else: + rx_los_data = self._read_eeprom_bytes(self.eeprom_path, SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if (rx_los_data is not None): + data = int(rx_los_data[0], 16) + rx_los = (sffbase().test_bit(data, 1) != 0) + + return rx_los + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + """ + tx_fault = None + tx_fault_list = [] + if (self.sfp_type == 'QSFP'): + tx_fault_data = self._get_eeprom_data('tx_fault') + if (tx_fault_data is not None): + tx_fault = tx_fault_data['data']['Tx1Fault']['value'] + if (tx_fault is 'On'): + tx_fault_list.append(True) + else: + tx_fault_list.append(False) + tx_fault = tx_fault_data['data']['Tx2Fault']['value'] + if (tx_fault is 'On'): + tx_fault_list.append(True) + else: + tx_fault_list.append(False) + tx_fault = tx_fault_data['data']['Tx3Fault']['value'] + if (tx_fault is 'On'): + tx_fault_list.append(True) + else: + tx_fault_list.append(False) + tx_fault = tx_fault_data['data']['Tx4Fault']['value'] + if (tx_fault is 'On'): + tx_fault_list.append(True) + else: + tx_fault_list.append(False) + + if (tx_fault_list[0] and tx_fault_list[1] + and tx_fault_list[2] and tx_fault_list[3]): + tx_fault = True + else: + tx_fault = False + + else: + tx_fault_data = self._read_eeprom_bytes(self.eeprom_path, SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if (tx_fault_data is not None): + data = int(tx_fault_data[0], 16) + tx_fault = (sffbase().test_bit(data, 2) != 0) + + return tx_fault + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + """ + tx_disable = None + tx_disable_list = [] + if (self.sfp_type == 'QSFP'): + tx_disable_data = self._get_eeprom_data('tx_disable') + if (tx_disable_data is not None): + tx_disable = tx_disable_data['data']['Tx1Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(True) + else: + tx_disable_list.append(False) + tx_disable = tx_disable_data['data']['Tx2Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(True) + else: + tx_disable_list.append(False) + tx_disable = tx_disable_data['data']['Tx3Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(True) + else: + tx_disable_list.append(False) + tx_disable = tx_disable_data['data']['Tx4Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(True) + else: + tx_disable_list.append(False) + + if (tx_disable_list[0] and tx_disable_list[1] + and tx_disable_list[2] and tx_disable_list[3]): + tx_disable = True + else: + tx_disable = False + + else: + tx_disable_data = self._read_eeprom_bytes(self.eeprom_path, SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if (tx_disable_data is not None): + data = int(tx_disable_data[0], 16) + tx_disable_hard = (sffbase().test_bit(data, SFP_TX_DISABLE_HARD_BIT) != 0) + tx_disable_soft = (sffbase().test_bit(data, SFP_TX_DISABLE_SOFT_BIT) != 0) + tx_disable = tx_disable_hard | tx_disable_soft + + + return tx_disable + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + """ + tx_disable = None + tx_disable_list = [] + tx_disable_channel = 0 + + if (self.sfp_type == 'QSFP'): + tx_disable_data = self._get_eeprom_data('tx_disable') + if (tx_disable_data is not None): + tx_disable = tx_disable_data['data']['Tx1Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(1) + else: + tx_disable_list.append(0) + tx_disable = tx_disable_data['data']['Tx2Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(1) + else: + tx_disable_list.append(0) + tx_disable = tx_disable_data['data']['Tx3Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(1) + else: + tx_disable_list.append(0) + tx_disable = tx_disable_data['data']['Tx4Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(1) + else: + tx_disable_list.append(0) + + bit4 = int(tx_disable_list[3]) * 8 + bit3 = int(tx_disable_list[2]) * 4 + bit2 = int(tx_disable_list[1]) * 2 + bit1 = int(tx_disable_list[0]) * 1 + + tx_disable_channel = hex(bit4 + bit3 + bit2 + bit1) + + return tx_disable_channel + + def get_lpmode(self): + """ + Retrieves the lpmode(low power mode) of this SFP + """ + lpmode_state = False + if (self.sfp_type == 'QSFP'): + + # Port offset starts with 0x4000 + port_offset = 16384 + ((self.index-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == ""): + return lpmode_state + + # Mask off 6th bit for lpmode + mask = (1 << 6) + + # LPMode is active high + if reg_value & mask == 0: + lpmode_state = False + else: + lpmode_state = True + + return lpmode_state + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + """ + power_override_state = False + + if (self.sfp_type == 'QSFP'): + power_override_data = self._get_eeprom_data('power_override') + if (power_override_data is not None): + power_override = power_override_data['data']['PowerOverRide']['value'] + if (power_override is 'On'): + power_override_state = True + else: + power_override_state = False + + return power_override_state + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + """ + temperature = None + + temperature_data = self._get_eeprom_data('Temperature') + if (temperature_data is not None): + temperature = temperature_data['data']['Temperature']['value'] + + return temperature + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + """ + voltage = None + + voltage_data = self._get_eeprom_data('Voltage') + if (voltage_data is not None): + voltage = voltage_data['data']['Vcc']['value'] + + return voltage + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + """ + tx_bias = None + tx_bias_list = [] + + tx_bias_data = self._get_eeprom_data('ChannelMonitor') + if (tx_bias_data is not None): + if (self.sfp_type == 'QSFP'): + tx_bias = tx_bias_data['data']['TX1Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = tx_bias_data['data']['TX2Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = tx_bias_data['data']['TX3Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = tx_bias_data['data']['TX4Bias']['value'] + tx_bias_list.append(tx_bias) + else: + tx1_bias = tx_bias_data['data']['TXBias']['value'] + return [tx1_bias, "N/A", "N/A", "N/A"] + + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + """ + rx_power = None + rx_power_list = [] + + rx_power_data = self._get_eeprom_data('ChannelMonitor') + if (rx_power_data is not None): + if (self.sfp_type == 'QSFP'): + rx_power = rx_power_data['data']['RX1Power']['value'] + rx_power_list.append(rx_power) + rx_power = rx_power_data['data']['RX2Power']['value'] + rx_power_list.append(rx_power) + rx_power = rx_power_data['data']['RX3Power']['value'] + rx_power_list.append(rx_power) + rx_power = rx_power_data['data']['RX4Power']['value'] + rx_power_list.append(rx_power) + else: + rx1_pw = rx_power_data['data']['RXPower']['value'] + return [rx1_pw, "N/A", "N/A", "N/A"] + + return rx_power_list + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + """ + tx_power_list = [] + 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') + if (qspf_dom_capability_data is not None and qsfp_dom_rev_data is not None): + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value'] + else: + return tx_power_list + + # 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 tx_power_list + else: + channel_monitor_data = self._get_eeprom_data('ChannelMonitor_TxPower') + if (channel_monitor_data is not None): + tx1_pw = channel_monitor_data['data']['TX1Power']['value'] + tx2_pw = channel_monitor_data['data']['TX2Power']['value'] + tx3_pw = channel_monitor_data['data']['TX3Power']['value'] + tx4_pw = channel_monitor_data['data']['TX4Power']['value'] + else: + return tx_power_list + + else: + channel_monitor_data = self._get_eeprom_data('ChannelMonitor') + if (channel_monitor_data is not None): + tx1_pw = channel_monitor_data['data']['TXPower']['value'] + tx2_pw = 'N/A' + tx3_pw = 'N/A' + tx4_pw = 'N/A' + else: + return tx_power_list + + tx_power_list.append(tx1_pw) + tx_power_list.append(tx2_pw) + tx_power_list.append(tx3_pw) + tx_power_list.append(tx4_pw) + + return tx_power_list + + def reset(self): + """ + Reset the SFP and returns all user settings to their default state + """ + if (self.sfp_type == 'QSFP'): + # Port offset starts with 0x4000 + port_offset = 16384 + ((self.index-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == ""): + return False + + # Mask off 4th bit for reset + mask = (1 << 4) + + # ResetL is active low + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + # Sleep 1 second to allow it to settle + time.sleep(1) + + reg_value = reg_value | mask + + # Convert our register value back to a hex string and write back + self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + return True + + else: + return False + + def set_lpmode(self, lpmode): + """ + Sets the lpmode(low power mode) of this SFP + """ + if (self.sfp_type == 'QSFP'): + # Port offset starts with 0x4000 + port_offset = 16384 + ((self.index-1) * 16) + + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) + + # Absence of status throws error + if (reg_value == ""): + return False + + # Mask off 6th bit for lowpower mode + mask = (1 << 6) + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = reg_value | mask + else: + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + return True + + else: + return False + + 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() + + if (reset == True): + status = False + else: + status = True + + return status diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/thermal.py new file mode 100644 index 000000000000..6634a6982eb8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/thermal.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python + +######################################################################## +# DellEMC S5224F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermals' information which are available in the platform +# +######################################################################## + + +try: + from sonic_platform_base.thermal_base import ThermalBase + from sonic_platform.ipmihelper import IpmiSensor +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 = [ + ['CPU On-board', 0xe], + ['ASIC On-board', 0x2], + ['System Front Left', 0x3], + ['System Front Middle', 0x1], + ['System Front Right', 0x4], + ['Inlet Airflow Sensor', 0x5], + ['PSU1 Airflow Sensor', 0x7], + ['PSU2 Airflow Sensor', 0x8] + ] + + def __init__(self, thermal_index): + ThermalBase.__init__(self) + self.index = thermal_index + 1 + self.sensor = IpmiSensor(self.SENSOR_MAPPING[self.index - 1][1]) + + 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 + """ + is_valid, temperature = self.sensor.get_reading() + if not is_valid: + temperature = 0 + + 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 + """ + is_valid, high_threshold = self.sensor.get_threshold("UpperNonCritical") + if not is_valid: + return super(Thermal, self).get_high_threshold() + + return float(high_threshold) + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature of thermal + + Returns: + A float number, the high critical threshold temperature of thermal in + Celsius up to nearest thousandth of one degree Celsius, + e.g. 30.125 + """ + is_valid, high_crit_threshold = self.sensor.get_threshold("UpperCritical") + if not is_valid: + return super(Thermal, self).get_high_critical_threshold() + + return float(high_crit_threshold) + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature of thermal + + Returns: + A float number, the low threshold temperature of thermal in + Celsius up to nearest thousandth of one degree Celsius, + e.g. 30.125 + """ + is_valid, low_threshold = self.sensor.get_threshold("LowerNonRecoverable") + if not is_valid: + low_threshold = 0 + + return float(low_threshold) + + 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/s5224f/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/watchdog.py new file mode 100644 index 000000000000..b7e96546569a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/watchdog.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python + +######################################################################## +# +# DELLEMC S5248f +# +# Abstract base class for implementing a platform-specific class with +# which to interact with a hardware watchdog module in SONiC +# +######################################################################## + +try: + import ctypes + import subprocess + import syslog + import sonic_platform.component as Component + 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,80,100,120,140,160,180,210,240] + + 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'.encode()) + 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 + + cpld_version = Component.get_cpld0_version() + wd_enabled_version = "0.8" + + if cpld_version < wd_enabled_version: + syslog.syslog(syslog.LOG_ERR, + 'Older System CPLD ver, Update to 0.8 to support watchdog ') + return -1 + + # Extracting 5th to 8th bits for WD timer values + reg_val = self._get_reg_val() + wd_timer_offset = (reg_val >> 4) & 0xf + + if wd_timer_offset != timer_offset: + # Setting 5th to 7th bits + # value from timer_offset + self.disarm() + self._set_reg_val((reg_val & 0x07) | (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 + + 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. + + S5224f 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/s5224f/systemd/platform-modules-s5224f.service b/platform/broadcom/sonic-platform-modules-dell/s5224f/systemd/platform-modules-s5224f.service new file mode 100644 index 000000000000..69c0c0a11083 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/systemd/platform-modules-s5224f.service @@ -0,0 +1,13 @@ +[Unit] +Description=Dell S5224f Platform modules +Before=pmon.service +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/s5224f_platform.sh init +ExecStop=/usr/local/bin/s5224f_platform.sh deinit +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target From 052490334763e41b646eba6eca4a7cd6cbbdd596 Mon Sep 17 00:00:00 2001 From: Arun LK Date: Thu, 9 Sep 2021 21:15:30 +0530 Subject: [PATCH 2/4] DellEMC: Initial commit for S5224F platform support --- device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/psuutil.py | 3 --- .../s5224f/scripts/platform_sensors.py | 4 ---- 2 files changed, 7 deletions(-) diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/psuutil.py b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/psuutil.py index 1cacc0558c6d..8ae70b9755e1 100644 --- a/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/psuutil.py +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/psuutil.py @@ -4,7 +4,6 @@ # -import os.path import logging import sys import subprocess @@ -40,9 +39,7 @@ def isDockerEnv(self): # Fetch a BMC register def get_pmc_register(self, reg_name): - status = 1 global ipmi_sdr_list - ipmi_dev_node = "/dev/pmi0" ipmi_cmd = IPMI_PSU_DATA dockerenv = self.isDockerEnv() if dockerenv == True: diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/platform_sensors.py index b1e3776d17fe..e958bc530100 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/platform_sensors.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/platform_sensors.py @@ -11,10 +11,8 @@ # * PSU -import os import sys import logging -import subprocess import commands S5224F_MAX_FAN_TRAYS = 4 @@ -38,7 +36,6 @@ def ipmi_sensor_dump(): - status = 1 global ipmi_sdr_list ipmi_cmd = IPMI_SENSOR_DATA status, ipmi_sdr_list = commands.getstatusoutput(ipmi_cmd) @@ -231,7 +228,6 @@ def get_psu_status(index): :param index: An integer, index of the PSU of which to query status :return: Boolean, True if PSU is plugged, False if not """ - status = 0 ret_status = 1 ipmi_cmd_ret = 'f' From dccccc6efe1de1e1433cba7417532b677a7d9fb6 Mon Sep 17 00:00:00 2001 From: Arun LK Date: Fri, 10 Sep 2021 00:47:04 +0530 Subject: [PATCH 3/4] DellEMC: Initial commit for S5224F platform support --- .../DellEMC-S5224f-P-25G/td3-s5224f-25g.config.bcm | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/td3-s5224f-25g.config.bcm b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/td3-s5224f-25g.config.bcm index f88ebcf3aa73..fe37fbe0819c 100644 --- a/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/td3-s5224f-25g.config.bcm +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/DellEMC-S5224f-P-25G/td3-s5224f-25g.config.bcm @@ -176,10 +176,6 @@ pbmp_xport_xe=0x7fff9fffffffffffffffe port_flex_enable=1 phy_an_c73=3 -#25G,10G,1G support -serdes_10g_at_25g_vco=1 -serdes_1000x_at_25g_vco=1 - l2xmsg_mode=1 #Need for mac learn scale @@ -238,14 +234,4 @@ host_as_route_disable=1 sai_eapp_config_file=/etc/broadcom/eapps_cfg.json sai_fast_convergence_support=1 flow_init_mode=1 -mpls_mem_entries=16384 -vlan_xlate_1_mem_entries=65536 -vlan_xlate_2_mem_entries=16384 sai_load_hw_config=/usr/lib/cancun/ -sai_nbr_bcast_ifp_optimized=1 -sai_brcm_sonic_acl_enhancements=1 -# Reduced Trap Group QSET for BRCM Sonic -sai_brcm_sonic_trap_group=1 -l2_entry_used_as_my_station=1 -multi_hash_recurse_depth_l3=2 -sai_interface_type_auto_detect=0 From fc0704d42521f23cb1eaade069c7a7915d189103 Mon Sep 17 00:00:00 2001 From: Arun LK Date: Tue, 21 Sep 2021 14:14:56 +0530 Subject: [PATCH 4/4] DellEMC: Initial commit for S5224F platform support --- .../plugins/sfputil.py | 9 ++++-- .../s5224f/scripts/platform_sensors.py | 28 +++++++++++-------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/sfputil.py index 2ee649d0dc22..b0fb250b0bb7 100644 --- a/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/sfputil.py @@ -6,8 +6,6 @@ try: import struct - import sys - import getopt import time from sonic_sfp.sfputilbase import SfpUtilBase from os import * @@ -15,7 +13,6 @@ import io from sonic_sfp.sff8436 import sff8436InterfaceId from sonic_sfp.sff8436 import sff8436Dom - from sonic_sfp.sff8472 import sff8472InterfaceId from sonic_sfp.sff8472 import sff8472Dom except ImportError as e: @@ -205,6 +202,8 @@ def set_low_power_mode(self, port_num, lpmode): # Convert our register value back to a hex string and write back status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + if status != reg_value: + print ("Error: Set LP mode status %d", status) return True @@ -232,6 +231,8 @@ def reset(self, port_num): # Convert our register value back to a hex string and write back status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + if status != reg_value: + print ("Error: pci_set_value reset status %d", status) # Sleep 1 second to allow it to settle time.sleep(1) @@ -240,6 +241,8 @@ def reset(self, port_num): # Convert our register value back to a hex string and write back status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + if status != reg_value: + print ("Error: pci_set_value reset status %d", status) return True diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/platform_sensors.py index e958bc530100..483dd59a5607 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/platform_sensors.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/scripts/platform_sensors.py @@ -13,7 +13,7 @@ import sys import logging -import commands +import subprocess S5224F_MAX_FAN_TRAYS = 4 S5224F_MAX_PSUS = 2 @@ -38,7 +38,7 @@ def ipmi_sensor_dump(): global ipmi_sdr_list ipmi_cmd = IPMI_SENSOR_DATA - status, ipmi_sdr_list = commands.getstatusoutput(ipmi_cmd) + status, ipmi_sdr_list = subprocess.getstatusoutput(ipmi_cmd) if status: logging.error('Failed to execute:' + ipmi_sdr_list) @@ -47,7 +47,7 @@ def ipmi_sensor_dump(): # Fetch a Fan Status def get_fan_status(fan_id): - ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_FAN_PRESENCE.format(fan_id)) + ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_FAN_PRESENCE.format(fan_id)) if ret_status: logging.error('Failed to execute : %s'%IPMI_FAN_PRESENCE.format(fan_id)) sys.exit(0) @@ -75,7 +75,7 @@ def get_pmc_register(reg_name): #Fetch FRU Data for given fruid def get_psu_airflow(psu_id): fru_id = 'PSU' + str(psu_id) + '_fru' - ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_FRU) + ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_FRU) if ret_status: logging.error('Failed to execute ipmitool: '+ IPMI_FRU) sys.exit(0) @@ -89,11 +89,11 @@ def get_psu_airflow(psu_id): # Fetch FRU on given offset def fetch_raw_fru(dev_id, offset): - ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_RAW_STORAGE_READ.format(dev_id)) + ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_RAW_STORAGE_READ.format(dev_id)) if ret_status: logging.error('Failed to execute ipmitool :' + IPMI_RAW_STORAGE_READ.format(dev_id)) sys.exit(0) - return int((ipmi_cmd_ret.splitlines()[offset/16]).split(' ')[(offset%16+1)]) + return int((ipmi_cmd_ret.splitlines()[int(offset/16)]).split(' ')[(int(offset%16)+1)]) def get_fan_airflow(fan_id): Airflow_Direction = ['Exhaust', 'Intake'] @@ -119,7 +119,9 @@ def print_temperature_sensors(): print (' CPU Temp: ',\ (get_pmc_register('CPU_temp'))) -ret_status, ipmi_cmd_ret = commands.getstatusoutput('echo 0 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us') +ret_status, ipmi_cmd_ret = subprocess.getstatusoutput('echo 0 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us') +if ret_status: + logging.error("platform_sensors: Failed to set kipmid_max_busy_us to 0") ipmi_sensor_dump() print_temperature_sensors() @@ -210,9 +212,9 @@ def get_psu_presence(index): ret_status = 1 if index == 1: - ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_PSU1_DATA_DOCKER) + ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_PSU1_DATA_DOCKER) elif index == 2: - ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_PSU2_DATA_DOCKER) + ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_PSU2_DATA_DOCKER) if ret_status: logging.error('Failed to execute ipmitool :' + IPMI_PSU1_DATA_DOCKER) @@ -232,9 +234,9 @@ def get_psu_status(index): ipmi_cmd_ret = 'f' if index == 1: - ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_PSU1_DATA_DOCKER) + ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_PSU1_DATA_DOCKER) elif index == 2: - ret_status, ipmi_cmd_ret = commands.getstatusoutput(IPMI_PSU2_DATA_DOCKER) + ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_PSU2_DATA_DOCKER) if ret_status: logging.error('Failed to execute ipmitool : ' + IPMI_PSU2_DATA_DOCKER) @@ -314,4 +316,6 @@ def print_psu(psu): print ('\n Total Power: ',\ get_pmc_register('PSU_Total_watt')) -ret_status, ipmi_cmd_ret = commands.getstatusoutput('echo 1000 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us') +ret_status, ipmi_cmd_ret = subprocess.getstatusoutput('echo 1000 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us') +if ret_status: + logging.error("platform_sensors: Failed to set kipmid_max_busy_us to 1000")