diff --git a/share/man/man4/qat.4 b/share/man/man4/qat.4 --- a/share/man/man4/qat.4 +++ b/share/man/man4/qat.4 @@ -1,7 +1,7 @@ .\" SPDX-License-Identifier: BSD-3-Clause .\" Copyright(c) 2007-2022 Intel Corporation .\" $FreeBSD$ -.Dd June 30, 2022 +.Dd September 1, 2022 .Dt QAT 4 .Os .Sh NAME @@ -30,6 +30,8 @@ .It qat_dh895xcc_fw_load="YES" .It +qat_4xxx_fw_load="YES" +.It qat_load="YES" .El .Sh DESCRIPTION @@ -53,6 +55,8 @@ Intel (R) Communications Chipset 8925 to 8955 Series .It Intel (R) Atom P5300 processor product family +.It +Intel (R) QAT 4xxx Series .El .Pp The diff --git a/sys/contrib/dev/qat/qat_4xxx.bin b/sys/contrib/dev/qat/qat_4xxx.bin new file mode 100644 index 0000000000000000000000000000000000000000..baec3ad9ca32a87113fe185afc94ec264ff5fa4f GIT binary patch literal 532308 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

q#ncN4_wqhZ#!n@H@Zz9@{q6lF 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 loRq~qM8Q>Ss{lwSkIpJ?Z zm9l0x;h%M*9*OuCJvYGr)HS=YPq>7h%iv4&ocPhkDviFUdX~|1k{9>mIq7-#R3+$p zYIixFGvX`sJn1L?l%)PpJu6U;kN5^XCwY2rRf_r(VE$YzlBfRp5%)y)kG+rU$38B} zCDy2jIHa=sV?=y|5@p?&6~wWv*`%MlRYlxKjNe0S`}ZsD3s$;^&%Q5@u~^*D0UP56 z=|PNj#SwSF*dRUUab9r)``_%!IO4+?yD^S?(ippwp5q+AHVZyvJ>PA8_qbK=pjFSL zs5h$f_z{<1rvB;(^d|O_)&4Z^j~%zjhMypMV$9(7U&x6kh{0ayhh8h<95t+41NPio zb;Ogn>zD03LUiQc_~iblO}|@jd>!NG5gOMp{=K@6@qPEDoB6$pPMqT=B?tNCk0^GW z<7r!oo_-5`g!qTlmKJf2O-#o%u}tG6pw!`jT5xjOQ4ChT(-VIUu!eP zIg?0MoJ+CpU9#h}TIQwx?rB=z&CusFB(D*#l_I?r@me{_iQ{tm*@$}!8RE7$%<}lr za6#N0;&X#e96YPntp265=?vmGweG~2yPoZJ%H&J<_$5jE+7Zy@yeq^xAW8rF5u$gq zUY5B3#JXR%A|35{3(IIU?|XN$4C!YZ7inXN1G%RzF^2OAe#DcQIM1_+<`wayDRIB% zto>$ZUA8yKn&)Nz-_ykBnyWiF{tpHZKE&61g?MWxZgzorPTh$B%JF!HmU-qkpUz0^ zAA>JFWMKU(NfB>Yv3&Nz%hvJoeE~8#*N$eMJuPT%OOtOKEL3s(*?9nwP2xKS#%%xqJ1Cq0_#5N z1+06~Siye09T#rLr^lIYn1O;g@g$F*rgp_WyQiAlJVrYut2`t103 z#HZg!^3slf5B&aYwkKB@Z=TFSkMUz1`GRr_{NL%ueFRN}Tv` z265F1et#irK)iYI6nyxd4EJg`&wKLV(Jf zIC1OukbKFJr-^S208%}D93rkcF@A*4r-&18K7Cyt=MF3RFP~?rIcQi{^Yuibl`r;yv+kU^H&apfB?>J*Wfxh1=U7gsT3_9nGNRIv(dW8L6 zT438X+Ve+9&i4eaX4?(WC-m=7S$&oIx2di}hh2Z~Y3uZTvd=kZXTSeL^}Egdy~OV0 z?9>-#9&Eph6Xz5Y=Y}9hKsU55_AkG~|q(uG*@tN7<{l$4nrB7{5>~;Om-vwP{5dWp+kI=l>=eF$ntE9xg9U*(j zj^l4`W50Sj?`J-ob0GfdgZ=_JVx4oa`EThtIakh#^L!Wmjls>jn zKEV6K$*8}AU$l}!S+eMUU* z_@aPa-w@B$r^N52&xzmtFA6yLYwsLnn3pp8HUwSu2|LmUdlY!L=)niQIy1Xo zjd{K71o6?fRP{4hPu6}#bN61Z2NLA;_C&DjA^86)>w{vwD+`pBbtl3o$LXr2O`r1& z)$?R9M*Nw_VMoUm$f0a>T<3D9(STkX>*ME0o(!(0c0#An8+EH4_3d15?B2`uz5T() zhxonamYz~tPFWzYt=r4L=lWe!G^y>$a(T(mgP5CGYzx*=1^G|<&8>B7f+)|==dmuV z7u@Hbn>(KJJNiM{`P3e)n~*cFq*f9CXO4asfPM!(!P=K_^t-c0g?`te>lr2B>UXWS z9agO0kvw|yIOfOFKg!M<#>F|L=9bOkd|}IGe!h@?r*>vhFU}YG96o-sYN@_46L!uQ zDsxwfb0c$CiE|@!SBY~Y^~67E-cnKG2O9Jz*i#`EL0nOi$KPFaJWI8P4kWkGJnOA8 z%M<^WT2tH~7h5QgZpC-^GcNai(TH++JV5I8Lhk2}LO-JQkc=k6@P9|5;$CYeYh+i2 zasGtIv(x-tbe!}<<*c#f7A7&hm)apdF7;;2edz$3)14UI3jNlydwkJV>gDST{B_p3 zcpvUr=6rj#mk!}KVB53|@ZDRX} zZMwEsLEI|*^^pJaqH*ZSxKEk*h&>+x)Jx@~s26&7m9Bvw1W-=)JM9tubc{n@ETZ>$ zf8qPZ;~L}b?SY@#s;^q2??DF@>I+5ad*a6-+^0rDmH(2Extn%}59w>zKL_9Bw)R{K-Q9lBUsT}Me zOMZebE<6VOOkWMWvq-K5e%opuZy#pW5!}NaaP%nqypM}db@@2yi}YMOox-(%%Jz>wNaYC0PsxuW-aD7$Is_29Vb2( z0-njf38MZ)pa9QQKdmQr8t@pzyk~Y9ey3fU_r7t+MGMdFd-L3Jnm4q!Cs~B&zH!(Y z73vGj!}nAUc&2&-z%%JtRd`SQ)VVhs@lM!Z8^XQWBwtpnNp3ORI9iEJ^L+}*Z6B>C z**%xVm;YJ@3Ug}pA^}?>MO7MHh1H4?= zX)n&q3&$Z(&Y<_$$8z7V9M^)py*)%1c74?neGj^>P+urQ--90Pbq0F@ac3yU{RZ?M z*8?rS2Kvo$d3@1v!jr$dKgs1&pY3-r-Z)P7p44Y@eE63TKGGq#d=6qI%9@VO{R}#!w_faYP!h{LFatF^BQmbs! z_mSMHlFSz-vdrmM6?=%iLi$gYLh@bnx&2af(XUor^owATAGB3zNvv_>1)5g{uXrZw zV;jzZy$iahcF@1riwx&lYuJ@ZoZ~v#m#;-$rkbT=Y&+3S&42w9dw}$mlkfh5zFq8> z^Zml8lz(9Y`^5LGO5IC(KtMGOgXHqbHD71j3Gd+^@Qo1G4}C||u@-fj$LQXKiMBbA6d9wd%?`h~L@mMWw{`kTX@J zO5?lA?QSM{Pkem<=YEM#q1{w@yUnY<_rNpx5Y%WD=gvsf4v*)dm%c;a2z*+6Q0mN^ z`{?(+p_K0!@Vz3RMgEEXEAo1V+B1C*(YoUPnmfle4nI1saeaCHxDI+?cZ_p?CA)oG z2Ona$as7NSC+2-1$LBrRpVRiCKbD?aH4t0Lj**?SY>eAEks;~_%_FUA{fk)tvzC7; zL1ROCZoj)Vo6b5Ul-GC4zW+w~8`JCnA3wK0 z%FE}4ojH`}dPHzAuk9l_Sv9oUU?+IFB-STeYWwN4pBPU;j^&E&uRhCPZ_~>YG+y{g z`;y^l_`y1ae?;ob>W^!%PmR0AvF{NHp3Tp{T2QOani=>%`jk1-*za`gKl6ccqF;wD zEj}al7+k*2>CE_!p?_x?oGza~%h2Jk%J~lJqbisCY3OqV?;qDdf9AGvo#!LiGOk0; zo13B66Wjzn!tSr_4+t*JTJtK#9qS{y9HseLaf0t}MLG>WuQ7H||01Gs zJJ&}e!5*;>E}+io66K6J)1ccW+5AYx^^-aI6#}bu_@m-XIWnPvKmVHhIgsCm)A5Qt z8-aW~Kb^(CJR+m{IffqSPqbdUGA8;HW_RkN=!bfM);E2>B%K{LppT7aN1)HNtO=invWvr4(VAa6@) zf2ukNPg=-nkMyty$4%zQEvMZw`(_8(H>5{*GA>7|xLs4Z-7wpoG=RUZjAHQpl-yy= zXOvAQ4blT^Lc;G74Lq*zB7HMDNc}_{MK{e8{Lc62I^r~&TlVV6%Ta}Ru_V{`m6izn zix~z#LX_>+fY(5$ZC|imu+yA+Mlw3$L)%&o=sZ3Wab+}b(OyMu=?^<{Tl(BFqAU6} z0J}=L4>^H*uqvN1gr{7sV z{x*!C^d)=zb9$)XqyB<^?@fb$upY!$ge&jsmGs;0hlFuu_`dsBcz!N>+|1tZ{08R( zZe9oZYp|zSU_Re3_k~6L8L^_TK^}zD=3~zg{|;|Vv5h3J!vQCrD>tEVK7M!t>&AM{ z@I2u@FKs`Z4&%v_>}^PYlMEE-N*d`fh1qI zjvo3+npe`lT0sxsOPn48I0veHwBaNQP`J_ckp-x zrfd?h?K2`?;hqeSFK%8qnt705v@yeWrQG=SXlJrp*+F_>r@lg2&xrrD9r-Edy@U7+ z)?XL#8TdbZd$Yr2hp_uh9r4gD=r7qvu||{aBEA_#zsY`!^|G49qcjfR2{rx!y2}^|l1_k9kTyIZo?35CPvKef+<^!|s8;+Y!mY??H6& zB%jCr6Fd)Q^Pu+RGh{bMm(qLa?^0@Ng6gsDNv6_w@b4~N!+5;Oid1%(J0wmFyg3loZqZiyd&t)HR+e%9fw`J6zztbddkKzn9&jc8E5Ik@MDDI zVxKVF*r@FRUO=DlXGz*K&}%Wi2SC@|#Q%vOk|fg**BbPVGROmVW+JO&J#}aJzH_iE zr}O-Lohr9GYC5og3cnwX8{Z9T4ElS(HIBp3mh2^}7q>@PkkM(>Uy>LCbC^lMnDS(zv*M zK)zbC8@Rt+>{HcrlHG93o#)bi1xa4)Bff06NAlr^SnokDAHt_-cMaJ|VbbR^T#g32 zsa@>psBXT@FEc(K=!-98(BQioosv`p)W*R=Vy zeSVVYt9x-lTucz-QC)r(49I++*ItJ@$!Ey9DEqd)OFLD6h5y-If7D;-pVs;-?{6YI zO#O*U$8??W7{xlEe%CbS2oE7=J=CDTYr@U27P65t}W8tw!`O)3p?dG(qHN~uwM)P%+g1k`gV{W zN&Rmb)p0JVsxi$ljxgjp$(^cB>es5ETdv}`+4MN!qkP=QiEapwEiZAs#O`ku;(cj7 z)DA>y7Ow%{O#F7-kP62AztHLDsLu1GL2opP&KnJ)KN>gmM;do^Pox{?$IHiU z{?|D7|CEmV0L>%O3G|PgOV44he-OVUd@PQ*?3nxJ-0 zR&CTbl3o-3{YSF*5dYR{Nxvq$J`6hr>$wN{rcMzj+$rMQ%(H}^#~?3ApJ3WI8TfSh z^N%s)Ti0p{58z*&ipW>IBFoon)VCu$OmrBjUAWWVU6q;E*QCfARv>Gu~2 zFHx1`HGLoEb_ejA(MB=fWX0}-zHz2urm_EnbxZT_gMP0=kIK)PAU(#`531NpT87JU zlX3gEE5pENqiW9FN9#M*Z|E7)Q>*%OI_xdhL2@_gE8AC$U|*5wKpLR-2`{y0k=%t} z$BKKX?(I-6Sm&O9bn3I^cv*eK*Qp(8AjkPgWI6nfVMl)m_fUNi_xyJ`-VGCWUp4S< z6yklmzLDgvjdz{nJy3x6S>k#vyyt-5d;xwr=Ty>G)P~Ffxfu> znwh>{GhgXp{2m3f8*y);0{-!3Zhw?N7kq_jQO4u4*bf=}CU(1ad&@7nb?RBHFNe-- zy+qJiHQ%p8`C>nA75C!?opl!*x=~>}h(7&!o<|;jHt54_kco1BCdyHdP%h@*rn2?I z-(CFu%XY{5TA46lzT<~VF~&U<9RT3oR?CU$eEo)9|{X73G6d1k#i%^Bg4ghnDRK~)3}}4 z90)9Vmh4WwS7)!Nu!~K;FT_+P;*+d-Ari6dD>0wde%75>W^haRvFl7UYWD%lxmTL#zhRX?~SnwL3!VF3`&) zKJH$o@pGomdu>I81>N{$E5A)k>@$PUrfFX0%+=G>elyMybAOt0KKMdU&{Q@OJq?9( z>=7CM{DUGs+4?;sU$Wv^;===gq$l)oh<%;J5a0h~jSP7nn|%>0KKU7@C#mgl{!_=Z z$hIuAJ)~!T81oCcs+xj+O6=C^UR9Ah;6HKWlcC48#GbhDS*qt`@G16yf$`esEzJif z2=C2OUf#$6ecE=?H)@&SO=3V#W`zi2`UIPVMW z$x9}PFZTp|Y`cPJFT@l0%Id4szfI?xI_#2r&olLXq!$oftGl?rOuRoipmINE@VsN} z0TcF($^Cc1|B7c2@64pk+a_q8pBz%Te*}8 zUo*hemR0WlqH{k^V7~A>MHUMfTgIQ)u(KteH{`xNw{PwG?DOrlI5&2}wUcbWPXPWc z>VJPPi{!D-)GN+I+3TrB>yq+BFEwps{{p}LmK{>&2iVK^EfqY6T(I`uS1JF9%7-0xEhe-r#6KB_O}?q5a+sJ>A*zrf|2l>gX@@^)N;--=7{ zvyMgU3i!u{TxNvEUk$uL4(>;u2g$)(v_Hf1HrV-vqJBBD_yqAG&}r81<~_pqL~rHa zYmvq4kr$G_hdnTB{fWrpF^S7hehyC3*G;H2k6n3P#Ivw<&?jr5U+UmH<_9Kp`mPJ{ z%z&A0#NkB-S9gy>j~~3T`w^0lFLqP2BxhJxn#Vo=e8sj$4dM^SR&47Y<^FQx<_Vhj zW8JAoac=pA?!==wCtBM@@)h&MsD56)Lj69fpSM4A{iXFr$gbh%`z*dn{Oi^U*s1An zGUSPm!S7CV$VRs^oM(-J-zY)8KH)D@Tad?s_(Xq>=drN!IMt9Uf;_9$Z8^4&IX`8zp^__%nY`hO1aFw9dGl7#sNQ|pC$#xw**ZMH{j^e87V*8P5AE6eX`NKx-om^bVm+{rWHXSf3prg=Kl-yg z-$^6S4?}#zZ}5EU5$Qxmr{@viLkGXf^E@GTezaQPgXBO2{;&i;52WKBKU?o$`;pg* zh`@J%=b?-BngdE9`~R`s{MGCaoW$r`jD~=I01WuiG|3_EBwHM%xAd zYMY_$qIR9{tmn0OPV-jVrro?tmYjas{j~d64S5B>oWtMt^1MF|f8%-oh`;ru2~UB7 zyk>dAzr;Ga#rHP-xOuTsk@hk0TdJS;70`2v=LwgfCn!9R zS;wNy1?QIkz;pJtzT)ItYdOK?KtbLmRf*GY^dEY>JzmcLLylfhOG9os7G|5!FYpm3 zPrlIq+&uZ#Z|i(Q1ojZ=ANKi#NC)v5!oPDqAskTZ67Ib&1?Lm~Y9bjpMLlU9`}s~i z?K7WajWe=S8Q*6)Jb`^)E51PslO2uy!@-y|%{4Zo6sAJqVVNi)Y!S&RMM z!h4J2*9$$f(mrm99?I0G#P6lgiQoM%3OM*{@tlRl{Vst9aqml{T|n!+4wK&~e$RWC z_&vOV^bj%HjWUwD;)1ke8fj9%)!*UAzer_E);0 z6zoT=fPaDbFFzMf?QF{AkRPYEOX!hKeh%;t@K@lq(BE>Fnc0c`qAu$mva?uj1p2Z+ z8JFAlm~! ziwgM+y~8xYHymXK}tS#bkbe!(#);BN8a z9J2apjn72?sXn*=)KA@4v7fA85%k4WL0|W!bmXmU!G0C#>vsOkF!ItG0rN_EA&BjYF@WKk_#UAf&wkKamhx(7; z4}KhYCi|ll&*qRdUS}R=8*lNvyYXESzW;8^+XzzG?Qr{R$A?K$`XKyOH44V*bL3+c z)&bFfGvuR!xD}GKiBrm1o`RfFm&hzb{txe$6;X~ z4fp4`^JnjemhOM{oS!itpz+?&llLD>;de^EhxDtH=kH)QYwEKJga2|f|#eCn5H7?_J+^qSe zd=Ycl}kiM`9a*3#UXpSoO8SM2yJb>>D2j&a? zwnjBZX#GjJ&tAhoV)|%`=m+bnkX}D)ngFc&j+a%%7S$8FV@OkYlaE$T(S5F$8KfY~}>rtgpUpT37 zzS}a%xc${W$@!^%<|Hp~4o>Re7urRW3XhL?<0RjgEvxVRNqxrW6(D=_B;P+}t0zs~ z-fGm#258+tP7YY>umb%y-?=?;i0bhLMBL@UA=3Ma|FI#NaQFKr<_ zwg*Brhp2qhru@rWGk%wTEj|_Q%W8Y_$P**x-?vokzmO>@PZIt6Hs!Opr-uz0@-(d* zU!Y6Jeu{lgH6pRvNhZ1VTKS)bsuZ5*$Ii!MpS$jk@RiZNHgcjs;$U-c~K=c-|lqc^TqsieK-JXa)A4asf*df8JcT zN`qcbP=8STHepW?WINLwYCE(1InRq)OYQF=dDAQ>-*5SbHs=6^-us>??op7hY<&FO=lHYti840W})|KFTpxvI{3ps~# z@u%k3Y)2=u#I`YBc`E2>%jJGhpAOFbjSO)tNk%TzUK2H;RsGQ<_!|C5( zlIOW|@zj@Kj{EU`v4W*`fnFtTU=s7Z zDbGfTpZ#n_j{B2-7P|9MsAo<6EM~%gqDO^)Y~zAB{C{k7r-0iA#Pjr9#P99z5x++} z8T@L6=l>@mCw6>5ynpCp;``m0M>n4v!94PY7fCxPvV?QlE;sRWRu_j?wtRZ zO>H!RbFvCQ|L^8=PAr|Ib>v5U4B25J)}>(|Er9xEzOS-;l8ixCr)bdU{5-$1-)R@; z|G}TxISN1j@4h$Bozz5o{QSRFAI|?zQa>uy7m(?D>W6dwKZ1O-0e=2}lJp*%f0dut z?C1V`+kY4KB9CI&y|=N1PqX+k#{DquSs(QFbJ|Is5dQsbG*2nS`)3l9#9wTF z&g3r&zs$T#guPcSXGW->)q%{T2I!&Q_~j_shXF}XK;GH(#&+-I>zK98eDAe$&c3N} zu{K&5Zzjg;X9sUKn0xO%>m|8~^;e0HSbpu6JJ}_NG|9=^!@7{qGE`CDu-mis47)vB zZ>d!7B_tL-DbkL%YKo|dL~doF(|*2f4RF@7Jst-q;ST->{CmG4OK`z6cpEXR0! zjRySzcq!2z-0!V=^tXt7v>S;Jko>jj(oZ6UVleM+e_;&%;WHR9-1q_Cw$-| zY$iTJ^@9$qb?=MVaV4T%((B$m3H|9zdQa=$eb3fRQak<*;tSMomygi*w7x6V=La7l zeb5g+lIMITkNuD;yeGPL_()kCcL(2RwBwBI{1ZMO@sXUHUqJ#NiJXd$*xwN!SyjMC zEIXU%W_kklMU&Dno#Xmi!*t5;*fFrLGQ$39n9dgHbJqKCEz=$;)E}+qwjEQ)a%(5G zAm~BdOXt|Z0@i8T)ssXgdY{7M^6PZ->Pd{RPuNR!rgqIF@pHW|#qva_b!`7Nlc2Lc zL%i2kUOP$iqxYFY@6z{Q%jvBzFX}f}UI%?u?<0PvhnZ|XecdF{m9$jWA=ebF6N10R z{3jXq^-ZoHtYADZob3-yG{&X<#5ZENzurLHka`2g<*YAuow!%r$#W|I`J@6nO88&> zO-}yyKc6IdxcnmN&kqs4?fVs)R}J5ENDVvRvv!#vt%o*U=XRZSU$53f&xwAdE`y)f zXPr6j56}m!JSF`kZ=oObDsx~jn|^vu`ldu&iQ9`q;ER}tkaekb23L%u1ZS9LDSKtERI$+>H;rFQ1ZTz{WEes2-a zKkctgu|4pUEKFoaNbh3vaK1xw^Qrcd{zLQIJa-k(d+n2%`Uw0KQu_8u#KSGG<@@x_ zPt*!M!x@i!$0YHi!G@HCb3g8Q*d3EJ4h_#~{>sNAXLgdDQ|1M7iAU)9T%Fqygoj!3 zSD(w^|MJ%wY!Cc~XQi{8j@rn+P6XZY^wD^zeS189j0g6!WPTL%+WglT2d!tb#{UW` zuF2#^NdNYCCAb|^-rrPaC*e_<$9}nLBdx=^*&O%B+2^BYnSWRA#8l+jX{VwQB&EKx&_q&{xlr|kQeXgIX9rh0F45Cw&`@Mvp%J$b-^jqqu^1)A4Xir%E z2=|(npX&L$p>MGzV*EbPz0B?PgN_vBf|?8^0m)qbpCf@VM@_=UVvs=y*}U zu3wAi^OgyJvU*92m6wvQgFsm5EreR7HB&H;>=J%{x>+_KJjD3@w-Ll=#>33opI}O} z>iW}v66$&sbk!nj4;{+6`}}gdIH#es)Ax$&M}I!l_$c-rT4nRE4$=7R`$O$>9ZDy@ zm&)pIleMoLB01)Zio9rKFMR=aR2uZH5I=9AaTulgGTvCmC{-c-i*L)2H;kDrDHA4Qzw#s;xJP}*K&AGK%V>*x4+3#AY9TCne6 z?Jv#g&y!xp*T>&Z0`Y^4>&K<-#aZ@mq5s+KN>MxRiOLZ_s5oxOQNB;`B9HGU)}yp4 z1%4z;zpV+RxZlj_M#^*N0O=E)UzuNromvSG zFQFci)8+MihM#lrwUHcWJU_u+E{8fqUdGaTI*>n;^bO>9YgG#KCM@IYB*Vu&Q-7Zl zarA1I?a6XHeiQmETZ;Mfm$h>M^<={{)Fak`zdz6RK!29>Z*e?SSO+;i?wRlz5`IIX zL(w1eJFrvW5}yg5CmIBume+F!KlkWwOk4di4|4jn?vE&6m-Jo>7OuyGlf+j$u>Og@ z%GdoB+&@uyUd8$dc4XL|1kZ={)T9i*Bj_OT8s=5tCkXuTdb9(4U01+Q<#`qO2?9S! zu2217QVmzcPvv;i@F*O$nnJ9zx-9<-B`D&j8;{AKz4Whdd^ zser$Od_B&zjszaUz(bDD-!qe$P(?hvfO=SP?H0T0s+LQYk}Ll}7A z<1(M)`cnlw*m8BTtdAXno%vrej^8%yvyi+{hUj~Pm3`kX>;Ha;o^~LAB(-Pj1G}3n zdEX?fty%Y6yq&k*=C{5;i0mPT`O3k53FAHZ<2=#>L4OjPnoPO-4gM`^W-I9lK72=d zj=zDmEgE&>ZCFE|=Se6i|6}mQ2#*H{v&aTLvz6qFT|UylIu@-doHsE)yZxe{kbi~a zw)Nr0c55A3^2&hz0e;y@l&@-Fix(YZW#fcv68mqZdYL`Wt{!1;+wwBgE9?iQ zm&R#Irx>UC66ebe`A_k@<4!;IUtoRN=K!lW7@4iWx7E+;2G+gkSfH$*nRfBMR3Eha zY0G(q^&k2~?_$*x@8pgDYUruqx)_v4eC50?5P*zw7nV()Jk}U$xxAOnVX`Abg?f~Kiq>&s z6ZEJc&&S!S7OX!@|EJ|{<-yZVPG(`ho9yomUy*-f2aVH?i>s2%=}FR;qP@Ty@*vZ1 z@QV#*X4phLufS8RkJiC@S05#L`g`~vWt5|SQa!()qe@!3pn*)XX3VG&3&U}!)7oK8;`T_l>{&sX)@}jd8|CRc~!c!_M=nwrSdSV;$ zG@k)y9%>PXUJ%z++Mm+(Um4G=W(w=C?6>F_ntq+S;64Rb zlo$K#q||;m5hD47I9I-2+o#}n*|vir?*dDYvJCMr)|OBV9rjt0L&vX^>0lX}7q({= z%fMg1cMaqD;vPqNhGSbZP53+eO-)AL#x10NUY`@~hb<7}n;)6d8cA>97 zJFLUqr1SVW)*@%&_x2&)MD{uH%XZvxNRCLR%>BL!?tQiG-W7xF?8DSf>*9D|zvk-M z&UdodpPVf|Doz{;e6lPa(atY!)iYau@zT8F1^l50d?`+pJ4Nk>d0z2gK|EuIjld4> ziM0gH;H!^kboPblIniUOpE%6@ga!LdR(xEzJ#G03o6nsB-?i?U3^yV#2alWWn*x28 z#xs`ri48WA4m$Z-;%6bA(eL<&3&!6!#khPuZwhwE=7?$tzteeBgh#DU5pkEcU$R2H zqpcU69FTR~L!&HbEss$B&DOqtU`VNkzoj(3++H90IWhGS?k6!Xo+5tK%APp?FyTRe zd5FD|VX!-*XvdA04|GS;E+4YvE!)@=7at})NI$!V=P!vhB^lz9RNOZNeYT0p$?m$; zr|#nSIIFEmzVEHJTHm#neD_}`!@zUAJ<0i;+AiWCm3I10clB*uI{2yM#AgRP={p*y z+KKO=cjCK(I6~>FOHlYCT@_aw0n3hKXl3ivFkUqSteS5-ehx7eLr`RT*3!^i@I ze|i6kNw$aR_K{lRYa~aSYpruVwZ-RpPF{R1dw|wIi+q{!dvC0LR+>NGM%YV|_G#=J zez?}kV-iz^|Fu>Xagqf2{Z+NHB9FP}MeOt4k{k;`-jRB)9fyDVbd~R?+2eBiBkeXm@DFl)4k{d?#XLAAnA+ybdhSu*H|HE3|Xj9bBKb+u5@~#CcZiKU3<)3iH!g`R|RW zigW2iA0M8A-ZzSK+k8GhJS9UPzO$R(OEJ1Y#Gg8O5mFzWf*<#x4~X^+D^7C9dxZX6 zaXcb_q_iN}a#=@#-MgFW$GUau*YBKCPlba{=Cmr??)P7@i`2 zV(Y6c(pmDIwgGsHv-E~3v*7;c*g#3U`rT7}zc+g~^nNG)Sbj@MedflgB=6rnsL$4i z*}V6Z)WO;a>$ww}!5A1L`wyLZaKIMVlGypA5-_%U&Qt>V46f=?(5SodWS zSFXD2II{)wQ+ltXgnJzkFQPljIZR?Z)dtiZxM|PgGZRj8C=q!0|ZsXr~4V2WQ ze{u?To%)uN@3s4V+8*SwT}I`<9|KfG*n z0e%00a=|_qM0U>K!VXbt6&`2rob$2Iz1aFio4B`@7~S7arDiynQ=bs$a_URY<<#5f za;SaqXG;&X_r1%{;}|;lj-6jk=_EOx!)ZI5$KiHq1$q(pwZ#?$7Hfrh56F%hrg_(w z#)tQlJsDlfHk%|jY=5M^{@ggr%$K-5QW~de$v5Zx7UZH_4SM+#8$+9b_M#O1g2D5q6`7b3K6tf=;5SpWd@MNo|DY z*S&98v`c*Z3y_2Cj3m!z=)TuJ54nf-_882muUew-$$qL-pFc+5Lyp^Vme&2lRd}Cu z?c@mjzB$Cx;hr!gbr|D$s%*X1zE5w?;>74ytRst`O0}z$3*xTaDW`Y)yTIa=Ckpgk ze^pp9`v9GJ?KFXdeDO&^q>bl=s^#9(1RZIpa(tZ zK@WP+gC6vt2R-OP4|>pp9`v9GJ?KFXdeDO&^q>bl=s^#9(1RZIpa(tZK@WP+gC6vt z2R-OP4|>pp9`v9GJ?KFXdeDO&^q>bl=s^#9(1RZIpa(tZK@WP+gC6vt2R-OP4|>pp z9`v9GJ?KFXdeDO&^q>bl=s^#9(1RZIpa(tZK@WP+gC6vt2R-OP4|>pp9`v9GJ?KFX zdeDO&^q>bl=s^#9(1RZIpa(tZK@WP+gC6vt2R-OP4|>pp9`v9GJ?KFXdeDO&^q>bl z=s^#9(1RZIpa(tZK@WP+gC6vt2R-OP4|>pp9`v9GJ?KFXdeDO&^q>bl=s^#9(1RZI zpa(tZK@WP+gC6vt2R-OP4|>pp9`v9GJ?KFXdeDO&^q>bl=s^#9(1RZIpa(tZK@WP+ zgC6vt2R-OP4|>pp9`v9GJ?KFXdeDO&^q>bl=s^#9(1RZIpa(tZK@WP+gC6vt2R-OP z4|>pp9`v9GJ?KFXdeDO&^q>bl=s^#9(1RXy;U$;8^X>nBI({+M%zW(a?|$o5mtOGZ zw`)xN1uXdXH@%TRzsUN1QP{`qzd`H&L-gEp|ny!7Ps6PJDH7a1 zP_DcCy!Rei{U2X=|407vf;0YR`d{C>Y{Sz3y!sn0>iqwx{#E9x zw;cG5NZb{#KZD!8$!yoFnX5+KZp7#H)|J}EK^mmKDJuv>>AN|wK>d?Jk zGh)A4_JPh%G<=9%xP9B|Pux-co6qWJ?ELAs-t)`Pf9KX8+sEqTS#1zxAtMNbLFgr=Pn2&cM!Z|MN#L zzjXJ(?Z+Q~V&f%OJpb7b{?^#G{sY6$Zr%FhU!VTon^@j~g12OholT|cS*VPERE9~=FZ|LQ#_&5!kc{PXu7z3Sut?}~r>%Ft|MuYKl<`RB$j{#@WEONYL6Q+)hw zZ(P}9?|bggme-$N|H$Xxv$>|NKJ?<>ZF#O^dfB810(`PWa6>ch9Z>5=o+ z?|h5Cc4)~B?|Jm5?>u|XyWaEE*!?%1{QbYbujgd5v#lS|XO@IFBqwjg)EmuDNot6Lbz=8MP5IOXVH-~@z%r`%G z*)!Se&%W~$jpuId`Tq9~MHXEB#cw7OcWUj%SAX-0nfU&aH@@{v_9}~Km`SR=MS7 zXx@@`Hw_IJOeCUHW-28s!_FHbb@q@}8*WLEP8|d3}yVdS< z&O5JH=~gbe;kKJTy!N*1?03tRbLge2T=1bAZoKxYw|(fQtFOClxw1^T@Rplyy5V-^ zO&2X!mY%nC$<^odU9G(R_Ulq9s(ra~@gIK<=0yaI11gL)Mg+f4R*C0|^N_Ezp$(w&jgqfmRCe%;8|w51Y;+g zWR_2a*zg%L+e7^tK4S-afUr3^fO0gR0ju1AT~48LAx2$|?N9kwqK(D_stn9$89m5+ zVT0|-`dD+2sT&C%7@~Tp9X3SuC{%ig>Y;Jl^{}%>b31j3UDm-in^~Hdz;jfOpT)zh zI!}$LVH!7$v$WrAsiGJe`o2ftY4~h8zKef1Z$%^(aOTITW&T$bqLo^->pr*p+Z>3q z2LVIz{LTb@-$&nP@Sf(M`lIyGd}o*fEW3D&+PQ3# z{Gly0x$#!i>t|}KRd1_ZuV}Y9=(}yBit^@yv5cQJS9fH0(mGJusT_T$wp(=BPUVQZ z6qK8L57wKcpMiF%TyCcljl|PCHY4ubnlPfDZXQIp0}y>3nDXCYaeNqdiR>GkoRsS?}%oW_v$FKTPnW z%Fio|%kE$0_IUXj-gCM-MZ0$SqVc=+vA%4Q%GHCOiTTuno{6v4gPz@WlxPF}(O(-= zvCf#3>E(Pqu$c25TaJKE_v3d5z6+E7XZDV1J|^KktpkGjU4(bi3(pTLSv>tU>r$K;@{v zt{f;{Z+8Dn+m8=XIg%sl5cmso+Z&?xG?yPi*{%^ay}Mv+o?r6KBrt;K-aQK@EQ7^`d^9f6x5%8kmRufywbX|@#@rHPxU9< za*G1`g;|2}c5A*W@TbE5f0pWxH{g5XXASsXa_et^ybTuCe@T}3k1k|5E;oV-`m=h5^I!IM$UD}D`u%Rd`Yd@_Nk4PGZ;TtXF1Ce9 z52Nw9`be>!Q5}Zf;ObX_sKFrD)u<)MqRPz?Imk9i_&&fMSs+LADdLw{&j!)K0(C{i zkP7G^RGlIGS9k7~r_};|DH5u}ys=m)l7U>;=f;g>*y#_`TH*%Lp%QJoIYRn_-5w!~ z#({R07SS`?tg1EXQ?05?$WfLQMf*E?HH{$)?U&NOAb_|k6P&a5^I;{W*-0^Hm;&|OW(_^ z#X$cz<2QXL%PmHp;5Pb=e#r{`rti}9o8$+RRr;Qgw4HuKua&hH19;ql-_$QT(P9vP zc$nz#7$)Z-l%w}@lAfc#ceDWiqzC-@n3&hiW5kC^4|!ya%UARBV+MX}j|k{IFM^kC zVz+H1x{##wy&NwV9xCgHf*x)AK|dp+Zv?+{^hNEav24(h>#ts4WVei|VMi}1*B4o8 zEE{(8fLEQio6nZWL8Zas>z2Gx8f?C9*MB|B7|g+gpX|3iq_4J~9+B@Oe#Anuyp!-k^Pub` zy;oUa&99{&IPI3$i*ZKyHA0TO4`bX}=r?R5*I#GRGiK1AK0cNXIrCxLAv5StA0MNB zNO-SEfcaes?pM2O44q}hU1PLiP2f*1o@STRmK{j+#N~8} zUgFf-T3j#5yL-{^2Dr({R&hu2J{?@UgQpB|(Bl+&rU z9egp)a@)t0+37UiYw>~J5$oq;{l%~erxmDO8${jK2&a}xa*DUr302; zY}-SQzob|%w&%$QdQ68LdY|1+`NR0M%_r@37YMC3jI7W39SYrOV4m&Y;n1Ci!R>PK zI~cms02{BXr)8OZ9b!eL8md)?0dHbZ#uiF2GLxgvI0sMN* z)t5@vvkiY)lhF6kx(PPWJdqv|l+3>!%WywLW(@pz?*Pj{A5O2X&2zml7MoU?>ql(V zP1ql-H5Z(w@1*cc;c1$0XnHy5L#29_<$nwJWGp@F;jcihvTh?c0zuJ{w*91E8iU?d zs%Mqxd$~{-=~)td>!fGV`?U(`e?+fQMd*J_`4ZP}s-XvlT)Sa*{qL(|#3x++&$RW> zJ*bcM3VqJ$S9BKpAZpnMcK-v4pliz>Ci|Q8XdixayG)5Pc@fQvJC6}&Bqi3-z`}XL zi@WaG!U)M>AM~pv>Lta8=v5+xJf8`&wgvdU&>t)>jA+cMx4)I%D~0-+vM`bjIPaIX z)BB9CKt8Efd*c0MC%sPu3+zp8VTAM!`~6rCy{GxK?MS63u`rT%-yiFx_cST4d`K46 z|H1&hPcvt|D+4L&pU-)Je2Ctwp#u4!7me=(=8NnVcfQgKBT2vWK8E=r{JQgF6unpY z{1o~fG7BRK_kCBpRlhSoW>NoD%#U6;KiQ)GU5WW2Ip@w#u4w*Km>+7-ou7PB|A>=v zyNmc%+(^L>u~@*^GVxr#MEst2h4>x6UckmX#B*hnfNh@<&pW;-VAnUqbM-0ld+BrH zcmIn54*ps^AATZ}Ci~t9?ae$${7ULt$F@K|_eNwT>(cK=;F0um7mv)M1DWU+JKAUH z2GM(t|Td-d=K;zH5bjmtqCh%{sS8LqKMxEP#Y%#5GA3NEeugw$R@Ga_K z_YhyWpeG&3r>Gw2MQN@#{{1-V6Q6@kJ6iy5m#cjXZC313oXjq& zzgkL9jDgQt^GDCQ{^0a;0kxL_KBzt2oo};=>L-S&G^ui{>OQy2t!kxmGW2XJN6_hK zJC&pFm3BpLCBB;JwEEepDy^hC&S<73 zYkl5>e!}@D$uEwjLN2|bpCkvJem2N_e^P0{e7ft*TtM|Fp;x8kR^6qC`{w}fA-1Z? zn$M<^`D~?f2Ie^_w-Ue4V1A)*wWpL;(qo-|T72VP^fQfqCVs*3Zt<0S(NCkGpPg1e zJ4^c61H99`^rWdhcYWSpN9BmWtpZ&`s+G{S4!Tw_&$^gT%&!T4l2$-JPCqSvb|0V5 z0O&J6Ci@+JcORcmm(JDRohlGo21KK&`l z($|Oog8J*D{%$5YOL9ON<#M*Vo%)*yzYhER)l8b~2qQF_d64*_)Nz2%Z>)#89B!jPFDMN$5g2j&*?*0P7{H~18c`mU@4Swu7k*uDfaR#PO zQa>aXh$OX9;eQt%ihmBLhC-T)YSHn{I=_(@ytI0x~ouMAYy%=M}O$I3cpH- zMNm%Rc1Qe(?&389{|n?pC%fo4=|{?0Cz4x?ptDaAXT}>)PU_2;`)J&?-SX&G;v-IZ z*gLT62B|4egzob-es+uLsOk#^`M{!{2B3FQdv7g`Gk#NiRAA`?``|GV6SjUZND}d6r%> z`+RDmpU!+Hiu+lnmt@a6qMkx8nRPx>#rmkFm&`t&Nr87~K2ybbFVjn8^$6BSCB0Xbv`q^y;8ko_W3lpzU|IurdYo( z(@WCJk6?ePl3p_Fd}g_xUaFVOKA)!Or!$|~;(nItCE1}PX{oYaGV6Tii|r6gFPVKl za{}+qeCCVsUZ$7G7az&`UWHz=hU8|L1-V{QE;s-5a=uhAf&Cv~A+DDMUWffH)l1g1 zEu=?;p_gP>S%0+#m9Ix>9?5GHeA>L~h{_7|67x!~CzR(O#UHe|7}>6J>gdx#mbNOzn}L zkuKCr=zG{373vE|#P?z7C8TGBp_k~;OQ>9u$FE&^g!C0huYg~e)){Ley@K>^W#JCe zE3jYAI3D9H`Mx9A-)q;+eKfCCEu?1ZO8!cMra+a-w>1H2RMI>wZg7=J@T8+S@XL?^tWw{ z&+nX0>aQ^azgYl&Lwq9+e#3}Pw7ZX_g9ZFX(~s!P*+(Im-v#@}dM>e-$PSWNO~lkQ zgwHDQ8(Ifd5kniL^<1T9wY@osRWF4dgms?%=n=D!-#o5mNY4rMh<&pt>P0WBGTKNk zRN#jc?Zuh)i6gWg*g5n*6)1dv=MfF-&Arprv|O z=Y99;*9XVmE3A%||Gb;qj9(@EekYu}D@MrGCe{Ol>de_j90EXwZuie+_;S z1-~JAF0tKOhUhnddWru;Q7_^Xstj#}+KVENOA9#dk-qWp5t?^)w!!t4g7<%e_pvTR z+XMb()koub_z2=cD%2MvzPN|#i-F(JxMCetF7Jna^Y9TKzd_$A!Bg;y&B-m`&sKaX z={H~C{-~iG*KZ==AK3!G3(g6l|MlQkWY5eU<@%8nxKhVCkm~vLJ>m1U`dv1H-y~VV zK8seoALQ(_fZw?M#HPn2_F3}6A5duD?BM$>u)74mIRO8#=EuHLu^+o!zuA2R{V(A+ zPCp(0uvWa!;`oQvB7cTmE?JL$())U?$gjMk!SW9`DBQ1fV1c#IvOq1~XDRc$Bpy40 zg;U~parz1SRDqwlcwWp_Yd%{OMf(>U;de=fSQ38vB=P0;Vm$2Vv-X4fG>(S@1C}3q zAfdp&QQ7a3{>G84zs&FQKhHmYl1Y<%G_apZbR{h%ebA6t6#JR#>ybZ~>aSzmo}1G! zvwrob?{BI8dW`fzKdXWMnxBC`52@TQAPs_Vfey@Pk7Nqo#LzRur)t5UX`RP&i{2p7ITc!bteJS^wnl#V}oTs&hJldG5k)v67lC}j+iu`O-XZ~;%ENT zp$`U5p--+NeUQEnOp-oGa%vg)In{r^mId9tX21BX`(kqOKBGlH*Mje1U#`A*|L!61 zJ;vjMW$b$&;_{Ir=zk@@xWo5~{ca`{lakNObgB>a3$!Y_W1j~8;0 z_%rd9Q}E}X9wGiv(Jwx0TtTYXKWh2KXP-~u7kB4#HotiG81H8#zxb^4nJ(UEsEcuZ zX!iLOesOm`(+cEfWxu%m%Ok`m{-^!o*CMVUE0x6+JOsH6KXjiV=9Bw_;MdJ4kkgg@ z;)!1!Nrfx>#Vf@XIQCz*NFTHP;@86dON7e&=?`IjGsN$kV!bz6^VyUw?q``_JbmH_ z>Gu`=;;q(tFNw2p;|lV;y;8sUwLKPJDxvF#K-bvEr+G&F$Uz>DM0~0*U%ZaW{NmaF z;{J{@zxXqxmq;Wx50IQExumY)`^mvRlAC(L{8i+$a#5UFMSk0Cjq87$-=+iO>Hk4~ zyU3!GPK!=T*1y<_)m-Zk?TKA6!-H? zYu#ZTAfBjX9XwQT^|M|R{DJeCF!*+HKg;8zYRA*3;J35Jo282R!`T)e!#W`SpmZHP z)NZZ2_9T}l2Rp5Pb|OB?cdGcPdE;5BGQXWwE~Jas-8rvTF6aX9j$B9=$HkS$N4;S@ ze+qs(t6V6Fk2?3&%2^Q~<;sOwZe=Bwottx`029cdS5yJD&e;dA1n4h+`m%T z%h$GBbW(!1hdQlsbz1zE%XgeZmW$Z4c3>T_26-!f~3P zO7#UI^gXS6Cq7HTxhUA7RL+E5N#7X-e!fckpw7O8aml#p?n_i*UxMB{<$EkYVUOh} z?6&=c2lagd9G_gJ^DaUXOO=%4W8%JHP!oGH+sE9`^X^tX=7am0sHImMMrM!i+e z+6T=xSpK(J_dyeH9aqcavz&f9ay(hQe^McC+%C6{^AkUp*M;SbPK&>G3O`{M`~>p8 zXSQ{kzMShDCF|7br^8Q@Mf)`_KS>nDk!^w}6X>kBs6xN&y|be*A%@{?-FLekKNgtLc9o_V=~< zTeTjQw6+`9RDSM?(S#nGsn*;X>BjjZ3KQpo$oK* zI!^jgXs_7M!TuEYUoLR`mv@YVuT~|wzcCaS`Jn9f;>^5#9Q#krNxr{S@cy=O;+J71 zDdJ}qIR4Aq`Fg8RUpPYF)B1DbXW}RqhX3;R@f?rWxno=loMM0J1dq!t*k4*dPVL(J zOSRZvQhcY_U+PG1q4i+zFZr;)gn7Q-%)*|2)%)3ha=I&x+v?}`zaMd1`s*=H<<VrwH4_0Gc6CbIL zWVBK2bHsIRFX;hM=wVr$KbOpb|vm15tx!QMBfdZF)CCHOvX74+16z-cee z^iOkr@eK*SFH!J*WSsQ9>Ue_myO2{Kjpx(jS%1a)s!4C%L;7en)-}oF>UlUnO?(LD zl02W=1LM@4%5iO^4`P0-xWPD6{&HNSarS1+ePriWb(gH`GQP0aTGt{@B?>+uzxH_j zKRw-*#z$H4T!@d#z8?4QO7)8|zCSt#`i1g(T-T-g#WB){7^{JPk(yy$m+dz)butku zSl8N~am~%AMKHfB6L6kOY+5r^>@OztOfJOcU|o~FH7AlIc^zhR<|VbgWY5*a?R~!N zqvLvr#jvh3qI`zdK>+oV9FC%1v{RKQc^qUh^hfIT89^rgB)$uOc#twXuS3LxxbbISA1A%t zw)1?j^9tpCnVr|qoq>FRF5USkk&;I zdMtZA%DYlMb{&_`A?UGMxx6da3$>q*rwjE$?Zt83@8nw{nBS#@oaYj|lk0`yNM6qn zKlDL<=rk`8m7nAE4JNd`Dr0`=V=0u&=EljMs^xydFt-;o#E%20m--t;z4Vk-<+PC` zeTQ=vNw+=X=P!&Wse9+=xSz1#{ZF88`UZ2_9?}o(`e-~a@by-qJ|D@sJ&1#b{2;mJ z>xZ8Z@q|>4@p$PM$BAz`{2y^UG~cWpdLga%#ha5`^pF$ZP4eSskULV3!Q)jTXOTQG z3-n6pkAz>+BQH8ma#LBdgP#Mn<5j89(e~DI0Zj|u3&3qqC za^ea1c3OO>bJqM4zZ{pP%5q~?KBpG#r`YA(b6v%JZZqGPg#TXbpYB~?`3+}{C(Qn8 zJRwz<8_qsS@w`-uC$!~80{%?wLzVb5H}m}w>_ckYZ@0I{@;CO(<|mYYJDw=tKYjK7 z%v4d_x-B;n^_F}qp_k1KRzDk(JbuKT&sp!(Od>!)P zQafoc_q#^Z$6ys@Ro=-kL!ThI?8z)4Zqa!zrH=vv?H)cwaE?V+>0YO zSh2m~o{uZiJDqcO&VCOo+FwdHS^U_tHwyNXXF2zhP$szk@uxob@_+pt$^XyJ^|q_x zoL!rJ&Q4!3ktx(u^??bJv*qV{#dE|(CbG=lr;-13|tD;|advT_pH$mm>bG-%c`zA;pMtHsvU%|Ov`aT`3 zSYIR}zK`U^xxa`i^0-D&PQg9{eW#zwPa*cB?R#(HOgVo7dTM>%+-DH~2LH$x@SC!@ z?7dvil>#^F`$%7pA`TmI1e$o=6w^RoPV&)W7m`z2dp+S2gtv=?_u94@&EX*6}Fu=_t32^c zPKWP!o^WeD*oqYV6M%A*VgkH{LrzbZ?*QEqMQ)37wWF&h;vV=X&Y;lvJ_4 zD9-hgT#xd7&;W~eiMX2x%9&iBx@scHPQfoal3QTMJLfozB-wLb7793QY((@uHa8~&eMeh&6+d%;$Ipab zP5jLJC-QFI%Cd8Ivz`Ymj-PSP+0A+$P~=@a&}sE^*1U`98z(^5mCo7CdLA%Q6bI{^ zvzzripsBQRGK-CWeDeoOh030mi+e#=)spXs9b z^DT8Te*fd_^QnvYe`h|^#plY)^UwV)$9u`Sk5@mRnIb>VmeT}Zo_#(Iah}4N&rET= zXnFp*M>+p0Irs6};~z%3AF_I2<~*c-db#!gZ@X=V{lOnhWWoh**TgT7Y ziTII1`@$Ho;!&*g?AakJUSrnt?Ab#TnesfZUOeh-_R*>1QUCP)eU0a->QxaJFWYhP z`YRKu!t+%6zfTDNMag+8@x1grRfxyW5{#s@Q5shW=c$Nqg*$}5Ns{D$ouKxDdqp0N z^7B+wZ<0CZpMr?HP5Pbo;!OWH=>PV4s)F~wm>_x&;XGBg@H`cLpOq@s7s7ce(z8Q( z5%(8T#Jyb+luLrI(RXHnKWKqvZ!ECvjnjAV{VF%kPI-9(_DpAr?2RC+T3C`-@>QRw zO1w7z^PimVyz?%vtMe{>w65WogdaAGeHg87QZ9<0t(nwjI`1N$m!5Yi%ioCeF0`(y zp;rLkQZ_P4>nO5U#2b~LccFSs_q5_>E(PzaCkZcAIPaqP3eLOG z_o-mT`l@i=h4gYKe`8$42S-qj`vvH`WWlI^f$5t8_&(5Btbyt4gMLc)?gGoI@c5GRmM4WdaelmyWVT7Ddw@*^NZl1)_^Da~` z_JghSDbaa$UPIAdoFwBU*%S78mxA|aPSQAIIPXGuanHNZ_gDuN>WksLORgYK;ygP~ zB9+tmeSK$7=3YylM5B9B_y0HYB;Kj-BYnIY@*VGA<2g17_)>8Wz&w8v`h<(Wfl1PX z%k56_9Q$X6jAqF0%!Xe@9<}tjn77J#)Tmw-oFVU-XpiReJn+f#JZh|OlDAiyM~%LR zT~VRF%6ZhN9OLmt1CRri^`)^AyVDq)q*2*+=bR;C|Gu)_dCbbIE9}mi6(WxH)$aFe z^(nA?^$$T;B?u2e8u<2-P*(aucY{SaH`*ZF5@0P zs>i*DPb(^y?87~W!Ge3G6Gi23AF%F0bnd@P7QNp*WZhfm+k^wYv}C9zxP1+mEXz zpR?zm=JIAemp4Aqgo z9~r{<3-LpAW4dxUR!{E}h4fiWKl6Ye5^N@R#xx;7=+?q3tC}mkSGbt}=)k{Pi2r2K`|VAZ ze0K1kDyshx;9o1mzh3ly50_7c_%FVv_sJfMz8(Av`I}YBDID}MT90Jvgepqn>xL$gf9(LLzd;b1O?4MY12nFxAL9YxV z4ndI$;t=S2HC(a2AmR|Pj_f#i#39i7iJ%?d0GQ-}{k%aFW)G9gkeay0lC-!~#+K`~%fb^{}AA&o_i4V!zIAH_ptznxu8cnicNf zb>FjxV7H*XJ)ongeg1*Ihn`=dzDPjf_pUqf$Pp?>c2*VMrwZ(nsAX41ExWRMm9R^! z`N6&K`^Y{DRNHx)l`QI&*Di z67$?`to+$jGq^<%1e^IZxV|k#_aL%{@dpX z^m_Q0;Gf9;bdvDEVhZ~b_|05ZAEx^BKApW{(7Y|p3jVv)U>TAd{!T;8BSFlgoezcd z@ui7%K^GqZ-%k$_-|LB7&bAvwXYglf{5;uDIp3@L92-djt=F>*_=N2jvi9Qwz$57q zes({51@tu6&>{c)9VtBnKG0}Vf2e=Grsxkr^e52E&XG@qs2>X9HNEW3-kyS-Xl~oVuz%9hCjamd$(0bND|bIkhrCT9 z&y@VbNutyBv@Tzv{xW6ee&K#2J&C;7YHxzmotUTZzJc+$DBK3tsl9S)-Bne&28q74iTPfm2F|f5!EU&?KtRQzG04#eO23$*A1$ymg^b58So|c z-;_?}9J!zLp-su`Z~}3Av|h5@->)5q{?nLc8CqZdzO3Nm1i{BiZ(b{R(7M}{F?Lct zHOafeh$F8-KNPCJE}2LZ*4XJuPMHLy%LJ zUer8)O?D@Zm!Pqe@c2Zq>!Dpl@3lCWMBkOuN0!S&rB}JNZaqV}^iHCemNs+h5b2*! z24k6B*!Pmm3HSx$OrD$sA7F!x2Ie8w*JzNv`DAeQLpU$blqAcL9#TGT5r?8IQ18C% zm=EpfI|*<5gN+X%e&Q5(AE{f%$CcVi{JN>$;OCoYJ*05n)7->jTd2Jn?0bVxwCbWf zL0-OhOd1;F9!4(ii-Jn03x1@e9}wEZAb|DW2cprAY;GPBHuZ$7xgazJ>WtJDl)2?`?Un zH#z$Vr%jPw!xn;%2FWfUc@6o{M)Xa5t}=a>^7RYm9VUIr?O*DZNm^egtFB-V5WV+A zHjsRTUH2Kz*IR?1OKgW9qEqAtBDwbRB+X+Bqk2exkRTUyu5Ztq(xHd3UxA-4LOY0W zYZLc$+wblDjWGBzy{`f!yTxAjY@sRmfJ*im_-a>9(DOh}&?7<6W7Po3iMZs*35UO1 zd|?s$?ynCiA=bR&ge51QO>F0JV8}Ot{+hp;q;{GIPY5|Nn3z69^+b8UTs>CDzHSos zRbm?B3gId`MjH19rV~qa^hIPl@p6>IiXE+Ik6xqZfwLv6K24gq)!ALC#;PA7`XVP7pp9 zr@5R6wk1ez(R=hKU)~?3o#ezA@x_+SLQW`HcYg4X;FMetS7Onv!#`RfCzu=OW6{SP z&`S#Ure$fJ;y3p712gc;JmDkY$cY-r32NV#cQq>6gR~BqqI0{nbRHc2sFmcz36gVz z`RHNjb=E#l^Rlt*PU=5FV`svZ6Cu!tIum`^>yqTe30{uRN6R3qJxt?uk{X==t4nfh5;K#}k$q8Ej)Q-MWE|3%bq~}1Mm&q|9r+# zIc}FXH6d>c&qtF&UUXYt1hMZ*bn0(Nh7QX8Gspq57Zk_=(!-p5ZP`yqu5BJT}Td6KKS8SSh$PZ3?|(5n&0 z(+RuLwG(L`^1E_4$C!Kb6!8zX2X-#K*!v3xx+R4}9|j+i$xgxVrD>smSLA2xti-Bd z!FYUc#=2qiLYCcRF2=kuIb`t{M*R!0d(MDgi1-+OCpevSOwl^ncpmJAfb*OMUtuFT zl7oR)*mmf{kq`sj&f#{fd*0pNPxXNhVPCl>ts}pluZ{Q#$|)J{mnxl4e-CSx*GSZV zl3O`QE#N`im!(s`$-e12OtsJ1l+7crU90r@#CC@Kc;fsy**9lnd~-Ht$^N8%ZI+iD zru7=+a@5tc^ajViSu#a)wZ50=0)9v}DfHnoKA9xBiFjkRH8CnV^UGr4{4U5Hi7lB* z6KF^Xxz*snqdb9Hzjhz+|NYv2lK@11N{-dCwr>0ek^nQD7Yz4{5i;?kY6O%qbLu5%baW? z4ZUz#Ha9}^7+spt;a7}8|D}1FLH}JVlM+Vy1h)s+AovUQN6Idr%Fm$p4iP^~xcUyO zA-xU$7tjmoy3eI@y?6c^G~e%ibb;Ew_{SC_yg2Y`GP~_~ml_-<5;P+PV&ga$Mfc*=$~PIOQv} zZ!W;PBKzjTDb6J;*f%Q4AEJkH`D3l~UiE{QjWWlsbmSK7FX%fZFb1ii6^+<&5z=>2OrB{gdyU0>7=!=SHaiLCE1O_Zz=!3iS?@ z_>FD3Z_}hY_~{sMB|6n+*0HQ<1Nj`whQ8m7#T_ zJ#8L_-AH8(KA+h?n*v{9m-0Mr1##BzgWp*iwEUiyK2yh}E75PcQ|zZW-`yGG=d^Tu zM|{6dTlwB875*LQ4+Zr-PTzr_;Jihi@1yhca?*5+=ac)oJ4#W%_-w~ zo0C)UH`?=V=P8Wjg+5u4pT`y^4q#u0ZFJvL_6=4Su z9diChQ1CxXZ;#SA))eiF{z?1otb-W!Tju*`bN|2gzCKEhtGe@5clF0i_srB-W2wr!ZoVm4wDTlV;aNvsJHE)YwMvCu;2g zzv-aFZwV4FR3GV8&R|{ukM<0Z9K^c1rV(fT@zA6wLtYeb6WE6#jvN%ocPWk@m)B2j z6o^w4<%dOy{U}cg#2<>&&kN)o`W^v0jAJC7bsmC#M*V~Sif9wfdua~Sb#WSg(R5)` ziSYNiwN#$g;S|dA_>~0gTb(FRz1fNKSjW>gm;amLEc-vwD9?8KcJ&vzzyEeU>4nfE zP1|`0c*LagG`1OW@e<9yN3W*x#DCpf9@onP{Fp*{;{O!NL!PCx<0b0X z$2OsV9@V7sHZHdO0@cCGY%ENDBaeH*_bn{-4bNYBm zoNnNHj_dco|3!%xj=Unj`{*rno!)nJmndN!xMvTIJJHguMCrK`chL2y819zisiS@1 zlXQ{$t3$iBc`wP!jtsTW=6)G2(KxiRw2$t`&dj#}X zlG7hwgxn~*{a89E>lt{M<#aMF<6pgc(gztAhoF$TE+tA6vOUEK_q(hUT+i$S+&=?71>RR^!B1G>xGdhsXd#Y=*Ji+SMeGRc9MU;estOUhr`AoKka zj{d@;#re=ay-0ke+Dm%xy^GX-F(5K*_n9y<7EOKSa@NlO4!`kA5iF~rKgRvdu^NYZpZ*9u)b@g$Q8&VFek^UTvFYID8UJn9~ zP4AHB>d^R>7X{A6%+b1~`{l1a!+sZ4{?ZN^j}#c+2Ny{Ws`k?Oo@Css#y3mj%Y1$L z@%6@axxVhCGAy^9{!EG14dHAgO8wwWW>~H}@5q#(uRFJ7VCNOiZA7Wv&Ijo_eXn!S zrN`at54hzXcAtCFt><~S-WT2XydvM5Z08qOcG~p1-DjZhxp6N^o8{FT-R_n3)hyfT zps(((`f;ot4kG;n-=QT8<{yO@I?Yk%q$GmkD3{~A3q{>&=}yhGRRHPT+#Yt28l7_h^7<$!m93vnJBy)TRV zBwtd%I}V;V_*@xUkJ*lpN~`lQD%4(0q&dz=px!HbCIb6BU3{*}cWU+%z*`OYukg6p&+vM@1Mdsqz8@EFyX7~J-uSj>NpH-80^eL! z7O)G7ao7{#AF$q5gMG@{J@qWfBf8Fd67k=&i?kkff&ZXi_~%3}EH;FXw_Upj@!z)= zY5aV=?Uqw`d#kk16aQ5g3wi)=yX6$#MxO7y){3_||9A8G26~9NA-!xjT^6YPj!0u?r z196UcstK{F3$K|0}dm69{2I~)iTbk zYoH+U_5k5cdXEmgP4Y+|El_(9ho(*$U&~F5p4f)h8T*{jMVG z;_d63cA4Z$bgC)w^HhP`lhAfid0ixoCY7i5O#yEU@pw0l2enJbcz|EWbL_{8VLX6O zF&>Zy(T?%G=(khoFV8;%mbrgcW#L--o&T4`3&6G!>_@Gz|xR4xvD z3pu>4#CC~J#W3LkGbjT+Ybv99$c@Uws_katYICV zmGulv7C0W>Li~sYJXhfSxeA~4I@YRMHWt7~&gz=6WIem0X0v|S2fby*a@PEnwPIw& zax2}Z&*uFsW)I;pClSPBj~{IKdV|Ujp47~BHTZSJ+hzaiAK-qwG?Evm9L~S*;_ZAt zzC#Szc9G<(w$)+%Qe=wEKcx2*u#W_B3KBotKU1TAobFe6+Zm`e5XV?_IIcmJ_wcza zf2m*LZF^JA=I>fpv;BPL9h!Jk4f>w}JO;T&c&y3s3hR}XEf2kPW(0h*VmWJmv{qiZ z+)DRJf8+g@=GHdj>*5u?#~a^kYV0q2R?b6ZPZ_ktDaP&6|3l+@bq#)%pDD=kb@78R zEY@2HFG%~y_Nt4w?eQ9|yVI*=TpW$>#u~{rbCu;h1ifpOZ%+x9zqCrWD=@y-)bf6N zX?(|Oq$i4PG`?7Wls#o5jW4~&+`4ppy>VUc&wIo1c3#GJwDsEqZ~Oa?m7e=Xw|ixM z)ouTByshGYrcAcKwc_o{bBiR;p`Y(BasHRLvD|YiZ>?p8kGH+N5a!Mrt&bkwc5x%& zz-e4Jc)yqCms5Bf<$xEhomMRed?5II2d|vM+X;j7A7rQHz9|oH<2vTcRF>lne7v2b z_Qpk8r}b7uUjyD2H`H>P_;K-e2m6a-K7MuaWMV^6;n%m#NB5NNME{}Me}x4rMVsfK#H zO>S=|&gHS$zWR$b4Ayf0wu&F{@b~HJe{>rnY=Vn2nSG4-Kzfz;; zhODz+dKU96>-o2LV;%SKwrk%Ye)-omE8ySWsO&x3%{7v{#)!;|;gwT(d!w@V?EK|g z1?Qd#{tmC4!rL2Ndk^l@czSqyqigRm4c1cv{_U?|o$f+B1N=6w-Jvbs-b{F#?st!4 zpH&3@?LE)hv7r6-S6Giz{jT~;EQq)N^dRJKQpU5r(YW9dfALx1)^>QC@oJIH%>owu+Qv3K#BMrPA zf&NQ)oAqGA+c6(+Z*cMUD9IyQr$s;THrVSGiK~k)?l^Lri?@vu*gz zo|pemzsU4^*UR{?)M!!S=g}tnAA7Vp!cRK#-w5ny6{Cc=Ne-UtF0wx~jq(tF)SnoK z2+GrX7eRT*uTh)J|IJ#7x4VG13W3;u<5`P|jMdByVzwP2|lW;cl+Re_PoD z_B8LM^(fv4f34>Gx3499>d5_Y55camEz5W~it;44qJ4xKE8QU{~tP^Ewg-p0|-bAV>WL`$vxPyg2FF89coGJo}#$ z$jfA*U4=t6^l$QE*S~#E?&F+2L(gH|um&W(qczlj`eBKaJ-mIK%Xf^+^Gm&Y`aa0|k2rD0#oMq0@V?mtu=~O;#_<{+-hPqW z-^uv|qJBNb!_p4x;q9s@v!Bg64!q#`x2FrNms!YLQHfm!Z#y5aksu2ABR^3q#DnYE z$IvcXpNqhmE0(i%97)4Z3>8WA6S0A8(7hYlOF^@x0)D`$vJ-&B=zuW2*e> zJ>r<@m%lVA^M+}fxWC4B5c}>LJ+Io^q1i`jSIpP2YtNV_)HCW zXNx1pw;kRdo>l(sIefQ|x2@0B@|VHe?!IeP-pAYC_|Da+ypOl-KY|^J)C}q09>w?q zp8{`F{e$ptiy+>X2Gh2Z=VUO9!gCtbXa`@q!-Z%?{-dz;00CuOKS)RnKm9+;k>^}mET3(|+j z0{J-I{k5umr)K}pS}x$OAc9ZZn;kfChi?{PX4?9HWdf@GdhqqV4*=de@*G2m{ z^83CD`=W{?PxF2*&dc+)nuxUGY`1@WoIPM;UrR<8Q3w8oH7*`$!P)wC-=gbTP^{-I zI9ps-Cw?BXdbfTHaxklKw(<2^Gk~*QoKO8x!8+&RY!`p`ik;s8{}`N?C+?S1I2+|` z#4*i0UCTmV2|icPE2nTa&hepnl*N6L4<63Ob(6j;WAHlc<81S~I_WcA7-#4`?)bLF z*&7IFQ~B;un#VMs#%`MVOV}U$b;Nn52ESYj&MwRSsLS`Esr~hv37=L)5NChpAlj?q zazdQ_`f#=z7u15Y`+&0(;!OtOYz(@>*+z5Aw;GZ5IC~9nwgyT#JL2Q)jV{iH-3It& z1L17otadotr1z8jw1~ei&^#n+Ux5Eq;q2)==jDk^5zeFaUhE*84Li=E7bTu5z9QpS zkKE$otlQi;a>CbGFUo|k!AGZFWPi3e{R;cHzjqz-jAK8WO*rt?;<9%SzTa1WjFlP=+}V?*WabhGLED9CV1T*Ae>GA|8}j# ze(fHE^c&a<2v@?d8D+nzCZZWj`gM&Gmluazd{lf`?zcShyu{r{Uz9W>@N37! zW80-&B$mlb+?;7}`EKrC(y{D;cS{eqwA^uh8~EUXmWf(59%j*+=KdIe;T*gZ+_L)a^IG3 z_sMbnK7SQuoWUq?Hu2d>H=g01+hn{(M*5NCICt3uJ}xKf(07v0OFVjX7votmdqE(6 ziR84XLmw==_NtPL*9Q)A`2^y&5oe(4NxvxZG4-d!*?Uy{ceD=qb9z#a!yMst_?<^z zN4?r(V!sv)?l#a#z($^85E= zyp>;jMLUXkQ@t3(#r8m*?Yo@>6jILO2rTed9N0H;};uL*{ z%p*wSJA&t0>?niF;}*=JI@U?$*WOW)c9e`Q`C?gq1sboBI<2;T+=4w^x1nFsI#-VR z>X5U2n6WSm7^P zzaD4&x+2c5$o!e^{6>5|?A@8|OY>*?=c*$wrRLW&nUnk4VK23jU!!8xNiQK5A1Y-v zQQ9h^FPkEew^`wt?HvEKp?jioH{Az4PVX(PqVnud5uESWTt)NT@cByZgZARh+u(t} zi^zNz|0^Q%41PZ%^GQ*~8P*5HK!){sF`i*PLri7Z9xranl<F1^RSe$p-XW%s$K+ReKMb}`@WQBy`!E-7LWn)awG7*!3j6`@|;E$2Odc! zjhl}qynMnDF>cT0<6gf+Nq@%mDEwiBQ&f9WB!cR|J?gz|uZsrGUBS5<5ut6ZaQ@@& z?Z|(udpKRa*XyT#L%a-s5XPY#`RVhUo@2hTIR6UrMK|;HobdTj@mogvgT>6XWt-%a zxbr`ikI|&=8Ms3nBfTLyNRavt&F8B%gjb4C7k^}zOx>%W*7<*12kyJlEZa0+#cHE` zjO1jGo{{w+9}M{6N-=Dc9vVpqBR}EiEx!l$B#isMV)HQc^-&rJ2YEzX?b5`9jXc+4pJ@Ib_(*(F^3!;k&&TT~%KO;d@x}8)raxX6HWDKg6M=f& z_18#Cc_*Hbahh4jV*H(T<zPWNupS0})de<0#UPI6sMb#V*ccEw0#AI9`BU z6UJ3#U#{(%mUcEVm194r$`5HGe&J6}xT_J_&g4kbDK!$JFevTRVxYwHcIfIkS#^>X~(R+Y!TLkCh z75sL;-n`Fala`LW1S6By4d=nP6E?@w{_b=s4gKQ9>D;dKm{(Ip=4bUi@9fDZaZbva z9^>ujVaHCF*>AMsd0V1O+OfTJx77Ddhy%1_}Fgvj>Uz(Kbftbv9!Y-doh#1C|hDM&hkPyqx4|uQS`?a@nK1NbRq#Q`d z_+(YCm>^t6a<_dwa)0d5x;r>;k=lQ{ydF=Va`l+sN#!`tL^dVQH@Kre$MecNuOTHi zaeR2c!RI2}2>CD5*s9y2Pgn3>1=FRq9>kRQfsX&>o(JIB@hr1OSW&NA|9c4*mSSdY{^T7FJM zRBW=LN3Kc9^Gs=dd1~RMh{&bv#JMu>kNn5F#dzUI^*qOUJhiYpaydF)-OcBKT~po7 z_JsdZJlS~%KxBl zx88R!4>4{EAGFcKhd%UIPn~@!iu`n}e-G|$YMd8++5AfoU&0?3%Sb+o>7smpgX0TM z)N%b2X5~2eKUFd=(zwU;ciYJK6~p-tg3rhNqk2OV8~^yEagpTi_!o%M^=rO_|BUyZ zS~yE`?P2;4J;?PZ4NYaz;CFK>8Fh+~*Vv~X^Z3|nryGYn-J8$u%?0F#i{lb&a*W5~ zt7q-wrG)oBVdkV=O8KvT!gEr*`qX(TUVTgbnqsrX{^Bk^XAyQ4dhVr!*ZODWwIc7lqnw?|KWAq(Eonw__uoon4UN>6LkC6Itmp*Pk1bwTsICl{3 zbLESkm^E$);E0T<(0BO#fjCRfuc`I}x8Wmkv|suo?%BxpI%`tmc+bwz?zz$fZaxur zpPHVNcBG`m>$Mmwa9#qhf3x`v%Wstj-u2V3_?|iGH+gZpDBKUdQM0~Qhy341_?r0e zd)pm8XZm~b4}Bi$;b2yz9pH95CH4Bf{Ta?zG`msKLzD7)@g4I2kz3^dxk&*U1>dt> zG<&8Fz47R6^8P&^l;uzMOS`^`Gntm>$ZDE61N*bS(Os{vE>vbnUr*?AKex{3o@heX z%hnw6zrL+uAx}+eLh)1X5!eO4pK9{?7AilXKCR;YseY42JJz&jNRR2kIV5J>doSz~ zkSF3TxE~MPcOHcwLEqN2PUR9_eVrPWhn=BKeY%eF^!}ziCsLo1=MZ$@e$m$}ThC)W znm0`zlOhGBMSbV@b#+JbySs0uikk_K)=X*m-nSA`-7V29-pcC?(I`w zIxp0GwcULg{y8Yi=6mL|9Cs=DD-q;B*wSxU=V|;qGxB`nnAUu1;XVGm7seN*|E_Pf z#7UiI8RyBQlI71cj!cxkKUYFrF3E*n`kJ{Xncu`o*FQRCu>H5SA7q?+Ix(=?3gBV& zy`AEz-^MvT-n>uPoTo)35Vz4fpVar?yf6F7gEZbZ!wz2J{at@mFD{7__{%!R^(VE< z`1Y5966T8-;5?MHf)GV{H$SDgX`lqTC*D0!g1tbzk0_5rgwJd7>^jYF*CFr4hp2pv zE~h!aMGkhIBIN$%^J%O6naPnu>vkX2+uC)K;*dQDdFI)5#B-PjY9Bc1`O-e8;#A!I zI$r!)lO1N@XJ)gnzdhq!M{4~~}E%C{qdv1+8 z&QUyH4A>jTTHgQH{QeQFTf#s0#=}cJba_0i)ej1-;ynWZ3OV&d)kN1Jny^n&@dNm75?by%v zqv8PHkBWnQKZ-nQtgnos9i^4qLGL$uGrDi*aObVH8RHl6?YonPSbC19fZ z-;CO^fTbn)Llf;%g#9g$G-!NU&VNX~7U&1l}8+@vve`#Ez33Dg>s6w|` zuOK;bzE1P;uHHl9JbmxJp)~7-8t^OT%c{K0D{olr-@B{hCUKtR+rHkk8;7@4etLLG z$w_fj`l1oAf4l3yCy$k0pq^LdR?u(Xv`^f*H;;9g-v5&3$*s~F5q+8X*j%H|v6TI{ z?`OU&PSE$I{$29UdB`VyHTzdL#50wTJt8IB8>eL&Jf56kPtC*}Vm&&&TuUzGHo zSLF3lY5;kh#fg3?Pvb2MMmqtc$S{Qv&>eN;c)7advFKcX4DH}1Wca9Fy!h1z=+-KY8I-?uueTVnh^J}2BezmLkl zkZ4<98t3;l0_TK}sr>eIe?BVCK%b#`)M_8E<_~~rUHgGHQegSmwXS&bAaKmbEw)$d zsoCBe&iQ&ut3OYbJG5@+t-hQp4T2w|f%Bl3u1mVOiPk0I`ID0)h^R~i&Z|_4Iv zus>Us+cw?gbK%Tsyf@fi&5W`uq1+VoZ}z*Y_sa3;0S<+}*#}FmU$5vh2Cxt55%3T3 z`J6#9>QK4a@S?+%rZ`Fy!HTbZHvMfI{> zrg8Jmd)IT;9IZ1wI7gH8*ckS`6mSlMaaFZfc(@{pb3zKi^WLfcv%mp4YbJ|xF6nwn z_uiWk)>!p0wd|bqac|ciuad-x+ONUyqLS-u0IA-aByrJqdpv z4obhX7zD1M@m+ULo~P*P@wW4j5fk0RG!L_Z`IW#t^ygQrzM#rs9=6BN>c5ijR?3#~ z&?y-Y{o3_vdvo=LC3&1TRS(C-ur>eT%7c)LU1j*Osee9Py`9$YOm|tHr$aXrMjg_ZhIHq{mBUon zzE$vfr+aVZd@NMoZ!liT7`*Rp*!6plMC5x$BQjq6s)*|^G2hGk`NY@v*6>Ird8B<<$y%YUf)5_LmF?tj=Ek$SPVMx94t-OT;%kH^i` z7id0iR{lf!kMVk)z&^`-( z31i7Q&NE#D;#7%oM;7|1nm>f2n)f&2-u&rg{-bj7M(HrgsZQkMvjcI>ZS=Zdoucoh zaUYtZ_G-MpHFVTV!OOCULrnu1mj73^(ZLexW_>Aaq&2)fq3xu z$~fAw5AZ%(;ve4cO8hfkD$)zh&&vE!V_)R>T#=c8GYTU4Khd^x25srRV-IqE%0>to_&*ey00#lyf` zu$w`CZIkB=FPCR#V!$wF1N*03x$g6!@oUw?)cLyHpRV{&oqv`9A6h}VaN3m%jbFpK zsra_k1o%++eCXmbk^C;p*|gOieHnI%O(yXl>6J<1Kax`|{P$MyU#x}ydJ@VXBm1EX z^9}yTxJmp6ecP1#K2n%(t?Q1Wy-CbB`pzWUiTULGM)f7kSK_}C;{djojV1`smf3G8 z&mn8GUg!zKz&T`UT}Wcz5B#0VzooC2`bt)w_tdF13)TBH;Uu!G|A<6BaZ$uQJm0Cm zTb!bG&R-lm7jj5FzfL|hVAiX$|CFLhigJ}KCb!FEZHKND&{smq@UcOPkI zGO{1#CTaZ>k)COPgHiBpIlFL?CJ}_{oKw+ zq@JifU3p0a^hEJAaIxRc;_pGux7QP?Jk1ARPo)13LJk$>{?ujXeRWMe4_J7d9cqUJ&|zfz6{Boay;l){{-Xqj66@d1OGLgBP;QC3jgtbZ(X7G z>`VmK75BfluDJibbw&Q~z&effcrEEASyzcSn#JUChkvkrpthYyAMNc%2Rd3e= zdZHYU_UrSl;y{J%bH}Q?{W!@u^u%1u9}n@tC3<2KdLrS(B=kfJ_?h%X`mQ9}mwhdI zqMSdzo+#&!$A9rW$Dwo}uPfFImDjbMo@mnd(s&P<)L!=cixSoawN59XCqlpesp*N5 ze_Hg!5xGx5$s3=4WPkYk5nOrlI{D|L10=WLe;Sm0tKOsXKB)JkpeHtX-WLxOzo+z~ z&G|{%*yUH&6LX)3edEq;&=ZLdw}B56-uZxO@L@UOpF6s3&gDb%kE;(xJby~(IPqZx z_rZrzK1YD_7bL&P`#Mw56S3~DZ7~0(CP=SqVm~VQ&$mOg>WQ)+d_7V2!%wUyPPp@J zLe3ZBzf;xQkw=dBFDE?QJUUH!BI$=o?Aw8SZ{wegLr={3>q0m5MEJ#)>xlz$edyG( zk5pfXw&;nT9M=Di_d|&Z`TevG|5^2{;Cv&nyORF&P_;MuDte;JpPruR@@I>lDEY1j zdLq_~IL;%~MGwyFf}Xe)dZMo%%>3xx;soMnI1j8pFZ49E7yeAIz2eWSxAXb2^U!a* zp(hHQ7lHMc{p(KkY&>}X&UsqbBe-AW`}0`O1NU{Tv)#}WiK>1~X}QzY-H0c+iO)|= zLr;XgY`n;EG2PG;X&w5h>4|Oqb8Ym*4Mm6j-fy&?*tXqrKR~OVXn!64gupuXG~(ZU zJ@HD?*WxSdi9fNQUOZDB3hqY~XRCzwNKagSwwLrjo%FIs!jm5)-(CVg?gKt7`Tp$= z&3Xy`l4wfpyP^NPA@|-d?a!SC%at_NNvw0r^s1J1&C{#I>a$x&uDSa}hTJ%fmGq$X ztmnkU2G(<8VvO&{#hW8i4zHvKDg8(33r0f5VI{Tfl?#ODJiUm<1?O!dub@0%R>@Im z@9BcQN5Y_3Ps6T)*zE=SokqQfhx`p;@K% zO|A1@f9MU~H`0Uk75J^QT!g)^XWWtb@3RdV@4DpI7C_B{^`;k87~DI#PaR z+nuNC=FQkj&jtK_s=qbt|7%9QaiRJ6o$5~E?dMbc+o3tnS7%sHymFxz`~B29;v^Ox z49;izKSS$TO71gF;XiO9_#1X?cRoikpTVHZ^zs(|_VjXN^;yE9#NX22d-0wBaOSWs z3>|#VdP5oUqO@+UUZ8dD4dZin-dhQk&q~hw7CuilWZnX{Hwx(Q#l!Tlo-yV5(QY25 zmHAwrOS>QX6xBO4;l$70t`VQV^U|65xR}Lx6x7b{ZPY&o`*-3Cq-Vb2e7<5{D)6}< z53%w-Rd=6l3hQK|mCs#%R^vkW^Ofogy2sCvgs1l~|M>h&|Eb(`N}ZoY|99&mhH)c3 zmH4>`c^zZiuX%9{%iBloqH**6TixJe=%enu-j8*W_;DzSbt{7L>-ySGP0S|U@k^@l zlkI!M$FI$I`gysQj)S*vv5lQqe7qp#TZ^7!T)9Aa++QD(*-{gBOk?%J?S4ED^qbjo zq(#3m6K>p-(r?5~5*IJqCp)z3o14z=^y8?7vD$>6uZ$QbLgPC!oP6d0=@&gIdVj{BSEUg*?qg(W+=s}#-2_gL zx^he5r=iZV#@!@8OPk&JrKHTuU~XO-zjP`0@5NriX_t0iWgnq=b!qp17I)G25Vb!^ zd>8K&$%9lnLA`OX!e){L@*w*09x}f}ax-0bv_M?Pjhm9$gqIJXD=qoE7yH0T59_)% zIeX9&qOgP7NBn8-z`h`V-8+iJXr)9Tu0q8J%JcSyu04}G4*gc`1562HDC>XMn?HBb zxaiRRX+xaPi+~+p%Hv}wW)EBmQkMdZadcb>;MXDl~vy|ih8^rV)!xk1Fu(KZTcYxJ2~u9ZS3S;KUi1JpMB8phb}A4<45bm z`~vJqZRMei`_)qetE^rAytfmH^8LA(i1G8fuv7RS4gAkWA(vlB8P<7f-=iH^w<6yC zGbxk$9q*z0Wvnl@8}B6R-(tq+&kkWts2|`r7HJc4-70R?88jj4qy z4wipAN$Xr#5aNRzRb#Jio-;%i{?=2j!pnUW5$>x%J z^2duPFaA7P6v6Ac<0PleLF4Hp^-lc?L1TS%OB^;e^|IL`jd~d+Mlx0IJd<^5+5Yj z%&y)&=dXVz`jgfRYdXjHG?Z(hT>GbyYq^<)`N;nVa;;6C+3!1L;4~F)klaji?Sikj z`f{!ETMNCKFW1yQ6jxp@&(kr4JROZ-o(@;9a{YPY&Rnxdd}*%UQ{i!5eTQ>^`rF)I zHIA2%r>4sLb%|Dvq5W=rw$gJB#C}ab|0;eKd(ucCjy*Xk~tOQ z+YsJw-FGmTKVU{gV{?}M%-Uv~^OSZD7v~N-zMVBWIcxmVX~d0Fy|C-emr2pnMB)*< ze2m`PVa|$Uq%WpMN~U>+`uk41JVX7Va9eV#n7Ha_RNR?C-UZkPrJYXP*(@K1-_xtt zDcdy95|32M$DmzKIRbfpI<{50{`3wbx&A2Un=x$2aaVuu_&qDRek|&Jx0pv>q&U^n zpn77WYpNpdM;s^eBT+qFley&jGt}=WZwTS^XJuZpH#Im9PGW7Ye2nB__f$jNPyN=> zw@2{*HGiY>X)l-4b<~f-Y@D*XJx$j6yoRNqEjpXkA?dJ`$*mW zqUMG?^OKnQMA@eKpSbfAWys_B=uv_7qho_@n7e@E-2FF@H%0ivf6Fd4G_U@YW<9WQ z*0+b6onyu0rUuG+hzJ+Ub(Zk-RoTEk1d%SBEW~~M)Ycv+^Zw}x;8s6xQiqWKt|8+$ z|K#j$&D)POgmEW)H#9uU`i9W|fcL3uTJ8({9@FN1efu?>;|BZh=iK|^6!LT&z;*Z` z)1Tu!%rTY=5uBT1UC8qJDb5eGf~evAu!!p>QJrX(u0!tKWdE>1qprQ%{vq)L$vqo> zf{%kXqp*A0u;V$Pr1$(T&H>9}y)rm1qFsDmN5VFGs}XT#b0Go$K@xT-_%GW&C+&P4 ziQ@X*XX2uY=V;!q{G9aDbR;UiO>B_i*c(=>$0Abaak$UkNuM|(?Xts1fI)9y!R3tKfADn+VfVr zPwSn3-})=u$NNr|bg#Znjmp2EwXH9uQ+b;2DeT*FbdgHR{IVUmKkv_zRy}49>oLps zPsY}f9s{m){b(BULCn5dJ_uDVy?SRbf1=CxG=2x_;MYlW&BZ+P-I|L9KmUsIw~ADL z%|)v$|8LcA|_ z5%zL7&-DI;({aw^d`#b2ka1l?fHeeKRSNnk&(!*NtUfdA>n9+G=BpUocKFf8AWJ0>D8 zo_$Zu%g3Pd`iVZl`#Dj**YV$r^C$V7548`!jlFr;(tdFEc0On1jmc-a(dK-)^nqD< z?p^u(!p^uSZ$0~J56MN~#&nbOzDK8<(tbg7iTz?ay>9oMF073u)@MAqh`i#BK;8@Y zeJRa(335)!K_wsct!8I4N8^pW?8M*8^Um5^(%BP&^Gb>5=HoQoZ@7SU$$n{CyiDui z*bXCwyktW=u)c{F|4<{I{(On%!>G7HJo7?K*w=J(UdnV&p7nnY3-`d4i2 z((gmB*fo;p`Rnh;URG|N%2B`NaUP`=+=spNz3ThZ=w}-LcK!TbmA~T}k`on{3mwmC z34*1MM4x#ffpOq?s_c$zC-jV!`g^^&Gxp4b^c?(FB%h~{cbN2&?4+9qaG5_xJxAl4 zc!t&&yGy=r3idFeED<3BGU29eKGI3Y!9`QSu&&YE-HSs%~7ct@S7QeZhcW9%&+L{gIf!tRXGgQAlmYJESbul$2X0h)qCDMD44_)Oi6j--_6Sczd zb6fm8OIeV6 zSod5n=|M)*I%Pxyd98p2U0(p6&<7+PBdb|14)9AQJ z^Mv%EeaJ&Z|2z47x1N0GMb?)^q{{leMtCU_(vXHUq#+GyNJARZkcKp*Aq{CrLmJYM zhBTxh4QWV28q$!4G^8O7X-GpF(vXHUq#+GyNJARZkcKp*Aq{CrLmJYMhBTxh4QWV2 z8q$!4G^8O7X-GpF(vXHUq#+GyNJARZkcKp*Aq{CrLmJYMhBTxh4QWV28q$!4G^8O7 zX-GpF(vXHUq#+GyNJARZkcKp*Aq{CrLmJYMhBTxh4QWV28q$!4G^8O7X-GpF(vXHU zq#+GyNJARZkcKp*Aq{CrLmJYMhBTxh4QWV28q$!4G^8O7X-GpF(vXHUq#+GyNJARZ ekcKp*Aq{CrLmJYMhBTxh4QWV28q)vA=>Gu^+ncTc literal 0 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%0A0_|LIp#DnL-tojC|qQJWhCSiS2c=- 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 (ADF_SRV_TYPE_BIT_LEN * (srv))) & ADF_SRV_TYPE_MASK) +#define GET_CSR_OPS(accel_dev) (&(accel_dev)->hw_device->csr_info.csr_ops) + #define ADF_DEFAULT_RING_TO_SRV_MAP \ (CRYPTO | CRYPTO << ADF_CFG_SERV_RING_PAIR_1_SHIFT | \ NA << ADF_CFG_SERV_RING_PAIR_2_SHIFT | \ @@ -156,7 +167,9 @@ ADF_ACCEL_SERVICE_NULL = 0, ADF_ACCEL_INLINE_CRYPTO = 1, ADF_ACCEL_CRYPTO = 2, - ADF_ACCEL_COMPRESSION = 4 + ADF_ACCEL_COMPRESSION = 4, + ADF_ACCEL_ASYM = 8, + ADF_ACCEL_ADMIN = 16 }; struct adf_ae_info { @@ -182,6 +195,7 @@ u32 dc_ae_msk; u8 num_cy_au; u8 num_dc_au; + u8 num_asym_au; u8 num_inline_au; struct adf_accel_unit *au; const struct adf_ae_info *ae_info; @@ -231,6 +245,60 @@ u32 mailbox_offset; } __packed; +struct adf_hw_csr_ops { + u64 (*build_csr_ring_base_addr)(bus_addr_t addr, u32 size); + u32 (*read_csr_ring_head)(struct resource *csr_base_addr, + u32 bank, + u32 ring); + void (*write_csr_ring_head)(struct resource *csr_base_addr, + u32 bank, + u32 ring, + u32 value); + u32 (*read_csr_ring_tail)(struct resource *csr_base_addr, + u32 bank, + u32 ring); + void (*write_csr_ring_tail)(struct resource *csr_base_addr, + u32 bank, + u32 ring, + u32 value); + u32 (*read_csr_e_stat)(struct resource *csr_base_addr, u32 bank); + void (*write_csr_ring_config)(struct resource *csr_base_addr, + u32 bank, + u32 ring, + u32 value); + void (*write_csr_ring_base)(struct resource *csr_base_addr, + u32 bank, + u32 ring, + bus_addr_t addr); + void (*write_csr_int_flag)(struct resource *csr_base_addr, + u32 bank, + u32 value); + void (*write_csr_int_srcsel)(struct resource *csr_base_addr, u32 bank); + void (*write_csr_int_col_en)(struct resource *csr_base_addr, + u32 bank, + u32 value); + void (*write_csr_int_col_ctl)(struct resource *csr_base_addr, + u32 bank, + u32 value); + void (*write_csr_int_flag_and_col)(struct resource *csr_base_addr, + u32 bank, + u32 value); + u32 (*read_csr_ring_srv_arb_en)(struct resource *csr_base_addr, + u32 bank); + void (*write_csr_ring_srv_arb_en)(struct resource *csr_base_addr, + u32 bank, + u32 value); +}; + +struct adf_hw_csr_info { + struct adf_hw_csr_ops csr_ops; + u32 csr_addr_offset; + u32 ring_bundle_size; + u32 bank_int_flag_clear_mask; + u32 num_rings_per_int_srcsel; + u32 arb_enable_mask; +}; + struct adf_cfg_device_data; struct adf_accel_dev; struct adf_etr_data; @@ -282,8 +350,10 @@ void (*exit_arb)(struct adf_accel_dev *accel_dev); void (*get_arb_mapping)(struct adf_accel_dev *accel_dev, const uint32_t **cfg); + int (*init_device)(struct adf_accel_dev *accel_dev); int (*get_heartbeat_status)(struct adf_accel_dev *accel_dev); uint32_t (*get_ae_clock)(struct adf_hw_device_data *self); + uint32_t (*get_hb_clock)(struct adf_hw_device_data *self); void (*disable_iov)(struct adf_accel_dev *accel_dev); void (*configure_iov_threads)(struct adf_accel_dev *accel_dev, bool enable); @@ -298,6 +368,8 @@ void (*restore_device)(struct adf_accel_dev *accel_dev); uint32_t (*get_obj_cfg_ae_mask)(struct adf_accel_dev *accel_dev, enum adf_accel_unit_services services); + enum adf_accel_unit_services ( + *get_service_type)(struct adf_accel_dev *accel_dev, s32 obj_num); int (*add_pke_stats)(struct adf_accel_dev *accel_dev); void (*remove_pke_stats)(struct adf_accel_dev *accel_dev); int (*add_misc_error)(struct adf_accel_dev *accel_dev); @@ -311,6 +383,14 @@ enum adf_accel_unit_services services); void (*pre_reset)(struct adf_accel_dev *accel_dev); void (*post_reset)(struct adf_accel_dev *accel_dev); + void (*set_msix_rttable)(struct adf_accel_dev *accel_dev); + void (*get_ring_svc_map_data)(int ring_pair_index, + u16 ring_to_svc_map, + u8 *serv_type, + int *ring_index, + int *num_rings_per_srv, + int bundle_num); + struct adf_hw_csr_info csr_info; const char *fw_name; const char *fw_mmp_name; bool reset_ack; @@ -320,7 +400,10 @@ uint16_t accel_mask; u32 aerucm_mask; u32 ae_mask; + u32 admin_ae_mask; u32 service_mask; + u32 service_to_load_mask; + u32 heartbeat_ctr_num; uint16_t tx_rings_mask; uint8_t tx_rx_gap; uint8_t num_banks; diff --git a/sys/dev/qat/include/common/adf_cfg.h b/sys/dev/qat/include/common/adf_cfg.h --- a/sys/dev/qat/include/common/adf_cfg.h +++ b/sys/dev/qat/include/common/adf_cfg.h @@ -76,4 +76,14 @@ int adf_cfg_restore_section(struct adf_accel_dev *accel_dev, struct adf_cfg_section *section); void adf_cfg_keyval_del_all(struct list_head *head); + +static inline int +adf_cy_inst_cross_banks(struct adf_accel_dev *accel_dev) +{ + if (accel_dev->hw_device->num_rings_per_bank == 2) + return 1; + else + return 0; +} + #endif diff --git a/sys/dev/qat/include/common/adf_cfg_common.h b/sys/dev/qat/include/common/adf_cfg_common.h --- a/sys/dev/qat/include/common/adf_cfg_common.h +++ b/sys/dev/qat/include/common/adf_cfg_common.h @@ -27,7 +27,7 @@ #define ADF_MAX_ACCELENGINES 12 #define ADF_CFG_STORAGE_ENABLED 1 #define ADF_DEVS_ARRAY_SIZE BITS_TO_LONGS(ADF_MAX_DEVICES) -#define ADF_SSM_WDT_PKE_DEFAULT_VALUE 0x3000000 +#define ADF_GEN2_SSM_WDT_PKE_DEFAULT_VALUE 0x3000000 #define ADF_WDT_TIMER_SYM_COMP_MS 3 #define ADF_MIN_HB_TIMER_MS 100 #define ADF_CFG_MAX_NUM_OF_SECTIONS 16 @@ -87,7 +87,8 @@ DEV_200XX, DEV_200XXVF, DEV_C4XXX, - DEV_C4XXXVF + DEV_C4XXXVF, + DEV_4XXX }; enum adf_cfg_fw_image_type { @@ -158,6 +159,7 @@ /* contains all the info about rings */ struct adf_cfg_ring **rings; u16 in_use; + u16 max_cfg_svc_num; }; struct adf_cfg_instance { diff --git a/sys/dev/qat/include/common/adf_cfg_strings.h b/sys/dev/qat/include/common/adf_cfg_strings.h --- a/sys/dev/qat/include/common/adf_cfg_strings.h +++ b/sys/dev/qat/include/common/adf_cfg_strings.h @@ -22,6 +22,8 @@ #define ADF_RING_DC_RX "RingRx" #define ADF_ETRMGR_BANK "Bank" #define ADF_RING_BANK_NUM "BankNumber" +#define ADF_RING_BANK_NUM_ASYM "BankNumberAsym" +#define ADF_RING_BANK_NUM_SYM "BankNumberSym" #define ADF_CY "Cy" #define ADF_DC "Dc" #define ADF_DC_EXTENDED_FEATURES "Device_DcExtendedFeatures" @@ -112,6 +114,8 @@ #define ADF_CY_CORE_AFFINITY_FORMAT ADF_CY "%d" ADF_ETRMGR_CORE_AFFINITY #define ADF_DC_CORE_AFFINITY_FORMAT ADF_DC "%d" ADF_ETRMGR_CORE_AFFINITY #define ADF_CY_BANK_NUM_FORMAT ADF_CY "%d" ADF_RING_BANK_NUM +#define ADF_CY_ASYM_BANK_NUM_FORMAT ADF_CY "%d" ADF_RING_BANK_NUM_ASYM +#define ADF_CY_SYM_BANK_NUM_FORMAT ADF_CY "%d" ADF_RING_BANK_NUM_SYM #define ADF_DC_BANK_NUM_FORMAT ADF_DC "%d" ADF_RING_BANK_NUM #define ADF_CY_ASYM_TX_FORMAT ADF_CY "%d" ADF_RING_ASYM_TX #define ADF_CY_SYM_TX_FORMAT ADF_CY "%d" ADF_RING_SYM_TX diff --git a/sys/dev/qat/include/common/adf_common_drv.h b/sys/dev/qat/include/common/adf_common_drv.h --- a/sys/dev/qat/include/common/adf_common_drv.h +++ b/sys/dev/qat/include/common/adf_common_drv.h @@ -203,10 +203,14 @@ void adf_exit_arb(struct adf_accel_dev *accel_dev); void adf_disable_arb(struct adf_accel_dev *accel_dev); void adf_update_ring_arb(struct adf_etr_ring_data *ring); -void -adf_enable_ring_arb(void *csr_addr, unsigned int bank_nr, unsigned int mask); -void -adf_disable_ring_arb(void *csr_addr, unsigned int bank_nr, unsigned int mask); +void adf_enable_ring_arb(struct adf_accel_dev *accel_dev, + void *csr_addr, + unsigned int bank_nr, + unsigned int mask); +void adf_disable_ring_arb(struct adf_accel_dev *accel_dev, + void *csr_addr, + unsigned int bank_nr, + unsigned int mask); int adf_set_ssm_wdtimer(struct adf_accel_dev *accel_dev); struct adf_accel_dev *adf_devmgr_get_dev_by_bdf(struct adf_pci_address *addr); struct adf_accel_dev *adf_devmgr_get_dev_by_pci_bus(u8 bus); @@ -238,9 +242,7 @@ int qat_hal_init(struct adf_accel_dev *accel_dev); void qat_hal_deinit(struct icp_qat_fw_loader_handle *handle); -void qat_hal_start(struct icp_qat_fw_loader_handle *handle, - unsigned char ae, - unsigned int ctx_mask); +int qat_hal_start(struct icp_qat_fw_loader_handle *handle); void qat_hal_stop(struct icp_qat_fw_loader_handle *handle, unsigned char ae, unsigned int ctx_mask); diff --git a/sys/dev/qat/include/common/adf_gen2_hw_data.h b/sys/dev/qat/include/common/adf_gen2_hw_data.h new file mode 100644 --- /dev/null +++ b/sys/dev/qat/include/common/adf_gen2_hw_data.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2021 Intel Corporation */ +/* $FreeBSD$ */ +#ifndef ADF_GEN2_HW_DATA_H_ +#define ADF_GEN2_HW_DATA_H_ + +#include "adf_accel_devices.h" +#include "adf_cfg_common.h" + +/* Transport access */ +#define ADF_BANK_INT_SRC_SEL_MASK_0 0x4444444CUL +#define ADF_BANK_INT_SRC_SEL_MASK_X 0x44444444UL +#define ADF_RING_CSR_RING_CONFIG 0x000 +#define ADF_RING_CSR_RING_LBASE 0x040 +#define ADF_RING_CSR_RING_UBASE 0x080 +#define ADF_RING_CSR_RING_HEAD 0x0C0 +#define ADF_RING_CSR_RING_TAIL 0x100 +#define ADF_RING_CSR_E_STAT 0x14C +#define ADF_RING_CSR_INT_FLAG 0x170 +#define ADF_RING_CSR_INT_SRCSEL 0x174 +#define ADF_RING_CSR_INT_SRCSEL_2 0x178 +#define ADF_RING_CSR_INT_COL_EN 0x17C +#define ADF_RING_CSR_INT_COL_CTL 0x180 +#define ADF_RING_CSR_INT_FLAG_AND_COL 0x184 +#define ADF_RING_CSR_INT_COL_CTL_ENABLE 0x80000000 +#define ADF_RING_BUNDLE_SIZE 0x1000 +#define ADF_GEN2_RX_RINGS_OFFSET 8 +#define ADF_GEN2_TX_RINGS_MASK 0xFF + +#define BUILD_RING_BASE_ADDR(addr, size) \ + (((addr) >> 6) & (GENMASK_ULL(63, 0) << (size))) +#define READ_CSR_RING_HEAD(csr_base_addr, bank, ring) \ + ADF_CSR_RD(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + ADF_RING_CSR_RING_HEAD + \ + ((ring) << 2)) +#define READ_CSR_RING_TAIL(csr_base_addr, bank, ring) \ + ADF_CSR_RD(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + ADF_RING_CSR_RING_TAIL + \ + ((ring) << 2)) +#define READ_CSR_E_STAT(csr_base_addr, bank) \ + ADF_CSR_RD(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + ADF_RING_CSR_E_STAT) +#define WRITE_CSR_RING_CONFIG(csr_base_addr, bank, ring, value) \ + ADF_CSR_WR(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + \ + ADF_RING_CSR_RING_CONFIG + ((ring) << 2), \ + value) +#define WRITE_CSR_RING_BASE(csr_base_addr, bank, ring, value) \ + do { \ + u32 l_base = 0, u_base = 0; \ + l_base = (u32)((value)&0xFFFFFFFF); \ + u_base = (u32)(((value)&0xFFFFFFFF00000000ULL) >> 32); \ + ADF_CSR_WR(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + \ + ADF_RING_CSR_RING_LBASE + ((ring) << 2), \ + l_base); \ + ADF_CSR_WR(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + \ + ADF_RING_CSR_RING_UBASE + ((ring) << 2), \ + u_base); \ + } while (0) + +#define WRITE_CSR_RING_HEAD(csr_base_addr, bank, ring, value) \ + ADF_CSR_WR(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + ADF_RING_CSR_RING_HEAD + \ + ((ring) << 2), \ + value) +#define WRITE_CSR_RING_TAIL(csr_base_addr, bank, ring, value) \ + ADF_CSR_WR(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + ADF_RING_CSR_RING_TAIL + \ + ((ring) << 2), \ + value) +#define WRITE_CSR_INT_FLAG(csr_base_addr, bank, value) \ + ADF_CSR_WR(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + ADF_RING_CSR_INT_FLAG, \ + value) +#define WRITE_CSR_INT_SRCSEL(csr_base_addr, bank) \ + do { \ + ADF_CSR_WR(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + \ + ADF_RING_CSR_INT_SRCSEL, \ + ADF_BANK_INT_SRC_SEL_MASK_0); \ + ADF_CSR_WR(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + \ + ADF_RING_CSR_INT_SRCSEL_2, \ + ADF_BANK_INT_SRC_SEL_MASK_X); \ + } while (0) +#define WRITE_CSR_INT_COL_EN(csr_base_addr, bank, value) \ + ADF_CSR_WR(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + ADF_RING_CSR_INT_COL_EN, \ + value) +#define WRITE_CSR_INT_COL_CTL(csr_base_addr, bank, value) \ + ADF_CSR_WR(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + ADF_RING_CSR_INT_COL_CTL, \ + ADF_RING_CSR_INT_COL_CTL_ENABLE | (value)) +#define WRITE_CSR_INT_FLAG_AND_COL(csr_base_addr, bank, value) \ + ADF_CSR_WR(csr_base_addr, \ + (ADF_RING_BUNDLE_SIZE * (bank)) + \ + ADF_RING_CSR_INT_FLAG_AND_COL, \ + value) + +/* AE to function map */ +#define AE2FUNCTION_MAP_A_OFFSET (0x3A400 + 0x190) +#define AE2FUNCTION_MAP_B_OFFSET (0x3A400 + 0x310) +#define AE2FUNCTION_MAP_REG_SIZE 4 +#define AE2FUNCTION_MAP_VALID BIT(7) + +#define READ_CSR_AE2FUNCTION_MAP_A(pmisc_bar_addr, index) \ + ADF_CSR_RD(pmisc_bar_addr, \ + AE2FUNCTION_MAP_A_OFFSET + \ + AE2FUNCTION_MAP_REG_SIZE * (index)) +#define WRITE_CSR_AE2FUNCTION_MAP_A(pmisc_bar_addr, index, value) \ + ADF_CSR_WR(pmisc_bar_addr, \ + AE2FUNCTION_MAP_A_OFFSET + \ + AE2FUNCTION_MAP_REG_SIZE * (index), \ + value) +#define READ_CSR_AE2FUNCTION_MAP_B(pmisc_bar_addr, index) \ + ADF_CSR_RD(pmisc_bar_addr, \ + AE2FUNCTION_MAP_B_OFFSET + \ + AE2FUNCTION_MAP_REG_SIZE * (index)) +#define WRITE_CSR_AE2FUNCTION_MAP_B(pmisc_bar_addr, index, value) \ + ADF_CSR_WR(pmisc_bar_addr, \ + AE2FUNCTION_MAP_B_OFFSET + \ + AE2FUNCTION_MAP_REG_SIZE * (index), \ + value) + +/* Admin Interface Offsets */ +#define ADF_ADMINMSGUR_OFFSET (0x3A000 + 0x574) +#define ADF_ADMINMSGLR_OFFSET (0x3A000 + 0x578) +#define ADF_MAILBOX_BASE_OFFSET 0x20970 + +/* Arbiter configuration */ +#define ADF_ARB_OFFSET 0x30000 +#define ADF_ARB_WRK_2_SER_MAP_OFFSET 0x180 +#define ADF_ARB_CONFIG (BIT(31) | BIT(6) | BIT(0)) +#define ADF_ARB_REG_SLOT 0x1000 +#define ADF_ARB_RINGSRVARBEN_OFFSET 0x19C + +#define READ_CSR_RING_SRV_ARB_EN(csr_addr, index) \ + ADF_CSR_RD(csr_addr, \ + ADF_ARB_RINGSRVARBEN_OFFSET + (ADF_ARB_REG_SLOT * (index))) + +#define WRITE_CSR_RING_SRV_ARB_EN(csr_addr, index, value) \ + ADF_CSR_WR(csr_addr, \ + ADF_ARB_RINGSRVARBEN_OFFSET + (ADF_ARB_REG_SLOT * (index)), \ + value) + +/* Power gating */ +#define ADF_POWERGATE_DC BIT(23) +#define ADF_POWERGATE_PKE BIT(24) + +/* Default ring mapping */ +#define ADF_GEN2_DEFAULT_RING_TO_SRV_MAP \ + (CRYPTO << ADF_CFG_SERV_RING_PAIR_0_SHIFT | \ + CRYPTO << ADF_CFG_SERV_RING_PAIR_1_SHIFT | \ + UNUSED << ADF_CFG_SERV_RING_PAIR_2_SHIFT | \ + COMP << ADF_CFG_SERV_RING_PAIR_3_SHIFT) + +/* Error detection and correction */ +#define ADF_GEN2_AE_CTX_ENABLES(i) ((i)*0x1000 + 0x20818) +#define ADF_GEN2_AE_MISC_CONTROL(i) ((i)*0x1000 + 0x20960) +#define ADF_GEN2_ENABLE_AE_ECC_ERR BIT(28) +#define ADF_GEN2_ENABLE_AE_ECC_PARITY_CORR (BIT(24) | BIT(12)) +#define ADF_GEN2_UERRSSMSH(i) ((i)*0x4000 + 0x18) +#define ADF_GEN2_CERRSSMSH(i) ((i)*0x4000 + 0x10) +#define ADF_GEN2_ERRSSMSH_EN BIT(3) + +#define ADF_NUM_HB_CNT_PER_AE (ADF_NUM_THREADS_PER_AE + ADF_NUM_PKE_STRAND) + +void adf_gen2_init_hw_csr_info(struct adf_hw_csr_info *csr_info); + +#endif diff --git a/sys/dev/qat/include/common/adf_gen4_hw_data.h b/sys/dev/qat/include/common/adf_gen4_hw_data.h new file mode 100644 --- /dev/null +++ b/sys/dev/qat/include/common/adf_gen4_hw_data.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2021 Intel Corporation */ +/* $FreeBSD$ */ +#ifndef ADF_GEN4_HW_CSR_DATA_H_ +#define ADF_GEN4_HW_CSR_DATA_H_ + +#include "adf_accel_devices.h" + +/* Transport access */ +#define ADF_BANK_INT_SRC_SEL_MASK 0x44UL +#define ADF_RING_CSR_RING_CONFIG 0x1000 +#define ADF_RING_CSR_RING_LBASE 0x1040 +#define ADF_RING_CSR_RING_UBASE 0x1080 +#define ADF_RING_CSR_RING_HEAD 0x0C0 +#define ADF_RING_CSR_RING_TAIL 0x100 +#define ADF_RING_CSR_E_STAT 0x14C +#define ADF_RING_CSR_INT_FLAG 0x170 +#define ADF_RING_CSR_INT_SRCSEL 0x174 +#define ADF_RING_CSR_INT_COL_CTL 0x180 +#define ADF_RING_CSR_INT_FLAG_AND_COL 0x184 +#define ADF_RING_CSR_INT_COL_CTL_ENABLE 0x80000000 +#define ADF_RING_CSR_INT_COL_EN 0x17C +#define ADF_RING_CSR_ADDR_OFFSET 0x100000 +#define ADF_RING_BUNDLE_SIZE 0x2000 + +#define BUILD_RING_BASE_ADDR(addr, size) \ + ((((addr) >> 6) & (GENMASK_ULL(63, 0) << (size))) << 6) +#define READ_CSR_RING_HEAD(csr_base_addr, bank, ring) \ + ADF_CSR_RD((csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + ADF_RING_BUNDLE_SIZE * (bank) + \ + ADF_RING_CSR_RING_HEAD + ((ring) << 2)) +#define READ_CSR_RING_TAIL(csr_base_addr, bank, ring) \ + ADF_CSR_RD((csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + ADF_RING_BUNDLE_SIZE * (bank) + \ + ADF_RING_CSR_RING_TAIL + ((ring) << 2)) +#define READ_CSR_E_STAT(csr_base_addr, bank) \ + ADF_CSR_RD((csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + ADF_RING_BUNDLE_SIZE * (bank) + \ + ADF_RING_CSR_E_STAT) +#define WRITE_CSR_RING_CONFIG(csr_base_addr, bank, ring, value) \ + ADF_CSR_WR((csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + ADF_RING_BUNDLE_SIZE * (bank) + \ + ADF_RING_CSR_RING_CONFIG + ((ring) << 2), \ + value) +#define WRITE_CSR_RING_BASE(csr_base_addr, bank, ring, value) \ + do { \ + struct resource *_csr_base_addr = csr_base_addr; \ + u32 _bank = bank; \ + u32 _ring = ring; \ + dma_addr_t _value = value; \ + u32 l_base = 0, u_base = 0; \ + l_base = lower_32_bits(_value); \ + u_base = upper_32_bits(_value); \ + ADF_CSR_WR((_csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + \ + ADF_RING_BUNDLE_SIZE * (_bank) + \ + ADF_RING_CSR_RING_LBASE + ((_ring) << 2), \ + l_base); \ + ADF_CSR_WR((_csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + \ + ADF_RING_BUNDLE_SIZE * (_bank) + \ + ADF_RING_CSR_RING_UBASE + ((_ring) << 2), \ + u_base); \ + } while (0) + +#define WRITE_CSR_RING_HEAD(csr_base_addr, bank, ring, value) \ + ADF_CSR_WR((csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + ADF_RING_BUNDLE_SIZE * (bank) + \ + ADF_RING_CSR_RING_HEAD + ((ring) << 2), \ + value) +#define WRITE_CSR_RING_TAIL(csr_base_addr, bank, ring, value) \ + ADF_CSR_WR((csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + ADF_RING_BUNDLE_SIZE * (bank) + \ + ADF_RING_CSR_RING_TAIL + ((ring) << 2), \ + value) +#define WRITE_CSR_INT_FLAG(csr_base_addr, bank, value) \ + ADF_CSR_WR((csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + ADF_RING_BUNDLE_SIZE * (bank) + \ + ADF_RING_CSR_INT_FLAG, \ + (value)) +#define WRITE_CSR_INT_SRCSEL(csr_base_addr, bank) \ + ADF_CSR_WR((csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + ADF_RING_BUNDLE_SIZE * (bank) + \ + ADF_RING_CSR_INT_SRCSEL, \ + ADF_BANK_INT_SRC_SEL_MASK) +#define WRITE_CSR_INT_COL_EN(csr_base_addr, bank, value) \ + ADF_CSR_WR((csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + ADF_RING_BUNDLE_SIZE * (bank) + \ + ADF_RING_CSR_INT_COL_EN, \ + (value)) +#define WRITE_CSR_INT_COL_CTL(csr_base_addr, bank, value) \ + ADF_CSR_WR((csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + ADF_RING_BUNDLE_SIZE * (bank) + \ + ADF_RING_CSR_INT_COL_CTL, \ + ADF_RING_CSR_INT_COL_CTL_ENABLE | (value)) +#define WRITE_CSR_INT_FLAG_AND_COL(csr_base_addr, bank, value) \ + ADF_CSR_WR((csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + ADF_RING_BUNDLE_SIZE * (bank) + \ + ADF_RING_CSR_INT_FLAG_AND_COL, \ + (value)) + +/* Arbiter configuration */ +#define ADF_RING_CSR_RING_SRV_ARB_EN 0x19C + +#define READ_CSR_RING_SRV_ARB_EN(csr_base_addr, bank) \ + ADF_CSR_RD((csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + ADF_RING_BUNDLE_SIZE * (bank) + \ + ADF_RING_CSR_RING_SRV_ARB_EN) + +#define WRITE_CSR_RING_SRV_ARB_EN(csr_base_addr, bank, value) \ + ADF_CSR_WR((csr_base_addr), \ + ADF_RING_CSR_ADDR_OFFSET + ADF_RING_BUNDLE_SIZE * (bank) + \ + ADF_RING_CSR_RING_SRV_ARB_EN, \ + (value)) + +/* WDT timers + * + * Timeout is in cycles. Clock speed may vary across products but this + * value should be a few milli-seconds. + */ +#define ADF_SSM_WDT_DEFAULT_VALUE 0x7000000ULL +#define ADF_SSM_WDT_PKE_DEFAULT_VALUE 0x8000000 +#define ADF_SSMWDTL_OFFSET 0x54 +#define ADF_SSMWDTH_OFFSET 0x5C +#define ADF_SSMWDTPKEL_OFFSET 0x58 +#define ADF_SSMWDTPKEH_OFFSET 0x60 + +#define ADF_NUM_HB_CNT_PER_AE (ADF_NUM_THREADS_PER_AE) + +int adf_gen4_set_ssm_wdtimer(struct adf_accel_dev *accel_dev); +void adf_gen4_init_hw_csr_info(struct adf_hw_csr_info *csr_info); +#endif diff --git a/sys/dev/qat/include/common/icp_qat_fw_loader_handle.h b/sys/dev/qat/include/common/icp_qat_fw_loader_handle.h --- a/sys/dev/qat/include/common/icp_qat_fw_loader_handle.h +++ b/sys/dev/qat/include/common/icp_qat_fw_loader_handle.h @@ -16,6 +16,7 @@ struct icp_qat_fw_loader_hal_handle { struct icp_qat_fw_loader_ae_data aes[ICP_QAT_UCLO_MAX_AE]; unsigned int ae_mask; + unsigned int admin_ae_mask; unsigned int slice_mask; unsigned int revision_id; unsigned int ae_max_num; diff --git a/sys/dev/qat/include/common/icp_qat_hal.h b/sys/dev/qat/include/common/icp_qat_hal.h --- a/sys/dev/qat/include/common/icp_qat_hal.h +++ b/sys/dev/qat/include/common/icp_qat_hal.h @@ -52,23 +52,32 @@ }; enum fcu_csr { - FCU_CONTROL = 0x0, - FCU_STATUS = 0x4, - FCU_DRAM_ADDR_LO = 0xc, + FCU_CONTROL = 0x00, + FCU_STATUS = 0x04, + FCU_DRAM_ADDR_LO = 0x0c, FCU_DRAM_ADDR_HI = 0x10, FCU_RAMBASE_ADDR_HI = 0x14, FCU_RAMBASE_ADDR_LO = 0x18 }; enum fcu_csr_c4xxx { - FCU_CONTROL_C4XXX = 0x0, - FCU_STATUS_C4XXX = 0x4, - FCU_STATUS1_C4XXX = 0xc, + FCU_CONTROL_C4XXX = 0x00, + FCU_STATUS_C4XXX = 0x04, + FCU_STATUS1_C4XXX = 0x0c, FCU_AE_LOADED_C4XXX = 0x10, FCU_DRAM_ADDR_LO_C4XXX = 0x14, FCU_DRAM_ADDR_HI_C4XXX = 0x18, }; +enum fcu_csr_4xxx { + FCU_CONTROL_4XXX = 0x00, + FCU_STATUS_4XXX = 0x04, + FCU_ME_BROADCAST_MASK_TYPE = 0x08, + FCU_AE_LOADED_4XXX = 0x10, + FCU_DRAM_ADDR_LO_4XXX = 0x14, + FCU_DRAM_ADDR_HI_4XXX = 0x18, +}; + enum fcu_cmd { FCU_CTRL_CMD_NOOP = 0, FCU_CTRL_CMD_AUTH = 1, @@ -104,6 +113,7 @@ #define LCS_STATUS (0x1) #define MMC_SHARE_CS_BITPOS 2 #define GLOBAL_CSR 0xA00 +#define FCU_CTRL_BROADCAST_POS 0x4 #define FCU_CTRL_AE_POS 0x8 #define FCU_AUTH_STS_MASK 0x7 #define FCU_STS_DONE_POS 0x9 @@ -111,20 +121,26 @@ #define FCU_LOADED_AE_POS 0x16 #define FW_AUTH_WAIT_PERIOD 10 #define FW_AUTH_MAX_RETRY 300 +#define FW_BROADCAST_MAX_RETRY 300 #define FCU_OFFSET 0x8c0 #define FCU_OFFSET_C4XXX 0x1000 +#define FCU_OFFSET_4XXX 0x1000 #define MAX_CPP_NUM 2 #define AE_CPP_NUM 2 #define AES_PER_CPP 16 #define SLICES_PER_CPP 6 #define ICP_QAT_AE_OFFSET 0x20000 #define ICP_QAT_AE_OFFSET_C4XXX 0x40000 +#define ICP_QAT_AE_OFFSET_4XXX 0x600000 #define ICP_QAT_CAP_OFFSET (ICP_QAT_AE_OFFSET + 0x10000) #define ICP_QAT_CAP_OFFSET_C4XXX 0x70000 +#define ICP_QAT_CAP_OFFSET_4XXX 0x640000 #define LOCAL_TO_XFER_REG_OFFSET 0x800 #define ICP_QAT_EP_OFFSET 0x3a000 #define ICP_QAT_EP_OFFSET_C4XXX 0x60000 +#define ICP_QAT_EP_OFFSET_4XXX 0x200000 /* HI MMIO CSRs */ #define MEM_CFG_ERR_BIT 0x20 +#define AE_TG_NUM_CPM2X 4 #define CAP_CSR_ADDR(csr) (csr + handle->hal_cap_g_ctl_csr_addr_v) #define SET_CAP_CSR(handle, csr, val) \ @@ -133,20 +149,17 @@ ADF_CSR_RD(handle->hal_misc_addr_v, CAP_CSR_ADDR(csr)) #define SET_GLB_CSR(handle, csr, val) \ ({ \ - typeof(handle) handle_ = (handle); \ - typeof(csr) csr_ = (csr); \ - typeof(val) val_ = (val); \ - (IS_QAT_GEN3(pci_get_device(GET_DEV(handle_->accel_dev)))) ? \ - SET_CAP_CSR(handle_, (csr_), (val_)) : \ - SET_CAP_CSR(handle_, csr_ + GLOBAL_CSR, val_); \ + u32 dev_id = pci_get_device(GET_DEV((handle)->accel_dev)); \ + (IS_QAT_GEN3_OR_GEN4(dev_id)) ? \ + SET_CAP_CSR((handle), (csr), (val)) : \ + SET_CAP_CSR((handle), (csr) + GLOBAL_CSR, val); \ }) #define GET_GLB_CSR(handle, csr) \ ({ \ - typeof(handle) handle_ = (handle); \ - typeof(csr) csr_ = (csr); \ - (IS_QAT_GEN3(pci_get_device(GET_DEV(handle_->accel_dev)))) ? \ - (GET_CAP_CSR(handle_, (csr_))) : \ - (GET_CAP_CSR(handle_, (GLOBAL_CSR + (csr_)))); \ + u32 dev_id = pci_get_device(GET_DEV((handle)->accel_dev)); \ + (IS_QAT_GEN3_OR_GEN4(dev_id)) ? \ + GET_CAP_CSR((handle), (csr)) : \ + GET_CAP_CSR((handle), (csr) + GLOBAL_CSR); \ }) #define SET_FCU_CSR(handle, csr, val) \ ({ \ @@ -157,7 +170,12 @@ SET_CAP_CSR(handle_, \ ((csr_) + FCU_OFFSET_C4XXX), \ (val_)) : \ - SET_CAP_CSR(handle_, ((csr_) + FCU_OFFSET), (val_)); \ + ((IS_QAT_GEN4( \ + pci_get_device(GET_DEV(handle_->accel_dev)))) ? \ + SET_CAP_CSR(handle_, \ + ((csr_) + FCU_OFFSET_4XXX), \ + (val_)) : \ + SET_CAP_CSR(handle_, ((csr_) + FCU_OFFSET), (val_))); \ }) #define GET_FCU_CSR(handle, csr) \ ({ \ @@ -165,7 +183,10 @@ typeof(csr) csr_ = (csr); \ (IS_QAT_GEN3(pci_get_device(GET_DEV(handle_->accel_dev)))) ? \ GET_CAP_CSR(handle_, (FCU_OFFSET_C4XXX + (csr_))) : \ - GET_CAP_CSR(handle_, (FCU_OFFSET + (csr_))); \ + ((IS_QAT_GEN4( \ + pci_get_device(GET_DEV(handle_->accel_dev)))) ? \ + GET_CAP_CSR(handle_, (FCU_OFFSET_4XXX + (csr_))) : \ + GET_CAP_CSR(handle_, (FCU_OFFSET + (csr_)))); \ }) #define AE_CSR(handle, ae) \ ((handle)->hal_cap_ae_local_csr_addr_v + ((ae) << 12)) @@ -184,13 +205,19 @@ ADF_CSR_WR((handle)->hal_sram_addr_v, addr, val) #define GET_CSR_OFFSET(device_id, cap_offset_, ae_offset_, ep_offset_) \ ({ \ - int gen3 = IS_QAT_GEN3(device_id); \ - cap_offset_ = \ - (gen3 ? ICP_QAT_CAP_OFFSET_C4XXX : ICP_QAT_CAP_OFFSET); \ - ae_offset_ = \ - (gen3 ? ICP_QAT_AE_OFFSET_C4XXX : ICP_QAT_AE_OFFSET); \ - ep_offset_ = \ - (gen3 ? ICP_QAT_EP_OFFSET_C4XXX : ICP_QAT_EP_OFFSET); \ + if (IS_QAT_GEN3(device_id)) { \ + cap_offset_ = ICP_QAT_CAP_OFFSET_C4XXX; \ + ae_offset_ = ICP_QAT_AE_OFFSET_C4XXX; \ + ep_offset_ = ICP_QAT_EP_OFFSET_C4XXX; \ + } else if (IS_QAT_GEN4(device_id)) { \ + cap_offset_ = ICP_QAT_CAP_OFFSET_4XXX; \ + ae_offset_ = ICP_QAT_AE_OFFSET_4XXX; \ + ep_offset_ = ICP_QAT_EP_OFFSET_4XXX; \ + } else { \ + cap_offset_ = ICP_QAT_CAP_OFFSET; \ + ae_offset_ = ICP_QAT_AE_OFFSET; \ + ep_offset_ = ICP_QAT_EP_OFFSET; \ + } \ }) #endif diff --git a/sys/dev/qat/include/common/icp_qat_uclo.h b/sys/dev/qat/include/common/icp_qat_uclo.h --- a/sys/dev/qat/include/common/icp_qat_uclo.h +++ b/sys/dev/qat/include/common/icp_qat_uclo.h @@ -9,6 +9,7 @@ #define ICP_QAT_AC_C3XXX_DEV_TYPE 0x02000000 #define ICP_QAT_AC_200XX_DEV_TYPE 0x02000000 #define ICP_QAT_AC_C4XXX_DEV_TYPE 0x04000000 +#define ICP_QAT_AC_4XXX_A_DEV_TYPE 0x08000000 #define ICP_QAT_UCLO_MAX_AE 32 #define ICP_QAT_UCLO_MAX_CTX 8 #define ICP_QAT_UCLO_MAX_CPPNUM 2 @@ -17,6 +18,7 @@ #define ICP_QAT_UCLO_MAX_XFER_REG 128 #define ICP_QAT_UCLO_MAX_GPR_REG 128 #define ICP_QAT_UCLO_MAX_LMEM_REG 1024 +#define ICP_QAT_UCLO_MAX_LMEM_REG_2X 1280 #define ICP_QAT_UCLO_AE_ALL_CTX 0xff #define ICP_QAT_UOF_OBJID_LEN 8 #define ICP_QAT_UOF_FID 0xc6c2 @@ -46,22 +48,42 @@ #define ICP_QAT_SUOF_IMAG "SUF_IMAG" #define ICP_QAT_SIMG_AE_INIT_SEQ_LEN (50 * sizeof(unsigned long long)) #define ICP_QAT_SIMG_AE_INSTS_LEN (0x4000 * sizeof(unsigned long long)) -#define ICP_QAT_CSS_FWSK_MODULUS_LEN 256 -#define ICP_QAT_CSS_FWSK_EXPONENT_LEN 4 -#define ICP_QAT_CSS_FWSK_PAD_LEN 252 -#define ICP_QAT_CSS_FWSK_PUB_LEN \ - (ICP_QAT_CSS_FWSK_MODULUS_LEN + ICP_QAT_CSS_FWSK_EXPONENT_LEN + \ - ICP_QAT_CSS_FWSK_PAD_LEN) -#define ICP_QAT_CSS_SIGNATURE_LEN 256 + +#define DSS_FWSK_MODULUS_LEN 384 // RSA3K +#define DSS_FWSK_EXPONENT_LEN 4 +#define DSS_FWSK_PADDING_LEN 380 +#define DSS_SIGNATURE_LEN 384 // RSA3K + +#define CSS_FWSK_MODULUS_LEN 256 // RSA2K +#define CSS_FWSK_EXPONENT_LEN 4 +#define CSS_FWSK_PADDING_LEN 252 +#define CSS_SIGNATURE_LEN 256 // RSA2K + +#define ICP_QAT_CSS_FWSK_MODULUS_LEN(ID) \ + (IS_QAT_GEN4(ID) ? DSS_FWSK_MODULUS_LEN : CSS_FWSK_MODULUS_LEN) + +#define ICP_QAT_CSS_FWSK_EXPONENT_LEN(ID) \ + (IS_QAT_GEN4(ID) ? DSS_FWSK_EXPONENT_LEN : CSS_FWSK_EXPONENT_LEN) + +#define ICP_QAT_CSS_FWSK_PAD_LEN(ID) \ + (IS_QAT_GEN4(ID) ? DSS_FWSK_PADDING_LEN : CSS_FWSK_PADDING_LEN) + +#define ICP_QAT_CSS_FWSK_PUB_LEN(ID) \ + (ICP_QAT_CSS_FWSK_MODULUS_LEN(ID) + \ + ICP_QAT_CSS_FWSK_EXPONENT_LEN(ID) + ICP_QAT_CSS_FWSK_PAD_LEN(ID)) + +#define ICP_QAT_CSS_SIGNATURE_LEN(ID) \ + (IS_QAT_GEN4(ID) ? DSS_SIGNATURE_LEN : CSS_SIGNATURE_LEN) + #define ICP_QAT_CSS_AE_IMG_LEN \ (sizeof(struct icp_qat_simg_ae_mode) + ICP_QAT_SIMG_AE_INIT_SEQ_LEN + \ ICP_QAT_SIMG_AE_INSTS_LEN) -#define ICP_QAT_CSS_AE_SIMG_LEN \ - (sizeof(struct icp_qat_css_hdr) + ICP_QAT_CSS_FWSK_PUB_LEN + \ - ICP_QAT_CSS_SIGNATURE_LEN + ICP_QAT_CSS_AE_IMG_LEN) -#define ICP_QAT_AE_IMG_OFFSET \ - (sizeof(struct icp_qat_css_hdr) + ICP_QAT_CSS_FWSK_MODULUS_LEN + \ - ICP_QAT_CSS_FWSK_EXPONENT_LEN + ICP_QAT_CSS_SIGNATURE_LEN) +#define ICP_QAT_CSS_AE_SIMG_LEN(ID) \ + (sizeof(struct icp_qat_css_hdr) + ICP_QAT_CSS_FWSK_PUB_LEN(ID) + \ + ICP_QAT_CSS_SIGNATURE_LEN(ID) + ICP_QAT_CSS_AE_IMG_LEN) +#define ICP_QAT_AE_IMG_OFFSET(ID) \ + (sizeof(struct icp_qat_css_hdr) + ICP_QAT_CSS_FWSK_MODULUS_LEN(ID) + \ + ICP_QAT_CSS_FWSK_EXPONENT_LEN(ID) + ICP_QAT_CSS_SIGNATURE_LEN(ID)) #define ICP_QAT_CSS_MAX_IMAGE_LEN 0x40000 #define ICP_QAT_CTX_MODE(ae_mode) ((ae_mode)&0xf) diff --git a/sys/dev/qat/include/icp_qat_fw_init_admin.h b/sys/dev/qat/include/icp_qat_fw_init_admin.h --- a/sys/dev/qat/include/icp_qat_fw_init_admin.h +++ b/sys/dev/qat/include/icp_qat_fw_init_admin.h @@ -200,10 +200,6 @@ u16 req_heartbeat_cnt; }; -struct icp_qat_fw_init_admin_hb_stats { - struct icp_qat_fw_init_admin_hb_cnt stats[ADF_NUM_HB_CNT_PER_AE]; -}; - #define ICP_QAT_FW_COMN_HEARTBEAT_OK 0 #define ICP_QAT_FW_COMN_HEARTBEAT_BLOCKED 1 #define ICP_QAT_FW_COMN_HEARTBEAT_FLAG_BITPOS 0 diff --git a/sys/dev/qat/include/qat_ocf_utils.h b/sys/dev/qat/include/qat_ocf_utils.h --- a/sys/dev/qat/include/qat_ocf_utils.h +++ b/sys/dev/qat/include/qat_ocf_utils.h @@ -45,8 +45,11 @@ is_use_sep_digest(const struct crypto_session_params *csp) { /* Use separated digest for all digest/hash operations, - * including GMAC */ - if (CSP_MODE_DIGEST == csp->csp_mode || CSP_MODE_ETA == csp->csp_mode) + * including GMAC. ETA and AEAD use separated digest + * due to FW limitation to specify offset to digest + * appended to pay-load buffer. */ + if (CSP_MODE_DIGEST == csp->csp_mode || CSP_MODE_ETA == csp->csp_mode || + CSP_MODE_AEAD == csp->csp_mode) return CPA_TRUE; return CPA_FALSE; diff --git a/sys/dev/qat/qat/qat_ocf.c b/sys/dev/qat/qat/qat_ocf.c --- a/sys/dev/qat/qat/qat_ocf.c +++ b/sys/dev/qat/qat/qat_ocf.c @@ -29,6 +29,9 @@ #include "icp_adf_accel_mgr.h" #include "lac_sal_types.h" +/* To disable AEAD HW MAC verification */ +#include "icp_sal_user.h" + /* QAT OCF specific headers */ #include "qat_ocf_mem_pool.h" #include "qat_ocf_utils.h" @@ -423,24 +426,6 @@ switch (csp->csp_mode) { case CSP_MODE_AEAD: - sessionSetupData.symOperation = - CPA_CY_SYM_OP_ALGORITHM_CHAINING; - /* Place the digest result in a buffer unrelated to srcBuffer */ - sessionSetupData.digestIsAppended = CPA_TRUE; - /* For GCM and CCM driver forces to verify digest on HW */ - sessionSetupData.verifyDigest = CPA_TRUE; - if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) { - sessionSetupData.cipherSetupData.cipherDirection = - CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT; - sessionSetupData.algChainOrder = - CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH; - } else { - sessionSetupData.cipherSetupData.cipherDirection = - CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT; - sessionSetupData.algChainOrder = - CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER; - } - break; case CSP_MODE_ETA: sessionSetupData.symOperation = CPA_CY_SYM_OP_ALGORITHM_CHAINING; @@ -1086,6 +1071,15 @@ goto fail; } + /* Disable forcing HW MAC validation for AEAD */ + status = icp_sal_setForceAEADMACVerify(cyInstHandle, CPA_FALSE); + if (CPA_STATUS_SUCCESS != status) { + device_printf( + qat_softc->sc_dev, + "unable to disable AEAD HW MAC verification\n"); + goto fail; + } + qat_ocf_instance->driver_id = qat_softc->cryptodev_id; startedInstances++; @@ -1222,6 +1216,7 @@ MODULE_DEPEND(qat, qat_c3xxx, 1, 1, 1); MODULE_DEPEND(qat, qat_c4xxx, 1, 1, 1); MODULE_DEPEND(qat, qat_dh895xcc, 1, 1, 1); +MODULE_DEPEND(qat, qat_4xxx, 1, 1, 1); MODULE_DEPEND(qat, crypto, 1, 1, 1); MODULE_DEPEND(qat, qat_common, 1, 1, 1); MODULE_DEPEND(qat, qat_api, 1, 1, 1); diff --git a/sys/dev/qat/qat_api/common/compression/dc_buffers.c b/sys/dev/qat/qat_api/common/compression/dc_buffers.c --- a/sys/dev/qat/qat_api/common/compression/dc_buffers.c +++ b/sys/dev/qat/qat_api/common/compression/dc_buffers.c @@ -26,9 +26,14 @@ #include "sal_types_compression.h" #include "icp_qat_fw_comp.h" +#include "sal_hw_gen.h" #define CPA_DC_CEIL_DIV(x, y) (((x) + (y)-1) / (y)) #define DC_DEST_BUFF_EXTRA_DEFLATE_GEN2 (55) +#define DC_DEST_BUFF_EXTRA_DEFLATE_GEN4_STATIC (1029) +#define DC_DEST_BUFF_EXTRA_DEFLATE_GEN4_DYN (512) +#define DC_DEST_BUFF_MIN_EXTRA_BYTES(x) ((x < 8) ? (8 - x) : 0) +#define DC_BUF_MAX_SIZE (0xFFFFFFFF) CpaStatus cpaDcBufferListGetMetaSize(const CpaInstanceHandle instanceHandle, @@ -72,13 +77,60 @@ static inline CpaStatus dcDeflateBoundGen2(CpaDcHuffType huffType, Cpa32U inputSize, Cpa32U *outputSize) { + Cpa64U inBufferSize = inputSize; + Cpa64U outBufferSize = 0; + /* Formula for GEN2 deflate: * ceil(9 * Total input bytes / 8) + 55 bytes. * 55 bytes is the skid pad value for GEN2 devices. + * Adding extra bytes = `DC_DEST_BUFF_MIN_EXTRA_BYTES(inputSize)` + * when calculated value from `CPA_DC_CEIL_DIV(9 * inputSize, 8) + + * DC_DEST_BUFF_EXTRA_DEFLATE_GEN2` is less than 64 bytes to + * achieve a safer output buffer size of 64 bytes. */ - *outputSize = - CPA_DC_CEIL_DIV(9 * inputSize, 8) + DC_DEST_BUFF_EXTRA_DEFLATE_GEN2; + outBufferSize = CPA_DC_CEIL_DIV(9 * inBufferSize, 8) + + DC_DEST_BUFF_EXTRA_DEFLATE_GEN2 + + DC_DEST_BUFF_MIN_EXTRA_BYTES(inputSize); + + if (outBufferSize > DC_BUF_MAX_SIZE) + *outputSize = DC_BUF_MAX_SIZE; + else + *outputSize = (Cpa32U)outBufferSize; + + return CPA_STATUS_SUCCESS; +} + +static inline CpaStatus +dcDeflateBoundGen4(CpaDcHuffType huffType, Cpa32U inputSize, Cpa32U *outputSize) +{ + Cpa64U outputSizeLong; + Cpa64U inputSizeLong = (Cpa64U)inputSize; + + switch (huffType) { + case CPA_DC_HT_STATIC: + /* Formula for GEN4 static deflate: + * ceil((9*sourceLen)/8) + 5 + 1024. */ + outputSizeLong = CPA_DC_CEIL_DIV(9 * inputSizeLong, 8) + + DC_DEST_BUFF_EXTRA_DEFLATE_GEN4_STATIC; + break; + case CPA_DC_HT_FULL_DYNAMIC: + /* Formula for GEN4 dynamic deflate: + * Ceil ((9*sourceLen)/8)â–’| + + * ((((8/7) * sourceLen)/ 16KB) * (150+5)) + 512 + */ + outputSizeLong = DC_DEST_BUFF_EXTRA_DEFLATE_GEN4_DYN; + outputSizeLong += CPA_DC_CEIL_DIV(9 * inputSizeLong, 8); + outputSizeLong += ((8 * inputSizeLong * 155) / 7) / (16 * 1024); + break; + default: + return CPA_STATUS_INVALID_PARAM; + } + /* Avoid output size overflow */ + if (outputSizeLong & 0xffffffff00000000UL) + return CPA_STATUS_INVALID_PARAM; + + *outputSize = (Cpa32U)outputSizeLong; return CPA_STATUS_SUCCESS; } @@ -88,6 +140,7 @@ Cpa32U inputSize, Cpa32U *outputSize) { + sal_compression_service_t *pService = NULL; CpaInstanceHandle insHandle = NULL; if (CPA_INSTANCE_HANDLE_SINGLE == dcInstance) { @@ -112,5 +165,10 @@ return CPA_STATUS_INVALID_PARAM; } - return dcDeflateBoundGen2(huffType, inputSize, outputSize); + pService = (sal_compression_service_t *)insHandle; + if (isDcGen4x(pService)) { + return dcDeflateBoundGen4(huffType, inputSize, outputSize); + } else { + return dcDeflateBoundGen2(huffType, inputSize, outputSize); + } } diff --git a/sys/dev/qat/qat_api/common/compression/dc_datapath.c b/sys/dev/qat/qat_api/common/compression/dc_datapath.c --- a/sys/dev/qat/qat_api/common/compression/dc_datapath.c +++ b/sys/dev/qat/qat_api/common/compression/dc_datapath.c @@ -42,6 +42,7 @@ #include "lac_sync.h" #include "sal_service_state.h" #include "sal_qat_cmn_msg.h" +#include "sal_hw_gen.h" #include "dc_error_counter.h" #define DC_COMP_MAX_BUFF_SIZE (1024 * 64) @@ -71,6 +72,28 @@ return 0; } +static inline void +dcUpdateXltOverflowChecksumsGen4(const dc_compression_cookie_t *pCookie, + const icp_qat_fw_resp_comp_pars_t *pRespPars, + CpaDcRqResults *pDcResults) +{ + dc_session_desc_t *pSessionDesc = + DC_SESSION_DESC_FROM_CTX_GET(pCookie->pSessionHandle); + + /* Recompute CRC checksum when either the checksum type + * is CPA_DC_CRC32 or when the integrity CRCs are enabled. + */ + if (CPA_DC_CRC32 == pSessionDesc->checksumType) { + pDcResults->checksum = pRespPars->crc.legacy.curr_crc32; + + /* No need to recalculate the swCrc64I here as this will get + * handled later in dcHandleIntegrityChecksumsGen4. + */ + } else if (CPA_DC_ADLER32 == pSessionDesc->checksumType) { + pDcResults->checksum = pRespPars->crc.legacy.curr_adler_32; + } +} + void dcCompression_ProcessCallback(void *pRespMsg) { @@ -86,6 +109,8 @@ dc_compression_cookie_t *pCookie = NULL; CpaDcOpData *pOpData = NULL; CpaBoolean cmpPass = CPA_TRUE, xlatPass = CPA_TRUE; + CpaBoolean isDcDp = CPA_FALSE; + CpaBoolean integrityCrcCheck = CPA_FALSE; CpaBoolean verifyHwIntegrityCrcs = CPA_FALSE; Cpa8U cmpErr = ERR_CODE_NO_ERROR, xlatErr = ERR_CODE_NO_ERROR; dc_request_dir_t compDecomp = DC_COMPRESSION_REQUEST; @@ -102,17 +127,20 @@ pCookie = (dc_compression_cookie_t *)pReqData; if (!pCookie) return; + pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pCookie->pSessionHandle); + pService = (sal_compression_service_t *)(pCookie->dcInstance); - if (CPA_TRUE == pSessionDesc->isDcDp) { + isDcDp = pSessionDesc->isDcDp; + if (CPA_TRUE == isDcDp) { pResponse = (CpaDcDpOpData *)pReqData; pResults = &(pResponse->results); if (CPA_DC_DIR_DECOMPRESS == pSessionDesc->sessDirection) { compDecomp = DC_DECOMPRESSION_REQUEST; } + pCookie = NULL; } else { - pSessionDesc = pCookie->pSessionDesc; pResults = pCookie->pResults; callbackTag = pCookie->callbackTag; pCbFunc = pCookie->pSessionDesc->pCompressionCb; @@ -120,8 +148,6 @@ pOpData = pCookie->pDcOpData; } - pService = (sal_compression_service_t *)(pCookie->dcInstance); - opStatus = pCompRespMsg->comn_resp.comn_status; if (NULL != pOpData) { @@ -142,15 +168,17 @@ pResults->status = (Cpa8S)cmpErr; pResults->consumed = 0; pResults->produced = 0; - if (CPA_TRUE == pSessionDesc->isDcDp) { + if (CPA_TRUE == isDcDp) { if (pResponse) pResponse->responseStatus = CPA_STATUS_UNSUPPORTED; (pService->pDcDpCb)(pResponse); } else { /* Free the memory pool */ - Lac_MemPoolEntryFree(pCookie); - pCookie = NULL; + if (NULL != pCookie) { + Lac_MemPoolEntryFree(pCookie); + pCookie = NULL; + } if (NULL != pCbFunc) { pCbFunc(callbackTag, status); } @@ -169,9 +197,23 @@ ICP_QAT_FW_COMN_RESP_CMP_STAT_GET(opStatus)); } - if (CPA_DC_INCOMPLETE_FILE_ERR == (Cpa8S)cmpErr) { - cmpPass = CPA_TRUE; - cmpErr = ERR_CODE_NO_ERROR; + if (isDcGen2x(pService)) { + /* QAT1.7 and QAT 1.8 hardware */ + if (CPA_DC_INCOMPLETE_FILE_ERR == (Cpa8S)cmpErr) { + cmpPass = CPA_TRUE; + cmpErr = ERR_CODE_NO_ERROR; + } + } else { + /* QAT2.0 hardware cancels the incomplete file errors + * only for DEFLATE algorithm. + * Decompression direction is not tested in the callback as + * the request does not allow it. + */ + if ((pSessionDesc->compType == CPA_DC_DEFLATE) && + (CPA_DC_INCOMPLETE_FILE_ERR == (Cpa8S)cmpErr)) { + cmpPass = CPA_TRUE; + cmpErr = ERR_CODE_NO_ERROR; + } } /* log the slice hang and endpoint push/pull error inside the response */ @@ -199,8 +241,7 @@ xlatErr = pCompRespMsg->comn_resp.comn_error.s1.xlat_err_code; /* Return a fatal error or a potential error in the translator - * slice - * if the compression slice did not return any error */ + * slice if the compression slice did not return any error */ if ((CPA_DC_OK == pResults->status) || (CPA_DC_FATALERR == (Cpa8S)xlatErr)) { pResults->status = (Cpa8S)xlatErr; @@ -209,7 +250,7 @@ /* Update dc error counter */ dcErrorLog(pResults->status); - if (CPA_FALSE == pSessionDesc->isDcDp) { + if (CPA_FALSE == isDcDp) { /* In case of any error for an end of packet request, we need to * update * the request type for the following request */ @@ -223,17 +264,27 @@ ((CPA_DC_STATELESS == pSessionDesc->sessState) && (DC_COMPRESSION_REQUEST == compDecomp))) { /* Overflow is a valid use case for Traditional API - * only. - * Stateful Overflow is supported in both compression - * and - * decompression direction. - * Stateless Overflow is supported only in compression - * direction. + * only. Stateful Overflow is supported in both + * compression and decompression direction. Stateless + * Overflow is supported only in compression direction. */ if (CPA_DC_OVERFLOW == (Cpa8S)cmpErr) cmpPass = CPA_TRUE; if (CPA_DC_OVERFLOW == (Cpa8S)xlatErr) { + if (isDcGen4x(pService) && + (CPA_TRUE == + pService->comp_device_data + .translatorOverflow)) { + pResults->consumed = + pCompRespMsg->comp_resp_pars + .input_byte_counter; + + dcUpdateXltOverflowChecksumsGen4( + pCookie, + &pCompRespMsg->comp_resp_pars, + pResults); + } xlatPass = CPA_TRUE; } } @@ -242,6 +293,7 @@ cmpPass = CPA_FALSE; } if (CPA_DC_OVERFLOW == (Cpa8S)xlatErr) { + /* XLT overflow is not valid for Data Plane requests */ xlatPass = CPA_FALSE; } } @@ -254,7 +306,13 @@ pCompRespMsg->comp_resp_pars.output_byte_counter; pSessionDesc->cumulativeConsumedBytes += pResults->consumed; - if (CPA_DC_OVERFLOW != (Cpa8S)xlatErr) { + /* Handle Checksum for end to end data integrity. */ + if (CPA_TRUE == + pService->generic_service_info.integrityCrcCheck && + CPA_TRUE == integrityCrcCheck) { + pSessionDesc->previousChecksum = + pSessionDesc->seedSwCrc.swCrc32I; + } else if (CPA_DC_OVERFLOW != (Cpa8S)xlatErr) { if (CPA_DC_CRC32 == pSessionDesc->checksumType) { pResults->checksum = pCompRespMsg->comp_resp_pars.crc.legacy @@ -279,7 +337,7 @@ if ((CPA_DC_OVERFLOW != (Cpa8S)xlatErr) && (CPA_TRUE == verifyHwIntegrityCrcs)) { pSessionDesc->previousChecksum = - pSessionDesc->seedSwCrc.swCrcI; + pSessionDesc->seedSwCrc.swCrc32I; } /* Check if a CNV recovery happened and @@ -292,7 +350,7 @@ pService); } - if (CPA_TRUE == pSessionDesc->isDcDp) { + if (CPA_TRUE == isDcDp) { if (pResponse) pResponse->responseStatus = CPA_STATUS_SUCCESS; } else { @@ -305,8 +363,26 @@ } } } else { +#ifdef ICP_DC_RETURN_COUNTERS_ON_ERROR + /* Extract the response from the firmware */ + pResults->consumed = + pCompRespMsg->comp_resp_pars.input_byte_counter; + pResults->produced = + pCompRespMsg->comp_resp_pars.output_byte_counter; + + if (CPA_DC_STATEFUL == pSessionDesc->sessState) { + pSessionDesc->cumulativeConsumedBytes += + pResults->consumed; + } else { + /* In the stateless case all requests have both SOP and + * EOP set */ + pSessionDesc->cumulativeConsumedBytes = + pResults->consumed; + } +#else pResults->consumed = 0; pResults->produced = 0; +#endif if (CPA_DC_OVERFLOW == pResults->status && CPA_DC_STATELESS == pSessionDesc->sessState) { /* This error message will be returned by Data Plane API @@ -319,7 +395,7 @@ "Unrecoverable error: stateless overflow. You may need to increase the size of your destination buffer.\n"); } - if (CPA_TRUE == pSessionDesc->isDcDp) { + if (CPA_TRUE == isDcDp) { if (pResponse) pResponse->responseStatus = CPA_STATUS_FAIL; } else { @@ -338,7 +414,7 @@ } } - if (CPA_TRUE == pSessionDesc->isDcDp) { + if (CPA_TRUE == isDcDp) { /* Decrement number of stateless pending callbacks for session */ pSessionDesc->pendingDpStatelessCbCount--; @@ -383,7 +459,7 @@ * @retval CPA_STATUS_INVALID_PARAM Invalid parameter passed in * *****************************************************************************/ -static CpaStatus +CpaStatus dcCheckOpData(sal_compression_service_t *pService, CpaDcOpData *pOpData) { CpaDcSkipMode skipMode = 0; @@ -440,6 +516,14 @@ "supported on this device"); return CPA_STATUS_INVALID_PARAM; } + + if (CPA_TRUE == pOpData->integrityCrcCheck && + NULL == pOpData->pCrcData) { + LAC_INVALID_PARAM_LOG("Integrity CRC data structure " + "not intialized in CpaDcOpData"); + return CPA_STATUS_INVALID_PARAM; + } + return CPA_STATUS_SUCCESS; } @@ -583,8 +667,9 @@ if (CPA_DC_HT_FULL_DYNAMIC == pSessionDesc->huffType) { /* Check if intermediate buffers are supported */ - if ((0 == pService->pInterBuffPtrsArrayPhyAddr) || - (NULL == pService->pInterBuffPtrsArray)) { + if ((isDcGen2x(pService)) && + ((0 == pService->pInterBuffPtrsArrayPhyAddr) || + (NULL == pService->pInterBuffPtrsArray))) { LAC_LOG_ERROR( "No intermediate buffer defined for this instance " "- see cpaDcStartInstance"); @@ -702,6 +787,7 @@ Cpa8U crcMode = ICP_QAT_FW_COMP_CRC_MODE_LEGACY; Cpa8U cnvDecompReq = ICP_QAT_FW_COMP_NO_CNV; Cpa8U cnvRecovery = ICP_QAT_FW_COMP_NO_CNV_RECOVERY; + CpaBoolean cnvErrorInjection = ICP_QAT_FW_COMP_NO_CNV_DFX; CpaBoolean integrityCrcCheck = CPA_FALSE; CpaStatus status = CPA_STATUS_SUCCESS; CpaDcFlush flush = CPA_DC_FLUSH_NONE; @@ -757,7 +843,7 @@ * bigger as allocated by the user. We ensure that this is not the case * in dcCheckSourceData and cast the values to Cpa32U here */ pCookie->srcTotalDataLenInBytes = (Cpa32U)srcTotalDataLenInBytes; - if ((DC_COMPRESSION_REQUEST == compDecomp) && + if ((isDcGen2x(pService)) && (DC_COMPRESSION_REQUEST == compDecomp) && (CPA_DC_HT_FULL_DYNAMIC == pSessionDesc->huffType)) { if (pService->minInterBuffSizeInBytes < (Cpa32U)dstTotalDataLenInBytes) { @@ -813,9 +899,9 @@ initial_crc32 = 0; if (CPA_DC_ADLER32 == pSessionDesc->checksumType) { - pSessionDesc->previousChecksum = 1; + pSessionDesc->previousChecksum = initial_adler; } else { - pSessionDesc->previousChecksum = 0; + pSessionDesc->previousChecksum = initial_crc32; } } else if (CPA_DC_STATELESS == pSessionDesc->sessState) { pSessionDesc->previousChecksum = pResults->checksum; @@ -906,7 +992,6 @@ eop = ICP_QAT_FW_COMP_NOT_EOP; } } else { - if (DC_REQUEST_FIRST == pSessionDesc->requestType) { /* Reinitialise the cumulative amount of consumed bytes */ @@ -928,6 +1013,9 @@ * cnvDecompReq also needs to be set */ case DC_CNV: cnvDecompReq = ICP_QAT_FW_COMP_CNV; + if (isDcGen4x(pService)) { + cnvErrorInjection = pSessionDesc->cnvErrorInjection; + } break; case DC_NO_CNV: cnvDecompReq = ICP_QAT_FW_COMP_NO_CNV; @@ -936,8 +1024,14 @@ } /* LW 18 */ - rpCmdFlags = ICP_QAT_FW_COMP_REQ_PARAM_FLAGS_BUILD( - sop, eop, bFinal, cnvDecompReq, cnvRecovery, crcMode); + rpCmdFlags = ICP_QAT_FW_COMP_REQ_PARAM_FLAGS_BUILD(sop, + eop, + bFinal, + cnvDecompReq, + cnvRecovery, + cnvErrorInjection, + crcMode); + pMsg->comp_pars.req_par_flags = rpCmdFlags; /* Populates the QAT common request middle part of the message @@ -1244,10 +1338,7 @@ COMPRESSION_STAT_INC(numDecompCompleted, pService); } - if (CPA_STATUS_SUCCESS != - LAC_SPINUNLOCK(&(pSessionDesc->sessionLock))) { - LAC_LOG_ERROR("Cannot unlock session lock"); - } + LAC_SPINUNLOCK(&(pSessionDesc->sessionLock)); if ((NULL != pCbFunc) && (LacSync_GenWakeupSyncCaller != pCbFunc)) { @@ -1371,7 +1462,7 @@ return dcCompDecompData(pService, pSessionDesc, - dcInstance, + insHandle, pSessionHandle, pSrcBuff, pDestBuff, @@ -1506,10 +1597,7 @@ if (CPA_DC_STATEFUL == pSessionDesc->sessState) { /* Lock the session to check if there are in-flight stateful * requests */ - if (CPA_STATUS_SUCCESS != - LAC_SPINLOCK(&(pSessionDesc->sessionLock))) { - LAC_LOG_ERROR("Cannot unlock session lock"); - } + LAC_SPINLOCK(&(pSessionDesc->sessionLock)); /* Check if there is already one in-flight stateful request */ if (0 != @@ -1517,10 +1605,7 @@ &(pSessionDesc->pendingStatefulCbCount))) { LAC_LOG_ERROR( "Only one in-flight stateful request supported"); - if (CPA_STATUS_SUCCESS != - LAC_SPINUNLOCK(&(pSessionDesc->sessionLock))) { - LAC_LOG_ERROR("Cannot unlock session lock"); - } + LAC_SPINUNLOCK(&(pSessionDesc->sessionLock)); return CPA_STATUS_RETRY; } @@ -1537,10 +1622,7 @@ } qatUtilsAtomicInc(&(pSessionDesc->pendingStatefulCbCount)); - if (CPA_STATUS_SUCCESS != - LAC_SPINUNLOCK(&(pSessionDesc->sessionLock))) { - LAC_LOG_ERROR("Cannot unlock session lock"); - } + LAC_SPINUNLOCK(&(pSessionDesc->sessionLock)); } if (CPA_TRUE == pOpData->compressAndVerify) { @@ -1549,7 +1631,7 @@ return dcCompDecompData(pService, pSessionDesc, - dcInstance, + insHandle, pSessionHandle, pSrcBuff, pDestBuff, @@ -1659,16 +1741,50 @@ pService = (sal_compression_service_t *)insHandle; + /* Check if SAL is initialised otherwise return an error */ + SAL_RUNNING_CHECK(insHandle); + + /* This check is outside the parameter checking as it is needed to + * manage zero length requests */ + if (CPA_STATUS_SUCCESS != + LacBuffDesc_BufferListVerifyNull(pSrcBuff, + &srcBuffSize, + LAC_NO_ALIGNMENT_SHIFT)) { + QAT_UTILS_LOG("Invalid source buffer list parameter"); + return CPA_STATUS_INVALID_PARAM; + } + + /* Ensure this is a compression instance */ + SAL_CHECK_INSTANCE_TYPE(insHandle, SAL_SERVICE_TYPE_COMPRESSION); + + if (dcCheckSourceData(pSessionHandle, + pSrcBuff, + pDestBuff, + pResults, + flushFlag, + srcBuffSize, + NULL) != CPA_STATUS_SUCCESS) { + return CPA_STATUS_INVALID_PARAM; + } + if (dcCheckDestinationData(pService, + pSessionHandle, + pDestBuff, + DC_DECOMPRESSION_REQUEST) != + CPA_STATUS_SUCCESS) { + return CPA_STATUS_INVALID_PARAM; + } pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pSessionHandle); + if (CPA_DC_DIR_COMPRESS == pSessionDesc->sessDirection) { + QAT_UTILS_LOG("Invalid sessDirection value"); + return CPA_STATUS_INVALID_PARAM; + } + + if (CPA_DC_STATEFUL == pSessionDesc->sessState) { /* Lock the session to check if there are in-flight stateful * requests */ - if (CPA_STATUS_SUCCESS != - LAC_SPINLOCK(&(pSessionDesc->sessionLock))) { - LAC_LOG_ERROR("Cannot lock session lock"); - return CPA_STATUS_RESOURCE; - } + LAC_SPINLOCK(&(pSessionDesc->sessionLock)); /* Check if there is already one in-flight stateful request */ if (0 != @@ -1676,37 +1792,36 @@ &(pSessionDesc->pendingStatefulCbCount))) { LAC_LOG_ERROR( "Only one in-flight stateful request supported"); - if (CPA_STATUS_SUCCESS != - LAC_SPINUNLOCK(&(pSessionDesc->sessionLock))) { - LAC_LOG_ERROR("Cannot unlock session lock"); - } + LAC_SPINUNLOCK(&(pSessionDesc->sessionLock)); return CPA_STATUS_RETRY; } - if ((0 == srcBuffSize) || - ((1 == srcBuffSize) && (CPA_DC_FLUSH_FINAL != flushFlag) && - (CPA_DC_FLUSH_FULL != flushFlag))) { - if (CPA_TRUE == - dcZeroLengthRequests(pService, - pSessionDesc, - pResults, - flushFlag, - callbackTag, - DC_DECOMPRESSION_REQUEST)) { - return CPA_STATUS_SUCCESS; + /* Gen 4 handle 0 len requests in FW */ + if (isDcGen2x(pService)) { + if ((0 == srcBuffSize) || + ((1 == srcBuffSize) && + (CPA_DC_FLUSH_FINAL != flushFlag) && + (CPA_DC_FLUSH_FULL != flushFlag))) { + if (CPA_TRUE == + dcZeroLengthRequests( + pService, + pSessionDesc, + pResults, + flushFlag, + callbackTag, + DC_DECOMPRESSION_REQUEST)) { + return CPA_STATUS_SUCCESS; + } } } qatUtilsAtomicInc(&(pSessionDesc->pendingStatefulCbCount)); - if (CPA_STATUS_SUCCESS != - LAC_SPINUNLOCK(&(pSessionDesc->sessionLock))) { - LAC_LOG_ERROR("Cannot unlock session lock"); - } + LAC_SPINUNLOCK(&(pSessionDesc->sessionLock)); } return dcCompDecompData(pService, pSessionDesc, - dcInstance, + insHandle, pSessionHandle, pSrcBuff, pDestBuff, @@ -1768,12 +1883,89 @@ pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pSessionHandle); - if (CPA_DC_STATEFUL == pSessionDesc->sessState) { - LAC_INVALID_PARAM_LOG("Invalid session: Stateful session is " - "not supported"); + LAC_CHECK_NULL_PARAM(insHandle); + + /* Check if SAL is initialised otherwise return an error */ + SAL_RUNNING_CHECK(insHandle); + + /* This check is outside the parameter checking as it is needed to + * manage zero length requests */ + if (CPA_STATUS_SUCCESS != + LacBuffDesc_BufferListVerifyNull(pSrcBuff, + &srcBuffSize, + LAC_NO_ALIGNMENT_SHIFT)) { + QAT_UTILS_LOG("Invalid source buffer list parameter"); + return CPA_STATUS_INVALID_PARAM; + } + + /* Ensure this is a compression instance */ + SAL_CHECK_INSTANCE_TYPE(insHandle, SAL_SERVICE_TYPE_COMPRESSION); + + if (CPA_STATUS_SUCCESS != + dcCheckSourceData(pSessionHandle, + pSrcBuff, + pDestBuff, + pResults, + CPA_DC_FLUSH_NONE, + srcBuffSize, + NULL)) { + return CPA_STATUS_INVALID_PARAM; + } + if (CPA_STATUS_SUCCESS != + dcCheckDestinationData(pService, + pSessionHandle, + pDestBuff, + DC_DECOMPRESSION_REQUEST)) { return CPA_STATUS_INVALID_PARAM; } + if (CPA_STATUS_SUCCESS != dcCheckOpData(pService, pOpData)) { + return CPA_STATUS_INVALID_PARAM; + } + + if (CPA_DC_DIR_COMPRESS == pSessionDesc->sessDirection) { + QAT_UTILS_LOG("Invalid sessDirection value"); + return CPA_STATUS_INVALID_PARAM; + } + + + if (CPA_DC_STATEFUL == pSessionDesc->sessState) { + /* Lock the session to check if there are in-flight stateful + * requests */ + LAC_SPINLOCK(&(pSessionDesc->sessionLock)); + + /* Check if there is already one in-flight stateful request */ + if (0 != + qatUtilsAtomicGet( + &(pSessionDesc->pendingStatefulCbCount))) { + LAC_LOG_ERROR( + "Only one in-flight stateful request supported"); + LAC_SPINUNLOCK(&(pSessionDesc->sessionLock)); + return CPA_STATUS_RETRY; + } + + /* Gen 4 handle 0 len requests in FW */ + if (isDcGen2x(pService)) { + if ((0 == srcBuffSize) || + ((1 == srcBuffSize) && + (CPA_DC_FLUSH_FINAL != pOpData->flushFlag) && + (CPA_DC_FLUSH_FULL != pOpData->flushFlag))) { + if (CPA_TRUE == + dcZeroLengthRequests( + pService, + pSessionDesc, + pResults, + pOpData->flushFlag, + callbackTag, + DC_DECOMPRESSION_REQUEST)) { + return CPA_STATUS_SUCCESS; + } + } + } + qatUtilsAtomicInc(&(pSessionDesc->pendingStatefulCbCount)); + LAC_SPINUNLOCK(&(pSessionDesc->sessionLock)); + } + return dcCompDecompData(pService, pSessionDesc, insHandle, diff --git a/sys/dev/qat/qat_api/common/compression/dc_dp.c b/sys/dev/qat/qat_api/common/compression/dc_dp.c --- a/sys/dev/qat/qat_api/common/compression/dc_dp.c +++ b/sys/dev/qat/qat_api/common/compression/dc_dp.c @@ -41,6 +41,7 @@ #include "sal_service_state.h" #include "sal_qat_cmn_msg.h" #include "icp_sal_poll.h" +#include "sal_hw_gen.h" /** ***************************************************************************** @@ -87,8 +88,8 @@ /* Compressing zero byte is not supported */ if ((CPA_DC_DIR_COMPRESS == pSessionDesc->sessDirection) && (0 == pOpData->bufferLenToCompress)) { - QAT_UTILS_LOG( - "The source buffer length to compress needs to be greater than zero byte.\n"); + QAT_UTILS_LOG("The source buffer length to compress needs to " + "be greater than zero byte.\n"); return CPA_STATUS_INVALID_PARAM; } @@ -171,8 +172,7 @@ } else { /* We are assuming that there is enough memory in the source and * destination buffer lists. We only receive physical addresses - * of the - * buffers so we are unable to test it here */ + * of the buffers so we are unable to test it here */ LAC_CHECK_8_BYTE_ALIGNMENT(pOpData->srcBuffer); LAC_CHECK_8_BYTE_ALIGNMENT(pOpData->destBuffer); } @@ -183,8 +183,9 @@ (CPA_DC_DIR_COMBINED == pSessionDesc->sessDirection)) { if (CPA_DC_HT_FULL_DYNAMIC == pSessionDesc->huffType) { /* Check if Intermediate Buffer Array pointer is NULL */ - if ((0 == pService->pInterBuffPtrsArrayPhyAddr) || - (NULL == pService->pInterBuffPtrsArray)) { + if (isDcGen2x(pService) && + ((0 == pService->pInterBuffPtrsArrayPhyAddr) || + (NULL == pService->pInterBuffPtrsArray))) { QAT_UTILS_LOG( "No intermediate buffer defined for this instance - see cpaDcStartInstance.\n"); return CPA_STATUS_INVALID_PARAM; @@ -312,7 +313,10 @@ Cpa8U cnvDecompReq = ICP_QAT_FW_COMP_NO_CNV; Cpa8U cnvnrCompReq = ICP_QAT_FW_COMP_NO_CNV_RECOVERY; + CpaBoolean cnvErrorInjection = ICP_QAT_FW_COMP_NO_CNV_DFX; + sal_compression_service_t *pService = NULL; + pService = (sal_compression_service_t *)(pOpData->dcInstance); pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pOpData->pSessionHandle); if (CPA_DC_DIR_COMPRESS == pOpData->sessDirection) { @@ -320,6 +324,11 @@ /* CNV check */ if (CPA_TRUE == pOpData->compressAndVerify) { cnvDecompReq = ICP_QAT_FW_COMP_CNV; + if (isDcGen4x(pService)) { + cnvErrorInjection = + pSessionDesc->cnvErrorInjection; + } + /* CNVNR check */ if (CPA_TRUE == pOpData->compressAndVerifyAndRecover) { cnvnrCompReq = ICP_QAT_FW_COMP_CNV_RECOVERY; @@ -343,7 +352,13 @@ pCurrentQatMsg->comp_pars.req_par_flags |= ICP_QAT_FW_COMP_REQ_PARAM_FLAGS_BUILD( - 0, 0, 0, cnvDecompReq, cnvnrCompReq, 0); + ICP_QAT_FW_COMP_NOT_SOP, + ICP_QAT_FW_COMP_NOT_EOP, + ICP_QAT_FW_COMP_NOT_BFINAL, + cnvDecompReq, + cnvnrCompReq, + cnvErrorInjection, + ICP_QAT_FW_COMP_CRC_MODE_LEGACY); SalQatMsg_CmnMidWrite((icp_qat_fw_la_bulk_req_t *)pCurrentQatMsg, pOpData, diff --git a/sys/dev/qat/qat_api/common/compression/dc_session.c b/sys/dev/qat/qat_api/common/compression/dc_session.c --- a/sys/dev/qat/qat_api/common/compression/dc_session.c +++ b/sys/dev/qat/qat_api/common/compression/dc_session.c @@ -23,6 +23,7 @@ #include "icp_qat_fw.h" #include "icp_qat_fw_comp.h" #include "icp_qat_hw.h" +#include "icp_qat_hw_20_comp.h" /* ******************************************************************************* @@ -36,6 +37,7 @@ #include "lac_buffer_desc.h" #include "sal_service_state.h" #include "sal_qat_cmn_msg.h" +#include "sal_hw_gen.h" /** ***************************************************************************** @@ -54,7 +56,7 @@ * @retval CPA_STATUS_UNSUPPORTED Unsupported algorithm/feature * *****************************************************************************/ -static CpaStatus +CpaStatus dcCheckSessionData(const CpaDcSessionSetupData *pSessionData, CpaInstanceHandle dcInstance) { @@ -67,6 +69,7 @@ QAT_UTILS_LOG("Invalid compLevel value\n"); return CPA_STATUS_INVALID_PARAM; } + if ((pSessionData->autoSelectBestHuffmanTree < CPA_DC_ASB_DISABLED) || (pSessionData->autoSelectBestHuffmanTree > CPA_DC_ASB_UNCOMP_STATIC_DYNAMIC_WITH_NO_HDRS)) { @@ -122,10 +125,10 @@ * *****************************************************************************/ static void -dcCompHwBlockPopulate(dc_session_desc_t *pSessionDesc, +dcCompHwBlockPopulate(sal_compression_service_t *pService, + dc_session_desc_t *pSessionDesc, icp_qat_hw_compression_config_t *pCompConfig, - dc_request_dir_t compDecomp, - icp_qat_hw_compression_delayed_match_t enableDmm) + dc_request_dir_t compDecomp) { icp_qat_hw_compression_direction_t dir = ICP_QAT_HW_COMPRESSION_DIR_COMPRESS; @@ -134,6 +137,7 @@ icp_qat_hw_compression_depth_t depth = ICP_QAT_HW_COMPRESSION_DEPTH_1; icp_qat_hw_compression_file_type_t filetype = ICP_QAT_HW_COMPRESSION_FILE_TYPE_0; + icp_qat_hw_compression_delayed_match_t dmm; /* Set the direction */ if (DC_COMPRESSION_REQUEST == compDecomp) { @@ -148,6 +152,13 @@ QAT_UTILS_LOG("Algorithm not supported for Compression\n"); } + /* Set delay match mode */ + if (CPA_TRUE == pService->comp_device_data.enableDmm) { + dmm = ICP_QAT_HW_COMPRESSION_DELAYED_MATCH_ENABLED; + } else { + dmm = ICP_QAT_HW_COMPRESSION_DELAYED_MATCH_DISABLED; + } + /* Set the depth */ if (DC_DECOMPRESSION_REQUEST == compDecomp) { depth = ICP_QAT_HW_COMPRESSION_DEPTH_1; @@ -162,8 +173,13 @@ case CPA_DC_L3: depth = ICP_QAT_HW_COMPRESSION_DEPTH_8; break; - default: + case CPA_DC_L4: depth = ICP_QAT_HW_COMPRESSION_DEPTH_16; + break; + default: + depth = pService->comp_device_data + .highestHwCompressionDepth; + break; } } @@ -171,10 +187,138 @@ * modes will be used in the future for precompiled huffman trees */ filetype = ICP_QAT_HW_COMPRESSION_FILE_TYPE_0; - pCompConfig->val = ICP_QAT_HW_COMPRESSION_CONFIG_BUILD( - dir, enableDmm, algo, depth, filetype); + pCompConfig->lower_val = ICP_QAT_HW_COMPRESSION_CONFIG_BUILD( + dir, dmm, algo, depth, filetype); + + /* Upper 32-bits of the configuration word do not need to be + * configured with legacy devices. + */ + pCompConfig->upper_val = 0; +} + +static void +dcCompHwBlockPopulateGen4(sal_compression_service_t *pService, + dc_session_desc_t *pSessionDesc, + icp_qat_hw_compression_config_t *pCompConfig, + dc_request_dir_t compDecomp) +{ + /* Compression related */ + if (DC_COMPRESSION_REQUEST == compDecomp) { + icp_qat_hw_comp_20_config_csr_upper_t hw_comp_upper_csr; + icp_qat_hw_comp_20_config_csr_lower_t hw_comp_lower_csr; + + memset(&hw_comp_upper_csr, 0, sizeof hw_comp_upper_csr); + memset(&hw_comp_lower_csr, 0, sizeof hw_comp_lower_csr); + + /* Disable Literal + Length Limit Block Drop by default and + * enable it only for dynamic deflate compression. + */ + hw_comp_lower_csr.lllbd = + ICP_QAT_HW_COMP_20_LLLBD_CTRL_LLLBD_DISABLED; + + switch (pSessionDesc->compType) { + case CPA_DC_DEFLATE: + /* DEFLATE algorithm settings */ + hw_comp_lower_csr.skip_ctrl = + ICP_QAT_HW_COMP_20_BYTE_SKIP_3BYTE_LITERAL; + + if (CPA_DC_HT_FULL_DYNAMIC == pSessionDesc->huffType) { + hw_comp_lower_csr.algo = + ICP_QAT_HW_COMP_20_HW_COMP_FORMAT_ILZ77; + } else /* Static DEFLATE */ + { + hw_comp_lower_csr.algo = + ICP_QAT_HW_COMP_20_HW_COMP_FORMAT_DEFLATE; + hw_comp_upper_csr.scb_ctrl = + ICP_QAT_HW_COMP_20_SCB_CONTROL_DISABLE; + } + + if (CPA_DC_STATEFUL == pSessionDesc->sessState) { + hw_comp_upper_csr.som_ctrl = + ICP_QAT_HW_COMP_20_SOM_CONTROL_REPLAY_MODE; + } + break; + default: + QAT_UTILS_LOG("Compression algorithm not supported\n"); + break; + } + /* Set the search depth */ + switch (pSessionDesc->compLevel) { + case CPA_DC_L1: + case CPA_DC_L2: + case CPA_DC_L3: + case CPA_DC_L4: + case CPA_DC_L5: + hw_comp_lower_csr.sd = + ICP_QAT_HW_COMP_20_SEARCH_DEPTH_LEVEL_1; + hw_comp_lower_csr.hash_col = + ICP_QAT_HW_COMP_20_SKIP_HASH_COLLISION_DONT_ALLOW; + break; + case CPA_DC_L6: + case CPA_DC_L7: + case CPA_DC_L8: + hw_comp_lower_csr.sd = + ICP_QAT_HW_COMP_20_SEARCH_DEPTH_LEVEL_6; + break; + case CPA_DC_L9: + hw_comp_lower_csr.sd = + ICP_QAT_HW_COMP_20_SEARCH_DEPTH_LEVEL_9; + break; + default: + hw_comp_lower_csr.sd = pService->comp_device_data + .highestHwCompressionDepth; + if ((CPA_DC_HT_FULL_DYNAMIC == + pSessionDesc->huffType) && + (CPA_DC_DEFLATE == pSessionDesc->compType)) { + /* Enable Literal + Length Limit Block Drop + * with dynamic deflate compression when + * highest compression levels are selected. + */ + hw_comp_lower_csr.lllbd = + ICP_QAT_HW_COMP_20_LLLBD_CTRL_LLLBD_ENABLED; + } + break; + } + /* Same for all algorithms */ + hw_comp_lower_csr.abd = ICP_QAT_HW_COMP_20_ABD_ABD_DISABLED; + hw_comp_lower_csr.hash_update = + ICP_QAT_HW_COMP_20_SKIP_HASH_UPDATE_DONT_ALLOW; + hw_comp_lower_csr.edmm = + (CPA_TRUE == pService->comp_device_data.enableDmm) ? + ICP_QAT_HW_COMP_20_EXTENDED_DELAY_MATCH_MODE_EDMM_ENABLED : + ICP_QAT_HW_COMP_20_EXTENDED_DELAY_MATCH_MODE_EDMM_DISABLED; + + /* Hard-coded HW-specific values */ + hw_comp_upper_csr.nice = + ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_DEFAULT_VAL; + hw_comp_upper_csr.lazy = + ICP_QAT_HW_COMP_20_CONFIG_CSR_LAZY_PARAM_DEFAULT_VAL; + + pCompConfig->upper_val = + ICP_QAT_FW_COMP_20_BUILD_CONFIG_UPPER(hw_comp_upper_csr); + + pCompConfig->lower_val = + ICP_QAT_FW_COMP_20_BUILD_CONFIG_LOWER(hw_comp_lower_csr); + } else /* Decompress */ + { + icp_qat_hw_decomp_20_config_csr_lower_t hw_decomp_lower_csr; + + memset(&hw_decomp_lower_csr, 0, sizeof hw_decomp_lower_csr); + + /* Set the algorithm */ + if (CPA_DC_DEFLATE == pSessionDesc->compType) { + hw_decomp_lower_csr.algo = + ICP_QAT_HW_DECOMP_20_HW_DECOMP_FORMAT_DEFLATE; + } else { + QAT_UTILS_LOG("Algorithm not supported for " + "Decompression\n"); + } - pCompConfig->reserved = 0; + pCompConfig->upper_val = 0; + pCompConfig->lower_val = + ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_LOWER( + hw_decomp_lower_csr); + } } /** @@ -268,10 +412,19 @@ pCompControlBlock->resrvd = 0; /* Populate Compression Hardware Setup Block */ - dcCompHwBlockPopulate(pSessionDesc, - pCompConfig, - compDecomp, - pService->comp_device_data.enableDmm); + if (isDcGen4x(pService)) { + dcCompHwBlockPopulateGen4(pService, + pSessionDesc, + pCompConfig, + compDecomp); + } else if (isDcGen2x(pService)) { + dcCompHwBlockPopulate(pService, + pSessionDesc, + pCompConfig, + compDecomp); + } else { + QAT_UTILS_LOG("Invalid QAT generation value\n"); + } } /** @@ -286,7 +439,7 @@ * @param[in] nextSlice Next slice * *****************************************************************************/ -static void +void dcTransContentDescPopulate(icp_qat_fw_comp_req_t *pMsg, icp_qat_fw_slice_t nextSlice) { @@ -333,14 +486,70 @@ *pContextSize = 0; if ((CPA_DC_STATEFUL == pSessionData->sessState) && - (CPA_DC_DEFLATE == pSessionData->compType) && (CPA_DC_DIR_COMPRESS != pSessionData->sessDirection)) { - *pContextSize = - pCompService->comp_device_data.inflateContextSize; + switch (pSessionData->compType) { + case CPA_DC_DEFLATE: + *pContextSize = + pCompService->comp_device_data.inflateContextSize; + break; + default: + QAT_UTILS_LOG("Invalid compression algorithm."); + return CPA_STATUS_FAIL; + } } return CPA_STATUS_SUCCESS; } +CpaStatus +dcGetCompressCommandId(sal_compression_service_t *pService, + CpaDcSessionSetupData *pSessionData, + Cpa8U *pDcCmdId) +{ + CpaStatus status = CPA_STATUS_SUCCESS; + LAC_CHECK_NULL_PARAM(pService); + LAC_CHECK_NULL_PARAM(pSessionData); + LAC_CHECK_NULL_PARAM(pDcCmdId); + + switch (pSessionData->compType) { + case CPA_DC_DEFLATE: + *pDcCmdId = (CPA_DC_HT_FULL_DYNAMIC == pSessionData->huffType) ? + ICP_QAT_FW_COMP_CMD_DYNAMIC : + ICP_QAT_FW_COMP_CMD_STATIC; + break; + default: + QAT_UTILS_LOG("Algorithm not supported for " + "compression\n"); + status = CPA_STATUS_UNSUPPORTED; + break; + } + + return status; +} + +CpaStatus +dcGetDecompressCommandId(sal_compression_service_t *pService, + CpaDcSessionSetupData *pSessionData, + Cpa8U *pDcCmdId) +{ + CpaStatus status = CPA_STATUS_SUCCESS; + LAC_CHECK_NULL_PARAM(pService); + LAC_CHECK_NULL_PARAM(pSessionData); + LAC_CHECK_NULL_PARAM(pDcCmdId); + + switch (pSessionData->compType) { + case CPA_DC_DEFLATE: + *pDcCmdId = ICP_QAT_FW_COMP_CMD_DECOMPRESS; + break; + default: + QAT_UTILS_LOG("Algorithm not supported for " + "decompression\n"); + status = CPA_STATUS_UNSUPPORTED; + break; + } + + return status; +} + CpaStatus dcInitSession(CpaInstanceHandle dcInstance, CpaDcSessionHandle pSessionHandle, @@ -394,7 +603,17 @@ return CPA_STATUS_UNSUPPORTED; } - if (CPA_DC_HT_FULL_DYNAMIC == pSessionData->huffType) { + /* Check for Gen4 and stateful, return error if both exist */ + if ((isDcGen4x(pService)) && + (CPA_DC_STATEFUL == pSessionData->sessState && + CPA_DC_DIR_DECOMPRESS != pSessionData->sessDirection)) { + QAT_UTILS_LOG("Stateful sessions are not supported for " + "compression direction"); + return CPA_STATUS_UNSUPPORTED; + } + + if ((isDcGen2x(pService)) && + (CPA_DC_HT_FULL_DYNAMIC == pSessionData->huffType)) { /* Test if DRAM is available for the intermediate buffers */ if ((NULL == pService->pInterBuffPtrsArray) && (0 == pService->pInterBuffPtrsArrayPhyAddr)) { @@ -404,7 +623,8 @@ pSessionData->huffType = CPA_DC_HT_STATIC; } else { QAT_UTILS_LOG( - "No buffer defined for this instance - see cpaDcStartInstance.\n"); + "No buffer defined for this instance - " + "see cpaDcStartInstance.\n"); return CPA_STATUS_RESOURCE; } } @@ -541,7 +761,8 @@ pSessionDesc->pendingDpStatelessCbCount = 0; if (CPA_DC_DIR_DECOMPRESS != pSessionData->sessDirection) { - if (CPA_DC_HT_FULL_DYNAMIC == pSessionData->huffType) { + if ((isDcGen2x(pService)) && + CPA_DC_HT_FULL_DYNAMIC == pSessionData->huffType) { /* Populate the compression section of the content * descriptor */ dcCompContentDescPopulate(pService, @@ -607,17 +828,29 @@ pDataIntegrityCrcs = &pSessionDesc->dataIntegrityCrcs; pDataIntegrityCrcs->crc32 = 0; pDataIntegrityCrcs->adler32 = 1; - pDataIntegrityCrcs->oCrc32Cpr = DC_INVALID_CRC; - pDataIntegrityCrcs->iCrc32Cpr = DC_INVALID_CRC; - pDataIntegrityCrcs->oCrc32Xlt = DC_INVALID_CRC; - pDataIntegrityCrcs->iCrc32Xlt = DC_INVALID_CRC; - pDataIntegrityCrcs->xorFlags = DC_XOR_FLAGS_DEFAULT; - pDataIntegrityCrcs->crcPoly = DC_CRC_POLY_DEFAULT; - pDataIntegrityCrcs->xorOut = DC_XOR_OUT_DEFAULT; - - /* Initialise seed checksums */ - pSessionDesc->seedSwCrc.swCrcI = 0; - pSessionDesc->seedSwCrc.swCrcO = 0; + + if (isDcGen2x(pService)) { + pDataIntegrityCrcs->oCrc32Cpr = DC_INVALID_CRC; + pDataIntegrityCrcs->iCrc32Cpr = DC_INVALID_CRC; + pDataIntegrityCrcs->oCrc32Xlt = DC_INVALID_CRC; + pDataIntegrityCrcs->iCrc32Xlt = DC_INVALID_CRC; + pDataIntegrityCrcs->xorFlags = DC_XOR_FLAGS_DEFAULT; + pDataIntegrityCrcs->crcPoly = DC_CRC_POLY_DEFAULT; + pDataIntegrityCrcs->xorOut = DC_XOR_OUT_DEFAULT; + } else { + pDataIntegrityCrcs->iCrc64Cpr = DC_INVALID_CRC; + pDataIntegrityCrcs->oCrc64Cpr = DC_INVALID_CRC; + pDataIntegrityCrcs->iCrc64Xlt = DC_INVALID_CRC; + pDataIntegrityCrcs->oCrc64Xlt = DC_INVALID_CRC; + pDataIntegrityCrcs->crc64Poly = DC_CRC64_POLY_DEFAULT; + pDataIntegrityCrcs->xor64Out = DC_XOR64_OUT_DEFAULT; + } + + /* Initialise seed checksums. + * It initializes swCrc32I, swCrc32O, too(union). + */ + pSessionDesc->seedSwCrc.swCrc64I = 0; + pSessionDesc->seedSwCrc.swCrc64O = 0; /* Populate the cmdFlags */ switch (pSessionDesc->autoSelectBestHuffmanTree) { @@ -646,6 +879,7 @@ ICP_QAT_FW_COMP_BFINAL, ICP_QAT_FW_COMP_NO_CNV, ICP_QAT_FW_COMP_NO_CNV_RECOVERY, + ICP_QAT_FW_COMP_NO_CNV_DFX, ICP_QAT_FW_COMP_CRC_MODE_LEGACY); cmdFlags = @@ -656,11 +890,16 @@ secureRam); if (CPA_DC_DIR_DECOMPRESS != pSessionData->sessDirection) { - if (CPA_DC_HT_FULL_DYNAMIC == pSessionDesc->huffType) { - dcCmdId = (icp_qat_fw_la_cmd_id_t)( - ICP_QAT_FW_COMP_CMD_DYNAMIC); - } + status = dcGetCompressCommandId(pService, + pSessionData, + (Cpa8U *)&dcCmdId); + if (CPA_STATUS_SUCCESS != status) { + QAT_UTILS_LOG( + "Couldn't get compress command ID for current " + "session data."); + return status; + } pReqCache = &(pSessionDesc->reqCacheComp); pReqCache->comp_pars.req_par_flags = rpCmdFlags; pReqCache->comp_pars.crc.legacy.initial_adler = 1; @@ -675,8 +914,16 @@ } if (CPA_DC_DIR_COMPRESS != pSessionData->sessDirection) { - dcCmdId = - (icp_qat_fw_la_cmd_id_t)(ICP_QAT_FW_COMP_CMD_DECOMPRESS); + status = dcGetDecompressCommandId(pService, + pSessionData, + (Cpa8U *)&dcCmdId); + if (CPA_STATUS_SUCCESS != status) { + QAT_UTILS_LOG( + "Couldn't get decompress command ID for current " + "session data."); + + return status; + } pReqCache = &(pSessionDesc->reqCacheDecomp); pReqCache->comp_pars.req_par_flags = rpCmdFlags; pReqCache->comp_pars.crc.legacy.initial_adler = 1; @@ -730,10 +977,14 @@ { CpaStatus status = CPA_STATUS_SUCCESS; CpaInstanceHandle insHandle = NULL; + sal_compression_service_t *pService = NULL; dc_session_desc_t *pSessionDesc = NULL; Cpa64U numPendingStateless = 0; Cpa64U numPendingStateful = 0; icp_comms_trans_handle trans_handle = NULL; + dc_integrity_crc_fw_t *pDataIntegrityCrcs = NULL; + dc_sw_checksums_t *pSwCrcs = NULL; + LAC_CHECK_NULL_PARAM(pSessionHandle); pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pSessionHandle); LAC_CHECK_NULL_PARAM(pSessionDesc); @@ -752,7 +1003,7 @@ /* Check if SAL is running otherwise return an error */ SAL_RUNNING_CHECK(insHandle); if (CPA_TRUE == pSessionDesc->isDcDp) { - trans_handle = ((sal_compression_service_t *)dcInstance) + trans_handle = ((sal_compression_service_t *)insHandle) ->trans_handle_compression_tx; if (CPA_TRUE == icp_adf_queueDataToSend(trans_handle)) { /* Process the remaining messages on the ring */ @@ -798,7 +1049,32 @@ } else { pSessionDesc->previousChecksum = 0; } + pSessionDesc->cnvErrorInjection = ICP_QAT_FW_COMP_NO_CNV_DFX; + + /* Reset integrity CRCs to default parameters. */ + pDataIntegrityCrcs = &pSessionDesc->dataIntegrityCrcs; + memset(pDataIntegrityCrcs, 0, sizeof(dc_integrity_crc_fw_t)); + pDataIntegrityCrcs->adler32 = 1; + + pService = (sal_compression_service_t *)insHandle; + if (isDcGen2x(pService)) { + pDataIntegrityCrcs->xorFlags = DC_XOR_FLAGS_DEFAULT; + pDataIntegrityCrcs->crcPoly = DC_CRC_POLY_DEFAULT; + pDataIntegrityCrcs->xorOut = DC_XOR_OUT_DEFAULT; + } else { + pDataIntegrityCrcs->crc64Poly = DC_CRC64_POLY_DEFAULT; + pDataIntegrityCrcs->xor64Out = DC_XOR64_OUT_DEFAULT; + } + + /* Reset seed SW checksums. */ + pSwCrcs = &pSessionDesc->seedSwCrc; + memset(pSwCrcs, 0, sizeof(dc_sw_checksums_t)); + + /* Reset integrity SW checksums. */ + pSwCrcs = &pSessionDesc->integritySwCrc; + memset(pSwCrcs, 0, sizeof(dc_sw_checksums_t)); } + /* Reset the pending callback counters */ qatUtilsAtomicSet(0, &pSessionDesc->pendingStatelessCbCount); qatUtilsAtomicSet(0, &pSessionDesc->pendingStatefulCbCount); @@ -886,12 +1162,7 @@ } if ((CPA_DC_STATEFUL == pSessionDesc->sessState) && (CPA_STATUS_SUCCESS == status)) { - if (CPA_STATUS_SUCCESS != - LAC_SPINLOCK_DESTROY( - &(pSessionDesc->sessionLock))) { - QAT_UTILS_LOG( - "Failed to destory session lock.\n"); - } + LAC_SPINLOCK_DESTROY(&(pSessionDesc->sessionLock)); } } @@ -955,3 +1226,33 @@ pSessionSize, pContextSize); } + +CpaStatus +dcSetCnvError(CpaInstanceHandle dcInstance, CpaDcSessionHandle pSessionHandle) +{ + LAC_CHECK_NULL_PARAM(pSessionHandle); + + dc_session_desc_t *pSessionDesc = NULL; + CpaInstanceHandle insHandle = NULL; + sal_compression_service_t *pService = NULL; + + if (CPA_INSTANCE_HANDLE_SINGLE == dcInstance) { + insHandle = dcGetFirstHandle(); + } else { + insHandle = dcInstance; + } + + pService = (sal_compression_service_t *)insHandle; + + if (isDcGen2x(pService)) { + QAT_UTILS_LOG("Unsupported compression feature.\n"); + return CPA_STATUS_UNSUPPORTED; + } + pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pSessionHandle); + + LAC_CHECK_NULL_PARAM(pSessionDesc); + + pSessionDesc->cnvErrorInjection = ICP_QAT_FW_COMP_CNV_DFX; + + return CPA_STATUS_SUCCESS; +} diff --git a/sys/dev/qat/qat_api/common/compression/include/dc_datapath.h b/sys/dev/qat/qat_api/common/compression/include/dc_datapath.h --- a/sys/dev/qat/qat_api/common/compression/include/dc_datapath.h +++ b/sys/dev/qat/qat_api/common/compression/include/dc_datapath.h @@ -26,6 +26,8 @@ * the management of skid buffers in the firmware */ #define DC_DEST_BUFFER_DYN_MIN_SIZE (128) #define DC_DEST_BUFFER_STA_MIN_SIZE (64) +#define DC_DEST_BUFFER_DYN_MIN_SIZE_GEN4 (512) +#define DC_DEST_BUFFER_STA_MIN_SIZE_GEN4 (1024) /* C62x and C3xxx pcie rev0 devices require an additional 32bytes */ #define DC_DEST_BUFFER_STA_ADDITIONAL_SIZE (32) @@ -93,8 +95,10 @@ * those are used to inform hardware of specifying CRC parameters to be used * when calculating CRCs */ #define DC_CRC_POLY_DEFAULT 0x04c11db7 +#define DC_CRC64_POLY_DEFAULT 0x42f0e1eba9ea3693ULL #define DC_XOR_FLAGS_DEFAULT 0xe0000 #define DC_XOR_OUT_DEFAULT 0xffffffff +#define DC_XOR64_OUT_DEFAULT 0x0ULL #define DC_INVALID_CRC 0x0 /** @@ -147,6 +151,13 @@ /**< virtual userspace ptr to source SGL */ CpaBufferList *pUserDestBuff; /**< virtual userspace ptr to destination SGL */ + CpaDcCallbackFn pCbFunc; + /**< Callback function defined for the traditional sessionless API */ + CpaDcChecksum checksumType; + /**< Type of checksum */ + dc_integrity_crc_fw_t dataIntegrityCrcs; + /**< Data integrity table */ + } dc_compression_cookie_t; /** @@ -165,6 +176,9 @@ *****************************************************************************/ void dcCompression_ProcessCallback(void *pRespMsg); +CpaStatus dcCheckOpData(sal_compression_service_t *pService, + CpaDcOpData *pOpData); + /** ***************************************************************************** * @ingroup Dc_DataCompression diff --git a/sys/dev/qat/qat_api/common/compression/include/dc_session.h b/sys/dev/qat/qat_api/common/compression/include/dc_session.h --- a/sys/dev/qat/qat_api/common/compression/include/dc_session.h +++ b/sys/dev/qat/qat_api/common/compression/include/dc_session.h @@ -17,6 +17,7 @@ #include "cpa_dc_dp.h" #include "icp_qat_fw_comp.h" #include "sal_qat_cmn_msg.h" +#include "sal_types_compression.h" /* Maximum number of intermediate buffers SGLs for devices * with a maximum of 6 compression slices */ @@ -35,6 +36,7 @@ /* Size of the history window. * Base 2 logarithm of maximum window size minus 8 */ +#define DC_4K_WINDOW_SIZE (4) #define DC_8K_WINDOW_SIZE (5) #define DC_16K_WINDOW_SIZE (6) #define DC_32K_WINDOW_SIZE (7) @@ -95,35 +97,81 @@ /* CRC32 checksum returned for compressed data */ Cpa32U adler32; /* ADLER32 checksum returned for compressed data */ - Cpa32U oCrc32Cpr; - /* CRC32 checksum returned for data output by compression accelerator */ - Cpa32U iCrc32Cpr; - /* CRC32 checksum returned for input data to compression accelerator */ - Cpa32U oCrc32Xlt; - /* CRC32 checksum returned for data output by translator accelerator */ - Cpa32U iCrc32Xlt; - /* CRC32 checksum returned for input data to translator accelerator */ - Cpa32U xorFlags; - /* Initialise transactor pCRC controls in state register */ - Cpa32U crcPoly; - /* CRC32 polynomial used by hardware */ - Cpa32U xorOut; - /* CRC32 from XOR stage (Input CRC is xor'ed with value in the state) */ - Cpa32U deflateBlockType; - /* Bit 1 - Bit 0 - * 0 0 -> RAW DATA + Deflate header. - * This will not produced any CRC check because - * the output will not come from the slices. - * It will be a simple copy from input to output - * buffers list. - * 0 1 -> Static deflate block type - * 1 0 -> Dynamic deflate block type - * 1 1 -> Invalid type */ + + union { + struct { + Cpa32U oCrc32Cpr; + /* CRC32 checksum returned for data output by + * compression accelerator */ + Cpa32U iCrc32Cpr; + /* CRC32 checksum returned for input data to compression + * accelerator + */ + Cpa32U oCrc32Xlt; + /* CRC32 checksum returned for data output by translator + * accelerator + */ + Cpa32U iCrc32Xlt; + /* CRC32 checksum returned for input data to translator + * accelerator + */ + Cpa32U xorFlags; + /* Initialise transactor pCRC controls in state register + */ + Cpa32U crcPoly; + /* CRC32 polynomial used by hardware */ + Cpa32U xorOut; + /* CRC32 from XOR stage (Input CRC is xor'ed with value + * in the state) */ + Cpa32U deflateBlockType; + /* Bit 1 - Bit 0 + * 0 0 -> RAW DATA + Deflate header. + * This will not produced any CRC check + * because the output will not come + * from the slices. It will be a simple + * copy from input to output buffer + * list. 0 1 -> Static deflate block type 1 0 -> + * Dynamic deflate block type 1 1 -> Invalid type + */ + }; + + struct { + Cpa64U iCrc64Cpr; + /* CRC64 checksum returned for input data to compression + * accelerator + */ + Cpa64U oCrc64Cpr; + /* CRC64 checksum returned for data output by + * compression accelerator */ + Cpa64U iCrc64Xlt; + /* CRC64 checksum returned for input data to translator + * accelerator + */ + Cpa64U oCrc64Xlt; + /* CRC64 checksum returned for data output by translator + * accelerator + */ + Cpa64U crc64Poly; + /* CRC64 polynomial used by hardware */ + Cpa64U xor64Out; + /* CRC64 from XOR stage (Input CRC is xor'ed with value + * in the state) */ + }; + }; } dc_integrity_crc_fw_t; typedef struct dc_sw_checksums_s { - Cpa32U swCrcI; - Cpa32U swCrcO; + union { + struct { + Cpa32U swCrc32I; + Cpa32U swCrc32O; + }; + + struct { + Cpa64U swCrc64I; + Cpa64U swCrc64O; + }; + }; } dc_sw_checksums_t; /* Session descriptor structure for compression */ @@ -211,6 +259,8 @@ dc_sw_checksums_t seedSwCrc; /* Driver calculated integrity software CRC */ dc_sw_checksums_t integritySwCrc; + /* Flag to disable or enable CnV Error Injection mechanism */ + CpaBoolean cnvErrorInjection; } dc_session_desc_t; /** @@ -275,4 +325,106 @@ Cpa32U *pSessionSize, Cpa32U *pContextSize); +/** + ***************************************************************************** + * @ingroup Dc_DataCompression + * Set the cnvErrorInjection flag in session descriptor + * + * @description + * This function enables the CnVError injection for the session + * passed in. All Compression requests sent within the session + * are injected with CnV errors. This error injection is for the + * duration of the session. Resetting the session results in + * setting being cleared. CnV error injection does not apply to + * Data Plane API. + * + * @param[in] dcInstance Instance Handle + * @param[in] pSessionHandle Pointer to a session handle + * + * @retval CPA_STATUS_SUCCESS Function executed successfully + * @retval CPA_STATUS_INVALID_PARAM Invalid parameter passed in + * @retval CPA_STATUS_UNSUPPORTED Unsupported feature + *****************************************************************************/ +CpaStatus dcSetCnvError(CpaInstanceHandle dcInstance, + CpaDcSessionHandle pSessionHandle); + +/** + ***************************************************************************** + * @ingroup Dc_DataCompression + * Check that pSessionData is valid + * + * @description + * Check that all the parameters defined in the pSessionData are valid + * + * @param[in] pSessionData Pointer to a user instantiated structure + * containing session data + * + * @retval CPA_STATUS_SUCCESS Function executed successfully + * @retval CPA_STATUS_FAIL Function failed to find device + * @retval CPA_STATUS_INVALID_PARAM Invalid parameter passed in + * @retval CPA_STATUS_UNSUPPORTED Unsupported algorithm/feature + * + *****************************************************************************/ +CpaStatus dcCheckSessionData(const CpaDcSessionSetupData *pSessionData, + CpaInstanceHandle dcInstance); + +/** + ***************************************************************************** + * @ingroup Dc_DataCompression + * Get the compression command id for the given session setup data. + * + * @description + * This function will get the compression command id based on parameters + * passed in the given session setup data. + * + * @param[in] pService Pointer to the service + * @param[in] pSessionData Pointer to a user instantiated + * structure containing session data + * @param[out] pDcCmdId Pointer to the command id + * + * @retval CPA_STATUS_SUCCESS Function executed successfully + * @retval CPA_STATUS_UNSUPPORTED Unsupported algorithm/feature + * + *****************************************************************************/ +CpaStatus dcGetCompressCommandId(sal_compression_service_t *pService, + CpaDcSessionSetupData *pSessionData, + Cpa8U *pDcCmdId); + +/** + ***************************************************************************** + * @ingroup Dc_DataCompression + * Get the decompression command id for the given session setup data. + * + * @description + * This function will get the decompression command id based on parameters + * passed in the given session setup data. + * + * @param[in] pService Pointer to the service + * @param[in] pSessionData Pointer to a user instantiated + * structure containing session data + * @param[out] pDcCmdId Pointer to the command id + * + * @retval CPA_STATUS_SUCCESS Function executed successfully + * @retval CPA_STATUS_UNSUPPORTED Unsupported algorithm/feature + * + *****************************************************************************/ +CpaStatus dcGetDecompressCommandId(sal_compression_service_t *pService, + CpaDcSessionSetupData *pSessionData, + Cpa8U *pDcCmdId); + +/** + ***************************************************************************** + * @ingroup Dc_DataCompression + * Populate the translator content descriptor + * + * @description + * This function will populate the translator content descriptor + * + * @param[out] pMsg Pointer to the compression message + * @param[in] nextSlice Next slice + * + *****************************************************************************/ +void dcTransContentDescPopulate(icp_qat_fw_comp_req_t *pMsg, + icp_qat_fw_slice_t nextSlice); + #endif /* DC_SESSION_H */ diff --git a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_session.h b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_session.h --- a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_session.h +++ b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_session.h @@ -107,6 +107,21 @@ * Include private header files ******************************************************************************* */ +/** +***************************************************************************** +* @ingroup LacSym +* Spc state +* +* @description +* This enum is used to indicate the Spc state. +* +*****************************************************************************/ +typedef enum lac_single_pass_state_e { + NON_SPC, /* Algorithms other than CHACHA-POLY and AES-GCM */ + LIKELY_SPC, /* AES-GCM - Likely to handle it as single pass */ + SPC /* CHACHA-POLY and AES-GCM */ +} lac_single_pass_state_t; + /** ******************************************************************************* * @ingroup LacSym_Session @@ -214,15 +229,17 @@ /**< Flag indicating whether the SymConstantsTable can be used or not */ CpaBoolean useOptimisedContentDesc : 1; /**< Flag indicating whether to use the optimised CD or not */ + CpaBoolean isPartialSupported : 1; + /**< Flag indicating whether symOperation support partial packet */ + CpaBoolean useStatefulSha3ContentDesc : 1; + /**< Flag indicating whether to use the stateful SHA3 CD or not */ icp_qat_la_bulk_req_hdr_t shramReqCacheHdr; icp_qat_fw_la_key_gen_common_t shramReqCacheMid; icp_qat_la_bulk_req_ftr_t shramReqCacheFtr; /**< Alternative pre-built request (header, mid & footer) * for use with symConstantsTable. */ - CpaBoolean isPartialSupported : 1; - /**< Flag indicating whether symOperation support partial packet */ - CpaBoolean isSinglePass : 1; - /**< Flag indicating whether symOperation is single pass operation */ + lac_single_pass_state_t singlePassState; + /**< Flag indicating whether symOperation support single pass */ icp_qat_fw_serv_specif_flags laCmdFlags; /**< Common request - Service specific flags type */ icp_qat_fw_comn_flags cmnRequestFlags; @@ -236,6 +253,23 @@ /**< Hash Mode for the qat slices. Not to be confused with QA-API * hashMode */ + Cpa32U cipherSliceType; + /**< Cipher slice type to be used, set at init session time */ + Cpa8U cipherAesXtsKey1Forward[LAC_CIPHER_AES_XTS_KEY_MAX_LENGTH]; + /**< Cached AES XTS Forward key + * For CPM2.0 AES XTS key convertion need to be done in SW. + * Because use can update session direction at any time, + * also forward key needs to be cached + */ + Cpa8U cipherAesXtsKey1Reverse[LAC_CIPHER_AES_XTS_KEY_MAX_LENGTH]; + /**< AES XTS Reverse key + * For CPM2.0 AES XTS key convertion need to be done in SW. + * Reverse key always will be calcilated at session setup time and + * cached to be used when needed */ + Cpa8U cipherAesXtsKey2[LAC_CIPHER_AES_XTS_KEY_MAX_LENGTH]; + /**< For AES XTS session need to store Key2 value in order to generate + * tweak + */ void *writeRingMsgFunc; /**< function which will be called to write ring message */ Cpa32U aadLenInBytes; @@ -325,8 +359,7 @@ * a decrypt operation. */ CpaCySymPacketType partialState; /**< state of the partial packet. This can be written to by the perform - * because the SpinLock pPartialInFlightSpinlock guarantees that that - * the + * because the SpinLock pPartialInFlightSpinlock guarantees that the * state is accessible in only one place at a time. */ icp_qat_la_bulk_req_hdr_t reqCacheHdr; icp_qat_fw_la_key_gen_common_t reqCacheMid; @@ -382,15 +415,17 @@ /**< Flag indicating whether the SymConstantsTable can be used or not */ CpaBoolean useOptimisedContentDesc : 1; /**< Flag indicating whether to use the optimised CD or not */ + CpaBoolean isPartialSupported : 1; + /**< Flag indicating whether symOperation support partial packet */ + CpaBoolean useStatefulSha3ContentDesc : 1; + /**< Flag indicating whether to use the stateful SHA3 CD or not */ icp_qat_la_bulk_req_hdr_t shramReqCacheHdr; icp_qat_fw_la_key_gen_common_t shramReqCacheMid; icp_qat_la_bulk_req_ftr_t shramReqCacheFtr; /**< Alternative pre-built request (header, mid & footer) * for use with symConstantsTable. */ - CpaBoolean isPartialSupported : 1; - /**< Flag indicating whether symOperation support partial packet */ - CpaBoolean isSinglePass : 1; - /**< Flag indicating whether symOperation is single pass operation */ + lac_single_pass_state_t singlePassState; + /**< Flag indicating whether symOperation support single pass */ icp_qat_fw_serv_specif_flags laCmdFlags; /**< Common request - Service specific flags type */ icp_qat_fw_comn_flags cmnRequestFlags; @@ -404,6 +439,23 @@ /**< Hash Mode for the qat slices. Not to be confused with QA-API * hashMode */ + Cpa32U cipherSliceType; + /**< Cipher slice type to be used, set at init session time */ + Cpa8U cipherAesXtsKey1Forward[LAC_CIPHER_AES_XTS_KEY_MAX_LENGTH]; + /**< Cached AES XTS Forward key + * For CPM2.0 AES XTS key convertion need to be done in SW. + * Because use can update session direction at any time, + * also forward key needs to be cached + */ + Cpa8U cipherAesXtsKey1Reverse[LAC_CIPHER_AES_XTS_KEY_MAX_LENGTH]; + /**< AES XTS Reverse key + * For CPM2.0 AES XTS key convertion need to be done in SW. + * Reverse key always will be calcilated at session setup time and + * cached to be used when needed */ + Cpa8U cipherAesXtsKey2[LAC_CIPHER_AES_XTS_KEY_MAX_LENGTH]; + /**< For AES XTS session need to store Key2 value in order to generate + * tweak + */ void *writeRingMsgFunc; /**< function which will be called to write ring message */ } lac_session_desc_d1_t; @@ -444,8 +496,8 @@ /**< info on the hash state prefix buffer */ CpaCySymHashAlgorithm hashAlgorithm; /**< hash algorithm */ - Cpa32U authKeyLenInBytes; - /**< Authentication key length in bytes */ + Cpa32U authKeyLenInBytes; + /**< Authentication key length in bytes */ CpaCySymHashMode hashMode; /**< Mode of the hash operation. plain, auth or nested */ Cpa32U hashResultSize; @@ -459,8 +511,7 @@ * a decrypt operation. */ CpaCySymPacketType partialState; /**< state of the partial packet. This can be written to by the perform - * because the SpinLock pPartialInFlightSpinlock guarantees that that - * the + * because the SpinLock pPartialInFlightSpinlock guarantees that the * state is accessible in only one place at a time. */ icp_qat_la_bulk_req_hdr_t reqCacheHdr; icp_qat_fw_la_key_gen_common_t reqCacheMid; @@ -516,15 +567,17 @@ /**< Flag indicating whether the SymConstantsTable can be used or not */ CpaBoolean useOptimisedContentDesc : 1; /**< Flag indicating whether to use the optimised CD or not */ + CpaBoolean isPartialSupported : 1; + /**< Flag indicating whether symOperation support partial packet */ + CpaBoolean useStatefulSha3ContentDesc : 1; + /**< Flag indicating whether to use the stateful SHA3 CD or not */ icp_qat_la_bulk_req_hdr_t shramReqCacheHdr; icp_qat_fw_la_key_gen_common_t shramReqCacheMid; icp_qat_la_bulk_req_ftr_t shramReqCacheFtr; /**< Alternative pre-built request (header. mid & footer) * for use with symConstantsTable. */ - CpaBoolean isPartialSupported : 1; - /**< Flag indicating whether symOperation support partial packet */ - CpaBoolean isSinglePass : 1; - /**< Flag indicating whether symOperation is single pass operation */ + lac_single_pass_state_t singlePassState; + /**< Flag indicating whether symOperation support single pass */ icp_qat_fw_serv_specif_flags laCmdFlags; /**< Common request - Service specific flags type */ icp_qat_fw_comn_flags cmnRequestFlags; @@ -538,6 +591,23 @@ /**< Hash Mode for the qat slices. Not to be confused with QA-API * hashMode */ + Cpa32U cipherSliceType; + /**< Cipher slice type to be used, set at init session time */ + Cpa8U cipherAesXtsKey1Forward[LAC_CIPHER_AES_XTS_KEY_MAX_LENGTH]; + /**< Cached AES XTS Forward key + * For CPM2.0 AES XTS key convertion need to be done in SW. + * Because use can update session direction at any time, + * also forward key needs to be cached + */ + Cpa8U cipherAesXtsKey1Reverse[LAC_CIPHER_AES_XTS_KEY_MAX_LENGTH]; + /**< AES XTS Reverse key + * For CPM2.0 AES XTS key convertion need to be done in SW. + * Reverse key always will be calcilated at session setup time and + * cached to be used when needed */ + Cpa8U cipherAesXtsKey2[LAC_CIPHER_AES_XTS_KEY_MAX_LENGTH]; + /**< For AES XTS session need to store Key2 value in order to generate + * tweak + */ void *writeRingMsgFunc; /**< function which will be called to write ring message */ Cpa32U aadLenInBytes; diff --git a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_cipher.h b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_cipher.h --- a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_cipher.h +++ b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_cipher.h @@ -228,6 +228,7 @@ #include "lac_session.h" #include "lac_sym.h" +#include "lac_sal_types_crypto.h" /* * WARNING: There are no checks done on the parameters of the functions in @@ -253,8 +254,9 @@ * @retval CPA_STATUS_INVALID_PARAM Invalid parameter. * *****************************************************************************/ -CpaStatus LacCipher_SessionSetupDataCheck( - const CpaCySymCipherSetupData *pCipherSetupData); +CpaStatus +LacCipher_SessionSetupDataCheck(const CpaCySymCipherSetupData *pCipherSetupData, + Cpa32U capabilitiesMask); /** ******************************************************************************* @@ -309,4 +311,22 @@ Cpa32U qatPacketType, Cpa8U **ppIvBuffer); +/** + ***************************************************************************** + * @ingroup LacCipher + * Return cipher slice type for given algorithm + * + * @description + * This function will check what cipher slice type should be used for given + * algorithms and CPM generation combination. + * Since CPM2.0 there is new UCS cipher slice available. + * + * @param[in] pService Pointer to service struct + * @param[in] cipherAlgorithm cipher algorithm + * @param[in] hashAlgorithm hash algorithm + * + *****************************************************************************/ +Cpa32U LacCipher_GetCipherSliceType(sal_crypto_service_t *pService, + CpaCySymCipherAlgorithm algorithm, + CpaCySymHashAlgorithm hash); #endif /* LAC_SYM_CIPHER_H */ diff --git a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_cipher_defs.h b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_cipher_defs.h --- a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_cipher_defs.h +++ b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_cipher_defs.h @@ -45,6 +45,14 @@ /* ARC4 256 bytes for key matrix, 2 for i and j and 6 bytes for padding */ #define LAC_CIPHER_ARC4_STATE_LEN_BYTES 264 +/* + * Constant values for CCM AAD buffer + */ +#define LAC_CIPHER_CCM_B0_SIZE 16 +#define LAC_CIPHER_CCM_ENCODED_AAD_LEN_SIZE 2 +#define LAC_CIPHER_CCM_AAD_OFFSET \ + (LAC_CIPHER_CCM_B0_SIZE + LAC_CIPHER_CCM_ENCODED_AAD_LEN_SIZE) + #define LAC_SYM_SNOW3G_CIPHER_CONFIG_FOR_HASH_SZ 40 /* Snow3g cipher config required for performing a Snow3g hash operation. * It contains 8 Bytes of config for hardware, 16 Bytes of Key and requires @@ -64,6 +72,9 @@ /* The IV length for AES F8 is 16 bytes */ #define LAC_CIPHER_AES_F8_IV_LENGTH 16 +/* The max key length for AES XTS 32 is bytes*/ +#define LAC_CIPHER_AES_XTS_KEY_MAX_LENGTH 32 + /* For Snow3G UEA2, need to make sure last 8 Bytes of IV buffer are * zero. */ #define LAC_CIPHER_SNOW3G_UEA2_IV_BUFFER_ZERO_LENGTH 8 @@ -171,12 +182,17 @@ /* Macro to check if the Algorithm Mode is XTS */ #define LAC_CIPHER_IS_XTS_MODE(algo) (algo == CPA_CY_SYM_CIPHER_AES_XTS) +/* Macro to check if the accelerator has AES V2 capability */ +#define LAC_CIPHER_AES_V2(mask) ((mask)&ICP_ACCEL_CAPABILITIES_AES_V2) + /* Macro to check if the Algorithm is single pass */ #define LAC_CIPHER_IS_SPC(cipher, hash, mask) \ - ((LAC_CIPHER_IS_CHACHA(cipher) && (CPA_CY_SYM_HASH_POLY == hash) && \ - ((mask)&ICP_ACCEL_CAPABILITIES_CHACHA_POLY)) || \ - (LAC_CIPHER_IS_GCM(cipher) && ((CPA_CY_SYM_HASH_AES_GCM == hash) || \ - (CPA_CY_SYM_HASH_AES_GMAC == hash)) && \ - ((mask)&ICP_ACCEL_CAPABILITIES_AESGCM_SPC))) + (((mask)&ICP_ACCEL_CAPABILITIES_CHACHA_POLY && \ + LAC_CIPHER_IS_CHACHA(cipher) && (CPA_CY_SYM_HASH_POLY == hash)) || \ + (((mask)&ICP_ACCEL_CAPABILITIES_AESGCM_SPC) && \ + LAC_CIPHER_IS_GCM(cipher) && \ + ((CPA_CY_SYM_HASH_AES_GCM == hash) || \ + (CPA_CY_SYM_HASH_AES_GMAC == hash))) || \ + (LAC_CIPHER_IS_CCM(cipher) && LAC_CIPHER_AES_V2(mask))) #endif /* LAC_CIPHER_DEFS_H */ diff --git a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_hash_defs.h b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_hash_defs.h --- a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_hash_defs.h +++ b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_hash_defs.h @@ -108,40 +108,37 @@ /* Constants for SHA3_384 algorithm */ #define LAC_HASH_SHA3_384_BLOCK_SIZE 104 /**< @ingroup LacHashDefs - * * SHA3_384 block size in bytes */ + * SHA3_384 block size in bytes */ #define LAC_HASH_SHA3_384_DIGEST_SIZE 48 /**< @ingroup LacHashDefs - * * SHA3_384 digest length in bytes */ + * SHA3_384 digest length in bytes */ #define LAC_HASH_SHA3_384_STATE_SIZE 48 /**< @ingroup LacHashDefs - * * SHA3_384 state size */ + * SHA3_384 state size */ /* Constants for SHA3_512 algorithm */ #define LAC_HASH_SHA3_512_BLOCK_SIZE 72 /**< @ingroup LacHashDefs - * * * SHA3_512 block size in bytes */ + * SHA3_512 block size in bytes */ #define LAC_HASH_SHA3_512_DIGEST_SIZE 64 /**< @ingroup LacHashDefs - * * * SHA3_512 digest length in bytes */ + * SHA3_512 digest length in bytes */ #define LAC_HASH_SHA3_512_STATE_SIZE 64 /**< @ingroup LacHashDefs - * * * SHA3_512 state size */ + * SHA3_512 state size */ -/* Constants for SHAKE_128 algorithm */ -#define LAC_HASH_SHAKE_128_BLOCK_SIZE 168 -/**< @ingroup LacHashDefs - * * * SHAKE_128 block size in bytes */ -#define LAC_HASH_SHAKE_128_DIGEST_SIZE 0xFFFFFFFF -/**< @ingroup LacHashDefs - * * * SHAKE_128 digest length in bytes ((2^32)-1)*/ +#define LAC_HASH_SHA3_STATEFUL_STATE_SIZE 200 -/* Constants for SHAKE_256 algorithm */ -#define LAC_HASH_SHAKE_256_BLOCK_SIZE 136 +/* Constants for SM3 algorithm */ +#define LAC_HASH_SM3_BLOCK_SIZE 64 +/**< @ingroup LacHashDefs + * SM3 block size in bytes */ +#define LAC_HASH_SM3_DIGEST_SIZE 32 /**< @ingroup LacHashDefs - * * * SHAKE_256 block size in bytes */ -#define LAC_HASH_SHAKE_256_DIGEST_SIZE 0xFFFFFFFF + * SM3 digest length */ +#define LAC_HASH_SM3_STATE_SIZE 32 /**< @ingroup LacHashDefs - * * * SHAKE_256 digest length in bytes ((2^ 32)-1)*/ + * SM3 state size */ /* Constants for POLY algorithm */ #define LAC_HASH_POLY_BLOCK_SIZE 64 @@ -154,17 +151,6 @@ /**< @ingroup LacHashDefs * POLY state size */ -/* Constants for SM3 algorithm */ -#define LAC_HASH_SM3_BLOCK_SIZE 64 -/**< @ingroup LacHashDefs - * SM3 block size in bytes */ -#define LAC_HASH_SM3_DIGEST_SIZE 32 -/**< @ingroup LacHashDefs - * SM3 digest length */ -#define LAC_HASH_SM3_STATE_SIZE 32 -/**< @ingroup LacHashDefs - * SM3 state size */ - /* Constants for XCBC precompute algorithm */ #define LAC_HASH_XCBC_PRECOMP_KEY_NUM 3 /**< @ingroup LacHashDefs @@ -285,7 +271,7 @@ * the size in an 8bit field */ #define LAC_MAX_HASH_STATE_STORAGE_SIZE \ - (sizeof(icp_qat_hw_auth_counter_t) + LAC_HASH_SHA512_STATE_SIZE) + (sizeof(icp_qat_hw_auth_counter_t) + LAC_HASH_SHA3_STATEFUL_STATE_SIZE) /**< Maximum size of the hash state storage section of the hash state prefix * buffer */ @@ -307,11 +293,8 @@ (algorithm == CPA_CY_SYM_HASH_SHA256) || \ (algorithm == CPA_CY_SYM_HASH_SHA384) || \ (algorithm == CPA_CY_SYM_HASH_SHA512) || \ - (algorithm == CPA_CY_SYM_HASH_SHA3_224) || \ - (algorithm == CPA_CY_SYM_HASH_SHA3_256) || \ - (algorithm == CPA_CY_SYM_HASH_SHA3_384) || \ - (algorithm == CPA_CY_SYM_HASH_SHA3_512) || \ - (algorithm == CPA_CY_SYM_HASH_SM3)) + (algorithm == CPA_CY_SYM_HASH_SM3)) || \ + (LAC_HASH_IS_SHA3(algorithm)) /**< @ingroup LacSymQatHash * Macro to detect if the hash algorithm is a HMAC algorithm */ @@ -341,4 +324,12 @@ * Nested. This applies to TLS. This is used to differentiate between * TLS and HMAC */ +#define LAC_HASH_IS_SHA3(algo) \ + ((algo == CPA_CY_SYM_HASH_SHA3_224) || \ + (algo == CPA_CY_SYM_HASH_SHA3_256) || \ + (algo == CPA_CY_SYM_HASH_SHA3_384) || \ + (algo == CPA_CY_SYM_HASH_SHA3_512)) +/**< @ingroup LacSymQatHash + * Macro to check if the hash algorithm is SHA3 */ + #endif /* LAC_SYM_HASH_DEFS_H */ diff --git a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat.h b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat.h --- a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat.h +++ b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat.h @@ -206,4 +206,43 @@ void LacSymQat_LaSetDefaultFlags(icp_qat_fw_serv_specif_flags *laCmdFlags, CpaCySymOp symOp); +/** + ****************************************************************************** + * @ingroup LacSymQat + * + * + * @description + * this function defines whether the shared constants table can be used + * for a particular cipher and hash algorithm + * + * @param[in] ptr to session + + * @param[in] ptr to return offset into table for cipher config + + * @param[in] ptr to return offset into table for hash config + * + * @return CPA_TRUE if Constants table is available for use, CPA_FALSE if it's + * not. + * + *****************************************************************************/ +CpaBoolean LacSymQat_UseSymConstantsTable(lac_session_desc_t *pSession, + Cpa8U *cipherOffset, + Cpa8U *hashOffset); + +/** + ****************************************************************************** + * @ingroup LacSymQat + * + * + * @description + * this function calculates whether the optimized content descriptor can + * be used for a particular chained cipher and hash algorithm + * + * @param[in] ptr to session + * + * @return CPA_TRUE if optimized CD can be used, CPA_FALSE if it's not. + * + *****************************************************************************/ +CpaBoolean LacSymQat_UseOptimisedContentDesc(lac_session_desc_t *pSession); + #endif /* LAC_SYM_QAT_H */ diff --git a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat_cipher.h b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat_cipher.h --- a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat_cipher.h +++ b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat_cipher.h @@ -42,9 +42,11 @@ #define LAC_SYM_QAT_CIPHER_NEXT_ID_BIT_OFFSET 24 #define LAC_SYM_QAT_CIPHER_CURR_ID_BIT_OFFSET 16 #define LAC_SYM_QAT_CIPHER_STATE_SIZE_BIT_OFFSET 8 -#define LAC_SYM_QAT_CIPHER_OFFSET_IN_DRAM_GCM_SPC 9 -#define LAC_SYM_QAT_CIPHER_OFFSET_IN_DRAM_CHACHA_SPC 2 -#define LAC_SYM_QAT_CIPHER_STATE_SIZE_SPC 48 +#define LAC_SYM_QAT_CIPHER_GCM_SPC_OFFSET_IN_DRAM 9 +#define LAC_SYM_QAT_CIPHER_CCM_SPC_OFFSET_IN_DRAM 8 +#define LAC_SYM_QAT_CIPHER_CHACHA_SPC_OFFSET_IN_DRAM 2 +#define LAC_SYM_QAT_CIPHER_SPC_STATE_SIZE 48 + /** ****************************************************************************** * @ingroup LacSymQat_Cipher @@ -111,11 +113,13 @@ * @retval void * *****************************************************************************/ -CpaStatus LacSymQat_CipherRequestParamsPopulate(icp_qat_fw_la_bulk_req_t *pReq, - Cpa32U cipherOffsetInBytes, - Cpa32U cipherLenInBytes, - Cpa64U ivBufferPhysAddr, - Cpa8U *pIvBufferVirt); +CpaStatus +LacSymQat_CipherRequestParamsPopulate(lac_session_desc_t *pSessionDesc, + icp_qat_fw_la_bulk_req_t *pReq, + Cpa32U cipherOffsetInBytes, + Cpa32U cipherLenInBytes, + Cpa64U ivBufferPhysAddr, + Cpa8U *pIvBufferVirt); /** ****************************************************************************** @@ -194,6 +198,8 @@ * @param[in] targetKeyLenInBytes cipher key length in bytes of selected * algorithm * + * @param[in] sliceType Cipher slice type to be used + * * @param[out] nextSlice SliceID for next control block * entry. This value is known only by * the calling component @@ -206,6 +212,7 @@ void LacSymQat_CipherCtrlBlockWrite(icp_qat_la_bulk_req_ftr_t *pMsg, Cpa32U cipherAlgorithm, Cpa32U targetKeyLenInBytes, + Cpa32U sliceType, icp_qat_fw_slice_t nextSlice, Cpa8U cipherCfgOffsetInQuadWord); @@ -274,6 +281,8 @@ * key length MUST match the key length * in the cipher setup data. * + * @param[in] sliceType Cipher slice type to be used + * * @param[in] pCipherHwBlock Pointer to the cipher hardware block * * @param[out] pCipherHwBlockSizeBytes Size in bytes of cipher setup block @@ -283,8 +292,10 @@ * *****************************************************************************/ void LacSymQat_CipherHwBlockPopulateKeySetup( + lac_session_desc_t *pSessionDesc, const CpaCySymCipherSetupData *pCipherSetupData, Cpa32U targetKeyLenInBytes, + Cpa32U sliceType, const void *pCipherHwBlock, Cpa32U *pCipherHwBlockSizeBytes); diff --git a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat_constants_table.h b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat_constants_table.h new file mode 100644 --- /dev/null +++ b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat_constants_table.h @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2007-2022 Intel Corporation */ +/* $FreeBSD$ */ + +/** + ***************************************************************************** + * @file lac_sym_qat_constants_table.h + * + * @ingroup LacSymQat + * + * API to be used for the CySym constants table. + * + *****************************************************************************/ + +#ifndef LAC_SYM_QAT_CONSTANTS_TABLE_H +#define LAC_SYM_QAT_CONSTANTS_TABLE_H + +#include "cpa.h" +#include "icp_qat_fw_la.h" + +typedef struct lac_sym_qat_constants_s { + /* Note these arrays must match the tables in lac_sym_qat_constants.c + * icp_qat_hw_cipher_lookup_tbl and icp_qat_hw_auth_lookup_tbl */ + uint8_t cipher_offset[ICP_QAT_HW_CIPHER_DELIMITER] + [ICP_QAT_HW_CIPHER_MODE_DELIMITER][2][2]; + uint8_t auth_offset[ICP_QAT_HW_AUTH_ALGO_DELIMITER] + [ICP_QAT_HW_AUTH_MODE_DELIMITER][2]; +} lac_sym_qat_constants_t; + +/** + ******************************************************************************* + * @ingroup LacSymQat + * LacSymQat_ConstantsInitLookupTables + * + * + * @description + * The SymCy constants table is 1K of static data which is passed down + * to the FW to be stored in SHRAM for use by the FW. + * This function populates the associated lookup tables which the IA + * driver uses. + * Where there is config data available in the constants table the lookup + * table stores the offset into the constants table. + * Where there's no suitable config data available in the constants table + * zero is stored in the lookup table. + * + * @return none + * + *****************************************************************************/ +void LacSymQat_ConstantsInitLookupTables(CpaInstanceHandle instanceHandle); + +/** +******************************************************************************* +* @ingroup LacSymQat +* LacSymQat_ConstantsGetCipherOffset +* +* @description +* This function looks up the cipher constants lookup array for +* a specific cipher algorithm, mode, direction and convert flag. +* If the lookup table value is zero then there's no suitable config data +* available in the constants table. +* If the value > zero, then there is config data available in the constants +* table which is stored in SHRAM for use by the FW. The value is the offset +* into the constants table, it is returned to the caller in poffset. +* +* +* @param[in] Cipher Algorithm +* @param[in] Cipher Mode +* @param[in] Direction - encrypt/decrypt +* @param[in] convert / no convert +* @param[out] offset into constants table +* +* @return none +* +*****************************************************************************/ +void LacSymQat_ConstantsGetCipherOffset(CpaInstanceHandle instanceHandle, + uint8_t algo, + uint8_t mode, + uint8_t direction, + uint8_t convert, + uint8_t *poffset); + +/** +******************************************************************************* +* @ingroup LacSymQat +* LacSymQat_ConstantsGetAuthOffset +* +* @description +* This function looks up the auth constants lookup array for +* a specific auth algorithm, mode, direction and convert flag. +* If the lookup table value is zero then there's no suitable config data +* available in the constants table. +* If the value > zero, then there is config data available in the constants +* table which is stored in SHRAM for use by the FW. The value is the offset +* into the constants table, it is returned to the caller in poffset. +* +* +* @param[in] auth Algorithm +* @param[in] auth Mode +* @param[in] nested / no nested +* @param[out] offset into constants table +* +* @return none +* +*****************************************************************************/ +void LacSymQat_ConstantsGetAuthOffset(CpaInstanceHandle instanceHandle, + uint8_t algo, + uint8_t mode, + uint8_t nested, + uint8_t *poffset); + +#endif /* LAC_SYM_QAT_SHRAM_CONSTANTS_TABLE_H */ diff --git a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat_hash.h b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat_hash.h --- a/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat_hash.h +++ b/sys/dev/qat/qat_api/common/crypto/sym/include/lac_sym_qat_hash.h @@ -126,6 +126,10 @@ * @param[in] useOptimisedContentDesc Indicate if optimised content desc * is used for this session. * + * @param[in] useStatefulSha3ContentDesc + * Indicate if stateful SHA3 content desc + * is used for this session. + * * @param[in] pPrecompute For auth mode, this is the pointer * to the precompute data. Otherwise this * should be set to NULL @@ -145,6 +149,7 @@ icp_qat_hw_auth_mode_t qatHashMode, CpaBoolean useSymConstantsTable, CpaBoolean useOptimisedContentDesc, + CpaBoolean useStatefulSha3ContentDesc, lac_sym_qat_hash_precompute_info_t *pPrecompute, Cpa32U *pHashBlkSizeInBytes); diff --git a/sys/dev/qat/qat_api/common/crypto/sym/key/lac_sym_key.c b/sys/dev/qat/qat_api/common/crypto/sym/key/lac_sym_key.c --- a/sys/dev/qat/qat_api/common/crypto/sym/key/lac_sym_key.c +++ b/sys/dev/qat/qat_api/common/crypto/sym/key/lac_sym_key.c @@ -798,8 +798,9 @@ ICP_QAT_FW_SLICE_DRAM_WR, ICP_QAT_HW_AUTH_MODE0, /* just a plain hash */ CPA_FALSE, /* Not using sym Constants Table in Shared SRAM - */ + */ CPA_FALSE, /* not using the optimised Content Desc */ + CPA_FALSE, /* Not using the stateful SHA3 Content Desc */ NULL, &hashBlkSizeInBytes); @@ -1550,9 +1551,11 @@ LAC_SYM_KEY_NO_HASH_BLK_OFFSET_QW, ICP_QAT_FW_SLICE_DRAM_WR, qatHashMode, - CPA_FALSE, /* Not using sym Constants Table in SRAM */ - CPA_FALSE, /* Not using the optimised content Desc */ - NULL, /* Precompute data */ + CPA_FALSE, /* Not using sym Constants Table in Shared SRAM + */ + CPA_FALSE, /* not using the optimised content Desc */ + CPA_FALSE, /* Not using the stateful SHA3 Content Desc */ + NULL, /* precompute data */ &hashBlkSizeInBytes); /* SSL3 */ diff --git a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_alg_chain.c b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_alg_chain.c --- a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_alg_chain.c +++ b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_alg_chain.c @@ -52,6 +52,72 @@ #include "sal_string_parse.h" #include "lac_sym_auth_enc.h" #include "lac_sym_qat.h" +#include "sal_hw_gen.h" + +/** + * @ingroup LacAlgChain + * This callback function will be invoked whenever a hash precompute + * operation completes. It will dequeue and send any QAT requests + * which were queued up while the precompute was in progress. + * + * @param[in] callbackTag Opaque value provided by user. This will + * be a pointer to the session descriptor. + * + * @retval + * None + * + */ +static void +LacSymAlgChain_HashPrecomputeDoneCb(void *callbackTag) +{ + LacSymCb_PendingReqsDequeue((lac_session_desc_t *)callbackTag); +} + +/** + * @ingroup LacAlgChain + * Walk the buffer list and find the address for the given offset within + * a buffer. + * + * @param[in] pBufferList Buffer List + * @param[in] packetOffset Offset in the buffer list for which address + * is to be found. + * @param[out] ppDataPtr This is where the sought pointer will be put + * @param[out] pSpaceLeft Pointer to a variable in which information about + * available space from the given offset to the end + * of the flat buffer it is located in will be returned + * + * @retval CPA_STATUS_SUCCESS Address with a given offset is found in the list + * @retval CPA_STATUS_FAIL Address with a given offset not found in the list. + * + */ +static CpaStatus +LacSymAlgChain_PtrFromOffsetGet(const CpaBufferList *pBufferList, + const Cpa32U packetOffset, + Cpa8U **ppDataPtr) +{ + Cpa32U currentOffset = 0; + Cpa32U i = 0; + + for (i = 0; i < pBufferList->numBuffers; i++) { + Cpa8U *pCurrData = pBufferList->pBuffers[i].pData; + Cpa32U currDataSize = pBufferList->pBuffers[i].dataLenInBytes; + + /* If the offset is within the address space of the current + * buffer */ + if ((packetOffset >= currentOffset) && + (packetOffset < (currentOffset + currDataSize))) { + /* increment by offset of the address in the current + * buffer */ + *ppDataPtr = pCurrData + (packetOffset - currentOffset); + return CPA_STATUS_SUCCESS; + } + + /* Increment by the size of the buffer */ + currentOffset += currDataSize; + } + + return CPA_STATUS_FAIL; +} /** * @ingroup LacAlgChain @@ -81,6 +147,7 @@ /* All others support partial */ default: isCipherPartialSupported = CPA_TRUE; + break; } switch (pSessionDesc->hashAlgorithm) { /* Following hash don't support partial */ @@ -88,8 +155,6 @@ case CPA_CY_SYM_HASH_SNOW3G_UIA2: case CPA_CY_SYM_HASH_POLY: case CPA_CY_SYM_HASH_ZUC_EIA3: - case CPA_CY_SYM_HASH_SHAKE_128: - case CPA_CY_SYM_HASH_SHAKE_256: break; /* Following hash may support partial based on device capabilities */ case CPA_CY_SYM_HASH_SHA3_256: @@ -100,6 +165,7 @@ /* All others support partial */ default: isHashPartialSupported = CPA_TRUE; + break; } switch (pSessionDesc->symOperation) { case CPA_CY_SYM_OP_CIPHER: @@ -115,73 +181,84 @@ break; case CPA_CY_SYM_OP_NONE: break; + default: + break; + } + + if (ICP_QAT_FW_LA_USE_UCS_SLICE_TYPE == pSessionDesc->cipherSliceType) { + /* UCS slice has no support for state flush and + * because of that is not able to do partial processing */ + isPartialSupported = CPA_FALSE; } + pSessionDesc->isPartialSupported = isPartialSupported; } -/** - * @ingroup LacAlgChain - * This callback function will be invoked whenever a hash precompute - * operation completes. It will dequeue and send any QAT requests - * which were queued up while the precompute was in progress. - * - * @param[in] callbackTag Opaque value provided by user. This will - * be a pointer to the session descriptor. - * - * @retval - * None - * - */ static void -LacSymAlgChain_HashPrecomputeDoneCb(void *callbackTag) +LacAlgChain_CipherCDBuild_ForOptimisedCD( + const CpaCySymCipherSetupData *pCipherData, + lac_session_desc_t *pSessionDesc, + icp_qat_fw_slice_t nextSlice, + Cpa8U cipherOffsetInConstantsTable, + Cpa8U *pOptimisedHwBlockBaseInDRAM, + Cpa32U *pOptimisedHwBlockOffsetInDRAM) { - LacSymCb_PendingReqsDequeue((lac_session_desc_t *)callbackTag); -} + Cpa8U *pCipherKeyField = NULL; + Cpa32U sizeInBytes = 0; + pCipherKeyField = pOptimisedHwBlockBaseInDRAM; -/** - * @ingroup LacAlgChain - * Walk the buffer list and find the address for the given offset within - * a buffer. - * - * @param[in] pBufferList Buffer List - * @param[in] packetOffset Offset in the buffer list for which address - * is to be found. - * @param[out] ppDataPtr This is where the sought pointer will be put - * @param[out] pSpaceLeft Pointer to a variable in which information about - * available space from the given offset to the end - * of the flat buffer it is located in will be returned - * - * @retval CPA_STATUS_SUCCESS Address with a given offset is found in the list - * @retval CPA_STATUS_FAIL Address with a given offset not found in the list. - * - */ -static CpaStatus -LacSymAlgChain_PtrFromOffsetGet(const CpaBufferList *pBufferList, - const Cpa32U packetOffset, - Cpa8U **ppDataPtr) -{ - Cpa32U currentOffset = 0; - Cpa32U i = 0; + /* Need to build up the alternative CD for SHRAM Constants Table use + * with an optimised content desc of 64 bytes for this case. Cipher key + * will be in the Content desc in DRAM, The cipher config data + * is now in the SHRAM constants table. */ - for (i = 0; i < pBufferList->numBuffers; i++) { - Cpa8U *pCurrData = pBufferList->pBuffers[i].pData; - Cpa32U currDataSize = pBufferList->pBuffers[i].dataLenInBytes; + LacSymQat_CipherHwBlockPopulateKeySetup( + pSessionDesc, + pCipherData, + pCipherData->cipherKeyLenInBytes, + pSessionDesc->cipherSliceType, + pCipherKeyField, + &sizeInBytes); - /* If the offset is within the address space of the current - * buffer */ - if ((packetOffset >= currentOffset) && - (packetOffset < (currentOffset + currDataSize))) { - /* increment by offset of the address in the current - * buffer */ - *ppDataPtr = pCurrData + (packetOffset - currentOffset); - return CPA_STATUS_SUCCESS; - } + LacSymQat_CipherCtrlBlockWrite(&(pSessionDesc->shramReqCacheFtr), + pSessionDesc->cipherAlgorithm, + pSessionDesc->cipherKeyLenInBytes, + pSessionDesc->cipherSliceType, + nextSlice, + cipherOffsetInConstantsTable); - /* Increment by the size of the buffer */ - currentOffset += currDataSize; - } + *pOptimisedHwBlockOffsetInDRAM += sizeInBytes; +} - return CPA_STATUS_FAIL; +static void +LacAlgChain_CipherCDBuild_ForSHRAM(const CpaCySymCipherSetupData *pCipherData, + lac_session_desc_t *pSessionDesc, + icp_qat_fw_slice_t nextSlice, + Cpa8U cipherOffsetInConstantsTable) +{ + Cpa32U sizeInBytes = 0; + Cpa8U *pCipherKeyField = NULL; + /* Need to build up the alternative CD for SHRAM Constants Table use + * Cipher key will be in the Request, The cipher config data is now in + * the SHRAM constants table. And nothing is now stored in the content + * desc */ + pCipherKeyField = (Cpa8U *)&( + pSessionDesc->shramReqCacheHdr.cd_pars.s1.serv_specif_fields); + + LacSymQat_CipherHwBlockPopulateKeySetup( + pSessionDesc, + pCipherData, + pCipherData->cipherKeyLenInBytes, + pSessionDesc->cipherSliceType, + pCipherKeyField, + &sizeInBytes); + + LacSymQat_CipherCtrlBlockWrite(&(pSessionDesc->shramReqCacheFtr), + pSessionDesc->cipherAlgorithm, + pSessionDesc->cipherKeyLenInBytes, + pSessionDesc->cipherSliceType, + nextSlice, + cipherOffsetInConstantsTable); } static void @@ -192,11 +269,14 @@ icp_qat_fw_comn_flags *pCmnRequestFlags, icp_qat_fw_serv_specif_flags *pLaCmdFlags, Cpa8U *pHwBlockBaseInDRAM, - Cpa32U *pHwBlockOffsetInDRAM) + Cpa32U *pHwBlockOffsetInDRAM, + Cpa32U capabilitiesMask) { Cpa8U *pCipherKeyField = NULL; Cpa8U cipherOffsetInReqQW = 0; Cpa32U sizeInBytes = 0; + void *pCfgData = NULL; + Cpa32U cfgOffset = 0; /* Construct the ContentDescriptor in DRAM */ cipherOffsetInReqQW = (*pHwBlockOffsetInDRAM / LAC_QUAD_WORD_IN_BYTES); @@ -204,11 +284,15 @@ *pLaCmdFlags, ICP_QAT_FW_CIPH_AUTH_CFG_OFFSET_IN_CD_SETUP); /* construct cipherConfig in CD in DRAM */ + cfgOffset = *pHwBlockOffsetInDRAM; + pCfgData = pHwBlockBaseInDRAM + cfgOffset; LacSymQat_CipherHwBlockPopulateCfgData(pSessionDesc, - pHwBlockBaseInDRAM + - *pHwBlockOffsetInDRAM, + pCfgData, &sizeInBytes); + ICP_QAT_FW_LA_SLICE_TYPE_SET(*pLaCmdFlags, + pSessionDesc->cipherSliceType); + *pHwBlockOffsetInDRAM += sizeInBytes; /* Cipher key will be in CD in DRAM. @@ -220,8 +304,10 @@ QAT_COMN_CD_FLD_TYPE_64BIT_ADR); LacSymQat_CipherHwBlockPopulateKeySetup( + pSessionDesc, pCipherData, pCipherData->cipherKeyLenInBytes, + pSessionDesc->cipherSliceType, pCipherKeyField, &sizeInBytes); /* update offset */ @@ -230,14 +316,15 @@ LacSymQat_CipherCtrlBlockWrite(&(pSessionDesc->reqCacheFtr), pSessionDesc->cipherAlgorithm, pSessionDesc->cipherKeyLenInBytes, + pSessionDesc->cipherSliceType, nextSlice, cipherOffsetInReqQW); - if (LAC_CIPHER_IS_GCM(pSessionDesc->cipherAlgorithm) || - LAC_CIPHER_IS_CHACHA(pSessionDesc->cipherAlgorithm)) { + if (NON_SPC != pSessionDesc->singlePassState) { LacSymQat_CipherCtrlBlockWrite( &(pSessionDesc->reqSpcCacheFtr), pSessionDesc->cipherAlgorithm, pSessionDesc->cipherKeyLenInBytes, + pSessionDesc->cipherSliceType, ICP_QAT_FW_SLICE_DRAM_WR, cipherOffsetInReqQW); } @@ -275,6 +362,7 @@ pSessionDesc->qatHashMode, CPA_FALSE, CPA_FALSE, + pSessionDesc->useStatefulSha3ContentDesc, pPrecomputeData, &sizeInBytes); @@ -282,6 +370,69 @@ *pHwBlockOffsetInDRAM += sizeInBytes; sizeInBytes = 0; + + if (pSessionDesc->useOptimisedContentDesc) { + LacSymQat_HashContentDescInit(&(pSessionDesc->shramReqCacheFtr), + instanceHandle, + pHashData, + pOptimisedHwBlockBaseInDRAM, + hashOffsetInConstantsTable, + nextSlice, + pSessionDesc->qatHashMode, + CPA_TRUE, + CPA_TRUE, + CPA_FALSE, + pPrecomputeDataOptimisedCd, + &sizeInBytes); + + *pOptimisedHwBlockOffsetInDRAM += sizeInBytes; + } else if (pSessionDesc->useSymConstantsTable) { + /* Need to build up the alternative CD for SHRAM Constants Table + * use */ + LacSymQat_HashContentDescInit(&(pSessionDesc->shramReqCacheFtr), + instanceHandle, + pHashData, + pHwBlockBaseInDRAM, + hashOffsetInConstantsTable, + nextSlice, + pSessionDesc->qatHashMode, + CPA_TRUE, + CPA_FALSE, + CPA_FALSE, + pPrecomputeData, + &sizeInBytes); + } +} + +static Cpa16U +LacAlgChain_GetCipherConfigSize(lac_session_desc_t *pSessionDesc) +{ + if (ICP_QAT_FW_LA_USE_UCS_SLICE_TYPE == pSessionDesc->cipherSliceType) { + return sizeof(icp_qat_hw_ucs_cipher_config_t); + } else { + return sizeof(icp_qat_hw_cipher_config_t); + } +} + +static Cpa16U +LacAlgChain_GetCipherConfigOffset(lac_session_desc_t *pSessionDesc) +{ + Cpa16U offset = 0; + + if (CPA_CY_SYM_OP_ALGORITHM_CHAINING == pSessionDesc->symOperation || + SPC == pSessionDesc->singlePassState) { + icp_qat_fw_cipher_auth_cd_ctrl_hdr_t *cd_ctrl = + (icp_qat_fw_cipher_auth_cd_ctrl_hdr_t *)&pSessionDesc + ->reqCacheFtr.cd_ctrl; + offset = cd_ctrl->cipher_cfg_offset; + } else if (CPA_CY_SYM_OP_CIPHER == pSessionDesc->symOperation) { + icp_qat_fw_cipher_cd_ctrl_hdr_t *cd_ctrl = + (icp_qat_fw_cipher_cd_ctrl_hdr_t *)&pSessionDesc + ->reqCacheFtr.cd_ctrl; + offset = cd_ctrl->cipher_cfg_offset; + } + + return offset * LAC_QUAD_WORD_IN_BYTES; } CpaStatus @@ -298,7 +449,7 @@ req_params->u2.aad_sz = LAC_ALIGN_POW2_ROUNDUP(newAADLength, LAC_HASH_AES_GCM_BLOCK_SIZE); - if (CPA_TRUE == pSessionDesc->isSinglePass) { + if (SPC == pSessionDesc->singlePassState) { Cpa8U *pHwBlockBaseInDRAM = NULL; Cpa32U hwBlockOffsetInDRAM = 0; Cpa32U pSizeInBytes = 0; @@ -310,10 +461,10 @@ CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT) { if (LAC_CIPHER_IS_GCM(cipher)) { hwBlockOffsetInDRAM = LAC_QUADWORDS_TO_BYTES( - LAC_SYM_QAT_CIPHER_OFFSET_IN_DRAM_GCM_SPC); + LAC_SYM_QAT_CIPHER_GCM_SPC_OFFSET_IN_DRAM); } else { hwBlockOffsetInDRAM = LAC_QUADWORDS_TO_BYTES( - LAC_SYM_QAT_CIPHER_OFFSET_IN_DRAM_CHACHA_SPC); + LAC_SYM_QAT_CIPHER_CHACHA_SPC_OFFSET_IN_DRAM); } } LacSymQat_CipherHwBlockPopulateCfgData(pSessionDesc, @@ -343,6 +494,8 @@ CpaCySymCipherSetupData cipherSetupData = { 0 }; Cpa32U sizeInBytes; Cpa8U *pCipherKeyField; + Cpa16U cipherConfigSize; + Cpa16U cipherConfigOffset; sal_qat_content_desc_info_t *pCdInfo = &(pSessionDesc->contentDescInfo); @@ -350,15 +503,23 @@ cipherSetupData.cipherKeyLenInBytes = pSessionDesc->cipherKeyLenInBytes; cipherSetupData.pCipherKey = pCipherKey; + cipherSetupData.cipherDirection = pSessionDesc->cipherDirection; + + cipherConfigSize = + LacAlgChain_GetCipherConfigSize(pSessionDesc); + cipherConfigOffset = + LacAlgChain_GetCipherConfigOffset(pSessionDesc); + + pCipherKeyField = (Cpa8U *)pCdInfo->pData + cipherConfigOffset + + cipherConfigSize; switch (pSessionDesc->symOperation) { case CPA_CY_SYM_OP_CIPHER: { - pCipherKeyField = (Cpa8U *)pCdInfo->pData + - sizeof(icp_qat_hw_cipher_config_t); - LacSymQat_CipherHwBlockPopulateKeySetup( + pSessionDesc, &(cipherSetupData), cipherSetupData.cipherKeyLenInBytes, + pSessionDesc->cipherSliceType, pCipherKeyField, &sizeInBytes); @@ -368,26 +529,21 @@ .serv_specif_fields); LacSymQat_CipherHwBlockPopulateKeySetup( + pSessionDesc, &(cipherSetupData), cipherSetupData.cipherKeyLenInBytes, + pSessionDesc->cipherSliceType, pCipherKeyField, &sizeInBytes); } } break; case CPA_CY_SYM_OP_ALGORITHM_CHAINING: { - icp_qat_fw_cipher_auth_cd_ctrl_hdr_t *cd_ctrl = - (icp_qat_fw_cipher_auth_cd_ctrl_hdr_t - *)&pSessionDesc->reqCacheFtr.cd_ctrl; - - pCipherKeyField = (Cpa8U *)pCdInfo->pData + - cd_ctrl->cipher_cfg_offset * - LAC_QUAD_WORD_IN_BYTES + - sizeof(icp_qat_hw_cipher_config_t); - LacSymQat_CipherHwBlockPopulateKeySetup( + pSessionDesc, &(cipherSetupData), cipherSetupData.cipherKeyLenInBytes, + pSessionDesc->cipherSliceType, pCipherKeyField, &sizeInBytes); } break; @@ -411,10 +567,13 @@ Cpa8U *pInnerState1 = NULL; Cpa8U *pInnerState2 = NULL; CpaCySymSessionSetupData sessionSetup = { 0 }; + Cpa16U cipherConfigSize; if (pSessionDesc == NULL || pAuthKey == NULL) return CPA_STATUS_FAIL; + cipherConfigSize = LacAlgChain_GetCipherConfigSize(pSessionDesc); + icp_qat_fw_cipher_auth_cd_ctrl_hdr_t *cd_ctrl = (icp_qat_fw_cipher_auth_cd_ctrl_hdr_t *)&pSessionDesc->reqCacheFtr .cd_ctrl; @@ -448,30 +607,28 @@ /* Calculate offset of cipher key */ if (pSessionDesc->laCmdId == ICP_QAT_FW_LA_CMD_CIPHER_HASH) { sessionSetup.cipherSetupData.pCipherKey = - (Cpa8U *)pHwBlockBaseInDRAM + - sizeof(icp_qat_hw_cipher_config_t); + (Cpa8U *)pHwBlockBaseInDRAM + cipherConfigSize; } else if (pSessionDesc->laCmdId == ICP_QAT_FW_LA_CMD_HASH_CIPHER) { sessionSetup.cipherSetupData.pCipherKey = - pOutHashSetup + sizeof(icp_qat_hw_cipher_config_t); - } else if (CPA_TRUE == pSessionDesc->isSinglePass) { + pOutHashSetup + cipherConfigSize; + } else if (SPC == pSessionDesc->singlePassState) { CpaCySymCipherAlgorithm cipher = pSessionDesc->cipherAlgorithm; Cpa32U hwBlockOffsetInDRAM = 0; if (pSessionDesc->cipherDirection == CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT) { sessionSetup.cipherSetupData.pCipherKey = - (Cpa8U *)pHwBlockBaseInDRAM + - sizeof(icp_qat_hw_cipher_config_t); + (Cpa8U *)pHwBlockBaseInDRAM + cipherConfigSize; } else { if (LAC_CIPHER_IS_GCM(cipher)) hwBlockOffsetInDRAM = LAC_QUADWORDS_TO_BYTES( - LAC_SYM_QAT_CIPHER_OFFSET_IN_DRAM_GCM_SPC); + LAC_SYM_QAT_CIPHER_GCM_SPC_OFFSET_IN_DRAM); else hwBlockOffsetInDRAM = LAC_QUADWORDS_TO_BYTES( - LAC_SYM_QAT_CIPHER_OFFSET_IN_DRAM_CHACHA_SPC); + LAC_SYM_QAT_CIPHER_CHACHA_SPC_OFFSET_IN_DRAM); sessionSetup.cipherSetupData.pCipherKey = (Cpa8U *)pHwBlockBaseInDRAM + hwBlockOffsetInDRAM + - sizeof(icp_qat_hw_cipher_config_t); + cipherConfigSize; } } @@ -497,8 +654,7 @@ /* SHRAM Constants Table not used for Auth-Enc */ } } else if (CPA_CY_SYM_HASH_SNOW3G_UIA2 == pSessionDesc->hashAlgorithm) { - Cpa8U *authKey = - (Cpa8U *)pOutHashSetup + sizeof(icp_qat_hw_cipher_config_t); + Cpa8U *authKey = (Cpa8U *)pOutHashSetup + cipherConfigSize; memcpy(authKey, pAuthKey, pSessionDesc->authKeyLenInBytes); } else if (CPA_CY_SYM_HASH_ZUC_EIA3 == pSessionDesc->hashAlgorithm || CPA_CY_SYM_HASH_AES_CBC_MAC == pSessionDesc->hashAlgorithm) { @@ -526,6 +682,247 @@ return status; } +static void +buildCmdData(sal_crypto_service_t *pService, + lac_session_desc_t *pSessionDesc, + CpaCySymAlgChainOrder *chainOrder, + Cpa16U *proto, + icp_qat_fw_serv_specif_flags *laCmdFlags, + icp_qat_fw_comn_flags *cmnRequestFlags) +{ + /* LW 28 is used to set hash flags for AlgChaining. */ + icp_qat_fw_cipher_auth_cd_ctrl_hdr_t *cd_ctrl = + (icp_qat_fw_cipher_auth_cd_ctrl_hdr_t *)&pSessionDesc->reqCacheFtr + .cd_ctrl; + + /* proto refers to Protocol Flags, which is legacy FW <=> IA interface + * for ZUC and Snow3G. Use extended protocol flags for AlgChaining. + */ + *proto = ICP_QAT_FW_LA_NO_PROTO; /* no CCM/GCM/Snow3G */ + + switch (pSessionDesc->symOperation) { + case CPA_CY_SYM_OP_CIPHER: + pSessionDesc->laCmdId = ICP_QAT_FW_LA_CMD_CIPHER; + + if (CPA_CY_SYM_CIPHER_SNOW3G_UEA2 == + pSessionDesc->cipherAlgorithm) { + *proto = ICP_QAT_FW_LA_SNOW_3G_PROTO; + } else if (CPA_CY_SYM_CIPHER_ZUC_EEA3 == + pSessionDesc->cipherAlgorithm) { + *proto = ICP_QAT_FW_LA_ZUC_3G_PROTO; + } + if (LAC_CIPHER_IS_CCM(pSessionDesc->cipherAlgorithm)) { + *proto = ICP_QAT_FW_LA_CCM_PROTO; + } + break; + + case CPA_CY_SYM_OP_HASH: + pSessionDesc->laCmdId = ICP_QAT_FW_LA_CMD_AUTH; + if (CPA_CY_SYM_HASH_SNOW3G_UIA2 == + pSessionDesc->hashAlgorithm) { + *proto = ICP_QAT_FW_LA_SNOW_3G_PROTO; + } else if (CPA_CY_SYM_HASH_ZUC_EIA3 == + pSessionDesc->hashAlgorithm) { + *proto = ICP_QAT_FW_LA_ZUC_3G_PROTO; + } + break; + + case CPA_CY_SYM_OP_ALGORITHM_CHAINING: + if (LAC_CIPHER_IS_CCM(pSessionDesc->cipherAlgorithm)) { + *proto = ICP_QAT_FW_LA_CCM_PROTO; + + /* Derive chainOrder from direction for isAuthEncryptOp + * cases */ + /* For CCM & GCM modes: force digest verify flag _TRUE + for decrypt and _FALSE for encrypt. For all other + cases use user defined value */ + + if (CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT == + pSessionDesc->cipherDirection) { + *chainOrder = + CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER; + pSessionDesc->digestVerify = CPA_FALSE; + } else { + *chainOrder = + CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH; + if (CPA_TRUE == pService->forceAEADMacVerify) { + pSessionDesc->digestVerify = CPA_TRUE; + } + } + } else if (LAC_CIPHER_IS_GCM(pSessionDesc->cipherAlgorithm)) { + *proto = ICP_QAT_FW_LA_GCM_PROTO; + + /* Derive chainOrder from direction for isAuthEncryptOp + * cases */ + /* For CCM & GCM modes: force digest verify flag _TRUE + for decrypt and _FALSE for encrypt. For all other + cases use user defined value */ + + if (CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT == + pSessionDesc->cipherDirection) { + *chainOrder = + CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH; + pSessionDesc->digestVerify = CPA_FALSE; + } else { + *chainOrder = + CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER; + if (CPA_TRUE == pService->forceAEADMacVerify) { + pSessionDesc->digestVerify = CPA_TRUE; + } + } + } else if (LAC_CIPHER_IS_CHACHA( + pSessionDesc->cipherAlgorithm)) { + if (CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT == + pSessionDesc->cipherDirection) { + *chainOrder = + CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH; + } else { + *chainOrder = + CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER; + } + } else { + pSessionDesc->isAuthEncryptOp = CPA_FALSE; + + if (CPA_CY_SYM_CIPHER_SNOW3G_UEA2 == + pSessionDesc->cipherAlgorithm) { + *proto = ICP_QAT_FW_LA_SNOW_3G_PROTO; + } else if (CPA_CY_SYM_CIPHER_ZUC_EEA3 == + pSessionDesc->cipherAlgorithm) { + *proto = ICP_QAT_FW_LA_ZUC_3G_PROTO; + } + + if (CPA_CY_SYM_HASH_SNOW3G_UIA2 == + pSessionDesc->hashAlgorithm) { + /* Need to set LW 28 hash flags as well. */ + ICP_QAT_FW_HASH_FLAG_SNOW3G_UIA2_SET( + cd_ctrl->hash_flags, QAT_FW_LA_SNOW3G_UIA2); + } else if (CPA_CY_SYM_HASH_ZUC_EIA3 == + pSessionDesc->hashAlgorithm) { + /* Need to set LW 28 hash flags as well. */ + ICP_QAT_FW_HASH_FLAG_ZUC_EIA3_SET( + cd_ctrl->hash_flags, QAT_FW_LA_ZUC_EIA3); + } + } + + if (CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH == + *chainOrder) { + pSessionDesc->laCmdId = ICP_QAT_FW_LA_CMD_CIPHER_HASH; + } else if (CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER == + *chainOrder) { + pSessionDesc->laCmdId = ICP_QAT_FW_LA_CMD_HASH_CIPHER; + } + break; + + default: + break; + } + + /* + * Build the header flags with the default settings for this session. + */ + if (pSessionDesc->isDPSession == CPA_TRUE) { + *cmnRequestFlags = + ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_CD_FLD_TYPE_64BIT_ADR, + LAC_SYM_DP_QAT_PTR_TYPE); + } else { + *cmnRequestFlags = + ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_CD_FLD_TYPE_64BIT_ADR, + LAC_SYM_DEFAULT_QAT_PTR_TYPE); + } + + LacSymQat_LaSetDefaultFlags(laCmdFlags, pSessionDesc->symOperation); + + return; +} + +static void +updateLaCmdFlags(lac_session_desc_t *pSessionDesc, + Cpa16U proto, + icp_qat_fw_serv_specif_flags *laCmdFlags) +{ + if (pSessionDesc->isAuth) { + if (pSessionDesc->digestVerify) { + ICP_QAT_FW_LA_CMP_AUTH_SET(*laCmdFlags, + ICP_QAT_FW_LA_CMP_AUTH_RES); + ICP_QAT_FW_LA_RET_AUTH_SET( + *laCmdFlags, ICP_QAT_FW_LA_NO_RET_AUTH_RES); + } else { + ICP_QAT_FW_LA_RET_AUTH_SET(*laCmdFlags, + ICP_QAT_FW_LA_RET_AUTH_RES); + ICP_QAT_FW_LA_CMP_AUTH_SET( + *laCmdFlags, ICP_QAT_FW_LA_NO_CMP_AUTH_RES); + } + } + + if ((CPA_CY_SYM_CIPHER_ZUC_EEA3 == pSessionDesc->cipherAlgorithm) || + (CPA_CY_SYM_HASH_ZUC_EIA3 == pSessionDesc->hashAlgorithm)) { + /* New bit position (12) for ZUC. The FW provides a specific + * macro to use to set the ZUC proto flag. With the new FW I/F + * this needs to be set for both Cipher and Auth */ + ICP_QAT_FW_LA_ZUC_3G_PROTO_FLAG_SET(*laCmdFlags, proto); + } else { + /* Configure the common header */ + ICP_QAT_FW_LA_PROTO_SET(*laCmdFlags, proto); + } + + /* set Append flag, if digest is appended */ + if (pSessionDesc->digestIsAppended) { + ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET( + *laCmdFlags, ICP_QAT_FW_LA_DIGEST_IN_BUFFER); + } else { + ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET( + *laCmdFlags, ICP_QAT_FW_LA_NO_DIGEST_IN_BUFFER); + } +} + +static lac_single_pass_state_t +LacSymAlgChain_GetSpcState(CpaCySymCipherAlgorithm cipher, + CpaCySymHashAlgorithm hash, + Cpa32U capabilitiesMask) +{ + lac_single_pass_state_t state = NON_SPC; + if (capabilitiesMask & ICP_ACCEL_CAPABILITIES_CHACHA_POLY) { + switch (cipher) { + case CPA_CY_SYM_CIPHER_CHACHA: { + if (CPA_CY_SYM_HASH_POLY == hash) + state = SPC; + break; + } + case CPA_CY_SYM_CIPHER_AES_GCM: { + if ((CPA_CY_SYM_HASH_AES_GCM == hash) || + (CPA_CY_SYM_HASH_AES_GMAC == hash)) + state = LIKELY_SPC; + break; + } + case CPA_CY_SYM_CIPHER_AES_CCM: { + if (LAC_CIPHER_AES_V2(capabilitiesMask)) + state = SPC; + } + default: + /* Do Nothing as it is NON_SPC */ + break; + } + } + return state; +} + +static CpaBoolean +LacAlgChain_UseStatefulSha3ContentDesc(CpaBoolean partialsNotRequired, + Cpa32U capabilitiesMask, + lac_session_desc_t *pSessionDesc) +{ + CpaBoolean hasSha3Ext = + ICP_ACCEL_CAPABILITIES_SHA3_EXT & capabilitiesMask; + CpaBoolean useStatefulSha3DescFlag = CPA_FALSE; + + if (hasSha3Ext && !partialsNotRequired && + (pSessionDesc->symOperation == CPA_CY_SYM_OP_HASH) && + LAC_HASH_IS_SHA3(pSessionDesc->hashAlgorithm)) { + useStatefulSha3DescFlag = CPA_TRUE; + } + return useStatefulSha3DescFlag; +} + /** @ingroup LacAlgChain */ CpaStatus LacAlgChain_SessionInit(const CpaInstanceHandle instanceHandle, @@ -534,6 +931,7 @@ { CpaStatus stat, status = CPA_STATUS_SUCCESS; sal_qat_content_desc_info_t *pCdInfo = NULL; + sal_qat_content_desc_info_t *pCdInfoOptimised = NULL; sal_crypto_service_t *pService = (sal_crypto_service_t *)instanceHandle; Cpa32U capabilitiesMask = pService->generic_service_info.capabilitiesMask; @@ -543,7 +941,9 @@ Cpa32U optimisedHwBlockOffsetInDRAM = 0; Cpa8U cipherOffsetInConstantsTable = 0; Cpa8U hashOffsetInConstantsTable = 0; + icp_qat_fw_comn_flags cmnRequestFlags = 0; icp_qat_fw_comn_req_t *pMsg = NULL; + icp_qat_fw_comn_req_t *pMsgS = NULL; const CpaCySymCipherSetupData *pCipherData; const CpaCySymHashSetupData *pHashData; Cpa16U proto = ICP_QAT_FW_LA_NO_PROTO; /* no CCM/GCM/Snow3G */ @@ -584,147 +984,58 @@ pSessionDesc->symOperation = pSessionSetupData->symOperation; switch (pSessionDesc->symOperation) { case CPA_CY_SYM_OP_CIPHER: - pSessionDesc->laCmdId = ICP_QAT_FW_LA_CMD_CIPHER; - pSessionDesc->isCipher = TRUE; - pSessionDesc->isAuth = FALSE; + pSessionDesc->isCipher = CPA_TRUE; + pSessionDesc->isAuth = CPA_FALSE; pSessionDesc->isAuthEncryptOp = CPA_FALSE; - - if (CPA_CY_SYM_CIPHER_SNOW3G_UEA2 == - pSessionSetupData->cipherSetupData.cipherAlgorithm) { - proto = ICP_QAT_FW_LA_SNOW_3G_PROTO; - } else if (CPA_CY_SYM_CIPHER_ZUC_EEA3 == - pSessionSetupData->cipherSetupData.cipherAlgorithm) { - proto = ICP_QAT_FW_LA_ZUC_3G_PROTO; - } + pSessionDesc->singlePassState = NON_SPC; break; case CPA_CY_SYM_OP_HASH: - pSessionDesc->laCmdId = ICP_QAT_FW_LA_CMD_AUTH; - pSessionDesc->isCipher = FALSE; - pSessionDesc->isAuth = TRUE; + pSessionDesc->isCipher = CPA_FALSE; + pSessionDesc->isAuth = CPA_TRUE; pSessionDesc->isAuthEncryptOp = CPA_FALSE; - - if (CPA_CY_SYM_HASH_SNOW3G_UIA2 == - pSessionSetupData->hashSetupData.hashAlgorithm) { - proto = ICP_QAT_FW_LA_SNOW_3G_PROTO; - } else if (CPA_CY_SYM_HASH_ZUC_EIA3 == - pSessionSetupData->hashSetupData.hashAlgorithm) { - proto = ICP_QAT_FW_LA_ZUC_3G_PROTO; - } - + pSessionDesc->singlePassState = NON_SPC; break; - case CPA_CY_SYM_OP_ALGORITHM_CHAINING: - pSessionDesc->isCipher = TRUE; - pSessionDesc->isAuth = TRUE; - - { - /* set up some useful shortcuts */ - CpaCySymCipherAlgorithm cipherAlgorithm = - pSessionSetupData->cipherSetupData.cipherAlgorithm; - CpaCySymCipherDirection cipherDir = - pSessionSetupData->cipherSetupData.cipherDirection; - - if (LAC_CIPHER_IS_CCM(cipherAlgorithm)) { - pSessionDesc->isAuthEncryptOp = CPA_TRUE; - pSessionDesc->digestIsAppended = CPA_TRUE; - proto = ICP_QAT_FW_LA_CCM_PROTO; - - /* Derive chainOrder from direction for - * isAuthEncryptOp - * cases */ - /* For CCM & GCM modes: force digest verify flag - _TRUE - for decrypt and _FALSE for encrypt. For all - other cases - use user defined value */ - - if (CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT == - cipherDir) { - chainOrder = - CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER; - pSessionDesc->digestVerify = CPA_FALSE; - } else { - chainOrder = - CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH; - pSessionDesc->digestVerify = CPA_TRUE; - } - } else if (LAC_CIPHER_IS_GCM(cipherAlgorithm)) { - pSessionDesc->isAuthEncryptOp = CPA_TRUE; - proto = ICP_QAT_FW_LA_GCM_PROTO; - - /* Derive chainOrder from direction for - * isAuthEncryptOp - * cases */ - /* For CCM & GCM modes: force digest verify flag - _TRUE - for decrypt and _FALSE for encrypt. For all - other cases - use user defined value */ - - if (CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT == - cipherDir) { - chainOrder = - CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH; - pSessionDesc->digestVerify = CPA_FALSE; - } else { - chainOrder = - CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER; - pSessionDesc->digestVerify = CPA_TRUE; - } - } else if (LAC_CIPHER_IS_CHACHA(cipherAlgorithm)) { - pSessionDesc->isAuthEncryptOp = CPA_TRUE; - proto = ICP_QAT_FW_LA_SINGLE_PASS_PROTO; - - if (CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT == - cipherDir) { - chainOrder = - CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH; - } else { - chainOrder = - CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER; - } - } else { - pSessionDesc->isAuthEncryptOp = CPA_FALSE; - /* Use the chainOrder passed in */ - chainOrder = pSessionSetupData->algChainOrder; - if ((chainOrder != - CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER) && - (chainOrder != - CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH)) { - LAC_INVALID_PARAM_LOG("algChainOrder"); - return CPA_STATUS_INVALID_PARAM; - } - - if (CPA_CY_SYM_HASH_SNOW3G_UIA2 == - pSessionSetupData->hashSetupData - .hashAlgorithm) { - proto = ICP_QAT_FW_LA_SNOW_3G_PROTO; - } else if (CPA_CY_SYM_HASH_ZUC_EIA3 == - pSessionSetupData->hashSetupData - .hashAlgorithm) { - proto = ICP_QAT_FW_LA_ZUC_3G_PROTO; - } - } - - if (CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH == - chainOrder) { - pSessionDesc->laCmdId = - ICP_QAT_FW_LA_CMD_CIPHER_HASH; - } else if ( - CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER == - chainOrder) { - pSessionDesc->laCmdId = - ICP_QAT_FW_LA_CMD_HASH_CIPHER; + case CPA_CY_SYM_OP_ALGORITHM_CHAINING: { + pSessionDesc->isCipher = CPA_TRUE; + pSessionDesc->isAuth = CPA_TRUE; + pSessionDesc->singlePassState = + LacSymAlgChain_GetSpcState(pCipherData->cipherAlgorithm, + pHashData->hashAlgorithm, + capabilitiesMask); + + switch (pSessionSetupData->cipherSetupData.cipherAlgorithm) { + case CPA_CY_SYM_CIPHER_AES_CCM: { + pSessionDesc->isAuthEncryptOp = CPA_TRUE; + pSessionDesc->digestIsAppended = CPA_TRUE; + } break; + case CPA_CY_SYM_CIPHER_AES_GCM: + case CPA_CY_SYM_CIPHER_CHACHA: + pSessionDesc->isAuthEncryptOp = CPA_TRUE; + break; + default: { + pSessionDesc->isAuthEncryptOp = CPA_FALSE; + /* Use the chainOrder passed in */ + chainOrder = pSessionSetupData->algChainOrder; + if ((chainOrder != + CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER) && + (chainOrder != + CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH)) { + LAC_INVALID_PARAM_LOG("algChainOrder"); + return CPA_STATUS_INVALID_PARAM; } + } break; } - break; + } break; default: + pSessionDesc->singlePassState = NON_SPC; break; } if (pSessionDesc->isCipher) { -/* Populate cipher specific session data */ + /* Populate cipher specific session data */ - status = LacCipher_SessionSetupDataCheck(pCipherData); + status = LacCipher_SessionSetupDataCheck(pCipherData, + capabilitiesMask); if (CPA_STATUS_SUCCESS == status) { pSessionDesc->cipherAlgorithm = @@ -735,16 +1046,12 @@ pCipherData->cipherDirection; /* ARC4 base key isn't added to the content descriptor, - * because - * we don't need to pass it directly to the QAT engine. - * Instead - * an initial cipher state & key matrix is derived from - * the - * base key and provided to the QAT through the state - * pointer - * in the request params. We'll store this initial state - * in - * the session descriptor. */ + * because we don't need to pass it directly to the QAT + * engine. Instead an initial cipher state & key matrix + * is derived from the base key and provided to the QAT + * through the state pointer in the request params. + * We'll store this initial state in the session + * descriptor. */ if (LAC_CIPHER_IS_ARC4(pSessionDesc->cipherAlgorithm)) { LacSymQat_CipherArc4StateInit( @@ -809,27 +1116,20 @@ ICP_QAT_HW_AUTH_MODE0; } else /* CPA_CY_SYM_HASH_MODE_AUTH && anything except CPA_CY_SYM_HASH_AES_CBC_MAC - */ + */ { if (IS_HMAC_ALG(pHashData->hashAlgorithm)) { - /* SHA3 and SM3 HMAC do not support - * precompute, force MODE2 - * for AUTH */ - if ((CPA_CY_SYM_HASH_SHA3_224 == - pHashData->hashAlgorithm) || - (CPA_CY_SYM_HASH_SHA3_256 == - pHashData->hashAlgorithm) || - (CPA_CY_SYM_HASH_SHA3_384 == - pHashData->hashAlgorithm) || - (CPA_CY_SYM_HASH_SHA3_512 == - pHashData->hashAlgorithm) || + /* SHA3 HMAC and SM3 do not support + * precompute, force MODE2 for AUTH */ + if (LAC_HASH_IS_SHA3( + pHashData->hashAlgorithm) || (CPA_CY_SYM_HASH_SM3 == pHashData->hashAlgorithm)) { pSessionDesc->qatHashMode = ICP_QAT_HW_AUTH_MODE2; } else { pSessionDesc->qatHashMode = - ICP_QAT_HW_AUTH_MODE1; + pService->qatHmacMode; } } else if (CPA_CY_SYM_HASH_ZUC_EIA3 == pHashData->hashAlgorithm) { @@ -847,39 +1147,71 @@ * build the message templates * create two content descriptors in the case we can support using SHRAM * constants and an optimised content descriptor. we have to do this in - *case - * of partials. - * 64 byte content desciptor is used in the SHRAM case for - *AES-128-HMAC-SHA1 + *case of partials. 64 byte content desciptor is used in the SHRAM case + *for AES-128-HMAC-SHA1 *-----------------------------------------------------------------------*/ if (CPA_STATUS_SUCCESS == status) { + pSessionDesc->cipherSliceType = + LacCipher_GetCipherSliceType(pService, + pSessionDesc->cipherAlgorithm, + pSessionDesc->hashAlgorithm); LacSymCheck_IsPartialSupported(capabilitiesMask, pSessionDesc); + pSessionDesc->useOptimisedContentDesc = CPA_FALSE; + pSessionDesc->useStatefulSha3ContentDesc = CPA_FALSE; + + /* Build configuration data */ + buildCmdData(pService, + pSessionDesc, + &chainOrder, + &proto, + &pSessionDesc->laCmdFlags, + &cmnRequestFlags); + + if (ICP_QAT_FW_LA_USE_UCS_SLICE_TYPE == + pSessionDesc->cipherSliceType) + pSessionDesc->useSymConstantsTable = CPA_FALSE; + else + pSessionDesc->useSymConstantsTable = + LacSymQat_UseSymConstantsTable( + pSessionDesc, + &cipherOffsetInConstantsTable, + &hashOffsetInConstantsTable); + + /* for a certain combination of Algorthm Chaining we want to + use an optimised cd block */ + + if (pSessionDesc->symOperation == + CPA_CY_SYM_OP_ALGORITHM_CHAINING && + pSessionDesc->useSymConstantsTable == CPA_TRUE) { + pSessionDesc->useOptimisedContentDesc = + LacSymQat_UseOptimisedContentDesc(pSessionDesc); + } + + /* check whether we need to construct content desc for stateful + * SHA3 */ + pSessionDesc->useStatefulSha3ContentDesc = + LacAlgChain_UseStatefulSha3ContentDesc( + pSessionSetupData->partialsNotRequired, + capabilitiesMask, + pSessionDesc); /* setup some convenience pointers */ pCdInfo = &(pSessionDesc->contentDescInfo); pHwBlockBaseInDRAM = (Cpa8U *)pCdInfo->pData; hwBlockOffsetInDRAM = 0; - /* - * Build the header flags with the default settings for this - * session. - */ - if (pSessionDesc->isDPSession == CPA_TRUE) { - pSessionDesc->cmnRequestFlags = - ICP_QAT_FW_COMN_FLAGS_BUILD( - QAT_COMN_CD_FLD_TYPE_64BIT_ADR, - LAC_SYM_DP_QAT_PTR_TYPE); - } else { - pSessionDesc->cmnRequestFlags = - ICP_QAT_FW_COMN_FLAGS_BUILD( - QAT_COMN_CD_FLD_TYPE_64BIT_ADR, - LAC_SYM_DEFAULT_QAT_PTR_TYPE); + /* set up the pointer for the optimised content desc if this is + * possible we still have to support both cd types in case of + * partials so we construct both */ + if (pSessionDesc->useOptimisedContentDesc == CPA_TRUE) { + pCdInfoOptimised = + &(pSessionDesc->contentDescOptimisedInfo); + pOptimisedHwBlockBaseInDRAM = + (Cpa8U *)pCdInfoOptimised->pData; + optimisedHwBlockOffsetInDRAM = 0; } - LacSymQat_LaSetDefaultFlags(&pSessionDesc->laCmdFlags, - pSessionDesc->symOperation); - switch (pSessionDesc->symOperation) { case CPA_CY_SYM_OP_CIPHER: { LacAlgChain_CipherCDBuild( @@ -890,13 +1222,22 @@ &pSessionDesc->cmnRequestFlags, &pSessionDesc->laCmdFlags, pHwBlockBaseInDRAM, - &hwBlockOffsetInDRAM); + &hwBlockOffsetInDRAM, + capabilitiesMask); + + if (pSessionDesc->useSymConstantsTable) { + LacAlgChain_CipherCDBuild_ForSHRAM( + pCipherData, + pSessionDesc, + ICP_QAT_FW_SLICE_DRAM_WR, + cipherOffsetInConstantsTable); + } } break; case CPA_CY_SYM_OP_HASH: LacAlgChain_HashCDBuild(pHashData, instanceHandle, pSessionDesc, - ICP_QAT_FW_SLICE_DRAM_WR, + ICP_QAT_FW_SLICE_NULL, hashOffsetInConstantsTable, &pSessionDesc->cmnRequestFlags, &pSessionDesc->laCmdFlags, @@ -909,14 +1250,10 @@ break; case CPA_CY_SYM_OP_ALGORITHM_CHAINING: /* For CCM/GCM, CPM firmware currently expects the - * cipher and - * hash h/w setup blocks to be arranged according to the - * chain - * order (Except for GCM/CCM, order doesn't actually - * matter as - * long as the config offsets are set correctly in CD - * control - * blocks + * cipher and hash h/w setup blocks to be arranged + * according to the chain order (Except for GCM/CCM, + * order doesn't actually matter as long as the config + * offsets are set correctly in CD control blocks */ if (CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER == chainOrder) { @@ -943,11 +1280,20 @@ &pSessionDesc->cmnRequestFlags, &pSessionDesc->laCmdFlags, pHwBlockBaseInDRAM, - &hwBlockOffsetInDRAM); - if (LAC_CIPHER_IS_SPC( - pCipherData->cipherAlgorithm, - pHashData->hashAlgorithm, - capabilitiesMask)) { + &hwBlockOffsetInDRAM, + capabilitiesMask); + + if (pSessionDesc->useOptimisedContentDesc) { + LacAlgChain_CipherCDBuild_ForOptimisedCD( + pCipherData, + pSessionDesc, + ICP_QAT_FW_SLICE_DRAM_WR, + cipherOffsetInConstantsTable, + pOptimisedHwBlockBaseInDRAM, + &optimisedHwBlockOffsetInDRAM); + } + + if (NON_SPC != pSessionDesc->singlePassState) { pCdInfo->hwBlkSzQuadWords = (LAC_BYTES_TO_QUADWORDS( hwBlockOffsetInDRAM)); @@ -957,7 +1303,8 @@ (icp_qat_fw_comn_req_t *)pMsg, pCdInfo); } - } else { + } else /* CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH */ + { LacAlgChain_CipherCDBuild( pCipherData, pSessionDesc, @@ -966,12 +1313,20 @@ &pSessionDesc->cmnRequestFlags, &pSessionDesc->laCmdFlags, pHwBlockBaseInDRAM, - &hwBlockOffsetInDRAM); + &hwBlockOffsetInDRAM, + capabilitiesMask); + + if (pSessionDesc->useOptimisedContentDesc) { + LacAlgChain_CipherCDBuild_ForOptimisedCD( + pCipherData, + pSessionDesc, + ICP_QAT_FW_SLICE_AUTH, + cipherOffsetInConstantsTable, + pOptimisedHwBlockBaseInDRAM, + &optimisedHwBlockOffsetInDRAM); + } - if (LAC_CIPHER_IS_SPC( - pCipherData->cipherAlgorithm, - pHashData->hashAlgorithm, - capabilitiesMask)) { + if (NON_SPC != pSessionDesc->singlePassState) { pCdInfo->hwBlkSzQuadWords = LAC_BYTES_TO_QUADWORDS( hwBlockOffsetInDRAM); @@ -1009,8 +1364,7 @@ CpaBoolean hashStateBuffer = CPA_TRUE; /* set up fields in both the cd_ctrl and reqParams which - * describe - * the ReqParams block */ + * describe the ReqParams block */ LacSymQat_HashSetupReqParamsMetaData( &(pSessionDesc->reqCacheFtr), instanceHandle, @@ -1019,6 +1373,17 @@ pSessionDesc->qatHashMode, pSessionDesc->digestVerify); + if (pSessionDesc->useSymConstantsTable) { + /* Need to set up for SHRAM Constants Table use also */ + LacSymQat_HashSetupReqParamsMetaData( + &(pSessionDesc->shramReqCacheFtr), + instanceHandle, + pHashData, + hashStateBuffer, + pSessionDesc->qatHashMode, + pSessionDesc->digestVerify); + } + /* populate the hash state prefix buffer info structure * (part of user allocated session memory & the * buffer itself. For CCM/GCM the buffer is stored in the @@ -1056,86 +1421,122 @@ pSessionDesc->hashStatePrefixBuffer, precomputeData.pState1, precomputeData.pState2); + if (pSessionDesc->useOptimisedContentDesc) { + status = LacHash_PrecomputeDataCreate( + instanceHandle, + (CpaCySymSessionSetupData *) + pSessionSetupData, + LacSymAlgChain_HashPrecomputeDoneCb, + pSessionDesc, + pSessionDesc->hashStatePrefixBuffer, + precomputeDataOptimisedCd.pState1, + precomputeDataOptimisedCd.pState2); + } } else if (pHashData->hashAlgorithm == CPA_CY_SYM_HASH_AES_CBC_MAC) { - LAC_OS_BZERO(precomputeData.pState2, - precomputeData.state2Size); - memcpy(precomputeData.pState2, - pHashData->authModeSetupData.authKey, - pHashData->authModeSetupData - .authKeyLenInBytes); - } - } - if (CPA_STATUS_SUCCESS == status) { - - if (pSessionDesc->digestVerify) { - - ICP_QAT_FW_LA_CMP_AUTH_SET( - pSessionDesc->laCmdFlags, - ICP_QAT_FW_LA_CMP_AUTH_RES); - ICP_QAT_FW_LA_RET_AUTH_SET( - pSessionDesc->laCmdFlags, - ICP_QAT_FW_LA_NO_RET_AUTH_RES); - } else { - - ICP_QAT_FW_LA_RET_AUTH_SET( - pSessionDesc->laCmdFlags, - ICP_QAT_FW_LA_RET_AUTH_RES); - ICP_QAT_FW_LA_CMP_AUTH_SET( - pSessionDesc->laCmdFlags, - ICP_QAT_FW_LA_NO_CMP_AUTH_RES); + if (NULL != precomputeData.pState2) { + LAC_OS_BZERO(precomputeData.pState2, + precomputeData.state2Size); + memcpy(precomputeData.pState2, + pHashData->authModeSetupData + .authKey, + pHashData->authModeSetupData + .authKeyLenInBytes); + } } } } if (CPA_STATUS_SUCCESS == status) { + /* Configure the ContentDescriptor field + in the request if not done already */ pCdInfo->hwBlkSzQuadWords = LAC_BYTES_TO_QUADWORDS(hwBlockOffsetInDRAM); pMsg = (icp_qat_fw_comn_req_t *)&(pSessionDesc->reqCacheHdr); - - /* Configure the ContentDescriptor field - * in the request if not done already */ SalQatMsg_ContentDescHdrWrite((icp_qat_fw_comn_req_t *)pMsg, pCdInfo); - if (CPA_CY_SYM_CIPHER_ZUC_EEA3 == - pSessionSetupData->cipherSetupData.cipherAlgorithm || - pHashData->hashAlgorithm == CPA_CY_SYM_HASH_ZUC_EIA3) { - /* New bit position (12) for ZUC. The FW provides a - * specific macro - * to use to set the ZUC proto flag. With the new FW I/F - * this needs - * to be set for both Cipher and Auth */ - ICP_QAT_FW_LA_ZUC_3G_PROTO_FLAG_SET( - pSessionDesc->laCmdFlags, proto); - } else { - /* Configure the common header */ - ICP_QAT_FW_LA_PROTO_SET(pSessionDesc->laCmdFlags, - proto); + pMsgS = + (icp_qat_fw_comn_req_t *)&(pSessionDesc->shramReqCacheHdr); + /*If we are using the optimised CD then + we have to set this up correctly in the SHARM reqCache*/ + if (pSessionDesc->useOptimisedContentDesc) { + pCdInfoOptimised->hwBlkSzQuadWords = + LAC_BYTES_TO_QUADWORDS( + optimisedHwBlockOffsetInDRAM); + SalQatMsg_ContentDescHdrWrite( + (icp_qat_fw_comn_req_t *)pMsgS, pCdInfoOptimised); } - /* set Append flag, if digest is appended */ - if (pSessionDesc->digestIsAppended) { - ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET( - pSessionDesc->laCmdFlags, - ICP_QAT_FW_LA_DIGEST_IN_BUFFER); - } else { - ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET( - pSessionDesc->laCmdFlags, - ICP_QAT_FW_LA_NO_DIGEST_IN_BUFFER); - } + /* Updates command flags basing on configured alg */ + updateLaCmdFlags(pSessionDesc, + proto, + &pSessionDesc->laCmdFlags); SalQatMsg_CmnHdrWrite((icp_qat_fw_comn_req_t *)pMsg, ICP_QAT_FW_COMN_REQ_CPM_FW_LA, pSessionDesc->laCmdId, pSessionDesc->cmnRequestFlags, pSessionDesc->laCmdFlags); + + /* Need to duplicate if SHRAM Constants Table used */ + if (pSessionDesc->useSymConstantsTable) { + ICP_QAT_FW_LA_CIPH_AUTH_CFG_OFFSET_FLAG_SET( + pSessionDesc->laCmdFlags, + ICP_QAT_FW_CIPH_AUTH_CFG_OFFSET_IN_SHRAM_CP); + + if (pSessionDesc->isCipher && + !pSessionDesc->useOptimisedContentDesc) { + ICP_QAT_FW_COMN_CD_FLD_TYPE_SET( + cmnRequestFlags, + QAT_COMN_CD_FLD_TYPE_16BYTE_DATA); + } + + SalQatMsg_CmnHdrWrite((icp_qat_fw_comn_req_t *)pMsgS, + ICP_QAT_FW_COMN_REQ_CPM_FW_LA, + pSessionDesc->laCmdId, + cmnRequestFlags, + pSessionDesc->laCmdFlags); + } } return status; } +static void +LacAlgChain_StatefulSha3_SkipStateLoadFlags(icp_qat_fw_la_bulk_req_t *pMsg, + Cpa32U packetType, + icp_qat_hw_auth_mode_t qatHashMode) +{ + icp_qat_fw_auth_cd_ctrl_hdr_t *pAuthCdCtrlHdr = NULL; + + pAuthCdCtrlHdr = (icp_qat_fw_auth_cd_ctrl_hdr_t *)&(pMsg->cd_ctrl); + + if (IS_HASH_MODE_2(qatHashMode)) { + if ((ICP_QAT_FW_LA_PARTIAL_START == packetType) || + (ICP_QAT_FW_LA_PARTIAL_NONE == packetType)) { + ICP_QAT_FW_HASH_FLAG_SKIP_INNER_STATE1_LOAD_SET( + pAuthCdCtrlHdr->hash_flags, + QAT_FW_LA_SKIP_INNER_STATE1_LOAD); + ICP_QAT_FW_HASH_FLAG_SKIP_OUTER_STATE1_LOAD_SET( + pAuthCdCtrlHdr->hash_flags, + QAT_FW_LA_SKIP_OUTER_STATE1_LOAD); + } else if (ICP_QAT_FW_LA_PARTIAL_END == packetType) { + ICP_QAT_FW_HASH_FLAG_SKIP_OUTER_STATE1_LOAD_SET( + pAuthCdCtrlHdr->hash_flags, + QAT_FW_LA_SKIP_OUTER_STATE1_LOAD); + } + } else { + if ((ICP_QAT_FW_LA_PARTIAL_START == packetType) || + (ICP_QAT_FW_LA_PARTIAL_NONE == packetType)) { + ICP_QAT_FW_HASH_FLAG_SKIP_INNER_STATE1_LOAD_SET( + pAuthCdCtrlHdr->hash_flags, + QAT_FW_LA_SKIP_INNER_STATE1_LOAD); + } + } +} + /** @ingroup LacAlgChain */ CpaStatus LacAlgChain_Perform(const CpaInstanceHandle instanceHandle, @@ -1171,7 +1572,10 @@ CpaCySymHashAlgorithm hash; Cpa8U paddingLen = 0; Cpa8U blockLen = 0; + CpaBoolean digestIsAppended = CPA_FALSE; + Cpa32U aadLenInBytes = 0; Cpa64U srcPktSize = 0; + Cpa64U dstPktSize = 0; /* Set the command id */ laCmdId = pSessionDesc->laCmdId; @@ -1179,35 +1583,51 @@ cipher = pSessionDesc->cipherAlgorithm; hash = pSessionDesc->hashAlgorithm; + CpaBoolean isSpCcm = + (LAC_CIPHER_IS_CCM(cipher) && LAC_CIPHER_AES_V2(capabilitiesMask)); + + if (CPA_CY_SYM_HASH_AES_GMAC == hash) { + pSessionDesc->aadLenInBytes = pOpData->messageLenToHashInBytes; + if (pOpData->messageLenToHashInBytes == 0 || + pOpData->pAdditionalAuthData != NULL) { + LAC_INVALID_PARAM_LOG( + "For AES_GMAC, AAD Length " + "(messageLenToHashInBytes) must " + "be non zero and pAdditionalAuthData " + "must be NULL"); + return CPA_STATUS_INVALID_PARAM; + } + } + + aadLenInBytes = pSessionDesc->aadLenInBytes; + /* Convert Alg Chain Request to Cipher Request for CCP and * AES_GCM single pass */ - if (!pSessionDesc->isSinglePass && - LAC_CIPHER_IS_SPC(cipher, hash, capabilitiesMask) && - (LAC_CIPHER_SPC_IV_SIZE == pOpData->ivLenInBytes)) { + if ((NON_SPC != pSessionDesc->singlePassState) && + (isSpCcm || (LAC_CIPHER_SPC_IV_SIZE == pOpData->ivLenInBytes))) { pSessionDesc->laCmdId = ICP_QAT_FW_LA_CMD_CIPHER; laCmdId = pSessionDesc->laCmdId; pSessionDesc->symOperation = CPA_CY_SYM_OP_CIPHER; - pSessionDesc->isSinglePass = CPA_TRUE; + pSessionDesc->singlePassState = SPC; pSessionDesc->isCipher = CPA_TRUE; pSessionDesc->isAuthEncryptOp = CPA_FALSE; pSessionDesc->isAuth = CPA_FALSE; - if (CPA_CY_SYM_HASH_AES_GMAC == pSessionDesc->hashAlgorithm) { - pSessionDesc->aadLenInBytes = - pOpData->messageLenToHashInBytes; - if (ICP_QAT_FW_SPC_AAD_SZ_MAX < - pSessionDesc->aadLenInBytes) { + + if (CPA_CY_SYM_HASH_AES_GMAC == hash) { + if (ICP_QAT_FW_SPC_AAD_SZ_MAX < aadLenInBytes) { LAC_INVALID_PARAM_LOG( "aadLenInBytes for AES_GMAC"); return CPA_STATUS_INVALID_PARAM; } } - /* New bit position (13) for SINGLE PASS. * The FW provides a specific macro to use to set the proto flag */ ICP_QAT_FW_LA_SINGLE_PASS_PROTO_FLAG_SET( pSessionDesc->laCmdFlags, ICP_QAT_FW_LA_SINGLE_PASS_PROTO); - ICP_QAT_FW_LA_PROTO_SET(pSessionDesc->laCmdFlags, 0); + if (isCyGen2x(pService)) { + ICP_QAT_FW_LA_PROTO_SET(pSessionDesc->laCmdFlags, 0); + } pCdInfo = &(pSessionDesc->contentDescInfo); pHwBlockBaseInDRAM = (Cpa8U *)pCdInfo->pData; @@ -1215,11 +1635,24 @@ pSessionDesc->cipherDirection) { if (LAC_CIPHER_IS_GCM(cipher)) hwBlockOffsetInDRAM = LAC_QUADWORDS_TO_BYTES( - LAC_SYM_QAT_CIPHER_OFFSET_IN_DRAM_GCM_SPC); - else + LAC_SYM_QAT_CIPHER_GCM_SPC_OFFSET_IN_DRAM); + else if (LAC_CIPHER_IS_CHACHA(cipher)) hwBlockOffsetInDRAM = LAC_QUADWORDS_TO_BYTES( - LAC_SYM_QAT_CIPHER_OFFSET_IN_DRAM_CHACHA_SPC); + LAC_SYM_QAT_CIPHER_CHACHA_SPC_OFFSET_IN_DRAM); + } else if (isSpCcm) { + hwBlockOffsetInDRAM = LAC_QUADWORDS_TO_BYTES( + LAC_SYM_QAT_CIPHER_CCM_SPC_OFFSET_IN_DRAM); } + + /* Update cipher slice type */ + pSessionDesc->cipherSliceType = + LacCipher_GetCipherSliceType(pService, + pSessionDesc->cipherAlgorithm, + pSessionDesc->hashAlgorithm); + + ICP_QAT_FW_LA_SLICE_TYPE_SET(pSessionDesc->laCmdFlags, + pSessionDesc->cipherSliceType); + /* construct cipherConfig in CD in DRAM */ LacSymQat_CipherHwBlockPopulateCfgData(pSessionDesc, pHwBlockBaseInDRAM + @@ -1228,31 +1661,53 @@ SalQatMsg_CmnHdrWrite((icp_qat_fw_comn_req_t *)&( pSessionDesc->reqSpcCacheHdr), ICP_QAT_FW_COMN_REQ_CPM_FW_LA, - pSessionDesc->laCmdId, + laCmdId, + pSessionDesc->cmnRequestFlags, + pSessionDesc->laCmdFlags); + } else if ((SPC == pSessionDesc->singlePassState) && + (LAC_CIPHER_SPC_IV_SIZE != pOpData->ivLenInBytes)) { + pSessionDesc->symOperation = CPA_CY_SYM_OP_ALGORITHM_CHAINING; + pSessionDesc->singlePassState = LIKELY_SPC; + pSessionDesc->isCipher = CPA_TRUE; + pSessionDesc->isAuthEncryptOp = CPA_TRUE; + pSessionDesc->isAuth = CPA_TRUE; + pCdInfo = &(pSessionDesc->contentDescInfo); + pHwBlockBaseInDRAM = (Cpa8U *)pCdInfo->pData; + + if (CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT == + pSessionDesc->cipherDirection) { + pSessionDesc->laCmdId = ICP_QAT_FW_LA_CMD_CIPHER_HASH; + } else { + pSessionDesc->laCmdId = ICP_QAT_FW_LA_CMD_HASH_CIPHER; + } + + laCmdId = pSessionDesc->laCmdId; + ICP_QAT_FW_LA_SINGLE_PASS_PROTO_FLAG_SET( + pSessionDesc->laCmdFlags, 0); + ICP_QAT_FW_LA_PROTO_SET(pSessionDesc->laCmdFlags, + ICP_QAT_FW_LA_GCM_PROTO); + + LacSymQat_CipherHwBlockPopulateCfgData(pSessionDesc, + pHwBlockBaseInDRAM + + hwBlockOffsetInDRAM, + &sizeInBytes); + + SalQatMsg_CmnHdrWrite((icp_qat_fw_comn_req_t *)&( + pSessionDesc->reqCacheHdr), + ICP_QAT_FW_COMN_REQ_CPM_FW_LA, + laCmdId, pSessionDesc->cmnRequestFlags, pSessionDesc->laCmdFlags); - } else if (CPA_CY_SYM_HASH_AES_GMAC == pSessionDesc->hashAlgorithm) { - pSessionDesc->aadLenInBytes = pOpData->messageLenToHashInBytes; } - if (LAC_CIPHER_IS_CHACHA(cipher) && - (LAC_CIPHER_SPC_IV_SIZE != pOpData->ivLenInBytes)) { + else if (LAC_CIPHER_IS_CHACHA(cipher) && + (LAC_CIPHER_SPC_IV_SIZE != pOpData->ivLenInBytes)) { LAC_INVALID_PARAM_LOG("IV for CHACHA"); return CPA_STATUS_INVALID_PARAM; - } else if (CPA_CY_SYM_HASH_AES_GMAC == pSessionDesc->hashAlgorithm) { - if (pOpData->messageLenToHashInBytes == 0 || - pOpData->pAdditionalAuthData != NULL) { - LAC_INVALID_PARAM_LOG( - "For AES_GMAC, AAD Length " - "(messageLenToHashInBytes) must " - "be non zero and pAdditionalAuthData " - "must be NULL"); - status = CPA_STATUS_INVALID_PARAM; - } } - if (CPA_TRUE == pSessionDesc->isAuthEncryptOp) { - if (CPA_CY_SYM_HASH_AES_CCM == pSessionDesc->hashAlgorithm) { + if ((CPA_TRUE == pSessionDesc->isAuthEncryptOp) || isSpCcm) { + if (CPA_CY_SYM_HASH_AES_CCM == hash) { status = LacSymAlgChain_CheckCCMData( pOpData->pAdditionalAuthData, pOpData->pIv, @@ -1266,9 +1721,8 @@ pOpData->messageLenToCipherInBytes, pOpData->ivLenInBytes); } - } else if (CPA_CY_SYM_HASH_AES_GCM == - pSessionDesc->hashAlgorithm) { - if (pSessionDesc->aadLenInBytes != 0 && + } else if (CPA_CY_SYM_HASH_AES_GCM == hash) { + if (aadLenInBytes != 0 && pOpData->pAdditionalAuthData == NULL) { LAC_INVALID_PARAM_LOG("pAdditionalAuthData"); status = CPA_STATUS_INVALID_PARAM; @@ -1304,37 +1758,48 @@ &srcAddrPhys, CPA_FALSE, &(pService->generic_service_info)); - } else { - status = LacBuffDesc_BufferListDescWrite( - (CpaBufferList *)pSrcBuffer, - &srcAddrPhys, - CPA_FALSE, - &(pService->generic_service_info)); - } - if (CPA_STATUS_SUCCESS != status) { - LAC_LOG_ERROR("Unable to write src buffer descriptors"); - } - - /* For out of place operations */ - if ((pSrcBuffer != pDstBuffer) && - (CPA_STATUS_SUCCESS == status)) { - if (IS_ZERO_LENGTH_BUFFER_SUPPORTED(cipher, hash)) { + if (CPA_STATUS_SUCCESS != status) { + LAC_LOG_ERROR( + "Unable to write src buffer descriptors"); + } + /* For out of place operations */ + if ((pSrcBuffer != pDstBuffer) && + (CPA_STATUS_SUCCESS == status)) { status = LacBuffDesc_BufferListDescWriteAndAllowZeroBuffer( pDstBuffer, &dstAddrPhys, CPA_FALSE, &(pService->generic_service_info)); - } else { + if (CPA_STATUS_SUCCESS != status) { + LAC_LOG_ERROR( + "Unable to write dest buffer descriptors"); + } + } + } else { + status = LacBuffDesc_BufferListDescWrite( + (CpaBufferList *)pSrcBuffer, + &srcAddrPhys, + CPA_FALSE, + &(pService->generic_service_info)); + if (CPA_STATUS_SUCCESS != status) { + LAC_LOG_ERROR( + "Unable to write src buffer descriptors in " + "LacBuffDesc_BufferListDescWrite"); + } + /* For out of place operations */ + if ((pSrcBuffer != pDstBuffer) && + (CPA_STATUS_SUCCESS == status)) { status = LacBuffDesc_BufferListDescWrite( pDstBuffer, &dstAddrPhys, CPA_FALSE, &(pService->generic_service_info)); - } - if (CPA_STATUS_SUCCESS != status) { - LAC_LOG_ERROR( - "Unable to write dest buffer descriptors"); + if (CPA_STATUS_SUCCESS != status) { + LAC_LOG_ERROR( + "Unable to write dest buffer descriptors in " + "LacBuffDesc_BufferListDescWrite"); + } } } } @@ -1359,9 +1824,9 @@ * the first partial has been sent. Set a flag here so the * response knows to do this. */ - if ((laCmdId != ICP_QAT_FW_LA_CMD_AUTH) && + if (LAC_CIPHER_IS_XTS_MODE(cipher) && + (laCmdId != ICP_QAT_FW_LA_CMD_AUTH) && (CPA_CY_SYM_PACKET_TYPE_PARTIAL == pOpData->packetType) && - (LAC_CIPHER_IS_XTS_MODE(pSessionDesc->cipherAlgorithm)) && (qatPacketType == ICP_QAT_FW_LA_PARTIAL_START)) { pCookie->updateKeySizeOnRecieve = CPA_TRUE; } @@ -1374,26 +1839,21 @@ pMsg = &(pCookie->qatMsg); pMsgDummy = (Cpa8U *)pMsg; - if (pSessionDesc->isSinglePass) { + if (SPC == pSessionDesc->singlePassState) { pCacheDummyHdr = (Cpa8U *)&(pSessionDesc->reqSpcCacheHdr); pCacheDummyFtr = (Cpa8U *)&(pSessionDesc->reqSpcCacheFtr); } else { /* Normally, we want to use the SHRAM Constants Table if - * possible - * for best performance (less DRAM accesses incurred by - * CPM). But - * we can't use it for partial-packet hash operations. - * This is why - * we build 2 versions of the message template at - * sessionInit, + * possible for best performance (less DRAM accesses + * incurred by CPM). But we can't use it for + * partial-packet hash operations. This is why we build + * 2 versions of the message template at sessionInit, * one for SHRAM Constants Table usage and the other - * (default) for - * Content Descriptor h/w setup data in DRAM. And we - * chose between - * them here on a per-request basis, when we know the - * packetType + * (default) for Content Descriptor h/w setup data in + * DRAM. And we chose between them here on a + * per-request basis, when we know the packetType */ if ((!pSessionDesc->useSymConstantsTable) || (pSessionDesc->isAuth && @@ -1418,8 +1878,9 @@ 0, (LAC_LONG_WORD_IN_BYTES * LAC_SIZE_OF_CACHE_TO_CLEAR_IN_LW)); - memcpy(pMsgDummy + (LAC_LONG_WORD_IN_BYTES * - LAC_START_OF_CACHE_FTR_IN_LW), + memcpy(pMsgDummy + + (LAC_LONG_WORD_IN_BYTES * + LAC_START_OF_CACHE_FTR_IN_LW), pCacheDummyFtr, (LAC_LONG_WORD_IN_BYTES * LAC_SIZE_OF_CACHE_FTR_IN_LW)); /* @@ -1442,11 +1903,11 @@ LacSymQat_LaPacketCommandFlagSet( qatPacketType, laCmdId, - pSessionDesc->cipherAlgorithm, + cipher, &pMsg->comn_hdr.serv_specif_flags, pOpData->ivLenInBytes); - if (pSessionDesc->isSinglePass) { + if (SPC == pSessionDesc->singlePassState) { ICP_QAT_FW_LA_GCM_IV_LEN_FLAG_SET( pMsg->comn_hdr.serv_specif_flags, ICP_QAT_FW_LA_GCM_IV_LEN_NOT_12_OCTETS); @@ -1463,7 +1924,11 @@ } } + ICP_QAT_FW_LA_SLICE_TYPE_SET(pMsg->comn_hdr.serv_specif_flags, + pSessionDesc->cipherSliceType); + LacBuffDesc_BufferListTotalSizeGet(pSrcBuffer, &srcPktSize); + LacBuffDesc_BufferListTotalSizeGet(pDstBuffer, &dstPktSize); /* * Populate the CipherRequestParams section of the Request @@ -1472,8 +1937,9 @@ Cpa8U *pIvBuffer = NULL; - status = LacCipher_PerformParamCheck( - pSessionDesc->cipherAlgorithm, pOpData, srcPktSize); + status = LacCipher_PerformParamCheck(cipher, + pOpData, + srcPktSize); if (CPA_STATUS_SUCCESS != status) { /* free the cookie */ Lac_MemPoolEntryFree(pCookie); @@ -1488,19 +1954,18 @@ qatPacketType, &pIvBuffer); } - if (pSessionDesc->isSinglePass && + if ((SPC == pSessionDesc->singlePassState) && ((ICP_QAT_FW_LA_PARTIAL_MID == qatPacketType) || (ICP_QAT_FW_LA_PARTIAL_END == qatPacketType))) { /* For SPC stateful cipher state size for mid - * and - * end partial packet is 48 bytes + * and end partial packet is 48 bytes */ pSpcCdCtrlHdr = (icp_qat_fw_cipher_cd_ctrl_hdr_t *)&( pMsg->cd_ctrl); pSpcCdCtrlHdr->cipher_state_sz = LAC_BYTES_TO_QUADWORDS( - LAC_SYM_QAT_CIPHER_STATE_SIZE_SPC); + LAC_SYM_QAT_CIPHER_SPC_STATE_SIZE); } /*populate the cipher request parameters */ if (CPA_STATUS_SUCCESS == status) { @@ -1525,6 +1990,7 @@ if (status == CPA_STATUS_SUCCESS) { status = LacSymQat_CipherRequestParamsPopulate( + pSessionDesc, pMsg, pOpData ->cryptoStartSrcOffsetInBytes, @@ -1535,39 +2001,45 @@ } } - if (CPA_STATUS_SUCCESS == status && - pSessionDesc->isSinglePass) { + if ((SPC == pSessionDesc->singlePassState) && + CPA_STATUS_SUCCESS == status) { Cpa64U aadBufferPhysAddr = 0; /* For CHACHA and AES-GCM there is an AAD buffer - * if - * aadLenInBytes is nonzero In case of AES-GMAC, - * AAD buffer - * passed in the src buffer. + * if aadLenInBytes is nonzero In case of + * AES-GMAC, AAD buffer passed in the src + * buffer. */ - if (0 != pSessionDesc->aadLenInBytes && - CPA_CY_SYM_HASH_AES_GMAC != - pSessionDesc->hashAlgorithm) { + if ((0 != aadLenInBytes && + CPA_CY_SYM_HASH_AES_GMAC != hash) || + isSpCcm) { LAC_CHECK_NULL_PARAM( pOpData->pAdditionalAuthData); + Cpa32U aadDataLen = + pSessionDesc->aadLenInBytes; + + /* In case of AES_CCM, B0 block size and + * 2 bytes of AAD len encoding need to + * be added to total AAD data len */ + if (isSpCcm) + aadDataLen += + LAC_CIPHER_CCM_AAD_OFFSET; + blockLen = LacSymQat_CipherBlockSizeBytesGet( - pSessionDesc->cipherAlgorithm); - if ((pSessionDesc->aadLenInBytes % - blockLen) != 0) { + cipher); + if ((aadDataLen % blockLen) != 0) { paddingLen = blockLen - - (pSessionDesc - ->aadLenInBytes % - blockLen); + (aadDataLen % blockLen); memset( - &pOpData->pAdditionalAuthData - [pSessionDesc - ->aadLenInBytes], + &pOpData + ->pAdditionalAuthData + [aadDataLen], 0, paddingLen); } - /* User OpData memory being used for aad + /* User OpData memory being used for AAD * buffer */ /* get the physical address */ aadBufferPhysAddr = @@ -1588,10 +2060,33 @@ *)((Cpa8U *)&( pMsg->serv_specif_rqpars) + ICP_QAT_FW_CIPHER_REQUEST_PARAMETERS_OFFSET); - pCipherReqParams->spc_aad_addr = - aadBufferPhysAddr; - pCipherReqParams->spc_aad_sz = - pSessionDesc->aadLenInBytes; + + icp_qat_fw_la_cipher_20_req_params_t + *pCipher20ReqParams = + (void + *)((Cpa8U *)&( + pMsg->serv_specif_rqpars) + + ICP_QAT_FW_CIPHER_REQUEST_PARAMETERS_OFFSET); + + if (isCyGen4x(pService)) { + pCipher20ReqParams + ->spc_aad_addr = + aadBufferPhysAddr; + pCipher20ReqParams->spc_aad_sz = + pSessionDesc->aadLenInBytes; + pCipher20ReqParams + ->spc_aad_offset = 0; + if (isSpCcm) + pCipher20ReqParams + ->spc_aad_sz += + LAC_CIPHER_CCM_AAD_OFFSET; + } else { + pCipherReqParams->spc_aad_addr = + aadBufferPhysAddr; + pCipherReqParams->spc_aad_sz = + (Cpa16U)pSessionDesc + ->aadLenInBytes; + } if (CPA_TRUE != pSessionDesc->digestIsAppended) { @@ -1605,13 +2100,24 @@ ->generic_service_info, pOpData->pDigestResult); if (0 != digestBufferPhysAddr) { - pCipherReqParams - ->spc_auth_res_addr = - digestBufferPhysAddr; - pCipherReqParams - ->spc_auth_res_sz = - pSessionDesc - ->hashResultSize; + if (isCyGen4x( + pService)) { + pCipher20ReqParams + ->spc_auth_res_addr = + digestBufferPhysAddr; + pCipher20ReqParams + ->spc_auth_res_sz = + (Cpa8U)pSessionDesc + ->hashResultSize; + } else { + pCipherReqParams + ->spc_auth_res_addr = + digestBufferPhysAddr; + pCipherReqParams + ->spc_auth_res_sz = + (Cpa8U)pSessionDesc + ->hashResultSize; + } } else { LAC_LOG_ERROR( "Unable to get the physical address " @@ -1619,6 +2125,35 @@ status = CPA_STATUS_FAIL; } + } else { + /* Check if the dest buffer can + * handle the digest, only for + * last packet */ + if (((ICP_QAT_FW_LA_PARTIAL_NONE == + qatPacketType) || + (ICP_QAT_FW_LA_PARTIAL_END == + qatPacketType))) { + if (dstPktSize < + (pOpData + ->cryptoStartSrcOffsetInBytes + + pOpData + ->messageLenToCipherInBytes + + pSessionDesc + ->hashResultSize)) + status = + CPA_STATUS_INVALID_PARAM; + } + if (isCyGen4x(pService)) { + pCipher20ReqParams + ->spc_auth_res_sz = + (Cpa8U)pSessionDesc + ->hashResultSize; + } else { + pCipherReqParams + ->spc_auth_res_sz = + (Cpa8U)pSessionDesc + ->hashResultSize; + } } } } @@ -1683,8 +2218,8 @@ pHashReqParams->u2.aad_sz); /* Overwrite hash state buffer info - * structure pointer - * with the one created for CCM/GCM */ + * structure pointer with the one + * created for CCM/GCM */ pHashStateBufferInfo = &hashStateBufferInfo; @@ -1692,10 +2227,8 @@ * case */ if (0 == hashStateBufferInfo.pDataPhys && - CPA_CY_SYM_HASH_AES_GCM != - pSessionDesc->hashAlgorithm && - CPA_CY_SYM_HASH_AES_GMAC != - pSessionDesc->hashAlgorithm) { + CPA_CY_SYM_HASH_AES_GCM != hash && + CPA_CY_SYM_HASH_AES_GMAC != hash) { LAC_LOG_ERROR( "Unable to get the physical address" "of the AAD\n"); @@ -1703,31 +2236,26 @@ } /* for CCM/GCM the hash and cipher data - * regions - * are equal */ + * regions are equal */ authOffsetInBytes = pOpData ->cryptoStartSrcOffsetInBytes; /* For authenticated encryption, - * authentication length is - * determined by - * messageLenToCipherInBytes for AES-GCM - * and - * AES-CCM, and by + * authentication length is determined + * by messageLenToCipherInBytes for + * AES-GCM and AES-CCM, and by * messageLenToHashInBytes for AES-GMAC. * You don't see the latter here, as - * that is the initial - * value of authLenInBytes. */ - if (pSessionDesc->hashAlgorithm != - CPA_CY_SYM_HASH_AES_GMAC) + * that is the initial value of + * authLenInBytes. */ + if (hash != CPA_CY_SYM_HASH_AES_GMAC) authLenInBytes = pOpData ->messageLenToCipherInBytes; } else if (CPA_CY_SYM_HASH_SNOW3G_UIA2 == - pSessionDesc->hashAlgorithm || - CPA_CY_SYM_HASH_ZUC_EIA3 == - pSessionDesc->hashAlgorithm) { + hash || + CPA_CY_SYM_HASH_ZUC_EIA3 == hash) { hashStateBufferInfo.pData = pOpData->pAdditionalAuthData; hashStateBufferInfo.pDataPhys = @@ -1739,7 +2267,7 @@ hashStateBufferInfo .prefixAadSzQuadWords = LAC_BYTES_TO_QUADWORDS( - pSessionDesc->aadLenInBytes); + aadLenInBytes); pHashStateBufferInfo = &hashStateBufferInfo; @@ -1752,23 +2280,22 @@ status = CPA_STATUS_FAIL; } } - if (CPA_CY_SYM_HASH_AES_CCM == - pSessionDesc->hashAlgorithm) { + if (CPA_CY_SYM_HASH_AES_CCM == hash) { if (CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT == pSessionDesc->cipherDirection) { /* On a decrypt path pSrcBuffer - * is used as this is - * where encrypted digest is - * located. Firmware - * uses encrypted digest for + * is used as this is where + * encrypted digest is located. + * Firmware uses encrypted + * digest for * compare/verification*/ pBufferList = (CpaBufferList *)pSrcBuffer; } else { /* On an encrypt path pDstBuffer - * is used as this is - * where encrypted digest will - * be written */ + * is used as this is where + * encrypted digest will be + * written */ pBufferList = (CpaBufferList *)pDstBuffer; } @@ -1787,21 +2314,29 @@ pDigestResult = pOpData->pDigestResult; } + if (CPA_TRUE == + pSessionDesc->useStatefulSha3ContentDesc) { + LacAlgChain_StatefulSha3_SkipStateLoadFlags( + pMsg, + qatPacketType, + pSessionDesc->qatHashMode); + } + if (CPA_CY_SYM_OP_ALGORITHM_CHAINING == pSessionDesc->symOperation) { /* In alg chaining mode, packets are not - * seen as partials - * for hash operations. Override to - * NONE. + * seen as partials for hash operations. + * Override to NONE. */ qatPacketType = ICP_QAT_FW_LA_PARTIAL_NONE; } - if (CPA_TRUE == - pSessionDesc->digestIsAppended) { + digestIsAppended = + pSessionDesc->digestIsAppended; + if (CPA_TRUE == digestIsAppended) { /*Check if the destination buffer can - * handle the digest - * if digestIsAppend is true*/ + * handle the digest if digestIsAppend + * is true*/ if (srcPktSize < (authOffsetInBytes + authLenInBytes + @@ -1824,10 +2359,10 @@ qatPacketType, pSessionDesc->hashResultSize, pSessionDesc->digestVerify, - pSessionDesc->digestIsAppended ? + digestIsAppended ? NULL : pDigestResult, - pSessionDesc->hashAlgorithm, + hash, NULL); } } diff --git a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_api.c b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_api.c --- a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_api.c +++ b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_api.c @@ -55,8 +55,9 @@ #include "lac_sal_types_crypto.h" #include "sal_service_state.h" -#define IS_EXT_ALG_CHAIN_UNSUPPORTED( \ - cipherAlgorithm, hashAlgorithm, extAlgchainSupported) \ +#define IS_EXT_ALG_CHAIN_UNSUPPORTED(cipherAlgorithm, \ + hashAlgorithm, \ + extAlgchainSupported) \ ((((CPA_CY_SYM_CIPHER_ZUC_EEA3 == cipherAlgorithm || \ CPA_CY_SYM_CIPHER_SNOW3G_UEA2 == cipherAlgorithm) && \ CPA_CY_SYM_HASH_AES_CMAC == hashAlgorithm) || \ @@ -77,6 +78,10 @@ const lac_session_desc_t *const pSessionDesc, const CpaCySymOpData *const pOpData); +void LacDp_WriteRingMsgFull(CpaCySymDpOpData *pRequest, + icp_qat_fw_la_bulk_req_t *pCurrentQatMsg); +void LacDp_WriteRingMsgOpt(CpaCySymDpOpData *pRequest, + icp_qat_fw_la_bulk_req_t *pCurrentQatMsg); void getCtxSize(const CpaCySymSessionSetupData *pSessionSetupData, Cpa32U *pSessionCtxSizeInBytes); @@ -151,45 +156,40 @@ /* Protect against value of cipher outside the bitmap * and check if cipher algorithm is correct */ - if ((pCipherSetupData->cipherAlgorithm >= - CPA_CY_SYM_CIPHER_CAP_BITMAP_SIZE) || - (!CPA_BITMAP_BIT_TEST(capInfo.ciphers, - pCipherSetupData->cipherAlgorithm))) { + if (pCipherSetupData->cipherAlgorithm >= + CPA_CY_SYM_CIPHER_CAP_BITMAP_SIZE) { LAC_INVALID_PARAM_LOG("cipherAlgorithm"); return CPA_STATUS_INVALID_PARAM; } + if (!CPA_BITMAP_BIT_TEST(capInfo.ciphers, + pCipherSetupData->cipherAlgorithm)) { + LAC_UNSUPPORTED_PARAM_LOG( + "UnSupported cipherAlgorithm"); + return CPA_STATUS_UNSUPPORTED; + } } /* Ensure hash algorithm is correct and supported */ if ((CPA_CY_SYM_OP_ALGORITHM_CHAINING == pSessionSetupData->symOperation) || (CPA_CY_SYM_OP_HASH == pSessionSetupData->symOperation)) { - /* Ensure SHAKE algorithms are not supported */ - if ((CPA_CY_SYM_HASH_SHAKE_128 == - pHashSetupData->hashAlgorithm) || - (CPA_CY_SYM_HASH_SHAKE_256 == - pHashSetupData->hashAlgorithm)) { - LAC_INVALID_PARAM_LOG( - "Hash algorithms SHAKE-128 and SHAKE-256 " - "are not supported."); - return CPA_STATUS_UNSUPPORTED; - } - /* Protect against value of hash outside the bitmap * and check if hash algorithm is correct */ - if ((pHashSetupData->hashAlgorithm >= - CPA_CY_SYM_HASH_CAP_BITMAP_SIZE) || - (!CPA_BITMAP_BIT_TEST(capInfo.hashes, - pHashSetupData->hashAlgorithm))) { + if (pHashSetupData->hashAlgorithm >= + CPA_CY_SYM_HASH_CAP_BITMAP_SIZE) { LAC_INVALID_PARAM_LOG("hashAlgorithm"); return CPA_STATUS_INVALID_PARAM; } + if (!CPA_BITMAP_BIT_TEST(capInfo.hashes, + pHashSetupData->hashAlgorithm)) { + LAC_UNSUPPORTED_PARAM_LOG("UnSupported hashAlgorithm"); + return CPA_STATUS_UNSUPPORTED; + } } /* ensure CCM, GCM, Kasumi, Snow3G and ZUC cipher and hash algorithms - * are - * selected together for Algorithm Chaining */ + * are selected together for Algorithm Chaining */ if (CPA_CY_SYM_OP_ALGORITHM_CHAINING == pSessionSetupData->symOperation) { /* ensure both hash and cipher algorithms are POLY and CHACHA */ @@ -435,7 +435,11 @@ } } /* Check that src Buffer and dst Buffer Lengths are equal */ - if (srcBufferLen != dstBufferLen) { + /* CCM output needs to be longer than input buffer for appending + * tag*/ + if (srcBufferLen != dstBufferLen && + pSessionDesc->cipherAlgorithm != + CPA_CY_SYM_CIPHER_AES_CCM) { LAC_INVALID_PARAM_LOG( "Source and Dest buffer lengths need to be equal "); return CPA_STATUS_INVALID_PARAM; @@ -451,8 +455,7 @@ return CPA_STATUS_INVALID_PARAM; } else { /* This function checks to see if the partial packet - * sequence - * is correct */ + * sequence is correct */ if (CPA_STATUS_SUCCESS != LacSym_PartialPacketStateCheck( pOpData->packetType, @@ -551,7 +554,7 @@ const CpaCySymCipherSetupData *pCipherSetupData = NULL; const CpaCySymHashSetupData *pHashSetupData = NULL; -/* Instance param checking done by calling function */ + /* Instance param checking done by calling function */ LAC_CHECK_NULL_PARAM(pSessionSetupData); LAC_CHECK_NULL_PARAM(pSessionCtx); @@ -580,7 +583,7 @@ if (0 == physAddress) { LAC_LOG_ERROR( - "Unable to get the physical address of the session"); + "Unable to get the physical address of the session\n"); return CPA_STATUS_FAIL; } @@ -631,8 +634,8 @@ /* For asynchronous - use the user supplied callback * for synchronous - use the internal synchronous callback */ pSessionDesc->pSymCb = ((void *)NULL != (void *)pSymCb) ? - pSymCb : - LacSync_GenBufListVerifyCb; + pSymCb : + LacSync_GenBufListVerifyCb; } pSessionDesc->isDPSession = isDPSession; @@ -649,10 +652,8 @@ if (CPA_STATUS_SUCCESS == status) { /* Session set up via API call (not internal one) */ /* Services such as DRBG call the crypto api as part of their - * service - * hence the need to for the flag, it is needed to distinguish - * between - * an internal and external session. + * service hence the need to for the flag, it is needed to + * distinguish between an internal and external session. */ pSessionDesc->internalSession = CPA_FALSE; @@ -697,14 +698,11 @@ /* * Based on one instance, we can initialize multiple sessions. * For example, we can initialize the session "X" and session - * "Y" with - * the same instance "A". If there is no operation pending for - * session - * "X", we can remove the session "X". + * "Y" with the same instance "A". If there is no operation + * pending for session "X", we can remove the session "X". * * Now we only check the @pSessionDesc->pendingDpCbCount, if it - * becomes - * zero, we can remove the session. + * becomes zero, we can remove the session. * * Why? * (1) We increase it in the cpaCySymDpEnqueueOp/ @@ -713,12 +711,10 @@ * * If the @pSessionDesc->pendingDpCbCount becomes zero, it means * there is no operation pending for the session "X" anymore, so - * we can - * remove this session. Maybe there is still some requests left - * in the - * instance's ring (icp_adf_queueDataToSend() returns true), but - * the - * request does not belong to "X", it belongs to session "Y". + * we can remove this session. Maybe there is still some + * requests left in the instance's ring + * (icp_adf_queueDataToSend() returns true), but the request + * does not belong to "X", it belongs to session "Y". */ numPendingRequests = qatUtilsAtomicGet(&(pSessionDesc->u.pendingDpCbCount)); @@ -734,8 +730,7 @@ status = CPA_STATUS_RETRY; if (CPA_TRUE == pSessionDesc->isDPSession) { /* Need to update tail if messages queue on tx hi ring - for - data plane api */ + for data plane api */ icp_comms_trans_handle trans_handle = ((sal_crypto_service_t *)instanceHandle) ->trans_handle_sym_tx; @@ -752,10 +747,7 @@ } } if (CPA_STATUS_SUCCESS == status) { - if (CPA_STATUS_SUCCESS != - LAC_SPINLOCK_DESTROY(&pSessionDesc->requestQueueLock)) { - LAC_LOG_ERROR("Failed to destroy request queue lock"); - } + LAC_SPINLOCK_DESTROY(&pSessionDesc->requestQueueLock); if (CPA_FALSE == pSessionDesc->isDPSession) { LAC_SYM_STAT_INC(numSessionsRemoved, instanceHandle); } diff --git a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_cb.c b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_cb.c --- a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_cb.c +++ b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_cb.c @@ -69,7 +69,7 @@ const CpaCySymOpData *pOpData, CpaBoolean isCCM) { - Cpa8U authTagLen = 0; + Cpa32U authTagLen = 0; /* Retrieve authTagLen */ authTagLen = pSessionDesc->hashResultSize; @@ -138,10 +138,10 @@ /* For a digest verify operation - for full packet and final partial * only, perform a comparison with the digest generated and with the one - * supplied in the packet. */ + * supplied in the packet. In case of AES_GCM in SPC mode, destination + * buffer needs to be cleared if digest verify operation fails */ - if (((pSessionDesc->isSinglePass && - (CPA_CY_SYM_CIPHER_AES_GCM == pSessionDesc->cipherAlgorithm)) || + if (((SPC == pSessionDesc->singlePassState) || (CPA_CY_SYM_OP_CIPHER != operationType)) && (CPA_TRUE == pSessionDesc->digestVerify) && ((CPA_CY_SYM_PACKET_TYPE_FULL == pOpData->packetType) || @@ -151,14 +151,10 @@ instanceHandle); /* The comparison has failed at this point (status is - * fail), - * need to clean any sensitive calculated data up to - * this point. - * The data calculated is no longer useful to the end - * result and - * does not need to be returned to the user so setting - * buffers to - * zero. + * fail), need to clean any sensitive calculated data up + * to this point. The data calculated is no longer + * useful to the end result and does not need to be + * returned to the user so setting buffers to zero. */ if (pSessionDesc->cipherAlgorithm == CPA_CY_SYM_CIPHER_AES_CCM) { @@ -200,8 +196,7 @@ /* Update the user's IV buffer * Very important to do this BEFORE dequeuing * subsequent partial requests, as the state - * buffer - * may get overwritten + * buffer may get overwritten */ memcpy(pCookie->pOpData->pIv, pSessionDesc->cipherPartialOpState, @@ -218,8 +213,9 @@ } else if (CPA_CY_SYM_PACKET_TYPE_LAST_PARTIAL == pOpData->packetType) { if ((CPA_CY_SYM_OP_CIPHER == operationType) || (CPA_CY_SYM_OP_ALGORITHM_CHAINING == operationType)) { - if (CPA_TRUE == LAC_CIPHER_IS_XTS_MODE( - pSessionDesc->cipherAlgorithm)) { + if (CPA_TRUE == + LAC_CIPHER_IS_XTS_MODE( + pSessionDesc->cipherAlgorithm)) { /* * For XTS mode, we replace the updated key with * the original key - for subsequent partial @@ -294,51 +290,46 @@ static void LacSymCb_ProcessDpCallback(CpaCySymDpOpData *pResponse, CpaBoolean qatRespStatusOkFlag, + CpaStatus status, lac_session_desc_t *pSessionDesc) { - CpaStatus status = CPA_STATUS_SUCCESS; + CpaCySymDpCbFunc pSymDpCb = NULL; /* For CCM and GCM, if qatRespStatusOkFlag is false, the data has to be * cleaned as stated in RFC 3610; in DP mode, it is the user - * responsability - * to do so */ - - if (CPA_FALSE == pSessionDesc->isSinglePass) { - if ((CPA_CY_SYM_OP_CIPHER == pSessionDesc->symOperation) || - (CPA_FALSE == pSessionDesc->digestVerify)) { - /* If not doing digest compare and qatRespStatusOkFlag - != - CPA_TRUE - then there is something very wrong */ - if (CPA_FALSE == qatRespStatusOkFlag) { - LAC_LOG_ERROR( - "Response status value not as expected"); - status = CPA_STATUS_FAIL; - } + * responsability to do so */ + + if (((CPA_CY_SYM_OP_CIPHER == pSessionDesc->symOperation) && + SPC != pSessionDesc->singlePassState) || + (CPA_FALSE == pSessionDesc->digestVerify)) { + /* If not doing digest compare and qatRespStatusOkFlag != + CPA_TRUE then there is something very wrong */ + if ((CPA_FALSE == qatRespStatusOkFlag) && + (status != CPA_STATUS_UNSUPPORTED)) { + LAC_LOG_ERROR("Response status value not as expected"); + status = CPA_STATUS_FAIL; } } - ((sal_crypto_service_t *)pResponse->instanceHandle) - ->pSymDpCb(pResponse, status, qatRespStatusOkFlag); + pSymDpCb = + ((sal_crypto_service_t *)pResponse->instanceHandle)->pSymDpCb; + + pSymDpCb(pResponse, status, qatRespStatusOkFlag); + /* * Decrement the number of pending CB. * * If the @pendingDpCbCount becomes zero, we may remove the session, - * please - * read more information in the cpaCySymRemoveSession(). + * please read more information in the cpaCySymRemoveSession(). * * But there is a field in the @pResponse to store the session, * the "sessionCtx". In another word, in the above @->pSymDpCb() - * callback, - * it may use the session again. If we decrease the @pendingDpCbCount - * before - * the @->pSymDpCb(), there is a _risk_ the @->pSymDpCb() may reference - * to - * a deleted session. + * callback, it may use the session again. If we decrease the + * @pendingDpCbCount before the @->pSymDpCb(), there is a _risk_ the + * @->pSymDpCb() may reference to a deleted session. * * So in order to avoid the risk, we decrease the @pendingDpCbCount - * after - * the @->pSymDpCb() callback. + * after the @->pSymDpCb() callback. */ qatUtilsAtomicDec(&pSessionDesc->u.pendingDpCbCount); } @@ -367,6 +358,7 @@ void *pOpaqueData, icp_qat_fw_comn_flags cmnRespFlags) { + CpaStatus status = CPA_STATUS_SUCCESS; CpaCySymDpOpData *pDpOpData = (CpaCySymDpOpData *)pOpaqueData; lac_session_desc_t *pSessionDesc = LAC_SYM_SESSION_DESC_FROM_CTX_GET(pDpOpData->sessionCtx); @@ -376,8 +368,13 @@ if (CPA_TRUE == pSessionDesc->isDPSession) { /* DP session */ + if (ICP_QAT_FW_COMN_RESP_UNSUPPORTED_REQUEST_STAT_GET( + cmnRespFlags)) { + status = CPA_STATUS_UNSUPPORTED; + } LacSymCb_ProcessDpCallback(pDpOpData, qatRespStatusOkFlag, + status, pSessionDesc); } else { /* Trad session */ @@ -414,11 +411,7 @@ * be accessed by multiple contexts simultaneously for enqueue and * dequeue operations */ - if (CPA_STATUS_SUCCESS != - LAC_SPINLOCK(&pSessionDesc->requestQueueLock)) { - LAC_LOG_ERROR("Failed to lock request queue"); - return CPA_STATUS_RESOURCE; - } + LAC_SPINLOCK(&pSessionDesc->requestQueueLock); /* Clear the blocking flag in the session descriptor */ pSessionDesc->nonBlockingOpsInProgress = CPA_TRUE; @@ -427,10 +420,9 @@ (CPA_TRUE == pSessionDesc->nonBlockingOpsInProgress)) { /* If we send a partial packet request, set the - * blockingOpsInProgress - * flag for the session to indicate that subsequent requests - * must be - * queued up until this request completes + * blockingOpsInProgress flag for the session to indicate that + * subsequent requests must be queued up until this request + * completes */ if (CPA_CY_SYM_PACKET_TYPE_FULL != pSessionDesc->pRequestQueueHead->pOpData->packetType) { @@ -438,14 +430,10 @@ } /* At this point, we're clear to send the request. For cipher - * requests, - * we need to check if the session IV needs to be updated. This - * can - * only be done when no other partials are in flight for this - * session, - * to ensure the cipherPartialOpState buffer in the session - * descriptor - * is not currently in use + * requests, we need to check if the session IV needs to be + * updated. This can only be done when no other partials are in + * flight for this session, to ensure the cipherPartialOpState + * buffer in the session descriptor is not currently in use */ if (CPA_TRUE == pSessionDesc->pRequestQueueHead->updateSessionIvOnSend) { @@ -464,13 +452,11 @@ /* * Now we'll attempt to send the message directly to QAT. We'll - * keep - * looing until it succeeds (or at least a very high number of - * retries), - * as the failure only happens when the ring is full, and this - * is only - * a temporary situation. After a few retries, space will become - * availble, allowing the putMsg to succeed. + * keep looing until it succeeds (or at least a very high number + * of retries), as the failure only happens when the ring is + * full, and this is only a temporary situation. After a few + * retries, space will become availble, allowing the putMsg to + * succeed. */ retries = 0; do { @@ -483,8 +469,7 @@ retries++; /* * Yield to allow other threads that may be on this - * session to poll - * and make some space on the ring + * session to poll and make some space on the ring */ if (CPA_STATUS_SUCCESS != status) { qatUtilsYield(); @@ -509,10 +494,7 @@ } cleanup: - if (CPA_STATUS_SUCCESS != - LAC_SPINUNLOCK(&pSessionDesc->requestQueueLock)) { - LAC_LOG_ERROR("Failed to unlock request queue"); - } + LAC_SPINUNLOCK(&pSessionDesc->requestQueueLock); return status; } diff --git a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_cipher.c b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_cipher.c --- a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_cipher.c +++ b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_cipher.c @@ -49,6 +49,7 @@ #include "lac_sym_qat_cipher.h" #include "lac_log.h" #include "lac_buffer_desc.h" +#include "sal_hw_gen.h" /* ******************************************************************************* @@ -66,14 +67,23 @@ lac_session_desc_t *pSessionDesc = LAC_SYM_SESSION_DESC_FROM_CTX_GET(pOpData->sessionCtx); CpaCySymCipherAlgorithm algorithm = pSessionDesc->cipherAlgorithm; + unsigned ivLenInBytes = 0; - /* Perform IV check. */ - if (LAC_CIPHER_IS_CTR_MODE(algorithm) || - LAC_CIPHER_IS_CBC_MODE(algorithm) || - LAC_CIPHER_IS_AES_F8(algorithm) || - LAC_CIPHER_IS_XTS_MODE(algorithm)) { - unsigned ivLenInBytes = - LacSymQat_CipherIvSizeBytesGet(algorithm); + switch (algorithm) { + /* Perform IV check for CTR, CBC, XTS, F8 MODE. */ + case CPA_CY_SYM_CIPHER_AES_CTR: + case CPA_CY_SYM_CIPHER_3DES_CTR: + case CPA_CY_SYM_CIPHER_SM4_CTR: + case CPA_CY_SYM_CIPHER_AES_CCM: + case CPA_CY_SYM_CIPHER_AES_GCM: + case CPA_CY_SYM_CIPHER_CHACHA: + case CPA_CY_SYM_CIPHER_AES_CBC: + case CPA_CY_SYM_CIPHER_DES_CBC: + case CPA_CY_SYM_CIPHER_3DES_CBC: + case CPA_CY_SYM_CIPHER_SM4_CBC: + case CPA_CY_SYM_CIPHER_AES_F8: + case CPA_CY_SYM_CIPHER_AES_XTS: { + ivLenInBytes = LacSymQat_CipherIvSizeBytesGet(algorithm); LAC_CHECK_NULL_PARAM(pOpData->pIv); if (pOpData->ivLenInBytes != ivLenInBytes) { if (!(/* GCM with 12 byte IV is OK */ @@ -96,26 +106,21 @@ /* Set the value of the ppIvBuffer to that supplied * by the user. * NOTE: There is no guarantee that this address is - * aligned on - * an 8 or 64 Byte address. */ + * aligned on an 8 or 64 Byte address. */ *ppIvBuffer = pOpData->pIv; } else { /* For partial packets, we use a per-session buffer to - * maintain - * the IV. This allows us to easily pass the updated IV - * forward - * to the next partial in the sequence. This makes - * internal - * buffering of partials easier to implement. + * maintain the IV. This allows us to easily pass the + * updated IV forward to the next partial in the + * sequence. This makes internal buffering of partials + * easier to implement. */ *ppIvBuffer = pSessionDesc->cipherPartialOpState; /* Ensure that the user's IV buffer gets updated between - * partial - * requests so that they may also see the residue from - * the - * previous partial. Not needed for final partials - * though. + * partial requests so that they may also see the + * residue from the previous partial. Not needed for + * final partials though. */ if ((ICP_QAT_FW_LA_PARTIAL_START == qatPacketType) || (ICP_QAT_FW_LA_PARTIAL_MID == qatPacketType)) { @@ -124,97 +129,87 @@ if (ICP_QAT_FW_LA_PARTIAL_START == qatPacketType) { /* if the previous partial state was - * full, then this is - * the first partial in the sequence so - * we need to copy - * in the user's IV. But, we have to be - * very careful - * here not to overwrite the - * cipherPartialOpState just - * yet in case there's a previous - * partial sequence in - * flight, so we defer the copy for now. - * This will be - * completed in the - * LacSymQueue_RequestSend() function. + * full, then this is the first partial + * in the sequence so we need to copy in + * the user's IV. But, we have to be + * very careful here not to overwrite + * the cipherPartialOpState just yet in + * case there's a previous partial + * sequence in flight, so we defer the + * copy for now. This will be completed + * in the LacSymQueue_RequestSend() + * function. */ pCbCookie->updateSessionIvOnSend = CPA_TRUE; } /* For subsequent partials in a sequence, we'll - * re-use the - * IV that was written back by the QAT, using - * internal - * request queueing if necessary to ensure that - * the next - * partial request isn't issued to the QAT until - * the + * re-use the IV that was written back by the + * QAT, using internal request queueing if + * necessary to ensure that the next partial + * request isn't issued to the QAT until the * previous one completes */ } } - } else if (LAC_CIPHER_IS_KASUMI(algorithm)) { + } break; + case CPA_CY_SYM_CIPHER_KASUMI_F8: { LAC_CHECK_NULL_PARAM(pOpData->pIv); - if (LAC_CIPHER_IS_KASUMI(algorithm) && - (pOpData->ivLenInBytes != LAC_CIPHER_KASUMI_F8_IV_LENGTH)) { + if (pOpData->ivLenInBytes != LAC_CIPHER_KASUMI_F8_IV_LENGTH) { LAC_INVALID_PARAM_LOG("invalid cipher IV size"); return CPA_STATUS_INVALID_PARAM; } - *ppIvBuffer = pOpData->pIv; - } else if (LAC_CIPHER_IS_SNOW3G_UEA2(algorithm)) { + } break; + case CPA_CY_SYM_CIPHER_SNOW3G_UEA2: { LAC_CHECK_NULL_PARAM(pOpData->pIv); - if (LAC_CIPHER_IS_SNOW3G_UEA2(algorithm) && - (pOpData->ivLenInBytes != ICP_QAT_HW_SNOW_3G_UEA2_IV_SZ)) { + if (pOpData->ivLenInBytes != ICP_QAT_HW_SNOW_3G_UEA2_IV_SZ) { LAC_INVALID_PARAM_LOG("invalid cipher IV size"); return CPA_STATUS_INVALID_PARAM; } *ppIvBuffer = pOpData->pIv; - } else if (LAC_CIPHER_IS_ARC4(algorithm)) { + } break; + case CPA_CY_SYM_CIPHER_ARC4: { if (ICP_QAT_FW_LA_PARTIAL_NONE == qatPacketType) { /* For full packets, the initial ARC4 state is stored in - * the - * session descriptor. Use it directly. + * the session descriptor. Use it directly. */ *ppIvBuffer = pSessionDesc->cipherARC4InitialState; } else { /* For partial packets, we maintain the running ARC4 - * state in - * dedicated buffer in the session descriptor + * state in dedicated buffer in the session descriptor */ *ppIvBuffer = pSessionDesc->cipherPartialOpState; if (ICP_QAT_FW_LA_PARTIAL_START == qatPacketType) { /* if the previous partial state was full, then - * this is the - * first partial in the sequence so we need to - * (re-)initialise - * the contents of the state buffer using the - * initial state - * that is stored in the session descriptor. - * But, we have to be - * very careful here not to overwrite the - * cipherPartialOpState - * just yet in case there's a previous partial - * sequence in + * this is the first partial in the sequence so + * we need to (re-)initialise the contents of + * the state buffer using the initial state that + * is stored in the session descriptor. But, we + * have to be very careful here not to overwrite + * the cipherPartialOpState just yet in case + * there's a previous partial sequence in * flight, so we defer the copy for now. This - * will be completed - * in the LacSymQueue_RequestSend() function - * when clear to send. + * will be completed in the + * LacSymQueue_RequestSend() function when clear + * to send. */ pCbCookie->updateSessionIvOnSend = CPA_TRUE; } } - } else if (LAC_CIPHER_IS_ZUC_EEA3(algorithm)) { + } break; + case CPA_CY_SYM_CIPHER_ZUC_EEA3: { LAC_CHECK_NULL_PARAM(pOpData->pIv); if (pOpData->ivLenInBytes != ICP_QAT_HW_ZUC_3G_EEA3_IV_SZ) { LAC_INVALID_PARAM_LOG("invalid cipher IV size"); return CPA_STATUS_INVALID_PARAM; } *ppIvBuffer = pOpData->pIv; - } else { + } break; + default: *ppIvBuffer = NULL; } @@ -223,40 +218,50 @@ CpaStatus -LacCipher_SessionSetupDataCheck(const CpaCySymCipherSetupData *pCipherSetupData) +LacCipher_SessionSetupDataCheck(const CpaCySymCipherSetupData *pCipherSetupData, + Cpa32U capabilitiesMask) { /* No key required for NULL algorithm */ if (!LAC_CIPHER_IS_NULL(pCipherSetupData->cipherAlgorithm)) { LAC_CHECK_NULL_PARAM(pCipherSetupData->pCipherKey); /* Check that algorithm and keys passed in are correct size */ - if (LAC_CIPHER_IS_ARC4(pCipherSetupData->cipherAlgorithm)) { + switch (pCipherSetupData->cipherAlgorithm) { + case CPA_CY_SYM_CIPHER_ARC4: if (pCipherSetupData->cipherKeyLenInBytes > ICP_QAT_HW_ARC4_KEY_SZ) { LAC_INVALID_PARAM_LOG( "Invalid ARC4 cipher key length"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_CCM( - pCipherSetupData->cipherAlgorithm)) { - if (pCipherSetupData->cipherKeyLenInBytes != - ICP_QAT_HW_AES_128_KEY_SZ) { + break; + case CPA_CY_SYM_CIPHER_AES_CCM: + if (!LAC_CIPHER_AES_V2(capabilitiesMask) && + pCipherSetupData->cipherKeyLenInBytes != + ICP_QAT_HW_AES_128_KEY_SZ) { LAC_INVALID_PARAM_LOG( "Invalid AES CCM cipher key length"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_XTS_MODE( - pCipherSetupData->cipherAlgorithm)) { + break; + case CPA_CY_SYM_CIPHER_AES_XTS: if ((pCipherSetupData->cipherKeyLenInBytes != ICP_QAT_HW_AES_128_XTS_KEY_SZ) && (pCipherSetupData->cipherKeyLenInBytes != - ICP_QAT_HW_AES_256_XTS_KEY_SZ)) { + ICP_QAT_HW_AES_256_XTS_KEY_SZ) && + (pCipherSetupData->cipherKeyLenInBytes != + ICP_QAT_HW_UCS_AES_128_XTS_KEY_SZ) && + (pCipherSetupData->cipherKeyLenInBytes != + ICP_QAT_HW_UCS_AES_256_XTS_KEY_SZ)) { LAC_INVALID_PARAM_LOG( "Invalid AES XTS cipher key length"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_AES( - pCipherSetupData->cipherAlgorithm)) { + break; + case CPA_CY_SYM_CIPHER_AES_ECB: + case CPA_CY_SYM_CIPHER_AES_CBC: + case CPA_CY_SYM_CIPHER_AES_CTR: + case CPA_CY_SYM_CIPHER_AES_GCM: if ((pCipherSetupData->cipherKeyLenInBytes != ICP_QAT_HW_AES_128_KEY_SZ) && (pCipherSetupData->cipherKeyLenInBytes != @@ -267,8 +272,8 @@ "Invalid AES cipher key length"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_AES_F8( - pCipherSetupData->cipherAlgorithm)) { + break; + case CPA_CY_SYM_CIPHER_AES_F8: if ((pCipherSetupData->cipherKeyLenInBytes != ICP_QAT_HW_AES_128_F8_KEY_SZ) && (pCipherSetupData->cipherKeyLenInBytes != @@ -279,35 +284,37 @@ "Invalid AES cipher key length"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_DES( - pCipherSetupData->cipherAlgorithm)) { + break; + case CPA_CY_SYM_CIPHER_DES_ECB: + case CPA_CY_SYM_CIPHER_DES_CBC: if (pCipherSetupData->cipherKeyLenInBytes != ICP_QAT_HW_DES_KEY_SZ) { LAC_INVALID_PARAM_LOG( "Invalid DES cipher key length"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_TRIPLE_DES( - pCipherSetupData->cipherAlgorithm)) { + break; + case CPA_CY_SYM_CIPHER_3DES_ECB: + case CPA_CY_SYM_CIPHER_3DES_CBC: + case CPA_CY_SYM_CIPHER_3DES_CTR: if (pCipherSetupData->cipherKeyLenInBytes != ICP_QAT_HW_3DES_KEY_SZ) { LAC_INVALID_PARAM_LOG( "Invalid Triple-DES cipher key length"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_KASUMI( - pCipherSetupData->cipherAlgorithm)) { + break; + case CPA_CY_SYM_CIPHER_KASUMI_F8: /* QAT-FW only supports 128 bits Cipher Key size for - * Kasumi F8 - * Ref: 3GPP TS 55.216 V6.2.0 */ + * Kasumi F8 Ref: 3GPP TS 55.216 V6.2.0 */ if (pCipherSetupData->cipherKeyLenInBytes != ICP_QAT_HW_KASUMI_KEY_SZ) { LAC_INVALID_PARAM_LOG( "Invalid Kasumi cipher key length"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_SNOW3G_UEA2( - pCipherSetupData->cipherAlgorithm)) { + break; + case CPA_CY_SYM_CIPHER_SNOW3G_UEA2: /* QAT-FW only supports 256 bits Cipher Key size for * Snow_3G */ if (pCipherSetupData->cipherKeyLenInBytes != @@ -316,8 +323,8 @@ "Invalid Snow_3G cipher key length"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_ZUC_EEA3( - pCipherSetupData->cipherAlgorithm)) { + break; + case CPA_CY_SYM_CIPHER_ZUC_EEA3: /* ZUC EEA3 */ if (pCipherSetupData->cipherKeyLenInBytes != ICP_QAT_HW_ZUC_3G_EEA3_KEY_SZ) { @@ -325,23 +332,26 @@ "Invalid ZUC cipher key length"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_CHACHA( - pCipherSetupData->cipherAlgorithm)) { + break; + case CPA_CY_SYM_CIPHER_CHACHA: if (pCipherSetupData->cipherKeyLenInBytes != ICP_QAT_HW_CHACHAPOLY_KEY_SZ) { LAC_INVALID_PARAM_LOG( "Invalid CHACHAPOLY cipher key length"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_SM4( - pCipherSetupData->cipherAlgorithm)) { + break; + case CPA_CY_SYM_CIPHER_SM4_ECB: + case CPA_CY_SYM_CIPHER_SM4_CBC: + case CPA_CY_SYM_CIPHER_SM4_CTR: if (pCipherSetupData->cipherKeyLenInBytes != ICP_QAT_HW_SM4_KEY_SZ) { LAC_INVALID_PARAM_LOG( "Invalid SM4 cipher key length"); return CPA_STATUS_INVALID_PARAM; } - } else { + break; + default: LAC_INVALID_PARAM_LOG("Invalid cipher algorithm"); return CPA_STATUS_INVALID_PARAM; } @@ -365,52 +375,86 @@ LAC_INVALID_PARAM_LOG("cipher len + offset greater than " "srcBuffer packet len"); status = CPA_STATUS_INVALID_PARAM; - } - - if (CPA_STATUS_SUCCESS == status) { + } else { + /* Perform algorithm-specific checks */ + switch (algorithm) { + case CPA_CY_SYM_CIPHER_ARC4: + case CPA_CY_SYM_CIPHER_AES_CTR: + case CPA_CY_SYM_CIPHER_3DES_CTR: + case CPA_CY_SYM_CIPHER_SM4_CTR: + case CPA_CY_SYM_CIPHER_AES_CCM: + case CPA_CY_SYM_CIPHER_AES_GCM: + case CPA_CY_SYM_CIPHER_CHACHA: + case CPA_CY_SYM_CIPHER_KASUMI_F8: + case CPA_CY_SYM_CIPHER_AES_F8: + case CPA_CY_SYM_CIPHER_SNOW3G_UEA2: + case CPA_CY_SYM_CIPHER_ZUC_EEA3: + /* No action needed */ + break; /* * XTS Mode allow for ciphers which are not multiples of * the block size. */ - /* Perform algorithm-specific checks */ - if (LAC_CIPHER_IS_XTS_MODE(algorithm) && - ((pOpData->packetType == CPA_CY_SYM_PACKET_TYPE_FULL) || - (pOpData->packetType == - CPA_CY_SYM_PACKET_TYPE_LAST_PARTIAL))) { - /* - * If this is the last of a partial request - */ - if (pOpData->messageLenToCipherInBytes < - ICP_QAT_HW_AES_BLK_SZ) { - LAC_INVALID_PARAM_LOG( - "data size must be greater than block " - "size for last XTS partial or XTS " - "full packet"); - status = CPA_STATUS_INVALID_PARAM; + case CPA_CY_SYM_CIPHER_AES_XTS: + if ((pOpData->packetType == + CPA_CY_SYM_PACKET_TYPE_FULL) || + (pOpData->packetType == + CPA_CY_SYM_PACKET_TYPE_LAST_PARTIAL)) { + /* + * If this is the last of a partial request + */ + if (pOpData->messageLenToCipherInBytes < + ICP_QAT_HW_AES_BLK_SZ) { + LAC_INVALID_PARAM_LOG( + "data size must be greater than block" + " size for last XTS partial or XTS " + "full packet"); + status = CPA_STATUS_INVALID_PARAM; + } } - } else if (!(LAC_CIPHER_IS_ARC4(algorithm) || - LAC_CIPHER_IS_CTR_MODE(algorithm) || - LAC_CIPHER_IS_F8_MODE(algorithm) || - LAC_CIPHER_IS_SNOW3G_UEA2(algorithm) || - LAC_CIPHER_IS_XTS_MODE(algorithm) || - LAC_CIPHER_IS_CHACHA(algorithm) || - LAC_CIPHER_IS_ZUC_EEA3(algorithm))) { + break; + default: /* Mask & check below is based on assumption that block - * size is - * a power of 2. If data size is not a multiple of the - * block size, - * the "remainder" bits selected by the mask be non-zero + * size is a power of 2. If data size is not a multiple + * of the block size, the "remainder" bits selected by + * the mask be non-zero */ if (pOpData->messageLenToCipherInBytes & (LacSymQat_CipherBlockSizeBytesGet(algorithm) - 1)) { LAC_INVALID_PARAM_LOG( - "data size must be block size multiple"); + "data size must be block size" + " multiple"); status = CPA_STATUS_INVALID_PARAM; } } } - return status; } +Cpa32U +LacCipher_GetCipherSliceType(sal_crypto_service_t *pService, + CpaCySymCipherAlgorithm cipherAlgorithm, + CpaCySymHashAlgorithm hashAlgorithm) +{ + Cpa32U sliceType = ICP_QAT_FW_LA_USE_LEGACY_SLICE_TYPE; + Cpa32U capabilitiesMask = + pService->generic_service_info.capabilitiesMask; + + /* UCS Slice is supproted only in Gen4 */ + if (isCyGen4x(pService)) { + if (LAC_CIPHER_IS_XTS_MODE(cipherAlgorithm) || + LAC_CIPHER_IS_CHACHA(cipherAlgorithm) || + LAC_CIPHER_IS_GCM(cipherAlgorithm)) { + sliceType = ICP_QAT_FW_LA_USE_UCS_SLICE_TYPE; + } else if (LAC_CIPHER_IS_CCM(cipherAlgorithm) && + LAC_CIPHER_AES_V2(capabilitiesMask)) { + sliceType = ICP_QAT_FW_LA_USE_LEGACY_SLICE_TYPE; + } else if (LAC_CIPHER_IS_AES(cipherAlgorithm) && + LAC_CIPHER_IS_CTR_MODE(cipherAlgorithm)) { + sliceType = ICP_QAT_FW_LA_USE_UCS_SLICE_TYPE; + } + } + + return sliceType; +} diff --git a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_dp.c b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_dp.c --- a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_dp.c +++ b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_dp.c @@ -35,14 +35,16 @@ #include "qat_utils.h" -#include "lac_mem.h" +#include "lac_list.h" #include "lac_log.h" +#include "lac_mem.h" +#include "lac_sal_types_crypto.h" #include "lac_sym.h" +#include "lac_sym_cipher.h" +#include "lac_sym_auth_enc.h" #include "lac_sym_qat_cipher.h" -#include "lac_list.h" -#include "lac_sal_types_crypto.h" #include "sal_service_state.h" -#include "lac_sym_auth_enc.h" +#include "sal_hw_gen.h" typedef void (*write_ringMsgFunc_t)(CpaCySymDpOpData *pRequest, icp_qat_fw_la_bulk_req_t *pCurrentQatMsg); @@ -133,7 +135,7 @@ /* digestVerify and digestIsAppended on Hash-Only operation not * supported */ if (pSessionDesc->digestIsAppended && pSessionDesc->digestVerify && - (CPA_CY_SYM_OP_HASH == pSessionDesc->symOperation)) { + (pSessionDesc->symOperation == CPA_CY_SYM_OP_HASH)) { LAC_INVALID_PARAM_LOG( "digestVerify and digestIsAppended set " "on Hash-Only operation is not supported"); @@ -143,10 +145,17 @@ /* Cipher specific tests */ if (CPA_CY_SYM_OP_HASH != pSessionDesc->symOperation) { /* Perform IV check */ - if ((LAC_CIPHER_IS_CTR_MODE(pSessionDesc->cipherAlgorithm) || - LAC_CIPHER_IS_CBC_MODE(pSessionDesc->cipherAlgorithm) || - LAC_CIPHER_IS_AES_F8(pSessionDesc->cipherAlgorithm)) && - (!(LAC_CIPHER_IS_CCM(pSessionDesc->cipherAlgorithm)))) { + switch (pSessionDesc->cipherAlgorithm) { + case CPA_CY_SYM_CIPHER_AES_CTR: + case CPA_CY_SYM_CIPHER_3DES_CTR: + case CPA_CY_SYM_CIPHER_SM4_CTR: + case CPA_CY_SYM_CIPHER_AES_GCM: + case CPA_CY_SYM_CIPHER_CHACHA: + case CPA_CY_SYM_CIPHER_AES_CBC: + case CPA_CY_SYM_CIPHER_DES_CBC: + case CPA_CY_SYM_CIPHER_3DES_CBC: + case CPA_CY_SYM_CIPHER_SM4_CBC: + case CPA_CY_SYM_CIPHER_AES_F8: { Cpa32U ivLenInBytes = LacSymQat_CipherIvSizeBytesGet( pSessionDesc->cipherAlgorithm); if (pRequest->ivLenInBytes != ivLenInBytes) { @@ -164,11 +173,10 @@ LAC_INVALID_PARAM_LOG("invalid iv of 0"); return CPA_STATUS_INVALID_PARAM; } - /* pRequest->pIv is only used for CCM so is not checked * here */ - } else if (LAC_CIPHER_IS_KASUMI( - pSessionDesc->cipherAlgorithm)) { + } break; + case CPA_CY_SYM_CIPHER_KASUMI_F8: { if (LAC_CIPHER_KASUMI_F8_IV_LENGTH != pRequest->ivLenInBytes) { LAC_INVALID_PARAM_LOG("invalid cipher IV size"); @@ -178,8 +186,8 @@ LAC_INVALID_PARAM_LOG("invalid iv of 0"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_SNOW3G_UEA2( - pSessionDesc->cipherAlgorithm)) { + } break; + case CPA_CY_SYM_CIPHER_SNOW3G_UEA2: { if (ICP_QAT_HW_SNOW_3G_UEA2_IV_SZ != pRequest->ivLenInBytes) { LAC_INVALID_PARAM_LOG("invalid cipher IV size"); @@ -189,8 +197,8 @@ LAC_INVALID_PARAM_LOG("invalid iv of 0"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_ZUC_EEA3( - pSessionDesc->cipherAlgorithm)) { + } break; + case CPA_CY_SYM_CIPHER_ZUC_EEA3: { if (ICP_QAT_HW_ZUC_3G_EEA3_IV_SZ != pRequest->ivLenInBytes) { LAC_INVALID_PARAM_LOG("invalid cipher IV size"); @@ -200,7 +208,8 @@ LAC_INVALID_PARAM_LOG("invalid iv of 0"); return CPA_STATUS_INVALID_PARAM; } - } else if (LAC_CIPHER_IS_CCM(pSessionDesc->cipherAlgorithm)) { + } break; + case CPA_CY_SYM_CIPHER_AES_CCM: { if (CPA_STATUS_SUCCESS != LacSymAlgChain_CheckCCMData( pRequest->pAdditionalAuthData, @@ -209,30 +218,42 @@ pRequest->ivLenInBytes)) { return CPA_STATUS_INVALID_PARAM; } + } break; + default: + break; } - /* Perform algorithm-specific checks */ - if (!(LAC_CIPHER_IS_ARC4(pSessionDesc->cipherAlgorithm) || - LAC_CIPHER_IS_CTR_MODE(pSessionDesc->cipherAlgorithm) || - LAC_CIPHER_IS_F8_MODE(pSessionDesc->cipherAlgorithm) || - LAC_CIPHER_IS_SNOW3G_UEA2( - pSessionDesc->cipherAlgorithm) || - LAC_CIPHER_IS_ZUC_EEA3(pSessionDesc->cipherAlgorithm))) { + switch (pSessionDesc->cipherAlgorithm) { + case CPA_CY_SYM_CIPHER_ARC4: + case CPA_CY_SYM_CIPHER_AES_CTR: + case CPA_CY_SYM_CIPHER_3DES_CTR: + case CPA_CY_SYM_CIPHER_SM4_CTR: + case CPA_CY_SYM_CIPHER_AES_CCM: + case CPA_CY_SYM_CIPHER_AES_GCM: + case CPA_CY_SYM_CIPHER_CHACHA: + case CPA_CY_SYM_CIPHER_KASUMI_F8: + case CPA_CY_SYM_CIPHER_AES_F8: + case CPA_CY_SYM_CIPHER_SNOW3G_UEA2: + case CPA_CY_SYM_CIPHER_ZUC_EEA3: + /* No action needed */ + break; + default: { /* Mask & check below is based on assumption that block - * size is - * a power of 2. If data size is not a multiple of the - * block size, - * the "remainder" bits selected by the mask be non-zero + * size is a power of 2. If data size is not a multiple + * of the block size, the "remainder" bits selected by + * the mask be non-zero */ if (pRequest->messageLenToCipherInBytes & (LacSymQat_CipherBlockSizeBytesGet( pSessionDesc->cipherAlgorithm) - 1)) { LAC_INVALID_PARAM_LOG( - "Data size must be block size multiple"); + "Data size must be block size" + " multiple"); return CPA_STATUS_INVALID_PARAM; } } + } cipher = pSessionDesc->cipherAlgorithm; hash = pSessionDesc->hashAlgorithm; @@ -242,11 +263,9 @@ if (LAC_CIPHER_IS_SPC(cipher, hash, capabilitiesMask) && (LAC_CIPHER_SPC_IV_SIZE == pRequest->ivLenInBytes)) { /* For CHACHA and AES_GCM single pass there is an AAD - * buffer - * if aadLenInBytes is nonzero. AES_GMAC AAD is stored - * in - * source buffer, therefore there is no separate AAD - * buffer. */ + * buffer if aadLenInBytes is nonzero. AES_GMAC AAD is + * stored in source buffer, therefore there is no + * separate AAD buffer. */ if ((0 != pSessionDesc->aadLenInBytes) && (CPA_CY_SYM_HASH_AES_GMAC != pSessionDesc->hashAlgorithm)) { @@ -397,7 +416,7 @@ * @ingroup cpaCySymDp * Write Message on the ring and write request params * This is the optimized version, which should not be used for - * algorithm of CCM, GCM and RC4 + * algorithm of CCM, GCM, CHACHA and RC4 * * @description * Write Message on the ring and write request params @@ -425,12 +444,15 @@ /* Write Request */ /* * Fill in the header and footer bytes of the ET ring message - cached - * from - * the session descriptor. + * from the session descriptor. */ - pCacheDummyHdr = (Cpa8U *)&(pSessionDesc->reqCacheHdr); - pCacheDummyFtr = (Cpa8U *)&(pSessionDesc->reqCacheFtr); - + if (!pSessionDesc->useSymConstantsTable) { + pCacheDummyHdr = (Cpa8U *)&(pSessionDesc->reqCacheHdr); + pCacheDummyFtr = (Cpa8U *)&(pSessionDesc->reqCacheFtr); + } else { + pCacheDummyHdr = (Cpa8U *)&(pSessionDesc->shramReqCacheHdr); + pCacheDummyFtr = (Cpa8U *)&(pSessionDesc->shramReqCacheFtr); + } memcpy(pMsgDummy, pCacheDummyHdr, (LAC_LONG_WORD_IN_BYTES * LAC_SIZE_OF_CACHE_HDR_IN_LW)); @@ -457,6 +479,7 @@ if (pSessionDesc->isCipher) { LacSymQat_CipherRequestParamsPopulate( + pSessionDesc, pCurrentQatMsg, pRequest->cryptoStartSrcOffsetInBytes, pRequest->messageLenToCipherInBytes, @@ -493,14 +516,27 @@ * copied directly from the op request data because they share a * corresponding layout. The remaining 4 bytes are taken * from the session message template and use values - * preconfigured at - * sessionInit (updated per request for some specific cases - * below) + * preconfigured at sessionInit (updated per request for some + * specific cases below) */ - memcpy(pAuthReqPars, - (Cpa32U *)&(pRequest->hashStartSrcOffsetInBytes), - ((unsigned long)&(pAuthReqPars->u2.inner_prefix_sz) - - (unsigned long)pAuthReqPars)); + + /* We force a specific compiler optimisation here. The length + * to be copied turns out to be always 16, and by coding a + * memcpy with a literal value the compiler will compile inline + * code (in fact, only two vector instructions) to effect the + * copy. This gives us a huge performance increase. + */ + unsigned long cplen = + (unsigned long)&(pAuthReqPars->u2.inner_prefix_sz) - + (unsigned long)pAuthReqPars; + if (cplen == 16) + memcpy(pAuthReqPars, + (Cpa32U *)&(pRequest->hashStartSrcOffsetInBytes), + 16); + else + memcpy(pAuthReqPars, + (Cpa32U *)&(pRequest->hashStartSrcOffsetInBytes), + cplen); if (CPA_TRUE == pSessionDesc->isAuthEncryptOp) { pAuthReqPars->hash_state_sz = @@ -548,25 +584,29 @@ Cpa32U sizeInBytes = 0; CpaCySymCipherAlgorithm cipher = pSessionDesc->cipherAlgorithm; CpaCySymHashAlgorithm hash = pSessionDesc->hashAlgorithm; + sal_crypto_service_t *pService = + (sal_crypto_service_t *)pRequest->instanceHandle; Cpa32U capabilitiesMask = ((sal_crypto_service_t *)pRequest->instanceHandle) ->generic_service_info.capabilitiesMask; + CpaBoolean isSpCcm = LAC_CIPHER_IS_CCM(cipher) && + LAC_CIPHER_IS_SPC(cipher, hash, capabilitiesMask); + Cpa8U paddingLen = 0; Cpa8U blockLen = 0; + Cpa32U aadDataLen = 0; pMsgDummy = (Cpa8U *)pCurrentQatMsg; /* Write Request */ /* * Fill in the header and footer bytes of the ET ring message - cached - * from - * the session descriptor. + * from the session descriptor. */ - if (!pSessionDesc->isSinglePass && - LAC_CIPHER_IS_SPC(cipher, hash, capabilitiesMask) && - (LAC_CIPHER_SPC_IV_SIZE == pRequest->ivLenInBytes)) { - pSessionDesc->isSinglePass = CPA_TRUE; + if ((NON_SPC != pSessionDesc->singlePassState) && + (isSpCcm || (LAC_CIPHER_SPC_IV_SIZE == pRequest->ivLenInBytes))) { + pSessionDesc->singlePassState = SPC; pSessionDesc->isCipher = CPA_TRUE; pSessionDesc->isAuthEncryptOp = CPA_FALSE; pSessionDesc->isAuth = CPA_FALSE; @@ -581,7 +621,8 @@ */ ICP_QAT_FW_LA_SINGLE_PASS_PROTO_FLAG_SET( pSessionDesc->laCmdFlags, ICP_QAT_FW_LA_SINGLE_PASS_PROTO); - ICP_QAT_FW_LA_PROTO_SET(pSessionDesc->laCmdFlags, 0); + if (isCyGen2x(pService)) + ICP_QAT_FW_LA_PROTO_SET(pSessionDesc->laCmdFlags, 0); pCdInfo = &(pSessionDesc->contentDescInfo); pHwBlockBaseInDRAM = (Cpa8U *)pCdInfo->pData; @@ -589,11 +630,22 @@ pSessionDesc->cipherDirection) { if (LAC_CIPHER_IS_GCM(cipher)) hwBlockOffsetInDRAM = LAC_QUADWORDS_TO_BYTES( - LAC_SYM_QAT_CIPHER_OFFSET_IN_DRAM_GCM_SPC); - else + LAC_SYM_QAT_CIPHER_GCM_SPC_OFFSET_IN_DRAM); + else if (LAC_CIPHER_IS_CHACHA(cipher)) hwBlockOffsetInDRAM = LAC_QUADWORDS_TO_BYTES( - LAC_SYM_QAT_CIPHER_OFFSET_IN_DRAM_CHACHA_SPC); + LAC_SYM_QAT_CIPHER_CHACHA_SPC_OFFSET_IN_DRAM); + } else if (isSpCcm) { + hwBlockOffsetInDRAM = LAC_QUADWORDS_TO_BYTES( + LAC_SYM_QAT_CIPHER_CCM_SPC_OFFSET_IN_DRAM); } + + /* Update slice type, as used algos changed */ + pSessionDesc->cipherSliceType = + LacCipher_GetCipherSliceType(pService, cipher, hash); + + ICP_QAT_FW_LA_SLICE_TYPE_SET(pSessionDesc->laCmdFlags, + pSessionDesc->cipherSliceType); + /* construct cipherConfig in CD in DRAM */ LacSymQat_CipherHwBlockPopulateCfgData(pSessionDesc, pHwBlockBaseInDRAM + @@ -605,10 +657,42 @@ pSessionDesc->laCmdId, pSessionDesc->cmnRequestFlags, pSessionDesc->laCmdFlags); + } else if ((SPC == pSessionDesc->singlePassState) && + (LAC_CIPHER_SPC_IV_SIZE != pRequest->ivLenInBytes)) { + pSessionDesc->symOperation = CPA_CY_SYM_OP_ALGORITHM_CHAINING; + pSessionDesc->singlePassState = LIKELY_SPC; + pSessionDesc->isCipher = CPA_TRUE; + pSessionDesc->isAuthEncryptOp = CPA_TRUE; + pSessionDesc->isAuth = CPA_TRUE; + pCdInfo = &(pSessionDesc->contentDescInfo); + pHwBlockBaseInDRAM = (Cpa8U *)pCdInfo->pData; + + if (CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT == + pSessionDesc->cipherDirection) { + pSessionDesc->laCmdId = ICP_QAT_FW_LA_CMD_CIPHER_HASH; + } else { + pSessionDesc->laCmdId = ICP_QAT_FW_LA_CMD_HASH_CIPHER; + } + + ICP_QAT_FW_LA_SINGLE_PASS_PROTO_FLAG_SET( + pSessionDesc->laCmdFlags, 0); + ICP_QAT_FW_LA_PROTO_SET(pSessionDesc->laCmdFlags, + ICP_QAT_FW_LA_GCM_PROTO); + + LacSymQat_CipherHwBlockPopulateCfgData(pSessionDesc, + pHwBlockBaseInDRAM + + hwBlockOffsetInDRAM, + &sizeInBytes); + SalQatMsg_CmnHdrWrite((icp_qat_fw_comn_req_t *)&( + pSessionDesc->reqCacheHdr), + ICP_QAT_FW_COMN_REQ_CPM_FW_LA, + pSessionDesc->laCmdId, + pSessionDesc->cmnRequestFlags, + pSessionDesc->laCmdFlags); } else if (CPA_CY_SYM_HASH_AES_GMAC == pSessionDesc->hashAlgorithm) { pSessionDesc->aadLenInBytes = pRequest->messageLenToHashInBytes; } - if (pSessionDesc->isSinglePass) { + if (SPC == pSessionDesc->singlePassState) { pCacheDummyHdr = (Cpa8U *)&(pSessionDesc->reqSpcCacheHdr); pCacheDummyFtr = (Cpa8U *)&(pSessionDesc->reqSpcCacheFtr); } else { @@ -644,8 +728,9 @@ pRequest->srcBufferLen, pRequest->dstBufferLen); - if (CPA_CY_SYM_HASH_AES_CCM == pSessionDesc->hashAlgorithm && - pSessionDesc->isAuth == CPA_TRUE) { + if ((CPA_CY_SYM_HASH_AES_CCM == pSessionDesc->hashAlgorithm && + pSessionDesc->isAuth == CPA_TRUE) || + isSpCcm) { /* prepare IV and AAD for CCM */ LacSymAlgChain_PrepareCCMData( pSessionDesc, @@ -655,15 +740,14 @@ pRequest->ivLenInBytes); /* According to the API, for CCM and GCM, - * messageLenToHashInBytes - * and hashStartSrcOffsetInBytes are not initialized by the - * user and must be set by the driver + * messageLenToHashInBytes and hashStartSrcOffsetInBytes are not + * initialized by the user and must be set by the driver */ pRequest->hashStartSrcOffsetInBytes = pRequest->cryptoStartSrcOffsetInBytes; pRequest->messageLenToHashInBytes = pRequest->messageLenToCipherInBytes; - } else if (!pSessionDesc->isSinglePass && + } else if ((SPC != pSessionDesc->singlePassState) && (CPA_CY_SYM_HASH_AES_GCM == pSessionDesc->hashAlgorithm || CPA_CY_SYM_HASH_AES_GMAC == pSessionDesc->hashAlgorithm)) { /* GCM case */ @@ -693,56 +777,87 @@ if (pSessionDesc->isCipher) { if (CPA_CY_SYM_CIPHER_ARC4 == pSessionDesc->cipherAlgorithm) { /* ARC4 does not have an IV but the field is used to - * store the - * initial state */ + * store the initial state */ pRequest->iv = pSessionDesc->cipherARC4InitialStatePhysAddr; } + ICP_QAT_FW_LA_SLICE_TYPE_SET( + pCurrentQatMsg->comn_hdr.serv_specif_flags, + pSessionDesc->cipherSliceType); + LacSymQat_CipherRequestParamsPopulate( + pSessionDesc, pCurrentQatMsg, pRequest->cryptoStartSrcOffsetInBytes, pRequest->messageLenToCipherInBytes, pRequest->iv, pRequest->pIv); - if (pSessionDesc->isSinglePass) { + if (SPC == pSessionDesc->singlePassState) { icp_qat_fw_la_cipher_req_params_t *pCipherReqParams = (icp_qat_fw_la_cipher_req_params_t *)((Cpa8U *)&( pCurrentQatMsg->serv_specif_rqpars) + ICP_QAT_FW_CIPHER_REQUEST_PARAMETERS_OFFSET); - pCipherReqParams->spc_aad_addr = - (uint64_t)pRequest->additionalAuthData; - pCipherReqParams->spc_aad_sz = - pSessionDesc->aadLenInBytes; + icp_qat_fw_la_cipher_20_req_params_t *pCipher20ReqParams = + (void + *)((Cpa8U *)&( + pCurrentQatMsg->serv_specif_rqpars) + + ICP_QAT_FW_CIPHER_REQUEST_PARAMETERS_OFFSET); - pCipherReqParams->spc_auth_res_addr = - (uint64_t)pRequest->digestResult; - pCipherReqParams->spc_auth_res_sz = - pSessionDesc->hashResultSize; + if (isCyGen4x(pService)) { + pCipher20ReqParams->spc_aad_addr = + (uint64_t)pRequest->additionalAuthData; + pCipher20ReqParams->spc_aad_sz = + pSessionDesc->aadLenInBytes; + pCipher20ReqParams->spc_aad_offset = 0; + + if (isSpCcm) + pCipher20ReqParams->spc_aad_sz += + LAC_CIPHER_CCM_AAD_OFFSET; + + pCipher20ReqParams->spc_auth_res_addr = + (uint64_t)pRequest->digestResult; + pCipher20ReqParams->spc_auth_res_sz = + (Cpa8U)pSessionDesc->hashResultSize; + } else { + pCipherReqParams->spc_aad_addr = + (uint64_t)pRequest->additionalAuthData; + pCipherReqParams->spc_aad_sz = + (Cpa16U)pSessionDesc->aadLenInBytes; + + pCipherReqParams->spc_auth_res_addr = + (uint64_t)pRequest->digestResult; + pCipherReqParams->spc_auth_res_sz = + (Cpa8U)pSessionDesc->hashResultSize; + } /* For CHACHA and AES_GCM single pass AAD buffer needs - * alignment - * if aadLenInBytes is nonzero. - * In case of AES-GMAC, AAD buffer passed in the src - * buffer. + * alignment if aadLenInBytes is nonzero. In case of + * AES-GMAC, AAD buffer passed in the src buffer. */ if (0 != pSessionDesc->aadLenInBytes && CPA_CY_SYM_HASH_AES_GMAC != pSessionDesc->hashAlgorithm) { blockLen = LacSymQat_CipherBlockSizeBytesGet( pSessionDesc->cipherAlgorithm); - if ((pSessionDesc->aadLenInBytes % blockLen) != - 0) { - paddingLen = blockLen - - (pSessionDesc->aadLenInBytes % - blockLen); - memset( - &pRequest->pAdditionalAuthData - [pSessionDesc->aadLenInBytes], - 0, - paddingLen); + aadDataLen = pSessionDesc->aadLenInBytes; + + /* In case of AES_CCM, B0 block size and 2 bytes + * of AAD len + * encoding need to be added to total AAD data + * len */ + if (isSpCcm) + aadDataLen += LAC_CIPHER_CCM_AAD_OFFSET; + + if ((aadDataLen % blockLen) != 0) { + paddingLen = + blockLen - (aadDataLen % blockLen); + memset(&pRequest->pAdditionalAuthData + [aadDataLen], + 0, + paddingLen); } } } @@ -777,32 +892,14 @@ * copied directly from the op request data because they share a * corresponding layout. The remaining 4 bytes are taken * from the session message template and use values - * preconfigured at - * sessionInit (updated per request for some specific cases - * below) + * preconfigured at sessionInit (updated per request for some + * specific cases below) */ - - /* We force a specific compiler optimisation here. The length - * to - * be copied turns out to be always 16, and by coding a memcpy - * with - * a literal value the compiler will compile inline code (in - * fact, - * only two vector instructions) to effect the copy. This gives - * us - * a huge performance increase. - */ - unsigned long cplen = - (unsigned long)&(pAuthReqPars->u2.inner_prefix_sz) - - (unsigned long)pAuthReqPars; - if (cplen == 16) - memcpy(pAuthReqPars, - (Cpa32U *)&(pRequest->hashStartSrcOffsetInBytes), - 16); - else - memcpy(pAuthReqPars, - (Cpa32U *)&(pRequest->hashStartSrcOffsetInBytes), - cplen); + memcpy(pAuthReqPars, + (Cpa32U *)&(pRequest->hashStartSrcOffsetInBytes), + ((uintptr_t) & + (pAuthReqPars->u2.inner_prefix_sz) - + (uintptr_t)pAuthReqPars)); if (CPA_TRUE == pSessionDesc->isAuthEncryptOp) { pAuthReqPars->hash_state_sz = @@ -892,7 +989,7 @@ /* CPA_INSTANCE_HANDLE_SINGLE is not supported on DP apis */ LAC_CHECK_INSTANCE_HANDLE(instanceHandle); -/* All other param checks are common with trad api */ + /* All other param checks are common with trad api */ return cpaCySymRemoveSession(instanceHandle, sessionCtx); } @@ -932,6 +1029,10 @@ return status; } + /* Check if SAL is running in crypto data plane otherwise return an + * error */ + SAL_RUNNING_CHECK(pRequest->instanceHandle); + trans_handle = ((sal_crypto_service_t *)pRequest->instanceHandle) ->trans_handle_sym_tx; @@ -1029,6 +1130,10 @@ } } + /* Check if SAL is running in crypto data plane otherwise return an + * error */ + SAL_RUNNING_CHECK(pRequests[0]->instanceHandle); + trans_handle = ((sal_crypto_service_t *)pRequests[0]->instanceHandle) ->trans_handle_sym_tx; pSessionDesc = diff --git a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_hash.c b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_hash.c --- a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_hash.c +++ b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_hash.c @@ -50,17 +50,16 @@ (CPA_CY_SYM_HASH_AES_CMAC == (alg)) || \ (CPA_CY_SYM_HASH_ZUC_EIA3 == (alg))) && \ (CPA_CY_SYM_HASH_MODE_AUTH != (mode))) || \ - (((CPA_CY_SYM_HASH_SHA3_224 == (alg)) || \ - (CPA_CY_SYM_HASH_SHA3_256 == (alg)) || \ - (CPA_CY_SYM_HASH_SHA3_384 == (alg)) || \ - (CPA_CY_SYM_HASH_SHA3_512 == (alg))) && \ - (CPA_CY_SYM_HASH_MODE_NESTED == (mode))) || \ - (((CPA_CY_SYM_HASH_SHAKE_128 == (alg)) || \ - (CPA_CY_SYM_HASH_SHAKE_256 == (alg))) && \ - (CPA_CY_SYM_HASH_MODE_AUTH == (mode)))) - + ((LAC_HASH_IS_SHA3(alg)) && (CPA_CY_SYM_HASH_MODE_NESTED == (mode)))) /**< Macro to check for valid algorithm-mode combination */ +void LacSync_GenBufListVerifyCb(void *pCallbackTag, + CpaStatus status, + CpaCySymOp operationType, + void *pOpData, + CpaBufferList *pDstBuffer, + CpaBoolean opResult); + /** * @ingroup LacHash * This callback function will be invoked whenever a synchronous @@ -98,7 +97,7 @@ if (pHashStateBufferInfo->pDataPhys == 0) { LAC_LOG_ERROR("Unable to get the physical address of " - "the hash state buffer"); + "the hash state buffer\n"); return CPA_STATUS_FAIL; } @@ -110,9 +109,11 @@ pHashStateBufferInfo, pReq, pHashSetupData->nestedModeSetupData.pInnerPrefixData, - pHashSetupData->nestedModeSetupData.innerPrefixLenInBytes, + (Cpa8U)pHashSetupData->nestedModeSetupData + .innerPrefixLenInBytes, pHashSetupData->nestedModeSetupData.pOuterPrefixData, - pHashSetupData->nestedModeSetupData.outerPrefixLenInBytes); + (Cpa8U)pHashSetupData->nestedModeSetupData + .outerPrefixLenInBytes); } /* For mode2 HMAC the key gets copied into both the inner and * outer prefix fields */ @@ -121,9 +122,9 @@ pHashStateBufferInfo, pReq, pHashSetupData->authModeSetupData.authKey, - pHashSetupData->authModeSetupData.authKeyLenInBytes, + (Cpa8U)pHashSetupData->authModeSetupData.authKeyLenInBytes, pHashSetupData->authModeSetupData.authKey, - pHashSetupData->authModeSetupData.authKeyLenInBytes); + (Cpa8U)pHashSetupData->authModeSetupData.authKeyLenInBytes); } /* else do nothing for the other cases */ return CPA_STATUS_SUCCESS; @@ -226,22 +227,32 @@ pCallbackTag); } else if (CPA_CY_SYM_HASH_AES_CCM == hashAlgorithm) { /* - * The Inner Hash Initial State2 block must contain K - * (the cipher key) and 16 zeroes which will be replaced with - * EK(Ctr0) by the QAT-ME. - */ - - /* write the auth key which for CCM is equivalent to cipher key + * The Inner Hash Initial State2 block is 32 bytes long. + * Therefore, for keys bigger than 128 bits (16 bytes), + * there is no space for 16 zeroes. */ - memcpy(pState2, - pSessionSetup->cipherSetupData.pCipherKey, - pSessionSetup->cipherSetupData.cipherKeyLenInBytes); + if (pSessionSetup->cipherSetupData.cipherKeyLenInBytes == + ICP_QAT_HW_AES_128_KEY_SZ) { + /* + * The Inner Hash Initial State2 block must contain K + * (the cipher key) and 16 zeroes which will be replaced + * with EK(Ctr0) by the QAT-ME. + */ - /* initialize remaining buffer space to all zeroes */ - LAC_OS_BZERO( - pState2 + - pSessionSetup->cipherSetupData.cipherKeyLenInBytes, - ICP_QAT_HW_AES_CCM_CBC_E_CTR0_SZ); + /* write the auth key which for CCM is equivalent to + * cipher key + */ + memcpy( + pState2, + pSessionSetup->cipherSetupData.pCipherKey, + pSessionSetup->cipherSetupData.cipherKeyLenInBytes); + + /* initialize remaining buffer space to all zeroes */ + LAC_OS_BZERO(pState2 + + pSessionSetup->cipherSetupData + .cipherKeyLenInBytes, + ICP_QAT_HW_AES_CCM_CBC_E_CTR0_SZ); + } /* There is no request sent to the QAT for this operation, * so just invoke the user's callback directly to signal @@ -279,8 +290,8 @@ if (CPA_STATUS_SUCCESS == status) { /* write len(A) (the length of A) into bytes 16-19 of - * pState2 - * in big-endian format. This field is 8 bytes */ + * pState2 in big-endian format. This field is 8 bytes + */ *(Cpa32U *)&pState2[ICP_QAT_HW_GALOIS_H_SZ] = LAC_MEM_WR_32(pAuthModeSetupData->aadLenInBytes); } @@ -367,26 +378,15 @@ CpaCySymCapabilitiesInfo capInfo; /*Protect against value of hash outside the bitmap*/ - if ((pHashSetupData->hashAlgorithm) >= - CPA_CY_SYM_HASH_CAP_BITMAP_SIZE) { + if (pHashSetupData->hashAlgorithm >= CPA_CY_SYM_HASH_CAP_BITMAP_SIZE) { LAC_INVALID_PARAM_LOG("hashAlgorithm"); return CPA_STATUS_INVALID_PARAM; } + cpaCySymQueryCapabilities(instanceHandle, &capInfo); if (!CPA_BITMAP_BIT_TEST(capInfo.hashes, pHashSetupData->hashAlgorithm) && pHashSetupData->hashAlgorithm != CPA_CY_SYM_HASH_AES_CBC_MAC) { - /* Ensure SHAKE algorithms are not supported */ - if ((CPA_CY_SYM_HASH_SHAKE_128 == - pHashSetupData->hashAlgorithm) || - (CPA_CY_SYM_HASH_SHAKE_256 == - pHashSetupData->hashAlgorithm)) { - LAC_INVALID_PARAM_LOG( - "Hash algorithms SHAKE-128 and SHAKE-256 " - "are not supported."); - return CPA_STATUS_UNSUPPORTED; - } - LAC_INVALID_PARAM_LOG("hashAlgorithm"); return CPA_STATUS_INVALID_PARAM; } @@ -405,8 +405,9 @@ if (LAC_HASH_ALG_MODE_NOT_SUPPORTED(pHashSetupData->hashAlgorithm, pHashSetupData->hashMode)) { - LAC_INVALID_PARAM_LOG("hashAlgorithm and hashMode combination"); - return CPA_STATUS_INVALID_PARAM; + LAC_UNSUPPORTED_PARAM_LOG( + "hashAlgorithm and hashMode combination"); + return CPA_STATUS_UNSUPPORTED; } LacSymQat_HashAlgLookupGet(instanceHandle, @@ -432,10 +433,8 @@ Cpa32U aadDataSize = 0; /* RFC 4106: Implementations MUST support a full-length - * 16-octet - * ICV, and MAY support 8 or 12 octet ICVs, and MUST NOT - * support - * other ICV lengths. */ + * 16-octet ICV, and MAY support 8 or 12 octet ICVs, and + * MUST NOT support other ICV lengths. */ if ((pHashSetupData->digestResultLenInBytes != LAC_HASH_AES_GCM_ICV_SIZE_8) && (pHashSetupData->digestResultLenInBytes != @@ -490,15 +489,13 @@ aadDataSize = LAC_HASH_AES_CCM_BLOCK_SIZE; /* then, if there is some 'a' data, the buffer will - * store encoded - * length of 'a' and 'a' itself */ + * store encoded length of 'a' and 'a' itself */ if (pHashSetupData->authModeSetupData.aadLenInBytes > 0) { /* as the QAT API puts the requirement on the * pAdditionalAuthData not to be bigger than 240 - * bytes then we - * just need 2 bytes to store encoded length of - * 'a' */ + * bytes then we just need 2 bytes to store + * encoded length of 'a' */ aadDataSize += sizeof(Cpa16U); aadDataSize += pHashSetupData->authModeSetupData .aadLenInBytes; @@ -536,8 +533,7 @@ return CPA_STATUS_INVALID_PARAM; } /* For Snow3g hash aad field contains IV - it needs to - * be 16 - * bytes long + * be 16 bytes long */ if (pHashSetupData->authModeSetupData.aadLenInBytes != ICP_QAT_HW_SNOW_3G_UEA2_IV_SZ) { @@ -570,8 +566,7 @@ return CPA_STATUS_INVALID_PARAM; } /* For ZUC EIA3 hash aad field contains IV - it needs to - * be 16 - * bytes long + * be 16 bytes long */ if (pHashSetupData->authModeSetupData.aadLenInBytes != ICP_QAT_HW_ZUC_3G_EEA3_IV_SZ) { @@ -613,19 +608,6 @@ if (!CPA_BITMAP_BIT_TEST(capInfo.hashes, pHashSetupData->nestedModeSetupData .outerHashAlgorithm)) { - /* Ensure SHAKE algorithms are not supported */ - if ((CPA_CY_SYM_HASH_SHAKE_128 == - pHashSetupData->nestedModeSetupData - .outerHashAlgorithm) || - (CPA_CY_SYM_HASH_SHAKE_256 == - pHashSetupData->nestedModeSetupData - .outerHashAlgorithm)) { - LAC_INVALID_PARAM_LOG( - "Hash algorithms SHAKE-128 and SHAKE-256 " - "are not supported."); - return CPA_STATUS_UNSUPPORTED; - } - LAC_INVALID_PARAM_LOG("outerHashAlgorithm"); return CPA_STATUS_INVALID_PARAM; } @@ -689,11 +671,15 @@ { CpaStatus status = CPA_STATUS_SUCCESS; lac_sym_qat_hash_alg_info_t *pHashAlgInfo = NULL; + CpaBoolean digestIsAppended = pSessionDesc->digestIsAppended; + CpaBoolean digestVerify = pSessionDesc->digestVerify; + CpaCySymOp symOperation = pSessionDesc->symOperation; + CpaCySymHashAlgorithm hashAlgorithm = pSessionDesc->hashAlgorithm; /* digestVerify and digestIsAppended on Hash-Only operation not * supported */ - if (pSessionDesc->digestIsAppended && pSessionDesc->digestVerify && - (CPA_CY_SYM_OP_HASH == pSessionDesc->symOperation)) { + if (digestIsAppended && digestVerify && + (CPA_CY_SYM_OP_HASH == symOperation)) { LAC_INVALID_PARAM_LOG( "digestVerify and digestIsAppended set " "on Hash-Only operation is not supported"); @@ -702,21 +688,19 @@ /* check the digest result pointer */ if ((CPA_CY_SYM_PACKET_TYPE_PARTIAL != pOpData->packetType) && - !pSessionDesc->digestIsAppended && - (NULL == pOpData->pDigestResult)) { + !digestIsAppended && (NULL == pOpData->pDigestResult)) { LAC_INVALID_PARAM_LOG("pDigestResult is NULL"); return CPA_STATUS_INVALID_PARAM; } /* * Check if the pVerifyResult pointer is not null for hash operation - * when - * the packet is the last one and user has set verifyDigest flag + * when the packet is the last one and user has set verifyDigest flag * Also, this is only needed for symchronous operation, so check if the * callback pointer is the internal synchronous one rather than a user- * supplied one. */ - if ((CPA_TRUE == pSessionDesc->digestVerify) && + if ((CPA_TRUE == digestVerify) && (CPA_CY_SYM_PACKET_TYPE_PARTIAL != pOpData->packetType) && (LacSync_GenBufListVerifyCb == pSessionDesc->pSymCb)) { if (NULL == pVerifyResult) { @@ -732,8 +716,8 @@ * written anywhere so we cannot check for this been inside a buffer * CCM/GCM specify the auth region using just the cipher params as this * region is the same for auth and cipher. It is not checked here */ - if ((CPA_CY_SYM_HASH_AES_CCM == pSessionDesc->hashAlgorithm) || - (CPA_CY_SYM_HASH_AES_GCM == pSessionDesc->hashAlgorithm)) { + if ((CPA_CY_SYM_HASH_AES_CCM == hashAlgorithm) || + (CPA_CY_SYM_HASH_AES_GCM == hashAlgorithm)) { /* ensure AAD data pointer is non-NULL if AAD len > 0 */ if ((pSessionDesc->aadLenInBytes > 0) && (NULL == pOpData->pAdditionalAuthData)) { @@ -752,8 +736,8 @@ /* For Snow3g & ZUC hash pAdditionalAuthData field * of OpData should contain IV */ - if ((CPA_CY_SYM_HASH_SNOW3G_UIA2 == pSessionDesc->hashAlgorithm) || - (CPA_CY_SYM_HASH_ZUC_EIA3 == pSessionDesc->hashAlgorithm)) { + if ((CPA_CY_SYM_HASH_SNOW3G_UIA2 == hashAlgorithm) || + (CPA_CY_SYM_HASH_ZUC_EIA3 == hashAlgorithm)) { if (NULL == pOpData->pAdditionalAuthData) { LAC_INVALID_PARAM_LOG("pAdditionalAuthData is NULL"); return CPA_STATUS_INVALID_PARAM; @@ -761,12 +745,11 @@ } /* partial packets need to be multiples of the algorithm block size in - * hash - * only mode (except for final partial packet) */ + * hash only mode (except for final partial packet) */ if ((CPA_CY_SYM_PACKET_TYPE_PARTIAL == pOpData->packetType) && - (CPA_CY_SYM_OP_HASH == pSessionDesc->symOperation)) { + (CPA_CY_SYM_OP_HASH == symOperation)) { LacSymQat_HashAlgLookupGet(instanceHandle, - pSessionDesc->hashAlgorithm, + hashAlgorithm, &pHashAlgInfo); /* check if the message is a multiple of the block size. */ diff --git a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_queue.c b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_queue.c --- a/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_queue.c +++ b/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_queue.c @@ -57,11 +57,7 @@ */ if ((CPA_FALSE == pSessionDesc->nonBlockingOpsInProgress) || (NULL != pSessionDesc->pRequestQueueTail)) { - if (CPA_STATUS_SUCCESS != - LAC_SPINLOCK(&pSessionDesc->requestQueueLock)) { - LAC_LOG_ERROR("Failed to lock request queue"); - return CPA_STATUS_RESOURCE; - } + LAC_SPINLOCK(&pSessionDesc->requestQueueLock); /* Re-check blockingOpsInProgress and pRequestQueueTail in case * either @@ -95,10 +91,7 @@ /* request is queued, don't send to QAT here */ enqueued = CPA_TRUE; } - if (CPA_STATUS_SUCCESS != - LAC_SPINUNLOCK(&pSessionDesc->requestQueueLock)) { - LAC_LOG_ERROR("Failed to unlock request queue"); - } + LAC_SPINUNLOCK(&pSessionDesc->requestQueueLock); } if (CPA_FALSE == enqueued) { diff --git a/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat.c b/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat.c --- a/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat.c +++ b/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat.c @@ -31,6 +31,7 @@ #include "sal_string_parse.h" #include "lac_sym_key.h" #include "lac_sym_qat_hash_defs_lookup.h" +#include "lac_sym_qat_constants_table.h" #include "lac_sym_qat_cipher.h" #include "lac_sym_qat_hash.h" @@ -104,6 +105,9 @@ { CpaStatus status = CPA_STATUS_SUCCESS; + /* Initialize the SHRAM constants table */ + LacSymQat_ConstantsInitLookupTables(instanceHandle); + /* Initialise the Hash lookup table */ status = LacSymQat_HashLookupInit(instanceHandle); @@ -130,10 +134,10 @@ Cpa16U *pLaCommandFlags, Cpa32U ivLenInBytes) { - /* For Chacha ciphers set command flag as partial none to proceed + /* For SM4/Chacha ciphers set command flag as partial none to proceed * with stateless processing */ - if (LAC_CIPHER_IS_CHACHA(cipherAlgorithm) || - LAC_CIPHER_IS_SM4(cipherAlgorithm)) { + if (LAC_CIPHER_IS_SM4(cipherAlgorithm) || + LAC_CIPHER_IS_CHACHA(cipherAlgorithm)) { ICP_QAT_FW_LA_PARTIAL_SET(*pLaCommandFlags, ICP_QAT_FW_LA_PARTIAL_NONE); return; @@ -144,10 +148,10 @@ * must be disabled always. * For all other ciphers and auth * update state is disabled for full packets and final partials */ - if (((laCmdId != ICP_QAT_FW_LA_CMD_AUTH) && - LAC_CIPHER_IS_ECB_MODE(cipherAlgorithm)) || - (ICP_QAT_FW_LA_PARTIAL_NONE == qatPacketType) || - (ICP_QAT_FW_LA_PARTIAL_END == qatPacketType)) { + if ((ICP_QAT_FW_LA_PARTIAL_NONE == qatPacketType) || + (ICP_QAT_FW_LA_PARTIAL_END == qatPacketType) || + ((laCmdId != ICP_QAT_FW_LA_CMD_AUTH) && + LAC_CIPHER_IS_ECB_MODE(cipherAlgorithm))) { ICP_QAT_FW_LA_UPDATE_STATE_SET(*pLaCommandFlags, ICP_QAT_FW_LA_NO_UPDATE_STATE); } @@ -182,8 +186,9 @@ CpaCySymPacketType packetState, Cpa32U *pQatPacketType) { + switch (packetType) { /* partial */ - if (CPA_CY_SYM_PACKET_TYPE_PARTIAL == packetType) { + case CPA_CY_SYM_PACKET_TYPE_PARTIAL: /* if the previous state was full, then this is the first packet */ if (CPA_CY_SYM_PACKET_TYPE_FULL == packetState) { @@ -191,13 +196,15 @@ } else { *pQatPacketType = ICP_QAT_FW_LA_PARTIAL_MID; } - } + break; + /* final partial */ - else if (CPA_CY_SYM_PACKET_TYPE_LAST_PARTIAL == packetType) { + case CPA_CY_SYM_PACKET_TYPE_LAST_PARTIAL: *pQatPacketType = ICP_QAT_FW_LA_PARTIAL_END; - } + break; + /* full packet - CPA_CY_SYM_PACKET_TYPE_FULL */ - else { + default: *pQatPacketType = ICP_QAT_FW_LA_PARTIAL_NONE; } } @@ -225,3 +232,101 @@ ICP_QAT_FW_LA_GCM_IV_LEN_FLAG_SET( *laCmdFlags, ICP_QAT_FW_LA_GCM_IV_LEN_NOT_12_OCTETS); } + +CpaBoolean +LacSymQat_UseSymConstantsTable(lac_session_desc_t *pSession, + Cpa8U *pCipherOffset, + Cpa8U *pHashOffset) +{ + + CpaBoolean useOptimisedContentDesc = CPA_FALSE; + CpaBoolean useSHRAMConstants = CPA_FALSE; + + *pCipherOffset = 0; + *pHashOffset = 0; + + /* for chaining can we use the optimised content descritor */ + if (pSession->laCmdId == ICP_QAT_FW_LA_CMD_CIPHER_HASH || + pSession->laCmdId == ICP_QAT_FW_LA_CMD_HASH_CIPHER) { + useOptimisedContentDesc = + LacSymQat_UseOptimisedContentDesc(pSession); + } + + /* Cipher-only case or chaining */ + if (pSession->laCmdId == ICP_QAT_FW_LA_CMD_CIPHER || + useOptimisedContentDesc) { + icp_qat_hw_cipher_algo_t algorithm; + icp_qat_hw_cipher_mode_t mode; + icp_qat_hw_cipher_dir_t dir; + icp_qat_hw_cipher_convert_t key_convert; + + if (pSession->cipherKeyLenInBytes > + sizeof(icp_qat_fw_comn_req_hdr_cd_pars_t)) { + return CPA_FALSE; + } + + LacSymQat_CipherGetCfgData( + pSession, &algorithm, &mode, &dir, &key_convert); + + /* Check if cipher config is available in table. */ + LacSymQat_ConstantsGetCipherOffset(pSession->pInstance, + algorithm, + mode, + dir, + key_convert, + pCipherOffset); + if (*pCipherOffset > 0) { + useSHRAMConstants = CPA_TRUE; + } else { + useSHRAMConstants = CPA_FALSE; + } + } + + /* hash only case or when chaining, cipher must be found in SHRAM table + * for + * optimised CD case */ + if (pSession->laCmdId == ICP_QAT_FW_LA_CMD_AUTH || + (useOptimisedContentDesc && useSHRAMConstants)) { + icp_qat_hw_auth_algo_t algorithm; + CpaBoolean nested; + + if (pSession->digestVerify) { + return CPA_FALSE; + } + + if ((!(useOptimisedContentDesc && useSHRAMConstants)) && + (pSession->qatHashMode == ICP_QAT_HW_AUTH_MODE1)) { + /* we can only use the SHA1-mode1 in the SHRAM constants + * table when + * we are using the opimised content desc */ + return CPA_FALSE; + } + + LacSymQat_HashGetCfgData(pSession->pInstance, + pSession->qatHashMode, + pSession->hashMode, + pSession->hashAlgorithm, + &algorithm, + &nested); + + /* Check if config data is available in table. */ + LacSymQat_ConstantsGetAuthOffset(pSession->pInstance, + algorithm, + pSession->qatHashMode, + nested, + pHashOffset); + if (*pHashOffset > 0) { + useSHRAMConstants = CPA_TRUE; + } else { + useSHRAMConstants = CPA_FALSE; + } + } + + return useSHRAMConstants; +} + +CpaBoolean +LacSymQat_UseOptimisedContentDesc(lac_session_desc_t *pSession) +{ + return CPA_FALSE; +} diff --git a/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_cipher.c b/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_cipher.c --- a/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_cipher.c +++ b/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_cipher.c @@ -29,6 +29,9 @@ #include "lac_sym_cipher_defs.h" #include "icp_qat_hw.h" #include "icp_qat_fw_la.h" +#include "sal_hw_gen.h" + +#define LAC_UNUSED_POS_MASK 0x3 /***************************************************************************** * Internal data @@ -73,7 +76,7 @@ 0, 0, 0, - ICP_QAT_HW_CIPHER_ALGO_AES128, // ICP_QAT_HW_AES_128_XTS_KEY_SZ + ICP_QAT_HW_CIPHER_ALGO_AES128, /* ICP_QAT_HW_AES_128_XTS_KEY_SZ */ 0, 0, 0, @@ -105,7 +108,7 @@ 0, 0, 0, - ICP_QAT_HW_CIPHER_ALGO_AES256 // ICP_QAT_HW_AES_256_XTS_KEY_SZ + ICP_QAT_HW_CIPHER_ALGO_AES256 /* ICP_QAT_HW_AES_256_XTS_KEY_SZ */ }; /* LAC_CIPHER_IS_AES */ static const uint8_t key_size_aes[] = { @@ -125,7 +128,7 @@ 0, 0, 0, - ICP_QAT_HW_CIPHER_ALGO_AES128, // ICP_QAT_HW_AES_128_KEY_SZ + ICP_QAT_HW_CIPHER_ALGO_AES128, /* ICP_QAT_HW_AES_128_KEY_SZ */ 0, 0, 0, @@ -133,7 +136,7 @@ 0, 0, 0, - ICP_QAT_HW_CIPHER_ALGO_AES192, // ICP_QAT_HW_AES_192_KEY_SZ + ICP_QAT_HW_CIPHER_ALGO_AES192, /* ICP_QAT_HW_AES_192_KEY_SZ */ 0, 0, 0, @@ -141,7 +144,7 @@ 0, 0, 0, - ICP_QAT_HW_CIPHER_ALGO_AES256 // ICP_QAT_HW_AES_256_KEY_SZ + ICP_QAT_HW_CIPHER_ALGO_AES256 /* ICP_QAT_HW_AES_256_KEY_SZ */ }; /* LAC_CIPHER_IS_AES_F8 */ static const uint8_t key_size_f8[] = { @@ -177,23 +180,13 @@ 0, 0, 0, - ICP_QAT_HW_CIPHER_ALGO_AES128, // ICP_QAT_HW_AES_128_F8_KEY_SZ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, + ICP_QAT_HW_CIPHER_ALGO_AES128, /* ICP_QAT_HW_AES_128_F8_KEY_SZ */ 0, 0, 0, 0, 0, 0, - ICP_QAT_HW_CIPHER_ALGO_AES192, // ICP_QAT_HW_AES_192_F8_KEY_SZ 0, 0, 0, @@ -203,16 +196,9 @@ 0, 0, 0, + ICP_QAT_HW_CIPHER_ALGO_AES192, /* ICP_QAT_HW_AES_192_F8_KEY_SZ */ 0, 0, - 0, - 0, - 0, - 0, - ICP_QAT_HW_CIPHER_ALGO_AES256 // ICP_QAT_HW_AES_256_F8_KEY_SZ -}; -/* LAC_CIPHER_IS_SM4 */ -static const uint8_t key_size_sm4[] = { 0, 0, 0, @@ -226,10 +212,7 @@ 0, 0, 0, - 0, - 0, - 0, - ICP_QAT_HW_CIPHER_ALGO_SM4 // ICP_QAT_HW_SM4_KEY_SZ + ICP_QAT_HW_CIPHER_ALGO_AES256 /* ICP_QAT_HW_AES_256_F8_KEY_SZ */ }; typedef struct _icp_qat_hw_cipher_info { @@ -241,239 +224,237 @@ const uint8_t *pAlgByKeySize; } icp_qat_hw_cipher_info; -static const icp_qat_hw_cipher_info icp_qat_alg_info[] = - { - /* CPA_CY_SYM_CIPHER_NULL */ - { - ICP_QAT_HW_CIPHER_ALGO_NULL, - ICP_QAT_HW_CIPHER_ECB_MODE, - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, - IS_KEY_DEP_NO, - NULL, - }, - /* CPA_CY_SYM_CIPHER_ARC4 */ - { - ICP_QAT_HW_CIPHER_ALGO_ARC4, - ICP_QAT_HW_CIPHER_ECB_MODE, - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, - /* Streaming ciphers are a special case. Decrypt = encrypt */ - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, - IS_KEY_DEP_NO, - NULL, - }, - /* CPA_CY_SYM_CIPHER_AES_ECB */ - { - ICP_QAT_HW_CIPHER_ALGO_AES128, - ICP_QAT_HW_CIPHER_ECB_MODE, - /* AES decrypt key needs to be reversed. Instead of reversing the key - * at session registration, it is instead reversed on-the-fly by - * setting the KEY_CONVERT bit here - */ - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, - IS_KEY_DEP_YES, - key_size_aes, - }, - /* CPA_CY_SYM_CIPHER_AES_CBC */ - { - ICP_QAT_HW_CIPHER_ALGO_AES128, - ICP_QAT_HW_CIPHER_CBC_MODE, - /* AES decrypt key needs to be reversed. Instead of reversing the key - * at session registration, it is instead reversed on-the-fly by - * setting the KEY_CONVERT bit here - */ - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, - IS_KEY_DEP_YES, - key_size_aes, - }, - /* CPA_CY_SYM_CIPHER_AES_CTR */ - { - ICP_QAT_HW_CIPHER_ALGO_AES128, - ICP_QAT_HW_CIPHER_CTR_MODE, - /* AES decrypt key needs to be reversed. Instead of reversing the key - * at session registration, it is instead reversed on-the-fly by - * setting the KEY_CONVERT bit here - */ - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, - /* Streaming ciphers are a special case. Decrypt = encrypt - * Overriding default values previously set for AES - */ - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, - IS_KEY_DEP_YES, - key_size_aes, - }, - /* CPA_CY_SYM_CIPHER_AES_CCM */ - { - ICP_QAT_HW_CIPHER_ALGO_AES128, - ICP_QAT_HW_CIPHER_CTR_MODE, - /* AES decrypt key needs to be reversed. Instead of reversing the key - * at session registration, it is instead reversed on-the-fly by - * setting the KEY_CONVERT bit here - */ - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, - /* Streaming ciphers are a special case. Decrypt = encrypt - * Overriding default values previously set for AES - */ - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, - IS_KEY_DEP_YES, - key_size_aes, - }, - /* CPA_CY_SYM_CIPHER_AES_GCM */ - { - ICP_QAT_HW_CIPHER_ALGO_AES128, - ICP_QAT_HW_CIPHER_CTR_MODE, - /* AES decrypt key needs to be reversed. Instead of reversing the key - * at session registration, it is instead reversed on-the-fly by - * setting the KEY_CONVERT bit here - */ - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, - /* Streaming ciphers are a special case. Decrypt = encrypt - * Overriding default values previously set for AES - */ - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, - IS_KEY_DEP_YES, - key_size_aes, - }, - /* CPA_CY_SYM_CIPHER_DES_ECB */ - { - ICP_QAT_HW_CIPHER_ALGO_DES, - ICP_QAT_HW_CIPHER_ECB_MODE, - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, - IS_KEY_DEP_NO, - NULL, - }, - /* CPA_CY_SYM_CIPHER_DES_CBC */ - { - ICP_QAT_HW_CIPHER_ALGO_DES, - ICP_QAT_HW_CIPHER_CBC_MODE, - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, - IS_KEY_DEP_NO, - NULL, - }, - /* CPA_CY_SYM_CIPHER_3DES_ECB */ - { - ICP_QAT_HW_CIPHER_ALGO_3DES, - ICP_QAT_HW_CIPHER_ECB_MODE, - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, - IS_KEY_DEP_NO, - NULL, - }, - /* CPA_CY_SYM_CIPHER_3DES_CBC */ - { - ICP_QAT_HW_CIPHER_ALGO_3DES, - ICP_QAT_HW_CIPHER_CBC_MODE, - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, - IS_KEY_DEP_NO, - NULL, - }, - /* CPA_CY_SYM_CIPHER_3DES_CTR */ - { - ICP_QAT_HW_CIPHER_ALGO_3DES, - ICP_QAT_HW_CIPHER_CTR_MODE, - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, - /* Streaming ciphers are a special case. Decrypt = encrypt - * Overriding default values previously set for AES - */ - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, - IS_KEY_DEP_NO, - NULL, - }, - /* CPA_CY_SYM_CIPHER_KASUMI_F8 */ - { - ICP_QAT_HW_CIPHER_ALGO_KASUMI, - ICP_QAT_HW_CIPHER_F8_MODE, - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, - /* Streaming ciphers are a special case. Decrypt = encrypt */ - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, - IS_KEY_DEP_NO, - NULL, - }, - /* CPA_CY_SYM_CIPHER_SNOW3G_UEA2 */ - { - /* The KEY_CONVERT bit has to be set for Snow_3G operation */ - ICP_QAT_HW_CIPHER_ALGO_SNOW_3G_UEA2, - ICP_QAT_HW_CIPHER_ECB_MODE, - { ICP_QAT_HW_CIPHER_KEY_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, - IS_KEY_DEP_NO, - NULL, - }, - /* CPA_CY_SYM_CIPHER_AES_F8 */ - { - ICP_QAT_HW_CIPHER_ALGO_AES128, - ICP_QAT_HW_CIPHER_F8_MODE, - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, - /* Streaming ciphers are a special case. Decrypt = encrypt */ - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, - IS_KEY_DEP_YES, - key_size_f8, - }, - /* CPA_CY_SYM_CIPHER_AES_XTS */ - { - ICP_QAT_HW_CIPHER_ALGO_AES128, - ICP_QAT_HW_CIPHER_XTS_MODE, - /* AES decrypt key needs to be reversed. Instead of reversing the key - * at session registration, it is instead reversed on-the-fly by - * setting the KEY_CONVERT bit here - */ - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, - IS_KEY_DEP_YES, - key_size_xts, - }, - /* CPA_CY_SYM_CIPHER_ZUC_EEA3 */ - { - ICP_QAT_HW_CIPHER_ALGO_ZUC_3G_128_EEA3, - ICP_QAT_HW_CIPHER_ECB_MODE, - { ICP_QAT_HW_CIPHER_KEY_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, - IS_KEY_DEP_NO, - NULL, - }, - /* CPA_CY_SYM_CIPHER_CHACHA */ - { - ICP_QAT_HW_CIPHER_ALGO_CHACHA20_POLY1305, - ICP_QAT_HW_CIPHER_CTR_MODE, - { ICP_QAT_HW_CIPHER_KEY_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, - IS_KEY_DEP_NO, - NULL, - }, - /* CPA_CY_SYM_CIPHER_SM4_ECB */ - { - ICP_QAT_HW_CIPHER_ALGO_SM4, - ICP_QAT_HW_CIPHER_ECB_MODE, - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, - IS_KEY_DEP_YES, - key_size_sm4, - }, - /* CPA_CY_SYM_CIPHER_SM4_CBC */ - { - ICP_QAT_HW_CIPHER_ALGO_SM4, - ICP_QAT_HW_CIPHER_CBC_MODE, - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, - IS_KEY_DEP_YES, - key_size_sm4, - }, - /* CPA_CY_SYM_CIPHER_SM4_CTR */ - { - ICP_QAT_HW_CIPHER_ALGO_SM4, - ICP_QAT_HW_CIPHER_CTR_MODE, - { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, - /* Streaming ciphers are a special case. Decrypt = encrypt */ - { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, - IS_KEY_DEP_YES, - key_size_sm4, - }, - }; +static const icp_qat_hw_cipher_info icp_qat_alg_info[] = { + /* CPA_CY_SYM_CIPHER_NULL */ + { + ICP_QAT_HW_CIPHER_ALGO_NULL, + ICP_QAT_HW_CIPHER_ECB_MODE, + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, + IS_KEY_DEP_NO, + NULL, + }, + /* CPA_CY_SYM_CIPHER_ARC4 */ + { + ICP_QAT_HW_CIPHER_ALGO_ARC4, + ICP_QAT_HW_CIPHER_ECB_MODE, + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + /* Streaming ciphers are a special case. Decrypt = encrypt */ + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, + IS_KEY_DEP_NO, + NULL, + }, + /* CPA_CY_SYM_CIPHER_AES_ECB */ + { + ICP_QAT_HW_CIPHER_ALGO_AES128, + ICP_QAT_HW_CIPHER_ECB_MODE, + /* AES decrypt key needs to be reversed. Instead of reversing the + * key at session registration, it is instead reversed on-the-fly by + * setting the KEY_CONVERT bit here + */ + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, + IS_KEY_DEP_YES, + key_size_aes, + }, + /* CPA_CY_SYM_CIPHER_AES_CBC */ + { + ICP_QAT_HW_CIPHER_ALGO_AES128, + ICP_QAT_HW_CIPHER_CBC_MODE, + /* AES decrypt key needs to be reversed. Instead of reversing the + * key at session registration, it is instead reversed on-the-fly by + * setting the KEY_CONVERT bit here + */ + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, + IS_KEY_DEP_YES, + key_size_aes, + }, + /* CPA_CY_SYM_CIPHER_AES_CTR */ + { + ICP_QAT_HW_CIPHER_ALGO_AES128, + ICP_QAT_HW_CIPHER_CTR_MODE, + /* AES decrypt key needs to be reversed. Instead of reversing the + * key at session registration, it is instead reversed on-the-fly by + * setting the KEY_CONVERT bit here + */ + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + /* Streaming ciphers are a special case. Decrypt = encrypt + * Overriding default values previously set for AES + */ + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, + IS_KEY_DEP_YES, + key_size_aes, + }, + /* CPA_CY_SYM_CIPHER_AES_CCM */ + { + ICP_QAT_HW_CIPHER_ALGO_AES128, + ICP_QAT_HW_CIPHER_CTR_MODE, + /* AES decrypt key needs to be reversed. Instead of reversing the + * key at session registration, it is instead reversed on-the-fly by + * setting the KEY_CONVERT bit here + */ + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + /* Streaming ciphers are a special case. Decrypt = encrypt + * Overriding default values previously set for AES + */ + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, + IS_KEY_DEP_YES, + key_size_aes, + }, + /* CPA_CY_SYM_CIPHER_AES_GCM */ + { + ICP_QAT_HW_CIPHER_ALGO_AES128, + ICP_QAT_HW_CIPHER_CTR_MODE, + /* AES decrypt key needs to be reversed. Instead of reversing the + * key at session registration, it is instead reversed on-the-fly by + * setting the KEY_CONVERT bit here + */ + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + /* Streaming ciphers are a special case. Decrypt = encrypt + * Overriding default values previously set for AES + */ + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, + IS_KEY_DEP_YES, + key_size_aes, + }, + /* CPA_CY_SYM_CIPHER_DES_ECB */ + { + ICP_QAT_HW_CIPHER_ALGO_DES, + ICP_QAT_HW_CIPHER_ECB_MODE, + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, + IS_KEY_DEP_NO, + NULL, + }, + /* CPA_CY_SYM_CIPHER_DES_CBC */ + { + ICP_QAT_HW_CIPHER_ALGO_DES, + ICP_QAT_HW_CIPHER_CBC_MODE, + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, + IS_KEY_DEP_NO, + NULL, + }, + /* CPA_CY_SYM_CIPHER_3DES_ECB */ + { + ICP_QAT_HW_CIPHER_ALGO_3DES, + ICP_QAT_HW_CIPHER_ECB_MODE, + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, + IS_KEY_DEP_NO, + NULL, + }, + /* CPA_CY_SYM_CIPHER_3DES_CBC */ + { + ICP_QAT_HW_CIPHER_ALGO_3DES, + ICP_QAT_HW_CIPHER_CBC_MODE, + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, + IS_KEY_DEP_NO, + NULL, + }, + /* CPA_CY_SYM_CIPHER_3DES_CTR */ + { + ICP_QAT_HW_CIPHER_ALGO_3DES, + ICP_QAT_HW_CIPHER_CTR_MODE, + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + /* Streaming ciphers are a special case. Decrypt = encrypt + * Overriding default values previously set for AES + */ + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, + IS_KEY_DEP_NO, + NULL, + }, + /* CPA_CY_SYM_CIPHER_KASUMI_F8 */ + { + ICP_QAT_HW_CIPHER_ALGO_KASUMI, + ICP_QAT_HW_CIPHER_F8_MODE, + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + /* Streaming ciphers are a special case. Decrypt = encrypt */ + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, + IS_KEY_DEP_NO, + NULL, + }, + /* CPA_CY_SYM_CIPHER_SNOW3G_UEA2 */ + { + /* The KEY_CONVERT bit has to be set for Snow_3G operation */ + ICP_QAT_HW_CIPHER_ALGO_SNOW_3G_UEA2, + ICP_QAT_HW_CIPHER_ECB_MODE, + { ICP_QAT_HW_CIPHER_KEY_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, + IS_KEY_DEP_NO, + NULL, + }, + /* CPA_CY_SYM_CIPHER_AES_F8 */ + { + ICP_QAT_HW_CIPHER_ALGO_AES128, + ICP_QAT_HW_CIPHER_F8_MODE, + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + /* Streaming ciphers are a special case. Decrypt = encrypt */ + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, + IS_KEY_DEP_YES, + key_size_f8, + }, + /* CPA_CY_SYM_CIPHER_AES_XTS */ + { + ICP_QAT_HW_CIPHER_ALGO_AES128, + ICP_QAT_HW_CIPHER_XTS_MODE, + /* AES decrypt key needs to be reversed. Instead of reversing the + * key at session registration, it is instead reversed on-the-fly by + * setting the KEY_CONVERT bit here + */ + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, + IS_KEY_DEP_YES, + key_size_xts, + }, + /* CPA_CY_SYM_CIPHER_ZUC_EEA3 */ + { + ICP_QAT_HW_CIPHER_ALGO_ZUC_3G_128_EEA3, + ICP_QAT_HW_CIPHER_ECB_MODE, + { ICP_QAT_HW_CIPHER_KEY_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, + IS_KEY_DEP_NO, + NULL, + }, + /* CPA_CY_SYM_CIPHER_CHACHA */ + { + ICP_QAT_HW_CIPHER_ALGO_CHACHA20_POLY1305, + ICP_QAT_HW_CIPHER_CTR_MODE, + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, + IS_KEY_DEP_NO, + NULL, + }, + /* CPA_CY_SYM_CIPHER_SM4_ECB */ + { + ICP_QAT_HW_CIPHER_ALGO_SM4, + ICP_QAT_HW_CIPHER_ECB_MODE, + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, + IS_KEY_DEP_NO, + NULL, + }, + /* CPA_CY_SYM_CIPHER_SM4_CBC */ + { + ICP_QAT_HW_CIPHER_ALGO_SM4, + ICP_QAT_HW_CIPHER_CBC_MODE, + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_KEY_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_DECRYPT }, + IS_KEY_DEP_NO, + NULL, + }, + /* CPA_CY_SYM_CIPHER_SM4_CTR */ + { + ICP_QAT_HW_CIPHER_ALGO_SM4, + ICP_QAT_HW_CIPHER_CTR_MODE, + { ICP_QAT_HW_CIPHER_NO_CONVERT, ICP_QAT_HW_CIPHER_NO_CONVERT }, + { ICP_QAT_HW_CIPHER_ENCRYPT, ICP_QAT_HW_CIPHER_ENCRYPT }, + IS_KEY_DEP_NO, + NULL, + }, +}; /***************************************************************************** * Internal functions @@ -483,6 +464,7 @@ LacSymQat_CipherCtrlBlockWrite(icp_qat_la_bulk_req_ftr_t *pMsg, Cpa32U cipherAlgorithm, Cpa32U targetKeyLenInBytes, + Cpa32U sliceType, icp_qat_fw_slice_t nextSlice, Cpa8U cipherCfgOffsetInQuadWord) { @@ -492,33 +474,52 @@ /* state_padding_sz is nonzero for f8 mode only */ cd_ctrl->cipher_padding_sz = 0; + /* Special handling of AES 192 key for UCS slice. + UCS requires it to have 32 bytes - set is as targetKeyLen + in this case, and add padding. It makes no sense + to force applications to provide such key length for couple reasons: + 1. It won't be possible to distinguish between AES 192 and 256 based + on key lenght only + 2. Only some modes of AES will use UCS slice, then application will + have to know which ones */ + if (ICP_QAT_FW_LA_USE_UCS_SLICE_TYPE == sliceType && + ICP_QAT_HW_AES_192_KEY_SZ == targetKeyLenInBytes) { + targetKeyLenInBytes = ICP_QAT_HW_UCS_AES_192_KEY_SZ; + } + + switch (cipherAlgorithm) { /* Base Key is not passed down to QAT in the case of ARC4 or NULL */ - if (LAC_CIPHER_IS_ARC4(cipherAlgorithm) || - LAC_CIPHER_IS_NULL(cipherAlgorithm)) { + case CPA_CY_SYM_CIPHER_ARC4: + case CPA_CY_SYM_CIPHER_NULL: cd_ctrl->cipher_key_sz = 0; - } else if (LAC_CIPHER_IS_KASUMI(cipherAlgorithm)) { + break; + case CPA_CY_SYM_CIPHER_KASUMI_F8: cd_ctrl->cipher_key_sz = LAC_BYTES_TO_QUADWORDS(ICP_QAT_HW_KASUMI_F8_KEY_SZ); cd_ctrl->cipher_padding_sz = ICP_QAT_HW_MODE_F8_NUM_REG_TO_CLEAR; - } else if (LAC_CIPHER_IS_SNOW3G_UEA2(cipherAlgorithm)) { - /* For Snow3G UEA2 content descriptor key size is - key size plus iv size */ + break; + /* For Snow3G UEA2 content descriptor key size is + key size plus iv size */ + case CPA_CY_SYM_CIPHER_SNOW3G_UEA2: cd_ctrl->cipher_key_sz = LAC_BYTES_TO_QUADWORDS(ICP_QAT_HW_SNOW_3G_UEA2_KEY_SZ + ICP_QAT_HW_SNOW_3G_UEA2_IV_SZ); - } else if (LAC_CIPHER_IS_AES_F8(cipherAlgorithm)) { + break; + case CPA_CY_SYM_CIPHER_AES_F8: cd_ctrl->cipher_key_sz = LAC_BYTES_TO_QUADWORDS(targetKeyLenInBytes); cd_ctrl->cipher_padding_sz = - 2 * ICP_QAT_HW_MODE_F8_NUM_REG_TO_CLEAR; - } else if (LAC_CIPHER_IS_ZUC_EEA3(cipherAlgorithm)) { - /* For ZUC EEA3 content descriptor key size is - key size plus iv size */ + (2 * ICP_QAT_HW_MODE_F8_NUM_REG_TO_CLEAR); + break; + /* For ZUC EEA3 content descriptor key size is + key size plus iv size */ + case CPA_CY_SYM_CIPHER_ZUC_EEA3: cd_ctrl->cipher_key_sz = LAC_BYTES_TO_QUADWORDS(ICP_QAT_HW_ZUC_3G_EEA3_KEY_SZ + ICP_QAT_HW_ZUC_3G_EEA3_IV_SZ); - } else { + break; + default: cd_ctrl->cipher_key_sz = LAC_BYTES_TO_QUADWORDS(targetKeyLenInBytes); } @@ -539,6 +540,8 @@ icp_qat_hw_cipher_dir_t *pDir, icp_qat_hw_cipher_convert_t *pKey_convert) { + sal_crypto_service_t *pService = + (sal_crypto_service_t *)pSession->pInstance; CpaCySymCipherAlgorithm cipherAlgorithm = 0; icp_qat_hw_cipher_dir_t cipherDirection = 0; @@ -553,8 +556,8 @@ cipherAlgorithm = pSession->cipherAlgorithm - 1; cipherDirection = pSession->cipherDirection == CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT ? - ICP_QAT_HW_CIPHER_ENCRYPT : - ICP_QAT_HW_CIPHER_DECRYPT; + ICP_QAT_HW_CIPHER_ENCRYPT : + ICP_QAT_HW_CIPHER_DECRYPT; *pAlgorithm = icp_qat_alg_info[cipherAlgorithm].algorithm; *pMode = icp_qat_alg_info[cipherAlgorithm].mode; @@ -566,23 +569,22 @@ *pAlgorithm = icp_qat_alg_info[cipherAlgorithm] .pAlgByKeySize[pSession->cipherKeyLenInBytes]; } - /* Set the mode */ - if (LAC_CIPHER_IS_CTR_MODE(pSession->cipherAlgorithm)) { - *pMode = ICP_QAT_HW_CIPHER_CTR_MODE; - *pKey_convert = ICP_QAT_HW_CIPHER_NO_CONVERT; - /* CCP and AES_GCM single pass, despite being limited to - * CTR/AEAD mode, - * support both Encrypt/Decrypt modes - this is because of the - * differences in the hash computation/verification paths in - * encrypt/decrypt modes respectively. - * By default CCP is set as CTR Mode.Set AEAD Mode for AES_GCM. - */ - if (pSession->isSinglePass) { - if (LAC_CIPHER_IS_GCM(pSession->cipherAlgorithm)) - *pMode = ICP_QAT_HW_CIPHER_AEAD_MODE; - if (cipherDirection == ICP_QAT_HW_CIPHER_DECRYPT) - *pDir = ICP_QAT_HW_CIPHER_DECRYPT; - } + + /* CCP and AES_GCM single pass, despite being limited to CTR/AEAD mode, + * support both Encrypt/Decrypt modes - this is because of the + * differences in the hash computation/verification paths in + * encrypt/decrypt modes respectively. + * By default CCP is set as CTR Mode.Set AEAD Mode for AES_GCM. + */ + if (SPC == pSession->singlePassState) { + if (LAC_CIPHER_IS_GCM(pSession->cipherAlgorithm)) + *pMode = ICP_QAT_HW_CIPHER_AEAD_MODE; + else if (isCyGen4x(pService) && + LAC_CIPHER_IS_CCM(pSession->cipherAlgorithm)) + *pMode = ICP_QAT_HW_CIPHER_CCM_MODE; + + if (cipherDirection == ICP_QAT_HW_CIPHER_DECRYPT) + *pDir = ICP_QAT_HW_CIPHER_DECRYPT; } } @@ -597,6 +599,10 @@ icp_qat_hw_cipher_convert_t key_convert; icp_qat_hw_cipher_config_t *pCipherConfig = (icp_qat_hw_cipher_config_t *)pCipherHwBlock; + icp_qat_hw_ucs_cipher_config_t *pUCSCipherConfig = + (icp_qat_hw_ucs_cipher_config_t *)pCipherHwBlock; + + Cpa32U val, reserved; Cpa32U aed_hash_cmp_length = 0; *pSizeInBytes = 0; @@ -605,24 +611,38 @@ pSession, &algorithm, &mode, &dir, &key_convert); /* Build the cipher config into the hardware setup block */ - if (pSession->isSinglePass) { + if (SPC == pSession->singlePassState) { aed_hash_cmp_length = pSession->hashResultSize; - pCipherConfig->reserved = ICP_QAT_HW_CIPHER_CONFIG_BUILD_UPPER( + reserved = ICP_QAT_HW_CIPHER_CONFIG_BUILD_UPPER( pSession->aadLenInBytes); } else { - pCipherConfig->reserved = 0; + reserved = 0; } - pCipherConfig->val = ICP_QAT_HW_CIPHER_CONFIG_BUILD( + val = ICP_QAT_HW_CIPHER_CONFIG_BUILD( mode, algorithm, key_convert, dir, aed_hash_cmp_length); - *pSizeInBytes = sizeof(icp_qat_hw_cipher_config_t); + /* UCS slice has 128-bit configuration register. + Leacy cipher slice has 64-bit config register */ + if (ICP_QAT_FW_LA_USE_UCS_SLICE_TYPE == pSession->cipherSliceType) { + pUCSCipherConfig->val = val; + pUCSCipherConfig->reserved[0] = reserved; + pUCSCipherConfig->reserved[1] = 0; + pUCSCipherConfig->reserved[2] = 0; + *pSizeInBytes = sizeof(icp_qat_hw_ucs_cipher_config_t); + } else { + pCipherConfig->val = val; + pCipherConfig->reserved = reserved; + *pSizeInBytes = sizeof(icp_qat_hw_cipher_config_t); + } } void LacSymQat_CipherHwBlockPopulateKeySetup( + lac_session_desc_t *pSessionDesc, const CpaCySymCipherSetupData *pCipherSetupData, Cpa32U targetKeyLenInBytes, + Cpa32U sliceType, const void *pCipherHwBlock, Cpa32U *pSizeInBytes) { @@ -635,6 +655,20 @@ * Arc4 and Null cipher */ if (!(LAC_CIPHER_IS_ARC4(pCipherSetupData->cipherAlgorithm) || LAC_CIPHER_IS_NULL(pCipherSetupData->cipherAlgorithm))) { + /* Special handling of AES 192 key for UCS slice. + UCS requires it to have 32 bytes - set is as targetKeyLen + in this case, and add padding. It makes no sense + to force applications to provide such key length for couple + reasons: + 1. It won't be possible to distinguish between AES 192 and + 256 based on key lenght only + 2. Only some modes of AES will use UCS slice, then + application will have to know which ones */ + if (ICP_QAT_FW_LA_USE_UCS_SLICE_TYPE == sliceType && + ICP_QAT_HW_AES_192_KEY_SZ == targetKeyLenInBytes) { + targetKeyLenInBytes = ICP_QAT_HW_UCS_AES_192_KEY_SZ; + } + /* Set the Cipher key field in the cipher block */ memcpy(pCipherKey, pCipherSetupData->pCipherKey, @@ -646,9 +680,10 @@ } *pSizeInBytes += targetKeyLenInBytes; - /* For Kasumi in F8 mode Cipher Key is concatenated with - * Cipher Key XOR-ed with Key Modifier (CK||CK^KM) */ - if (LAC_CIPHER_IS_KASUMI(pCipherSetupData->cipherAlgorithm)) { + switch (pCipherSetupData->cipherAlgorithm) { + /* For Kasumi in F8 mode Cipher Key is concatenated with + * Cipher Key XOR-ed with Key Modifier (CK||CK^KM) */ + case CPA_CY_SYM_CIPHER_KASUMI_F8: { Cpa32U wordIndex = 0; Cpa32U *pu32CipherKey = (Cpa32U *)pCipherSetupData->pCipherKey; @@ -672,11 +707,10 @@ LAC_OS_BZERO((Cpa8U *)pTempKey + targetKeyLenInBytes, LAC_QUADWORDS_TO_BYTES( ICP_QAT_HW_MODE_F8_NUM_REG_TO_CLEAR)); - } - /* For AES in F8 mode Cipher Key is concatenated with - * Cipher Key XOR-ed with Key Mask (CK||CK^KM) */ - else if (LAC_CIPHER_IS_AES_F8( - pCipherSetupData->cipherAlgorithm)) { + } break; + /* For AES in F8 mode Cipher Key is concatenated with + * Cipher Key XOR-ed with Key Mask (CK||CK^KM) */ + case CPA_CY_SYM_CIPHER_AES_F8: { Cpa32U index = 0; Cpa8U *pTempKey = pCipherKey + (targetKeyLenInBytes / 2); @@ -690,20 +724,59 @@ /* also add padding for AES F8 */ *pSizeInBytes += 2 * targetKeyLenInBytes; LAC_OS_BZERO(pTempKey, 2 * targetKeyLenInBytes); - } else if (LAC_CIPHER_IS_SNOW3G_UEA2( - pCipherSetupData->cipherAlgorithm)) { + } break; + case CPA_CY_SYM_CIPHER_SNOW3G_UEA2: { /* For Snow3G zero area after the key for FW */ LAC_OS_BZERO(pCipherKey + targetKeyLenInBytes, ICP_QAT_HW_SNOW_3G_UEA2_IV_SZ); *pSizeInBytes += ICP_QAT_HW_SNOW_3G_UEA2_IV_SZ; - } else if (LAC_CIPHER_IS_ZUC_EEA3( - pCipherSetupData->cipherAlgorithm)) { + } break; + case CPA_CY_SYM_CIPHER_ZUC_EEA3: { /* For ZUC zero area after the key for FW */ LAC_OS_BZERO(pCipherKey + targetKeyLenInBytes, ICP_QAT_HW_ZUC_3G_EEA3_IV_SZ); *pSizeInBytes += ICP_QAT_HW_ZUC_3G_EEA3_IV_SZ; + } break; + case CPA_CY_SYM_CIPHER_AES_XTS: { + /* For AES in XTS mode Cipher Key is concatenated with + * second Cipher Key which is used for tweak calculation + * (CK1||CK2). For decryption Cipher Key needs to be + * converted to reverse key.*/ + if (ICP_QAT_FW_LA_USE_UCS_SLICE_TYPE == sliceType) { + Cpa32U key_len = + pCipherSetupData->cipherKeyLenInBytes / 2; + memcpy(pSessionDesc->cipherAesXtsKey1Forward, + pCipherSetupData->pCipherKey, + key_len); + + qatUtilsAESKeyExpansionForward( + pSessionDesc->cipherAesXtsKey1Forward, + key_len, + (uint32_t *) + pSessionDesc->cipherAesXtsKey1Reverse); + + memcpy(pSessionDesc->cipherAesXtsKey2, + pCipherSetupData->pCipherKey + key_len, + key_len); + + if (CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT == + pCipherSetupData->cipherDirection) { + memcpy(pCipherKey, + pSessionDesc + ->cipherAesXtsKey1Reverse, + key_len); + } else { + memcpy(pCipherKey, + pSessionDesc + ->cipherAesXtsKey1Forward, + key_len); + } + } + } break; + default: + break; } } } @@ -715,56 +788,94 @@ Cpa8U LacSymQat_CipherBlockSizeBytesGet(CpaCySymCipherAlgorithm cipherAlgorithm) { - if (LAC_CIPHER_IS_ARC4(cipherAlgorithm)) { - return LAC_CIPHER_ARC4_BLOCK_LEN_BYTES; - } else if (LAC_CIPHER_IS_AES(cipherAlgorithm) || - LAC_CIPHER_IS_AES_F8(cipherAlgorithm)) { - return ICP_QAT_HW_AES_BLK_SZ; - } else if (LAC_CIPHER_IS_DES(cipherAlgorithm)) { - return ICP_QAT_HW_DES_BLK_SZ; - } else if (LAC_CIPHER_IS_TRIPLE_DES(cipherAlgorithm)) { - return ICP_QAT_HW_3DES_BLK_SZ; - } else if (LAC_CIPHER_IS_KASUMI(cipherAlgorithm)) { - return ICP_QAT_HW_KASUMI_BLK_SZ; - } else if (LAC_CIPHER_IS_SNOW3G_UEA2(cipherAlgorithm)) { - return ICP_QAT_HW_SNOW_3G_BLK_SZ; - } else if (LAC_CIPHER_IS_ZUC_EEA3(cipherAlgorithm)) { - return ICP_QAT_HW_ZUC_3G_BLK_SZ; - } else if (LAC_CIPHER_IS_NULL(cipherAlgorithm)) { - return LAC_CIPHER_NULL_BLOCK_LEN_BYTES; - } else if (LAC_CIPHER_IS_CHACHA(cipherAlgorithm)) { - return ICP_QAT_HW_CHACHAPOLY_BLK_SZ; - } else if (LAC_CIPHER_IS_SM4(cipherAlgorithm)) { - return ICP_QAT_HW_SM4_BLK_SZ; - } else { - QAT_UTILS_LOG("Algorithm not supported in Cipher\n"); - return 0; + Cpa8U blockSize = 0; + switch (cipherAlgorithm) { + case CPA_CY_SYM_CIPHER_ARC4: + blockSize = LAC_CIPHER_ARC4_BLOCK_LEN_BYTES; + break; + /* Handle AES or AES_F8 */ + case CPA_CY_SYM_CIPHER_AES_ECB: + case CPA_CY_SYM_CIPHER_AES_CBC: + case CPA_CY_SYM_CIPHER_AES_CTR: + case CPA_CY_SYM_CIPHER_AES_CCM: + case CPA_CY_SYM_CIPHER_AES_GCM: + case CPA_CY_SYM_CIPHER_AES_XTS: + case CPA_CY_SYM_CIPHER_AES_F8: + blockSize = ICP_QAT_HW_AES_BLK_SZ; + break; + /* Handle DES */ + case CPA_CY_SYM_CIPHER_DES_ECB: + case CPA_CY_SYM_CIPHER_DES_CBC: + blockSize = ICP_QAT_HW_DES_BLK_SZ; + break; + /* Handle TRIPLE DES */ + case CPA_CY_SYM_CIPHER_3DES_ECB: + case CPA_CY_SYM_CIPHER_3DES_CBC: + case CPA_CY_SYM_CIPHER_3DES_CTR: + blockSize = ICP_QAT_HW_3DES_BLK_SZ; + break; + case CPA_CY_SYM_CIPHER_KASUMI_F8: + blockSize = ICP_QAT_HW_KASUMI_BLK_SZ; + break; + case CPA_CY_SYM_CIPHER_SNOW3G_UEA2: + blockSize = ICP_QAT_HW_SNOW_3G_BLK_SZ; + break; + case CPA_CY_SYM_CIPHER_ZUC_EEA3: + blockSize = ICP_QAT_HW_ZUC_3G_BLK_SZ; + break; + case CPA_CY_SYM_CIPHER_NULL: + blockSize = LAC_CIPHER_NULL_BLOCK_LEN_BYTES; + break; + case CPA_CY_SYM_CIPHER_CHACHA: + blockSize = ICP_QAT_HW_CHACHAPOLY_BLK_SZ; + break; + case CPA_CY_SYM_CIPHER_SM4_ECB: + case CPA_CY_SYM_CIPHER_SM4_CBC: + case CPA_CY_SYM_CIPHER_SM4_CTR: + blockSize = ICP_QAT_HW_SM4_BLK_SZ; + break; + default: + QAT_UTILS_LOG("Algorithm not supported in Cipher"); } + return blockSize; } Cpa32U LacSymQat_CipherIvSizeBytesGet(CpaCySymCipherAlgorithm cipherAlgorithm) { - if (CPA_CY_SYM_CIPHER_ARC4 == cipherAlgorithm) { - return LAC_CIPHER_ARC4_STATE_LEN_BYTES; - } else if (LAC_CIPHER_IS_KASUMI(cipherAlgorithm)) { - return ICP_QAT_HW_KASUMI_BLK_SZ; - } else if (LAC_CIPHER_IS_SNOW3G_UEA2(cipherAlgorithm)) { - return ICP_QAT_HW_SNOW_3G_UEA2_IV_SZ; - } else if (LAC_CIPHER_IS_ZUC_EEA3(cipherAlgorithm)) { - return ICP_QAT_HW_ZUC_3G_EEA3_IV_SZ; - } else if (LAC_CIPHER_IS_CHACHA(cipherAlgorithm)) { - return ICP_QAT_HW_CHACHAPOLY_IV_SZ; - } else if (LAC_CIPHER_IS_ECB_MODE(cipherAlgorithm)) { - return 0; - } else { - return (Cpa32U)LacSymQat_CipherBlockSizeBytesGet( - cipherAlgorithm); + Cpa32U ivSize = 0; + switch (cipherAlgorithm) { + case CPA_CY_SYM_CIPHER_ARC4: + ivSize = LAC_CIPHER_ARC4_STATE_LEN_BYTES; + break; + case CPA_CY_SYM_CIPHER_KASUMI_F8: + ivSize = ICP_QAT_HW_KASUMI_BLK_SZ; + break; + case CPA_CY_SYM_CIPHER_SNOW3G_UEA2: + ivSize = ICP_QAT_HW_SNOW_3G_UEA2_IV_SZ; + break; + case CPA_CY_SYM_CIPHER_ZUC_EEA3: + ivSize = ICP_QAT_HW_ZUC_3G_EEA3_IV_SZ; + break; + case CPA_CY_SYM_CIPHER_CHACHA: + ivSize = ICP_QAT_HW_CHACHAPOLY_IV_SZ; + break; + case CPA_CY_SYM_CIPHER_AES_ECB: + case CPA_CY_SYM_CIPHER_DES_ECB: + case CPA_CY_SYM_CIPHER_3DES_ECB: + case CPA_CY_SYM_CIPHER_SM4_ECB: + case CPA_CY_SYM_CIPHER_NULL: + /* for all ECB Mode IV size is 0 */ + break; + default: + ivSize = LacSymQat_CipherBlockSizeBytesGet(cipherAlgorithm); } + return ivSize; } inline CpaStatus -LacSymQat_CipherRequestParamsPopulate(icp_qat_fw_la_bulk_req_t *pReq, +LacSymQat_CipherRequestParamsPopulate(lac_session_desc_t *pSessionDesc, + icp_qat_fw_la_bulk_req_t *pReq, Cpa32U cipherOffsetInBytes, Cpa32U cipherLenInBytes, Cpa64U ivBufferPhysAddr, @@ -773,6 +884,8 @@ icp_qat_fw_la_cipher_req_params_t *pCipherReqParams; icp_qat_fw_cipher_cd_ctrl_hdr_t *pCipherCdCtrlHdr; icp_qat_fw_serv_specif_flags *pCipherSpecificFlags; + Cpa32U usedBufSize = 0; + Cpa32U totalBufSize = 0; pCipherReqParams = (icp_qat_fw_la_cipher_req_params_t *)((Cpa8U *)&(pReq->serv_specif_rqpars) + @@ -805,31 +918,40 @@ } else { /* Populate the field with the contents of the buffer, * zero field first as data may be smaller than the field */ - memset(pCipherReqParams->u.cipher_IV_array, - 0, - LAC_LONGWORDS_TO_BYTES(ICP_QAT_FW_NUM_LONGWORDS_4)); - - /* We force a specific compiler optimisation here. The length - * to - * be copied turns out to be always 16, and by coding a memcpy - * with - * a literal value the compiler will compile inline code (in - * fact, - * only two vector instructions) to effect the copy. This gives - * us - * a huge performance increase. - */ - unsigned long cplen = - LAC_QUADWORDS_TO_BYTES(pCipherCdCtrlHdr->cipher_state_sz); - - if (cplen == 16) - memcpy(pCipherReqParams->u.cipher_IV_array, - pIvBufferVirt, - 16); - else + + /* In case of XTS mode using UCS slice always embedd IV. + * IV provided by user needs to be encrypted to calculate + * initial tweak, use pCipherReqParams->u.cipher_IV_array as + * destination buffer for tweak value */ + if (ICP_QAT_FW_LA_USE_UCS_SLICE_TYPE == + pSessionDesc->cipherSliceType && + LAC_CIPHER_IS_XTS_MODE(pSessionDesc->cipherAlgorithm)) { + memset(pCipherReqParams->u.cipher_IV_array, + 0, + LAC_LONGWORDS_TO_BYTES( + ICP_QAT_FW_NUM_LONGWORDS_4)); + qatUtilsAESEncrypt( + pSessionDesc->cipherAesXtsKey2, + pSessionDesc->cipherKeyLenInBytes / 2, + pIvBufferVirt, + (Cpa8U *)pCipherReqParams->u.cipher_IV_array); + } else { + totalBufSize = + LAC_LONGWORDS_TO_BYTES(ICP_QAT_FW_NUM_LONGWORDS_4); + usedBufSize = LAC_QUADWORDS_TO_BYTES( + pCipherCdCtrlHdr->cipher_state_sz); + /* Only initialise unused buffer if applicable*/ + if (usedBufSize < totalBufSize) { + memset( + (&pCipherReqParams->u.cipher_IV_array + [usedBufSize & LAC_UNUSED_POS_MASK]), + 0, + totalBufSize - usedBufSize); + } memcpy(pCipherReqParams->u.cipher_IV_array, pIvBufferVirt, - cplen); + usedBufSize); + } /* Set the flag indicating the field format */ ICP_QAT_FW_LA_CIPH_IV_FLD_FLAG_SET( *pCipherSpecificFlags, ICP_QAT_FW_CIPH_IV_16BYTE_DATA); @@ -851,7 +973,7 @@ pArc4CipherState[i] = (Cpa8U)i; } - for (i = 0; i < LAC_CIPHER_ARC4_KEY_MATRIX_LEN_BYTES; ++i) { + for (i = 0, k = 0; i < LAC_CIPHER_ARC4_KEY_MATRIX_LEN_BYTES; ++i, ++k) { Cpa8U swap = 0; if (k >= keyLenInBytes) @@ -860,7 +982,6 @@ j = (j + pArc4CipherState[i] + pKey[k]); if (j >= LAC_CIPHER_ARC4_KEY_MATRIX_LEN_BYTES) j %= LAC_CIPHER_ARC4_KEY_MATRIX_LEN_BYTES; - ++k; /* Swap state[i] & state[j] */ swap = pArc4CipherState[i]; diff --git a/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_constants_table.c b/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_constants_table.c new file mode 100644 --- /dev/null +++ b/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_constants_table.c @@ -0,0 +1,257 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2007-2022 Intel Corporation */ +/* $FreeBSD$ */ + +/** + *************************************************************************** + * @file lac_sym_qat_constants_table.c + * + * @ingroup LacSymQat + ***************************************************************************/ + +/* +******************************************************************************* +* Include public/global header files +******************************************************************************* +*/ + +#include "cpa.h" + +/* +******************************************************************************* +* Include private header files +******************************************************************************* +*/ + +#include "lac_common.h" +#include "icp_qat_fw_la.h" +#include "lac_log.h" +#include "lac_mem.h" +#include "sal_string_parse.h" +#include "lac_sal_types_crypto.h" +#include "sal_types_compression.h" + +static uint8_t icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_DELIMITER] + [ICP_QAT_HW_CIPHER_MODE_DELIMITER][2] + [2]; /* IA version */ +static uint8_t icp_qat_hw_auth_lookup_tbl[ICP_QAT_HW_AUTH_ALGO_DELIMITER] + [ICP_QAT_HW_AUTH_MODE_DELIMITER] + [2]; /* IA version */ + +#define ICP_QAT_HW_FILL_LOOKUP_TBLS \ + { \ + \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_DES] \ + [ICP_QAT_HW_CIPHER_ECB_MODE] \ + [ICP_QAT_HW_CIPHER_ENCRYPT] \ + [ICP_QAT_HW_CIPHER_NO_CONVERT] = \ + 9; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_DES] \ + [ICP_QAT_HW_CIPHER_ECB_MODE] \ + [ICP_QAT_HW_CIPHER_DECRYPT] \ + [ICP_QAT_HW_CIPHER_NO_CONVERT] = \ + 10; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_DES] \ + [ICP_QAT_HW_CIPHER_CBC_MODE] \ + [ICP_QAT_HW_CIPHER_ENCRYPT] \ + [ICP_QAT_HW_CIPHER_NO_CONVERT] = \ + 11; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_DES] \ + [ICP_QAT_HW_CIPHER_CBC_MODE] \ + [ICP_QAT_HW_CIPHER_DECRYPT] \ + [ICP_QAT_HW_CIPHER_NO_CONVERT] = \ + 12; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_DES] \ + [ICP_QAT_HW_CIPHER_CTR_MODE] \ + [ICP_QAT_HW_CIPHER_ENCRYPT] \ + [ICP_QAT_HW_CIPHER_NO_CONVERT] = \ + 13; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_AES128] \ + [ICP_QAT_HW_CIPHER_ECB_MODE] \ + [ICP_QAT_HW_CIPHER_ENCRYPT] \ + [ICP_QAT_HW_CIPHER_NO_CONVERT] = \ + 14; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_AES128] \ + [ICP_QAT_HW_CIPHER_ECB_MODE] \ + [ICP_QAT_HW_CIPHER_ENCRYPT] \ + [ICP_QAT_HW_CIPHER_KEY_CONVERT] = \ + 15; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_AES128] \ + [ICP_QAT_HW_CIPHER_ECB_MODE] \ + [ICP_QAT_HW_CIPHER_DECRYPT] \ + [ICP_QAT_HW_CIPHER_NO_CONVERT] = \ + 16; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_AES128] \ + [ICP_QAT_HW_CIPHER_ECB_MODE] \ + [ICP_QAT_HW_CIPHER_DECRYPT] \ + [ICP_QAT_HW_CIPHER_KEY_CONVERT] = \ + 17; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_AES128] \ + [ICP_QAT_HW_CIPHER_CBC_MODE] \ + [ICP_QAT_HW_CIPHER_ENCRYPT] \ + [ICP_QAT_HW_CIPHER_NO_CONVERT] = \ + 18; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_AES128] \ + [ICP_QAT_HW_CIPHER_CBC_MODE] \ + [ICP_QAT_HW_CIPHER_ENCRYPT] \ + [ICP_QAT_HW_CIPHER_KEY_CONVERT] = \ + 19; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_AES128] \ + [ICP_QAT_HW_CIPHER_CBC_MODE] \ + [ICP_QAT_HW_CIPHER_DECRYPT] \ + [ICP_QAT_HW_CIPHER_NO_CONVERT] = \ + 20; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_AES128] \ + [ICP_QAT_HW_CIPHER_CBC_MODE] \ + [ICP_QAT_HW_CIPHER_DECRYPT] \ + [ICP_QAT_HW_CIPHER_KEY_CONVERT] = \ + 21; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_AES128] \ + [ICP_QAT_HW_CIPHER_CTR_MODE] \ + [ICP_QAT_HW_CIPHER_ENCRYPT] \ + [ICP_QAT_HW_CIPHER_NO_CONVERT] = \ + 22; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_AES128] \ + [ICP_QAT_HW_CIPHER_F8_MODE] \ + [ICP_QAT_HW_CIPHER_ENCRYPT] \ + [ICP_QAT_HW_CIPHER_NO_CONVERT] = \ + 23; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_ARC4] \ + [ICP_QAT_HW_CIPHER_ECB_MODE] \ + [ICP_QAT_HW_CIPHER_ENCRYPT] \ + [ICP_QAT_HW_CIPHER_NO_CONVERT] = \ + 24; \ + icp_qat_hw_cipher_lookup_tbl[ICP_QAT_HW_CIPHER_ALGO_ARC4] \ + [ICP_QAT_HW_CIPHER_ECB_MODE] \ + [ICP_QAT_HW_CIPHER_ENCRYPT] \ + [ICP_QAT_HW_CIPHER_KEY_CONVERT] = \ + 25; \ + \ + icp_qat_hw_auth_lookup_tbl \ + [ICP_QAT_HW_AUTH_ALGO_MD5][ICP_QAT_HW_AUTH_MODE0] \ + [ICP_QAT_FW_AUTH_HDR_FLAG_NO_NESTED] = 37; \ + icp_qat_hw_auth_lookup_tbl \ + [ICP_QAT_HW_AUTH_ALGO_SHA1][ICP_QAT_HW_AUTH_MODE0] \ + [ICP_QAT_FW_AUTH_HDR_FLAG_NO_NESTED] = 41; \ + icp_qat_hw_auth_lookup_tbl \ + [ICP_QAT_HW_AUTH_ALGO_SHA1][ICP_QAT_HW_AUTH_MODE1] \ + [ICP_QAT_FW_AUTH_HDR_FLAG_NO_NESTED] = 46; \ + icp_qat_hw_auth_lookup_tbl \ + [ICP_QAT_HW_AUTH_ALGO_SHA224][ICP_QAT_HW_AUTH_MODE0] \ + [ICP_QAT_FW_AUTH_HDR_FLAG_NO_NESTED] = 48; \ + icp_qat_hw_auth_lookup_tbl \ + [ICP_QAT_HW_AUTH_ALGO_SHA256][ICP_QAT_HW_AUTH_MODE0] \ + [ICP_QAT_FW_AUTH_HDR_FLAG_NO_NESTED] = 54; \ + icp_qat_hw_auth_lookup_tbl \ + [ICP_QAT_HW_AUTH_ALGO_SHA384][ICP_QAT_HW_AUTH_MODE0] \ + [ICP_QAT_FW_AUTH_HDR_FLAG_NO_NESTED] = 60; \ + icp_qat_hw_auth_lookup_tbl \ + [ICP_QAT_HW_AUTH_ALGO_SHA512][ICP_QAT_HW_AUTH_MODE0] \ + [ICP_QAT_FW_AUTH_HDR_FLAG_NO_NESTED] = 70; \ + } + +/** + ***************************************************************************** + * @ingroup LacSymQat + * LacSymQat_ConstantsInitLookupTables + * + * + *****************************************************************************/ +void +LacSymQat_ConstantsInitLookupTables(CpaInstanceHandle instanceHandle) +{ + sal_service_t *pService = (sal_service_t *)instanceHandle; + lac_sym_qat_constants_t *pConstantsLookupTables; + + /* Note the global tables are initialised first, then copied + * to the service which probably seems like a waste of memory + * and processing cycles as the global tables are never needed again + * but this allows use of the ICP_QAT_HW_FILL_LOOKUP_TBLS macro + * supplied by FW without modification */ + + if (SAL_SERVICE_TYPE_COMPRESSION == pService->type) { + /* DC chaining not supported yet */ + return; + } else { + pConstantsLookupTables = &( + ((sal_crypto_service_t *)pService)->constantsLookupTables); + } + + /* First fill the global lookup tables with zeroes. */ + memset(icp_qat_hw_cipher_lookup_tbl, + 0, + sizeof(icp_qat_hw_cipher_lookup_tbl)); + memset(icp_qat_hw_auth_lookup_tbl, + 0, + sizeof(icp_qat_hw_auth_lookup_tbl)); + + /* Override lookup tables with the offsets into the SHRAM table + * for supported algorithms/modes */ + ICP_QAT_HW_FILL_LOOKUP_TBLS; + + /* Copy the global tables to the service instance */ + memcpy(pConstantsLookupTables->cipher_offset, + icp_qat_hw_cipher_lookup_tbl, + sizeof(pConstantsLookupTables->cipher_offset)); + memcpy(pConstantsLookupTables->auth_offset, + icp_qat_hw_auth_lookup_tbl, + sizeof(pConstantsLookupTables->auth_offset)); +} + +/** + ***************************************************************************** + * @ingroup LacSymQat + * LacSymQat_ConstantsGetCipherOffset + * + * + *****************************************************************************/ +void +LacSymQat_ConstantsGetCipherOffset(CpaInstanceHandle instanceHandle, + uint8_t algo, + uint8_t mode, + uint8_t direction, + uint8_t convert, + uint8_t *poffset) +{ + sal_service_t *pService = (sal_service_t *)instanceHandle; + lac_sym_qat_constants_t *pConstantsLookupTables; + + if (SAL_SERVICE_TYPE_COMPRESSION == pService->type) { + /* DC chaining not supported yet */ + return; + } else { + pConstantsLookupTables = &( + ((sal_crypto_service_t *)pService)->constantsLookupTables); + } + + *poffset = pConstantsLookupTables + ->cipher_offset[algo][mode][direction][convert]; +} + +/** + ***************************************************************************** + * @ingroup LacSymQat + * LacSymQat_ConstantsGetAuthOffset + * + * + *****************************************************************************/ +void +LacSymQat_ConstantsGetAuthOffset(CpaInstanceHandle instanceHandle, + uint8_t algo, + uint8_t mode, + uint8_t nested, + uint8_t *poffset) +{ + sal_service_t *pService = (sal_service_t *)instanceHandle; + lac_sym_qat_constants_t *pConstantsLookupTables; + + if (SAL_SERVICE_TYPE_COMPRESSION == pService->type) { + /* DC chaining not supported yet */ + return; + } else { + pConstantsLookupTables = &( + ((sal_crypto_service_t *)pService)->constantsLookupTables); + } + + *poffset = pConstantsLookupTables->auth_offset[algo][mode][nested]; +} diff --git a/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_hash.c b/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_hash.c --- a/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_hash.c +++ b/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_hash.c @@ -28,8 +28,10 @@ #include "lac_sym_qat.h" #include "lac_list.h" #include "lac_sal_types.h" +#include "lac_sal_types_crypto.h" #include "lac_sym_qat_hash.h" #include "lac_sym_qat_hash_defs_lookup.h" +#include "sal_hw_gen.h" /** * This structure contains pointers into the hash setup block of the @@ -148,10 +150,10 @@ icp_qat_hw_auth_mode_t qatHashMode, CpaBoolean useSymConstantsTable, CpaBoolean useOptimisedContentDesc, + CpaBoolean useStatefulSha3ContentDesc, lac_sym_qat_hash_precompute_info_t *pPrecompute, Cpa32U *pHashBlkSizeInBytes) { - icp_qat_fw_auth_cd_ctrl_hdr_t *cd_ctrl = (icp_qat_fw_auth_cd_ctrl_hdr_t *)&(pMsg->cd_ctrl); lac_sym_qat_hash_defs_t *pHashDefs = NULL; @@ -159,7 +161,7 @@ Cpa32U hashSetupBlkSize = 0; /* setup the offset in QuadWords into the hw blk */ - cd_ctrl->hash_cfg_offset = hwBlockOffsetInQuadWords; + cd_ctrl->hash_cfg_offset = (Cpa8U)hwBlockOffsetInQuadWords; ICP_QAT_FW_COMN_NEXT_ID_SET(cd_ctrl, nextSlice); ICP_QAT_FW_COMN_CURR_ID_SET(cd_ctrl, ICP_QAT_FW_SLICE_AUTH); @@ -170,11 +172,19 @@ /* Hmac in mode 2 TLS */ if (IS_HASH_MODE_2(qatHashMode)) { - /* Set bit for nested hashing. - * Make sure not to overwrite other flags in hash_flags byte. - */ - ICP_QAT_FW_HASH_FLAG_AUTH_HDR_NESTED_SET( - cd_ctrl->hash_flags, ICP_QAT_FW_AUTH_HDR_FLAG_DO_NESTED); + if (isCyGen4x((sal_crypto_service_t *)instanceHandle)) { + /* CPM2.0 has a dedicated bit for HMAC mode2 */ + ICP_QAT_FW_HASH_FLAG_MODE2_SET(cd_ctrl->hash_flags, + QAT_FW_LA_MODE2); + } else { + /* Set bit for nested hashing. + * Make sure not to overwrite other flags in hash_flags + * byte. + */ + ICP_QAT_FW_HASH_FLAG_AUTH_HDR_NESTED_SET( + cd_ctrl->hash_flags, + ICP_QAT_FW_AUTH_HDR_FLAG_DO_NESTED); + } } /* Nested hash in mode 0 */ else if (CPA_CY_SYM_HASH_MODE_NESTED == pHashSetupData->hashMode) { @@ -190,16 +200,32 @@ cd_ctrl->hash_flags, ICP_QAT_FW_AUTH_HDR_FLAG_NO_NESTED); } + /* Set skip state load flags */ + if (useStatefulSha3ContentDesc) { + /* Here both skip state load flags are set. FW reads them based + * on partial packet type. */ + ICP_QAT_FW_HASH_FLAG_SKIP_INNER_STATE1_LOAD_SET( + cd_ctrl->hash_flags, QAT_FW_LA_SKIP_INNER_STATE1_LOAD); + ICP_QAT_FW_HASH_FLAG_SKIP_OUTER_STATE1_LOAD_SET( + cd_ctrl->hash_flags, QAT_FW_LA_SKIP_OUTER_STATE1_LOAD); + } + /* set the final digest size */ - cd_ctrl->final_sz = pHashSetupData->digestResultLenInBytes; + cd_ctrl->final_sz = (Cpa8U)pHashSetupData->digestResultLenInBytes; /* set the state1 size */ - cd_ctrl->inner_state1_sz = - LAC_ALIGN_POW2_ROUNDUP(pHashDefs->qatInfo->state1Length, - LAC_QUAD_WORD_IN_BYTES); + if (useStatefulSha3ContentDesc) { + cd_ctrl->inner_state1_sz = + LAC_ALIGN_POW2_ROUNDUP(LAC_HASH_SHA3_STATEFUL_STATE_SIZE, + LAC_QUAD_WORD_IN_BYTES); + } else { + cd_ctrl->inner_state1_sz = + LAC_ALIGN_POW2_ROUNDUP(pHashDefs->qatInfo->state1Length, + LAC_QUAD_WORD_IN_BYTES); + } /* set the inner result size to the digest length */ - cd_ctrl->inner_res_sz = pHashDefs->algInfo->digestLength; + cd_ctrl->inner_res_sz = (Cpa8U)pHashDefs->algInfo->digestLength; /* set the state2 size - only for mode 1 Auth algos and AES CBC MAC */ if (IS_HASH_MODE_1(qatHashMode) || @@ -212,13 +238,22 @@ cd_ctrl->inner_state2_sz = 0; } - cd_ctrl->inner_state2_offset = cd_ctrl->hash_cfg_offset + - LAC_BYTES_TO_QUADWORDS(sizeof(icp_qat_hw_auth_setup_t) + - cd_ctrl->inner_state1_sz); + if (useSymConstantsTable) { + cd_ctrl->inner_state2_offset = + LAC_BYTES_TO_QUADWORDS(cd_ctrl->inner_state1_sz); + + /* size of inner part of hash setup block */ + hashSetupBlkSize = + cd_ctrl->inner_state1_sz + cd_ctrl->inner_state2_sz; + } else { + cd_ctrl->inner_state2_offset = cd_ctrl->hash_cfg_offset + + LAC_BYTES_TO_QUADWORDS(sizeof(icp_qat_hw_auth_setup_t) + + cd_ctrl->inner_state1_sz); - /* size of inner part of hash setup block */ - hashSetupBlkSize = sizeof(icp_qat_hw_auth_setup_t) + - cd_ctrl->inner_state1_sz + cd_ctrl->inner_state2_sz; + /* size of inner part of hash setup block */ + hashSetupBlkSize = sizeof(icp_qat_hw_auth_setup_t) + + cd_ctrl->inner_state1_sz + cd_ctrl->inner_state2_sz; + } /* For nested hashing - Fill in the outer fields */ if (CPA_CY_SYM_HASH_MODE_NESTED == pHashSetupData->hashMode || @@ -238,18 +273,24 @@ cd_ctrl->outer_config_offset = cd_ctrl->inner_state2_offset + LAC_BYTES_TO_QUADWORDS(cd_ctrl->inner_state2_sz); - cd_ctrl->outer_state1_sz = - LAC_ALIGN_POW2_ROUNDUP(pOuterHashDefs->algInfo->stateSize, - LAC_QUAD_WORD_IN_BYTES); + if (useStatefulSha3ContentDesc) { + cd_ctrl->outer_state1_sz = LAC_ALIGN_POW2_ROUNDUP( + LAC_HASH_SHA3_STATEFUL_STATE_SIZE, + LAC_QUAD_WORD_IN_BYTES); + } else { + cd_ctrl->outer_state1_sz = LAC_ALIGN_POW2_ROUNDUP( + pOuterHashDefs->algInfo->stateSize, + LAC_QUAD_WORD_IN_BYTES); + } /* outer result size */ - cd_ctrl->outer_res_sz = pOuterHashDefs->algInfo->digestLength; + cd_ctrl->outer_res_sz = + (Cpa8U)pOuterHashDefs->algInfo->digestLength; /* outer_prefix_offset will be the size of the inner prefix data * plus the hash state storage size. */ /* The prefix buffer is part of the ReqParams, so this param - * will be - * setup where ReqParams are set up */ + * will be setup where ReqParams are set up */ /* add on size of outer part of hash block */ hashSetupBlkSize += @@ -325,8 +366,9 @@ if (IS_HASH_MODE_2(qatHashMode)) { /* Inner and outer prefixes are the block length */ pHashReqParams->u2.inner_prefix_sz = - pHashDefs->algInfo->blockLength; - cd_ctrl->outer_prefix_sz = pHashDefs->algInfo->blockLength; + (Cpa8U)pHashDefs->algInfo->blockLength; + cd_ctrl->outer_prefix_sz = + (Cpa8U)pHashDefs->algInfo->blockLength; cd_ctrl->outer_prefix_offset = LAC_BYTES_TO_QUADWORDS( LAC_ALIGN_POW2_ROUNDUP((pHashReqParams->u2.inner_prefix_sz), LAC_QUAD_WORD_IN_BYTES)); @@ -336,9 +378,11 @@ /* set inner and outer prefixes */ pHashReqParams->u2.inner_prefix_sz = - pHashSetupData->nestedModeSetupData.innerPrefixLenInBytes; + (Cpa8U)pHashSetupData->nestedModeSetupData + .innerPrefixLenInBytes; cd_ctrl->outer_prefix_sz = - pHashSetupData->nestedModeSetupData.outerPrefixLenInBytes; + (Cpa8U)pHashSetupData->nestedModeSetupData + .outerPrefixLenInBytes; cd_ctrl->outer_prefix_offset = LAC_BYTES_TO_QUADWORDS( LAC_ALIGN_POW2_ROUNDUP((pHashReqParams->u2.inner_prefix_sz), LAC_QUAD_WORD_IN_BYTES)); @@ -363,8 +407,9 @@ * just need 2 bytes to store encoded length of * 'a' */ aadDataSize += sizeof(Cpa16U); - aadDataSize += pHashSetupData->authModeSetupData - .aadLenInBytes; + aadDataSize += + (Cpa16U)pHashSetupData->authModeSetupData + .aadLenInBytes; } /* round the aad size to the multiple of CCM block @@ -375,7 +420,8 @@ } else if (CPA_CY_SYM_HASH_AES_GCM == pHashSetupData->hashAlgorithm) { aadDataSize = - pHashSetupData->authModeSetupData.aadLenInBytes; + (Cpa16U) + pHashSetupData->authModeSetupData.aadLenInBytes; /* round the aad size to the multiple of GCM hash block * size. */ @@ -406,7 +452,7 @@ /* auth result size in bytes to be read in for a verify * operation */ pHashReqParams->auth_res_sz = - pHashSetupData->digestResultLenInBytes; + (Cpa8U)pHashSetupData->digestResultLenInBytes; } else { pHashReqParams->auth_res_sz = 0; } @@ -453,7 +499,7 @@ { Cpa32U innerConfig = 0; lac_hash_blk_ptrs_t hashBlkPtrs = { 0 }; - Cpa32U aed_hash_cmp_length = 0; + Cpa32U aedHashCmpLength = 0; LacSymQat_HashHwBlockPtrsInit(pHashControlBlock, pHwBlockBase, @@ -610,7 +656,7 @@ ICP_QAT_HW_CIPHER_ALGO_SNOW_3G_UEA2, ICP_QAT_HW_CIPHER_KEY_CONVERT, ICP_QAT_HW_CIPHER_ENCRYPT, - aed_hash_cmp_length); + aedHashCmpLength); pCipherConfig->reserved = 0; @@ -633,7 +679,7 @@ ICP_QAT_HW_CIPHER_ALGO_ZUC_3G_128_EEA3, ICP_QAT_HW_CIPHER_KEY_CONVERT, ICP_QAT_HW_CIPHER_ENCRYPT, - aed_hash_cmp_length); + aedHashCmpLength); pCipherConfig->reserved = 0; @@ -820,7 +866,7 @@ CpaBoolean digestVerify, Cpa8U *pAuthResult, CpaCySymHashAlgorithm alg, - void *hkdf_secret) + void *pHKDFSecret) { Cpa64U authResultPhys = 0; icp_qat_fw_la_auth_req_params_t *pHashReqParams; @@ -833,11 +879,11 @@ pHashReqParams->auth_len = authLenInBytes; /* Set the physical location of secret for HKDF */ - if (NULL != hkdf_secret) { + if (NULL != pHKDFSecret) { LAC_MEM_SHARED_WRITE_VIRT_TO_PHYS_PTR_EXTERNAL( - (*pService), pHashReqParams->u1.aad_adr, hkdf_secret); + (*pService), pHashReqParams->u1.aad_adr, pHKDFSecret); - if (pHashReqParams->u1.aad_adr == 0) { + if (0 == pHashReqParams->u1.aad_adr) { LAC_LOG_ERROR( "Unable to get the physical address of the" " HKDF secret\n"); @@ -868,7 +914,7 @@ if (CPA_TRUE == digestVerify) { /* auth result size in bytes to be read in for a verify * operation */ - pHashReqParams->auth_res_sz = hashResultSize; + pHashReqParams->auth_res_sz = (Cpa8U)hashResultSize; } else { pHashReqParams->auth_res_sz = 0; } diff --git a/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_hash_defs_lookup.c b/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_hash_defs_lookup.c --- a/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_hash_defs_lookup.c +++ b/sys/dev/qat/qat_api/common/crypto/sym/qat/lac_sym_qat_hash_defs_lookup.c @@ -74,62 +74,70 @@ }; /* SHA 256 - 32 bytes - Initialiser state can be found in FIPS stds 180-2 */ -static Cpa8U sha256InitialState[LAC_HASH_SHA256_STATE_SIZE] = - { 0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae, 0x85, 0x3c, 0x6e, 0xf3, - 0x72, 0xa5, 0x4f, 0xf5, 0x3a, 0x51, 0x0e, 0x52, 0x7f, 0x9b, 0x05, - 0x68, 0x8c, 0x1f, 0x83, 0xd9, 0xab, 0x5b, 0xe0, 0xcd, 0x19 }; +static Cpa8U sha256InitialState[LAC_HASH_SHA256_STATE_SIZE] = { + 0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae, 0x85, 0x3c, 0x6e, 0xf3, + 0x72, 0xa5, 0x4f, 0xf5, 0x3a, 0x51, 0x0e, 0x52, 0x7f, 0x9b, 0x05, + 0x68, 0x8c, 0x1f, 0x83, 0xd9, 0xab, 0x5b, 0xe0, 0xcd, 0x19 +}; /* SHA 384 - 64 bytes - Initialiser state can be found in FIPS stds 180-2 */ -static Cpa8U sha384InitialState[LAC_HASH_SHA384_STATE_SIZE] = - { 0xcb, 0xbb, 0x9d, 0x5d, 0xc1, 0x05, 0x9e, 0xd8, 0x62, 0x9a, 0x29, - 0x2a, 0x36, 0x7c, 0xd5, 0x07, 0x91, 0x59, 0x01, 0x5a, 0x30, 0x70, - 0xdd, 0x17, 0x15, 0x2f, 0xec, 0xd8, 0xf7, 0x0e, 0x59, 0x39, 0x67, - 0x33, 0x26, 0x67, 0xff, 0xc0, 0x0b, 0x31, 0x8e, 0xb4, 0x4a, 0x87, - 0x68, 0x58, 0x15, 0x11, 0xdb, 0x0c, 0x2e, 0x0d, 0x64, 0xf9, 0x8f, - 0xa7, 0x47, 0xb5, 0x48, 0x1d, 0xbe, 0xfa, 0x4f, 0xa4 }; +static Cpa8U sha384InitialState[LAC_HASH_SHA384_STATE_SIZE] = { + 0xcb, 0xbb, 0x9d, 0x5d, 0xc1, 0x05, 0x9e, 0xd8, 0x62, 0x9a, 0x29, + 0x2a, 0x36, 0x7c, 0xd5, 0x07, 0x91, 0x59, 0x01, 0x5a, 0x30, 0x70, + 0xdd, 0x17, 0x15, 0x2f, 0xec, 0xd8, 0xf7, 0x0e, 0x59, 0x39, 0x67, + 0x33, 0x26, 0x67, 0xff, 0xc0, 0x0b, 0x31, 0x8e, 0xb4, 0x4a, 0x87, + 0x68, 0x58, 0x15, 0x11, 0xdb, 0x0c, 0x2e, 0x0d, 0x64, 0xf9, 0x8f, + 0xa7, 0x47, 0xb5, 0x48, 0x1d, 0xbe, 0xfa, 0x4f, 0xa4 +}; /* SHA 512 - 64 bytes - Initialiser state can be found in FIPS stds 180-2 */ -static Cpa8U sha512InitialState[LAC_HASH_SHA512_STATE_SIZE] = - { 0x6a, 0x09, 0xe6, 0x67, 0xf3, 0xbc, 0xc9, 0x08, 0xbb, 0x67, 0xae, - 0x85, 0x84, 0xca, 0xa7, 0x3b, 0x3c, 0x6e, 0xf3, 0x72, 0xfe, 0x94, - 0xf8, 0x2b, 0xa5, 0x4f, 0xf5, 0x3a, 0x5f, 0x1d, 0x36, 0xf1, 0x51, - 0x0e, 0x52, 0x7f, 0xad, 0xe6, 0x82, 0xd1, 0x9b, 0x05, 0x68, 0x8c, - 0x2b, 0x3e, 0x6c, 0x1f, 0x1f, 0x83, 0xd9, 0xab, 0xfb, 0x41, 0xbd, - 0x6b, 0x5b, 0xe0, 0xcd, 0x19, 0x13, 0x7e, 0x21, 0x79 }; +static Cpa8U sha512InitialState[LAC_HASH_SHA512_STATE_SIZE] = { + 0x6a, 0x09, 0xe6, 0x67, 0xf3, 0xbc, 0xc9, 0x08, 0xbb, 0x67, 0xae, + 0x85, 0x84, 0xca, 0xa7, 0x3b, 0x3c, 0x6e, 0xf3, 0x72, 0xfe, 0x94, + 0xf8, 0x2b, 0xa5, 0x4f, 0xf5, 0x3a, 0x5f, 0x1d, 0x36, 0xf1, 0x51, + 0x0e, 0x52, 0x7f, 0xad, 0xe6, 0x82, 0xd1, 0x9b, 0x05, 0x68, 0x8c, + 0x2b, 0x3e, 0x6c, 0x1f, 0x1f, 0x83, 0xd9, 0xab, 0xfb, 0x41, 0xbd, + 0x6b, 0x5b, 0xe0, 0xcd, 0x19, 0x13, 0x7e, 0x21, 0x79 +}; /* SHA3 224 - 28 bytes */ -static Cpa8U sha3_224InitialState[LAC_HASH_SHA3_224_STATE_SIZE] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static Cpa8U sha3_224InitialState[LAC_HASH_SHA3_224_STATE_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; /* SHA3 256 - 32 bytes */ -static Cpa8U sha3_256InitialState[LAC_HASH_SHA3_256_STATE_SIZE] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static Cpa8U sha3_256InitialState[LAC_HASH_SHA3_256_STATE_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; /* SHA3 384 - 48 bytes */ -static Cpa8U sha3_384InitialState[LAC_HASH_SHA3_384_STATE_SIZE] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static Cpa8U sha3_384InitialState[LAC_HASH_SHA3_384_STATE_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; /* SHA3 512 - 64 bytes */ -static Cpa8U sha3_512InitialState[LAC_HASH_SHA3_512_STATE_SIZE] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static Cpa8U sha3_512InitialState[LAC_HASH_SHA3_512_STATE_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; /* SM3 - 32 bytes */ -static Cpa8U sm3InitialState[LAC_HASH_SM3_STATE_SIZE] = - { 0x73, 0x80, 0x16, 0x6f, 0x49, 0x14, 0xb2, 0xb9, 0x17, 0x24, 0x42, - 0xd7, 0xda, 0x8a, 0x06, 0x00, 0xa9, 0x6f, 0x30, 0xbc, 0x16, 0x31, - 0x38, 0xaa, 0xe3, 0x8d, 0xee, 0x4d, 0xb0, 0xfb, 0x0e, 0x4e }; +static Cpa8U sm3InitialState[LAC_HASH_SM3_STATE_SIZE] = { + 0x73, 0x80, 0x16, 0x6f, 0x49, 0x14, 0xb2, 0xb9, 0x17, 0x24, 0x42, + 0xd7, 0xda, 0x8a, 0x06, 0x00, 0xa9, 0x6f, 0x30, 0xbc, 0x16, 0x31, + 0x38, 0xaa, 0xe3, 0x8d, 0xee, 0x4d, 0xb0, 0xfb, 0x0e, 0x4e +}; /* Constants used in generating K1, K2, K3 from a Key for AES_XCBC_MAC * State defined in RFC 3566 */ @@ -140,12 +148,10 @@ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, }; -static Cpa8U aesCmacKeySeed[LAC_HASH_CMAC_BLOCK_SIZE] = { 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00 }; +static Cpa8U aesCmacKeySeed[LAC_HASH_CMAC_BLOCK_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; /* Hash Algorithm specific structure */ @@ -179,57 +185,57 @@ sha512InitialState, LAC_HASH_SHA512_STATE_SIZE }; -static lac_sym_qat_hash_alg_info_t sha3_224Info = - { LAC_HASH_SHA3_224_DIGEST_SIZE, - LAC_HASH_SHA3_224_BLOCK_SIZE, - sha3_224InitialState, - LAC_HASH_SHA3_224_STATE_SIZE }; - -static lac_sym_qat_hash_alg_info_t sha3_256Info = - { LAC_HASH_SHA3_256_DIGEST_SIZE, - LAC_HASH_SHA3_256_BLOCK_SIZE, - sha3_256InitialState, - LAC_HASH_SHA3_256_STATE_SIZE }; - -static lac_sym_qat_hash_alg_info_t sha3_384Info = - { LAC_HASH_SHA3_384_DIGEST_SIZE, - LAC_HASH_SHA3_384_BLOCK_SIZE, - sha3_384InitialState, - LAC_HASH_SHA3_384_STATE_SIZE }; - -static lac_sym_qat_hash_alg_info_t sha3_512Info = - { LAC_HASH_SHA3_512_DIGEST_SIZE, - LAC_HASH_SHA3_512_BLOCK_SIZE, - sha3_512InitialState, - LAC_HASH_SHA3_512_STATE_SIZE }; +static lac_sym_qat_hash_alg_info_t sha3_224Info = { + LAC_HASH_SHA3_224_DIGEST_SIZE, + LAC_HASH_SHA3_224_BLOCK_SIZE, + sha3_224InitialState, + LAC_HASH_SHA3_224_STATE_SIZE +}; -static lac_sym_qat_hash_alg_info_t polyInfo = { LAC_HASH_POLY_DIGEST_SIZE, - LAC_HASH_POLY_BLOCK_SIZE, - NULL, /* intial state */ - LAC_HASH_POLY_STATE_SIZE }; +static lac_sym_qat_hash_alg_info_t sha3_256Info = { + LAC_HASH_SHA3_256_DIGEST_SIZE, + LAC_HASH_SHA3_256_BLOCK_SIZE, + sha3_256InitialState, + LAC_HASH_SHA3_256_STATE_SIZE +}; -static lac_sym_qat_hash_alg_info_t shake_128Info = - { LAC_HASH_SHAKE_128_DIGEST_SIZE, LAC_HASH_SHAKE_128_BLOCK_SIZE, NULL, 0 }; +static lac_sym_qat_hash_alg_info_t sha3_384Info = { + LAC_HASH_SHA3_384_DIGEST_SIZE, + LAC_HASH_SHA3_384_BLOCK_SIZE, + sha3_384InitialState, + LAC_HASH_SHA3_384_STATE_SIZE +}; -static lac_sym_qat_hash_alg_info_t shake_256Info = - { LAC_HASH_SHAKE_256_DIGEST_SIZE, LAC_HASH_SHAKE_256_BLOCK_SIZE, NULL, 0 }; +static lac_sym_qat_hash_alg_info_t sha3_512Info = { + LAC_HASH_SHA3_512_DIGEST_SIZE, + LAC_HASH_SHA3_512_BLOCK_SIZE, + sha3_512InitialState, + LAC_HASH_SHA3_512_STATE_SIZE +}; static lac_sym_qat_hash_alg_info_t sm3Info = { LAC_HASH_SM3_DIGEST_SIZE, LAC_HASH_SM3_BLOCK_SIZE, sm3InitialState, LAC_HASH_SM3_STATE_SIZE }; -static lac_sym_qat_hash_alg_info_t xcbcMacInfo = - { LAC_HASH_XCBC_MAC_128_DIGEST_SIZE, - LAC_HASH_XCBC_MAC_BLOCK_SIZE, - aesXcbcKeySeed, - LAC_SYM_QAT_XCBC_STATE_SIZE }; +static lac_sym_qat_hash_alg_info_t polyInfo = { LAC_HASH_POLY_DIGEST_SIZE, + LAC_HASH_POLY_BLOCK_SIZE, + NULL, /* intial state */ + LAC_HASH_POLY_STATE_SIZE }; -static lac_sym_qat_hash_alg_info_t aesCmacInfo = - { LAC_HASH_CMAC_128_DIGEST_SIZE, - LAC_HASH_CMAC_BLOCK_SIZE, - aesCmacKeySeed, - LAC_SYM_QAT_CMAC_STATE_SIZE }; +static lac_sym_qat_hash_alg_info_t xcbcMacInfo = { + LAC_HASH_XCBC_MAC_128_DIGEST_SIZE, + LAC_HASH_XCBC_MAC_BLOCK_SIZE, + aesXcbcKeySeed, + LAC_SYM_QAT_XCBC_STATE_SIZE +}; + +static lac_sym_qat_hash_alg_info_t aesCmacInfo = { + LAC_HASH_CMAC_128_DIGEST_SIZE, + LAC_HASH_CMAC_BLOCK_SIZE, + aesCmacKeySeed, + LAC_SYM_QAT_CMAC_STATE_SIZE +}; static lac_sym_qat_hash_alg_info_t aesCcmInfo = { LAC_HASH_AES_CCM_DIGEST_SIZE, @@ -259,11 +265,12 @@ 0 /* state size */ }; -static lac_sym_qat_hash_alg_info_t aesCbcMacInfo = - { LAC_HASH_AES_CBC_MAC_DIGEST_SIZE, - LAC_HASH_AES_CBC_MAC_BLOCK_SIZE, - NULL, - 0 }; +static lac_sym_qat_hash_alg_info_t aesCbcMacInfo = { + LAC_HASH_AES_CBC_MAC_DIGEST_SIZE, + LAC_HASH_AES_CBC_MAC_BLOCK_SIZE, + NULL, + 0 +}; static lac_sym_qat_hash_alg_info_t zucEia3Info = { LAC_HASH_ZUC_EIA3_DIGEST_SIZE, @@ -283,145 +290,154 @@ ICP_QAT_HW_SHA1_STATE1_SZ, ICP_QAT_HW_SHA1_STATE2_SZ }; -static lac_sym_qat_hash_qat_info_t sha224Config = - { ICP_QAT_HW_AUTH_ALGO_SHA224, - LAC_HASH_SHA224_BLOCK_SIZE, - ICP_QAT_HW_SHA224_STATE1_SZ, - ICP_QAT_HW_SHA224_STATE2_SZ }; - -static lac_sym_qat_hash_qat_info_t sha256Config = - { ICP_QAT_HW_AUTH_ALGO_SHA256, - LAC_HASH_SHA256_BLOCK_SIZE, - ICP_QAT_HW_SHA256_STATE1_SZ, - ICP_QAT_HW_SHA256_STATE2_SZ }; - -static lac_sym_qat_hash_qat_info_t sha384Config = - { ICP_QAT_HW_AUTH_ALGO_SHA384, - LAC_HASH_SHA384_BLOCK_SIZE, - ICP_QAT_HW_SHA384_STATE1_SZ, - ICP_QAT_HW_SHA384_STATE2_SZ }; - -static lac_sym_qat_hash_qat_info_t sha512Config = - { ICP_QAT_HW_AUTH_ALGO_SHA512, - LAC_HASH_SHA512_BLOCK_SIZE, - ICP_QAT_HW_SHA512_STATE1_SZ, - ICP_QAT_HW_SHA512_STATE2_SZ }; - -static lac_sym_qat_hash_qat_info_t sha3_224Config = - { ICP_QAT_HW_AUTH_ALGO_SHA3_224, - LAC_HASH_SHA3_224_BLOCK_SIZE, - ICP_QAT_HW_SHA3_224_STATE1_SZ, - ICP_QAT_HW_SHA3_224_STATE2_SZ }; - -static lac_sym_qat_hash_qat_info_t sha3_256Config = - { ICP_QAT_HW_AUTH_ALGO_SHA3_256, - LAC_HASH_SHA3_256_BLOCK_SIZE, - ICP_QAT_HW_SHA3_256_STATE1_SZ, - ICP_QAT_HW_SHA3_256_STATE2_SZ }; - -static lac_sym_qat_hash_qat_info_t sha3_384Config = - { ICP_QAT_HW_AUTH_ALGO_SHA3_384, - LAC_HASH_SHA3_384_BLOCK_SIZE, - ICP_QAT_HW_SHA3_384_STATE1_SZ, - ICP_QAT_HW_SHA3_384_STATE2_SZ }; - -static lac_sym_qat_hash_qat_info_t sha3_512Config = - { ICP_QAT_HW_AUTH_ALGO_SHA3_512, - LAC_HASH_SHA3_512_BLOCK_SIZE, - ICP_QAT_HW_SHA3_512_STATE1_SZ, - ICP_QAT_HW_SHA3_512_STATE2_SZ }; - -static lac_sym_qat_hash_qat_info_t shake_128Config = - { ICP_QAT_HW_AUTH_ALGO_SHAKE_128, LAC_HASH_SHAKE_128_BLOCK_SIZE, 0, 0 }; - -static lac_sym_qat_hash_qat_info_t shake_256Config = - { ICP_QAT_HW_AUTH_ALGO_SHAKE_256, LAC_HASH_SHAKE_256_BLOCK_SIZE, 0, 0 }; +static lac_sym_qat_hash_qat_info_t sha224Config = { + ICP_QAT_HW_AUTH_ALGO_SHA224, + LAC_HASH_SHA224_BLOCK_SIZE, + ICP_QAT_HW_SHA224_STATE1_SZ, + ICP_QAT_HW_SHA224_STATE2_SZ +}; -static lac_sym_qat_hash_qat_info_t polyConfig = { ICP_QAT_HW_AUTH_ALGO_POLY, - LAC_HASH_POLY_BLOCK_SIZE, - 0, - 0 }; +static lac_sym_qat_hash_qat_info_t sha256Config = { + ICP_QAT_HW_AUTH_ALGO_SHA256, + LAC_HASH_SHA256_BLOCK_SIZE, + ICP_QAT_HW_SHA256_STATE1_SZ, + ICP_QAT_HW_SHA256_STATE2_SZ +}; + +static lac_sym_qat_hash_qat_info_t sha384Config = { + ICP_QAT_HW_AUTH_ALGO_SHA384, + LAC_HASH_SHA384_BLOCK_SIZE, + ICP_QAT_HW_SHA384_STATE1_SZ, + ICP_QAT_HW_SHA384_STATE2_SZ +}; + +static lac_sym_qat_hash_qat_info_t sha512Config = { + ICP_QAT_HW_AUTH_ALGO_SHA512, + LAC_HASH_SHA512_BLOCK_SIZE, + ICP_QAT_HW_SHA512_STATE1_SZ, + ICP_QAT_HW_SHA512_STATE2_SZ +}; + +static lac_sym_qat_hash_qat_info_t sha3_224Config = { + ICP_QAT_HW_AUTH_ALGO_SHA3_224, + LAC_HASH_SHA3_224_BLOCK_SIZE, + ICP_QAT_HW_SHA3_224_STATE1_SZ, + ICP_QAT_HW_SHA3_224_STATE2_SZ +}; + +static lac_sym_qat_hash_qat_info_t sha3_256Config = { + ICP_QAT_HW_AUTH_ALGO_SHA3_256, + LAC_HASH_SHA3_256_BLOCK_SIZE, + ICP_QAT_HW_SHA3_256_STATE1_SZ, + ICP_QAT_HW_SHA3_256_STATE2_SZ +}; + +static lac_sym_qat_hash_qat_info_t sha3_384Config = { + ICP_QAT_HW_AUTH_ALGO_SHA3_384, + LAC_HASH_SHA3_384_BLOCK_SIZE, + ICP_QAT_HW_SHA3_384_STATE1_SZ, + ICP_QAT_HW_SHA3_384_STATE2_SZ +}; + +static lac_sym_qat_hash_qat_info_t sha3_512Config = { + ICP_QAT_HW_AUTH_ALGO_SHA3_512, + LAC_HASH_SHA3_512_BLOCK_SIZE, + ICP_QAT_HW_SHA3_512_STATE1_SZ, + ICP_QAT_HW_SHA3_512_STATE2_SZ +}; static lac_sym_qat_hash_qat_info_t sm3Config = { ICP_QAT_HW_AUTH_ALGO_SM3, LAC_HASH_SM3_BLOCK_SIZE, ICP_QAT_HW_SM3_STATE1_SZ, ICP_QAT_HW_SM3_STATE2_SZ }; -static lac_sym_qat_hash_qat_info_t xcbcMacConfig = - { ICP_QAT_HW_AUTH_ALGO_AES_XCBC_MAC, - 0, - ICP_QAT_HW_AES_XCBC_MAC_STATE1_SZ, - LAC_SYM_QAT_XCBC_STATE_SIZE }; - -static lac_sym_qat_hash_qat_info_t aesCmacConfig = - { ICP_QAT_HW_AUTH_ALGO_AES_XCBC_MAC, - 0, - ICP_QAT_HW_AES_XCBC_MAC_STATE1_SZ, - LAC_SYM_QAT_CMAC_STATE_SIZE }; - -static lac_sym_qat_hash_qat_info_t aesCcmConfig = - { ICP_QAT_HW_AUTH_ALGO_AES_CBC_MAC, - 0, - ICP_QAT_HW_AES_CBC_MAC_STATE1_SZ, - ICP_QAT_HW_AES_CBC_MAC_KEY_SZ + ICP_QAT_HW_AES_CCM_CBC_E_CTR0_SZ }; - -static lac_sym_qat_hash_qat_info_t aesGcmConfig = - { ICP_QAT_HW_AUTH_ALGO_GALOIS_128, - 0, - ICP_QAT_HW_GALOIS_128_STATE1_SZ, - ICP_QAT_HW_GALOIS_H_SZ + ICP_QAT_HW_GALOIS_LEN_A_SZ + - ICP_QAT_HW_GALOIS_E_CTR0_SZ }; - -static lac_sym_qat_hash_qat_info_t kasumiF9Config = - { ICP_QAT_HW_AUTH_ALGO_KASUMI_F9, - 0, - ICP_QAT_HW_KASUMI_F9_STATE1_SZ, - ICP_QAT_HW_KASUMI_F9_STATE2_SZ }; - -static lac_sym_qat_hash_qat_info_t snow3gUia2Config = - { ICP_QAT_HW_AUTH_ALGO_SNOW_3G_UIA2, - 0, - ICP_QAT_HW_SNOW_3G_UIA2_STATE1_SZ, - ICP_QAT_HW_SNOW_3G_UIA2_STATE2_SZ }; - -static lac_sym_qat_hash_qat_info_t aesCbcMacConfig = - { ICP_QAT_HW_AUTH_ALGO_AES_CBC_MAC, - 0, - ICP_QAT_HW_AES_CBC_MAC_STATE1_SZ, - ICP_QAT_HW_AES_CBC_MAC_STATE1_SZ + ICP_QAT_HW_AES_CBC_MAC_STATE1_SZ }; - -static lac_sym_qat_hash_qat_info_t zucEia3Config = - { ICP_QAT_HW_AUTH_ALGO_ZUC_3G_128_EIA3, - 0, - ICP_QAT_HW_ZUC_3G_EIA3_STATE1_SZ, - ICP_QAT_HW_ZUC_3G_EIA3_STATE2_SZ }; +static lac_sym_qat_hash_qat_info_t polyConfig = { ICP_QAT_HW_AUTH_ALGO_POLY, + LAC_HASH_POLY_BLOCK_SIZE, + 0, + 0 }; + +static lac_sym_qat_hash_qat_info_t xcbcMacConfig = { + ICP_QAT_HW_AUTH_ALGO_AES_XCBC_MAC, + 0, + ICP_QAT_HW_AES_XCBC_MAC_STATE1_SZ, + LAC_SYM_QAT_XCBC_STATE_SIZE +}; + +static lac_sym_qat_hash_qat_info_t aesCmacConfig = { + ICP_QAT_HW_AUTH_ALGO_AES_XCBC_MAC, + 0, + ICP_QAT_HW_AES_XCBC_MAC_STATE1_SZ, + LAC_SYM_QAT_CMAC_STATE_SIZE +}; + +static lac_sym_qat_hash_qat_info_t aesCcmConfig = { + ICP_QAT_HW_AUTH_ALGO_AES_CBC_MAC, + 0, + ICP_QAT_HW_AES_CBC_MAC_STATE1_SZ, + ICP_QAT_HW_AES_CBC_MAC_KEY_SZ + ICP_QAT_HW_AES_CCM_CBC_E_CTR0_SZ +}; + +static lac_sym_qat_hash_qat_info_t aesGcmConfig = { + ICP_QAT_HW_AUTH_ALGO_GALOIS_128, + 0, + ICP_QAT_HW_GALOIS_128_STATE1_SZ, + ICP_QAT_HW_GALOIS_H_SZ + ICP_QAT_HW_GALOIS_LEN_A_SZ + + ICP_QAT_HW_GALOIS_E_CTR0_SZ +}; + +static lac_sym_qat_hash_qat_info_t kasumiF9Config = { + ICP_QAT_HW_AUTH_ALGO_KASUMI_F9, + 0, + ICP_QAT_HW_KASUMI_F9_STATE1_SZ, + ICP_QAT_HW_KASUMI_F9_STATE2_SZ +}; + +static lac_sym_qat_hash_qat_info_t snow3gUia2Config = { + ICP_QAT_HW_AUTH_ALGO_SNOW_3G_UIA2, + 0, + ICP_QAT_HW_SNOW_3G_UIA2_STATE1_SZ, + ICP_QAT_HW_SNOW_3G_UIA2_STATE2_SZ +}; + +static lac_sym_qat_hash_qat_info_t aesCbcMacConfig = { + ICP_QAT_HW_AUTH_ALGO_AES_CBC_MAC, + 0, + ICP_QAT_HW_AES_CBC_MAC_STATE1_SZ, + ICP_QAT_HW_AES_CBC_MAC_STATE1_SZ + ICP_QAT_HW_AES_CBC_MAC_STATE1_SZ +}; + +static lac_sym_qat_hash_qat_info_t zucEia3Config = { + ICP_QAT_HW_AUTH_ALGO_ZUC_3G_128_EIA3, + 0, + ICP_QAT_HW_ZUC_3G_EIA3_STATE1_SZ, + ICP_QAT_HW_ZUC_3G_EIA3_STATE2_SZ +}; /* Array of mappings between algorithm and info structure * This array is used to populate the lookup table */ -static lac_sym_qat_hash_def_map_t lacHashDefsMapping[] = - { { CPA_CY_SYM_HASH_MD5, { &md5Info, &md5Config } }, - { CPA_CY_SYM_HASH_SHA1, { &sha1Info, &sha1Config } }, - { CPA_CY_SYM_HASH_SHA224, { &sha224Info, &sha224Config } }, - { CPA_CY_SYM_HASH_SHA256, { &sha256Info, &sha256Config } }, - { CPA_CY_SYM_HASH_SHA384, { &sha384Info, &sha384Config } }, - { CPA_CY_SYM_HASH_SHA512, { &sha512Info, &sha512Config } }, - { CPA_CY_SYM_HASH_SHA3_224, { &sha3_224Info, &sha3_224Config } }, - { CPA_CY_SYM_HASH_SHA3_256, { &sha3_256Info, &sha3_256Config } }, - { CPA_CY_SYM_HASH_SHA3_384, { &sha3_384Info, &sha3_384Config } }, - { CPA_CY_SYM_HASH_SHA3_512, { &sha3_512Info, &sha3_512Config } }, - { CPA_CY_SYM_HASH_SHAKE_128, { &shake_128Info, &shake_128Config } }, - { CPA_CY_SYM_HASH_SHAKE_256, { &shake_256Info, &shake_256Config } }, - { CPA_CY_SYM_HASH_POLY, { &polyInfo, &polyConfig } }, - { CPA_CY_SYM_HASH_SM3, { &sm3Info, &sm3Config } }, - { CPA_CY_SYM_HASH_AES_XCBC, { &xcbcMacInfo, &xcbcMacConfig } }, - { CPA_CY_SYM_HASH_AES_CMAC, { &aesCmacInfo, &aesCmacConfig } }, - { CPA_CY_SYM_HASH_AES_CCM, { &aesCcmInfo, &aesCcmConfig } }, - { CPA_CY_SYM_HASH_AES_GCM, { &aesGcmInfo, &aesGcmConfig } }, - { CPA_CY_SYM_HASH_KASUMI_F9, { &kasumiF9Info, &kasumiF9Config } }, - { CPA_CY_SYM_HASH_SNOW3G_UIA2, { &snow3gUia2Info, &snow3gUia2Config } }, - { CPA_CY_SYM_HASH_AES_GMAC, { &aesGcmInfo, &aesGcmConfig } }, - { CPA_CY_SYM_HASH_ZUC_EIA3, { &zucEia3Info, &zucEia3Config } }, - { CPA_CY_SYM_HASH_AES_CBC_MAC, { &aesCbcMacInfo, &aesCbcMacConfig } } }; +static lac_sym_qat_hash_def_map_t lacHashDefsMapping[] = { + { CPA_CY_SYM_HASH_MD5, { &md5Info, &md5Config } }, + { CPA_CY_SYM_HASH_SHA1, { &sha1Info, &sha1Config } }, + { CPA_CY_SYM_HASH_SHA224, { &sha224Info, &sha224Config } }, + { CPA_CY_SYM_HASH_SHA256, { &sha256Info, &sha256Config } }, + { CPA_CY_SYM_HASH_SHA384, { &sha384Info, &sha384Config } }, + { CPA_CY_SYM_HASH_SHA512, { &sha512Info, &sha512Config } }, + { CPA_CY_SYM_HASH_SHA3_224, { &sha3_224Info, &sha3_224Config } }, + { CPA_CY_SYM_HASH_SHA3_256, { &sha3_256Info, &sha3_256Config } }, + { CPA_CY_SYM_HASH_SHA3_384, { &sha3_384Info, &sha3_384Config } }, + { CPA_CY_SYM_HASH_SHA3_512, { &sha3_512Info, &sha3_512Config } }, + { CPA_CY_SYM_HASH_SM3, { &sm3Info, &sm3Config } }, + { CPA_CY_SYM_HASH_POLY, { &polyInfo, &polyConfig } }, + { CPA_CY_SYM_HASH_AES_XCBC, { &xcbcMacInfo, &xcbcMacConfig } }, + { CPA_CY_SYM_HASH_AES_CMAC, { &aesCmacInfo, &aesCmacConfig } }, + { CPA_CY_SYM_HASH_AES_CCM, { &aesCcmInfo, &aesCcmConfig } }, + { CPA_CY_SYM_HASH_AES_GCM, { &aesGcmInfo, &aesGcmConfig } }, + { CPA_CY_SYM_HASH_KASUMI_F9, { &kasumiF9Info, &kasumiF9Config } }, + { CPA_CY_SYM_HASH_SNOW3G_UIA2, { &snow3gUia2Info, &snow3gUia2Config } }, + { CPA_CY_SYM_HASH_AES_GMAC, { &aesGcmInfo, &aesGcmConfig } }, + { CPA_CY_SYM_HASH_ZUC_EIA3, { &zucEia3Info, &zucEia3Config } }, + { CPA_CY_SYM_HASH_AES_CBC_MAC, { &aesCbcMacInfo, &aesCbcMacConfig } } +}; /* * LacSymQat_HashLookupInit @@ -434,33 +450,35 @@ Cpa32U arraySize = 0; CpaStatus status = CPA_STATUS_SUCCESS; CpaCySymHashAlgorithm hashAlg = CPA_CY_SYM_HASH_NONE; - sal_crypto_service_t *pService = (sal_crypto_service_t *)instanceHandle; + sal_service_t *pService = (sal_service_t *)instanceHandle; + lac_sym_qat_hash_defs_t **pLacHashLookupDefs; arraySize = (CPA_CY_HASH_ALG_END + 1) * sizeof(lac_sym_qat_hash_defs_t *); /* Size round up for performance */ arraySize = LAC_ALIGN_POW2_ROUNDUP(arraySize, LAC_64BYTE_ALIGNMENT); - pService->pLacHashLookupDefs = LAC_OS_MALLOC(arraySize); - - if (NULL != pService->pLacHashLookupDefs) { - LAC_OS_BZERO(pService->pLacHashLookupDefs, arraySize); + pLacHashLookupDefs = LAC_OS_MALLOC(arraySize); + if (NULL == pLacHashLookupDefs) { + return CPA_STATUS_RESOURCE; + } - numEntries = sizeof(lacHashDefsMapping) / - sizeof(lac_sym_qat_hash_def_map_t); + LAC_OS_BZERO(pLacHashLookupDefs, arraySize); + numEntries = + sizeof(lacHashDefsMapping) / sizeof(lac_sym_qat_hash_def_map_t); - /* initialise the hash lookup definitions table so that the - * algorithm - * can be used to index into the table */ - for (entry = 0; entry < numEntries; entry++) { - hashAlg = lacHashDefsMapping[entry].hashAlgorithm; + /* initialise the hash lookup definitions table so that the algorithm + * can be used to index into the table */ + for (entry = 0; entry < numEntries; entry++) { + hashAlg = lacHashDefsMapping[entry].hashAlgorithm; - pService->pLacHashLookupDefs[hashAlg] = - &(lacHashDefsMapping[entry].hashDefs); - } - } else { - status = CPA_STATUS_RESOURCE; + pLacHashLookupDefs[hashAlg] = + &(lacHashDefsMapping[entry].hashDefs); } + + ((sal_crypto_service_t *)pService)->pLacHashLookupDefs = + pLacHashLookupDefs; + return status; } @@ -472,9 +490,11 @@ CpaCySymHashAlgorithm hashAlgorithm, lac_sym_qat_hash_alg_info_t **ppHashAlgInfo) { - sal_crypto_service_t *pService = (sal_crypto_service_t *)instanceHandle; + sal_service_t *pService = (sal_service_t *)instanceHandle; + lac_sym_qat_hash_defs_t **pLacHashLookupDefs = + ((sal_crypto_service_t *)pService)->pLacHashLookupDefs; - *ppHashAlgInfo = pService->pLacHashLookupDefs[hashAlgorithm]->algInfo; + *ppHashAlgInfo = pLacHashLookupDefs[hashAlgorithm]->algInfo; } /* @@ -485,7 +505,9 @@ CpaCySymHashAlgorithm hashAlgorithm, lac_sym_qat_hash_defs_t **ppHashDefsInfo) { - sal_crypto_service_t *pService = (sal_crypto_service_t *)instanceHandle; + sal_service_t *pService = (sal_service_t *)instanceHandle; + lac_sym_qat_hash_defs_t **pLacHashLookupDefs = + ((sal_crypto_service_t *)pService)->pLacHashLookupDefs; - *ppHashDefsInfo = pService->pLacHashLookupDefs[hashAlgorithm]; + *ppHashDefsInfo = pLacHashLookupDefs[hashAlgorithm]; } diff --git a/sys/dev/qat/qat_api/common/ctrl/sal_compression.c b/sys/dev/qat/qat_api/common/ctrl/sal_compression.c --- a/sys/dev/qat/qat_api/common/ctrl/sal_compression.c +++ b/sys/dev/qat/qat_api/common/ctrl/sal_compression.c @@ -47,6 +47,7 @@ #include "sal_service_state.h" #include "lac_buffer_desc.h" #include "icp_qat_fw_comp.h" +#include "icp_qat_hw_20_comp_defs.h" #include "icp_sal_versions.h" /* C string null terminator size */ @@ -124,6 +125,10 @@ SalCtrl_CompressionInit_CompData(icp_accel_dev_t *device, sal_compression_service_t *pCompService) { + int level = 0; + + pCompService->comp_device_data.uniqueCompressionLevels[0] = CPA_FALSE; + switch (device->deviceType) { case DEVICE_DH895XCC: case DEVICE_DH895XCCVF: @@ -191,13 +196,36 @@ ICP_QAT_FW_COMP_ENABLE_SECURE_RAM_USED_AS_INTMD_BUF; pCompService->comp_device_data.inflateContextSize = DC_INFLATE_EH_CONTEXT_SIZE; + pCompService->comp_device_data.highestHwCompressionDepth = + ICP_QAT_HW_COMPRESSION_DEPTH_16; pCompService->comp_device_data.windowSizeMask = - (1 << DC_16K_WINDOW_SIZE | 1 << DC_32K_WINDOW_SIZE); + (1 << DC_4K_WINDOW_SIZE | 1 << DC_8K_WINDOW_SIZE | + 1 << DC_16K_WINDOW_SIZE | 1 << DC_32K_WINDOW_SIZE); pCompService->comp_device_data.minOutputBuffSize = DC_DEST_BUFFER_STA_MIN_SIZE; + pCompService->comp_device_data.minOutputBuffSizeDynamic = + pCompService->comp_device_data.minOutputBuffSize; pCompService->comp_device_data.enableDmm = ICP_QAT_HW_COMPRESSION_DELAYED_MATCH_ENABLED; pCompService->comp_device_data.cnvnrSupported = CPA_TRUE; + + for (level = CPA_DC_L1; level <= CPA_DC_L9; level++) { + switch (level) { + case CPA_DC_L1: + case CPA_DC_L2: + case CPA_DC_L3: + case CPA_DC_L4: + pCompService->comp_device_data + .uniqueCompressionLevels[level] = CPA_TRUE; + break; + default: + pCompService->comp_device_data + .uniqueCompressionLevels[level] = CPA_FALSE; + break; + } + } + pCompService->comp_device_data.numCompressionLevels = + DC_NUM_COMPRESSION_LEVELS; break; case DEVICE_C4XXX: case DEVICE_C4XXXVF: @@ -227,6 +255,45 @@ (1 << DC_16K_WINDOW_SIZE | 1 << DC_32K_WINDOW_SIZE); pCompService->comp_device_data.cnvnrSupported = CPA_TRUE; break; + case DEVICE_GEN4: + pCompService->generic_service_info.integrityCrcCheck = CPA_TRUE; + pCompService->numInterBuffs = 0; + pCompService->comp_device_data.minOutputBuffSize = + DC_DEST_BUFFER_STA_MIN_SIZE_GEN4; + pCompService->comp_device_data.minOutputBuffSizeDynamic = + DC_DEST_BUFFER_DYN_MIN_SIZE_GEN4; + pCompService->comp_device_data.oddByteDecompNobFinal = CPA_TRUE; + pCompService->comp_device_data.oddByteDecompInterim = CPA_FALSE; + pCompService->comp_device_data.translatorOverflow = CPA_TRUE; + pCompService->comp_device_data.useDevRam = + ICP_QAT_FW_COMP_ENABLE_SECURE_RAM_USED_AS_INTMD_BUF; + pCompService->comp_device_data.enableDmm = + ICP_QAT_HW_COMPRESSION_DELAYED_MATCH_ENABLED; + + pCompService->comp_device_data.inflateContextSize = + DC_INFLATE_CONTEXT_SIZE; + pCompService->comp_device_data.highestHwCompressionDepth = + ICP_QAT_HW_COMP_20_SEARCH_DEPTH_LEVEL_9; + pCompService->comp_device_data.windowSizeMask = + (1 << DC_4K_WINDOW_SIZE | 1 << DC_8K_WINDOW_SIZE | + 1 << DC_16K_WINDOW_SIZE | 1 << DC_32K_WINDOW_SIZE); + for (level = CPA_DC_L1; level <= CPA_DC_L9; level++) { + switch (level) { + case CPA_DC_L1: + case CPA_DC_L6: + case CPA_DC_L9: + pCompService->comp_device_data + .uniqueCompressionLevels[level] = CPA_TRUE; + break; + default: + pCompService->comp_device_data + .uniqueCompressionLevels[level] = CPA_FALSE; + break; + } + } + pCompService->comp_device_data.numCompressionLevels = + DC_NUM_COMPRESSION_LEVELS; + break; default: QAT_UTILS_LOG("Unknown device type! - %d.\n", device->deviceType); diff --git a/sys/dev/qat/qat_api/common/ctrl/sal_create_services.c b/sys/dev/qat/qat_api/common/ctrl/sal_create_services.c --- a/sys/dev/qat/qat_api/common/ctrl/sal_create_services.c +++ b/sys/dev/qat/qat_api/common/ctrl/sal_create_services.c @@ -64,6 +64,9 @@ pCrypto_service->generic_service_info.shutdown = SalCtrl_CryptoShutdown; + /* Force HW MAC validation for GCM and CCM */ + pCrypto_service->forceAEADMacVerify = CPA_TRUE; + *(ppInst) = &(pCrypto_service->generic_service_info); return CPA_STATUS_SUCCESS; diff --git a/sys/dev/qat/qat_api/common/ctrl/sal_crypto.c b/sys/dev/qat/qat_api/common/ctrl/sal_crypto.c --- a/sys/dev/qat/qat_api/common/ctrl/sal_crypto.c +++ b/sys/dev/qat/qat_api/common/ctrl/sal_crypto.c @@ -59,7 +59,10 @@ #include "lac_sym_qat.h" #include "icp_sal_versions.h" #include "icp_sal_user.h" +#include "sal_hw_gen.h" +#define HMAC_MODE_1 1 +#define HMAC_MODE_2 2 #define TH_CY_RX_0 0 #define TH_CY_RX_1 1 #define MAX_CY_RX_RINGS 2 @@ -211,7 +214,7 @@ ICP_TRANS_TYPE_ETR, section, pCryptoService->acceleratorNum, - pCryptoService->bankNum, + pCryptoService->bankNumSym, temp_string, lac_getRingType(SAL_RING_TYPE_A_SYM_HI), NULL, @@ -235,7 +238,7 @@ ICP_TRANS_TYPE_ETR, section, pCryptoService->acceleratorNum, - pCryptoService->bankNum, + pCryptoService->bankNumSym, temp_string, lac_getRingType(SAL_RING_TYPE_NONE), (icp_trans_callback)LacSymQat_SymRespHandler, @@ -328,6 +331,7 @@ SalCtrl_SymInit(icp_accel_dev_t *device, sal_service_t *service) { CpaStatus status = CPA_STATUS_SUCCESS; + Cpa32U qatHmacMode = 0; Cpa32U numSymConcurrentReq = 0; char adfGetParam[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 }; char temp_string[SAL_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 }; @@ -344,6 +348,19 @@ * (Hash, Cipher, Algorithm-Chaining) (returns void)*/ LacSymCb_CallbacksRegister(); + qatHmacMode = (Cpa32U)Sal_Strtoul(adfGetParam, NULL, SAL_CFG_BASE_DEC); + switch (qatHmacMode) { + case HMAC_MODE_1: + pCryptoService->qatHmacMode = ICP_QAT_HW_AUTH_MODE1; + break; + case HMAC_MODE_2: + pCryptoService->qatHmacMode = ICP_QAT_HW_AUTH_MODE2; + break; + default: + pCryptoService->qatHmacMode = ICP_QAT_HW_AUTH_MODE1; + break; + } + /* Get num concurrent requests from config file */ status = Sal_StringParsing("Cy", @@ -524,6 +541,32 @@ return status; } +static CpaStatus +SalCtrl_GetBankNum(icp_accel_dev_t *device, + Cpa32U inst, + char *section, + char *bank_name, + Cpa16U *bank) +{ + char adfParamValue[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 }; + char adfParamName[SAL_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 }; + CpaStatus status = CPA_STATUS_SUCCESS; + + status = Sal_StringParsing("Cy", inst, bank_name, adfParamName); + LAC_CHECK_STATUS(status); + status = icp_adf_cfgGetParamValue(device, + section, + adfParamName, + adfParamValue); + if (CPA_STATUS_SUCCESS != status) { + QAT_UTILS_LOG("Failed to get %s from configuration file\n", + adfParamName); + return status; + } + *bank = (Cpa16U)Sal_Strtoul(adfParamValue, NULL, SAL_CFG_BASE_DEC); + return status; +} + static CpaStatus SalCtr_InstInit(icp_accel_dev_t *device, sal_service_t *service) { @@ -545,21 +588,62 @@ pCryptoService->acceleratorNum = 0; - status = - Sal_StringParsing("Cy", - pCryptoService->generic_service_info.instance, - "BankNumber", - temp_string); - LAC_CHECK_STATUS(status); - status = - icp_adf_cfgGetParamValue(device, section, temp_string, adfGetParam); - if (CPA_STATUS_SUCCESS != status) { - QAT_UTILS_LOG("Failed to get %s from configuration file\n", - temp_string); - return status; + /* Gen4, a bank only has 2 rings (1 ring pair), only one type of service + can be assigned one time. asym and sym will be in different bank*/ + if (isCyGen4x(pCryptoService)) { + switch (service->type) { + case SAL_SERVICE_TYPE_CRYPTO_ASYM: + status = SalCtrl_GetBankNum( + device, + pCryptoService->generic_service_info.instance, + section, + "BankNumberAsym", + &pCryptoService->bankNumAsym); + if (CPA_STATUS_SUCCESS != status) + return status; + break; + case SAL_SERVICE_TYPE_CRYPTO_SYM: + status = SalCtrl_GetBankNum( + device, + pCryptoService->generic_service_info.instance, + section, + "BankNumberSym", + &pCryptoService->bankNumSym); + if (CPA_STATUS_SUCCESS != status) + return status; + break; + case SAL_SERVICE_TYPE_CRYPTO: + status = SalCtrl_GetBankNum( + device, + pCryptoService->generic_service_info.instance, + section, + "BankNumberAsym", + &pCryptoService->bankNumAsym); + if (CPA_STATUS_SUCCESS != status) + return status; + status = SalCtrl_GetBankNum( + device, + pCryptoService->generic_service_info.instance, + section, + "BankNumberSym", + &pCryptoService->bankNumSym); + if (CPA_STATUS_SUCCESS != status) + return status; + break; + default: + return CPA_STATUS_FAIL; + } + } else { + status = SalCtrl_GetBankNum( + device, + pCryptoService->generic_service_info.instance, + section, + "BankNumber", + &pCryptoService->bankNumSym); + if (CPA_STATUS_SUCCESS != status) + return status; + pCryptoService->bankNumAsym = pCryptoService->bankNumSym; } - pCryptoService->bankNum = - (Cpa16U)Sal_Strtoul(adfGetParam, NULL, SAL_CFG_BASE_DEC); status = Sal_StringParsing("Cy", @@ -619,10 +703,18 @@ "", temp_string2); LAC_CHECK_STATUS(status); - status = Sal_StringParsing("Bank", - pCryptoService->bankNum, - "CoreAffinity", - temp_string); + if (service->type == SAL_SERVICE_TYPE_CRYPTO_ASYM) + status = Sal_StringParsing("Bank", + pCryptoService->bankNumAsym, + "CoreAffinity", + temp_string); + else + /* For cy service, asym bank and sym bank will set the + same core affinity. So Just read one*/ + status = Sal_StringParsing("Bank", + pCryptoService->bankNumSym, + "CoreAffinity", + temp_string); LAC_CHECK_STATUS(status); } else { strncpy(temp_string2, section, (strlen(section) + 1)); @@ -817,6 +909,9 @@ case CPA_STATUS_FATAL: LAC_COPY_STRING(pStatusText, CPA_STATUS_STR_FATAL); break; + case CPA_STATUS_UNSUPPORTED: + LAC_COPY_STRING(pStatusText, CPA_STATUS_STR_UNSUPPORTED); + break; default: status = CPA_STATUS_INVALID_PARAM; break; @@ -886,6 +981,10 @@ instanceHandle = instanceHandle_in; } LAC_CHECK_NULL_PARAM(instanceHandle); + SAL_CHECK_INSTANCE_TYPE(instanceHandle, + (SAL_SERVICE_TYPE_CRYPTO | + SAL_SERVICE_TYPE_CRYPTO_ASYM | + SAL_SERVICE_TYPE_CRYPTO_SYM)); pService = (sal_crypto_service_t *)instanceHandle; @@ -930,6 +1029,10 @@ instanceHandle = instanceHandle_in; } LAC_CHECK_NULL_PARAM(instanceHandle); + SAL_CHECK_INSTANCE_TYPE(instanceHandle, + (SAL_SERVICE_TYPE_CRYPTO | + SAL_SERVICE_TYPE_CRYPTO_ASYM | + SAL_SERVICE_TYPE_CRYPTO_SYM)); status = cpaCyInstanceGetInfo2(instanceHandle, &info); if (CPA_STATUS_SUCCESS != status) { @@ -1431,23 +1534,31 @@ } CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_NULL); - CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_ARC4); CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_ECB); CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_CBC); CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_CTR); CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_CCM); CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_GCM); - CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_DES_ECB); - CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_DES_CBC); - CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_3DES_ECB); - CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_3DES_CBC); - CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_3DES_CTR); - CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_KASUMI_F8); - CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_SNOW3G_UEA2); - CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_F8); CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_XTS); + if (isCyGen2x(pCryptoService)) { + CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_ARC4); + CPA_BITMAP_BIT_SET(pCapInfo->ciphers, + CPA_CY_SYM_CIPHER_DES_ECB); + CPA_BITMAP_BIT_SET(pCapInfo->ciphers, + CPA_CY_SYM_CIPHER_DES_CBC); + CPA_BITMAP_BIT_SET(pCapInfo->ciphers, + CPA_CY_SYM_CIPHER_3DES_ECB); + CPA_BITMAP_BIT_SET(pCapInfo->ciphers, + CPA_CY_SYM_CIPHER_3DES_CBC); + CPA_BITMAP_BIT_SET(pCapInfo->ciphers, + CPA_CY_SYM_CIPHER_3DES_CTR); + CPA_BITMAP_BIT_SET(pCapInfo->ciphers, + CPA_CY_SYM_CIPHER_KASUMI_F8); + CPA_BITMAP_BIT_SET(pCapInfo->ciphers, + CPA_CY_SYM_CIPHER_SNOW3G_UEA2); + CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_F8); + } - CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_MD5); CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA1); CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA224); CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA256); @@ -1456,11 +1567,15 @@ CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_XCBC); CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_CCM); CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_GCM); - CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_KASUMI_F9); - CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SNOW3G_UIA2); CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_CMAC); CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_GMAC); CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_CBC_MAC); + if (isCyGen2x(pCryptoService)) { + CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_MD5); + CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_KASUMI_F9); + CPA_BITMAP_BIT_SET(pCapInfo->hashes, + CPA_CY_SYM_HASH_SNOW3G_UIA2); + } if (pGenericService->capabilitiesMask & ICP_ACCEL_CAPABILITIES_CRYPTO_ZUC) { @@ -1660,18 +1775,33 @@ Lac_GetFirstAsymHandle(icp_accel_dev_t *adfInsts[ADF_MAX_DEVICES], Cpa16U num_dev) { + CpaStatus status = CPA_STATUS_SUCCESS; icp_accel_dev_t *dev_addr = NULL; sal_t *base_addr = NULL; sal_list_t *list_temp = NULL; CpaInstanceHandle cyInst = NULL; + CpaInstanceInfo2 info; Cpa16U i = 0; for (i = 0; i < num_dev; i++) { dev_addr = (icp_accel_dev_t *)adfInsts[i]; base_addr = dev_addr->pSalHandle; - if ((NULL != base_addr) && (NULL != base_addr->asym_services)) { - list_temp = base_addr->asym_services; + if (NULL == base_addr) { + continue; + } + list_temp = base_addr->asym_services; + while (NULL != list_temp) { cyInst = SalList_getObject(list_temp); + status = cpaCyInstanceGetInfo2(cyInst, &info); + list_temp = SalList_next(list_temp); + if (CPA_STATUS_SUCCESS != status || + CPA_TRUE != info.isPolled) { + cyInst = NULL; + continue; + } + break; + } + if (cyInst) { break; } } @@ -1684,18 +1814,33 @@ Lac_GetFirstSymHandle(icp_accel_dev_t *adfInsts[ADF_MAX_DEVICES], Cpa16U num_dev) { + CpaStatus status = CPA_STATUS_SUCCESS; icp_accel_dev_t *dev_addr = NULL; sal_t *base_addr = NULL; sal_list_t *list_temp = NULL; CpaInstanceHandle cyInst = NULL; + CpaInstanceInfo2 info; Cpa16U i = 0; for (i = 0; i < num_dev; i++) { dev_addr = (icp_accel_dev_t *)adfInsts[i]; base_addr = dev_addr->pSalHandle; - if ((NULL != base_addr) && (NULL != base_addr->sym_services)) { - list_temp = base_addr->sym_services; + if (NULL == base_addr) { + continue; + } + list_temp = base_addr->sym_services; + while (NULL != list_temp) { cyInst = SalList_getObject(list_temp); + status = cpaCyInstanceGetInfo2(cyInst, &info); + list_temp = SalList_next(list_temp); + if (CPA_STATUS_SUCCESS != status || + CPA_TRUE != info.isPolled) { + cyInst = NULL; + continue; + } + break; + } + if (cyInst) { break; } } @@ -1709,22 +1854,37 @@ static CpaInstanceHandle Lac_GetFirstCyHandle(icp_accel_dev_t *adfInsts[ADF_MAX_DEVICES], Cpa16U num_dev) { + CpaStatus status = CPA_STATUS_SUCCESS; icp_accel_dev_t *dev_addr = NULL; sal_t *base_addr = NULL; sal_list_t *list_temp = NULL; CpaInstanceHandle cyInst = NULL; + CpaInstanceInfo2 info; Cpa16U i = 0; for (i = 0; i < num_dev; i++) { dev_addr = (icp_accel_dev_t *)adfInsts[i]; base_addr = dev_addr->pSalHandle; - if ((NULL != base_addr) && - (NULL != base_addr->crypto_services)) { - list_temp = base_addr->crypto_services; + if (NULL == base_addr) { + continue; + } + list_temp = base_addr->crypto_services; + while (NULL != list_temp) { cyInst = SalList_getObject(list_temp); + status = cpaCyInstanceGetInfo2(cyInst, &info); + list_temp = SalList_next(list_temp); + if (CPA_STATUS_SUCCESS != status || + CPA_TRUE != info.isPolled) { + cyInst = NULL; + continue; + } + break; + } + if (cyInst) { break; } } + return cyInst; } @@ -1835,3 +1995,16 @@ numInflightRequests); } + +CpaStatus +icp_sal_setForceAEADMACVerify(CpaInstanceHandle instanceHandle, + CpaBoolean forceAEADMacVerify) +{ + sal_crypto_service_t *crypto_handle = NULL; + + crypto_handle = (sal_crypto_service_t *)instanceHandle; + LAC_CHECK_NULL_PARAM(crypto_handle); + crypto_handle->forceAEADMacVerify = forceAEADMacVerify; + + return CPA_STATUS_SUCCESS; +} diff --git a/sys/dev/qat/qat_api/common/ctrl/sal_ctrl_services.c b/sys/dev/qat/qat_api/common/ctrl/sal_ctrl_services.c --- a/sys/dev/qat/qat_api/common/ctrl/sal_ctrl_services.c +++ b/sys/dev/qat/qat_api/common/ctrl/sal_ctrl_services.c @@ -458,6 +458,37 @@ return status; } +static CpaStatus +selectGeneration(device_type_t deviceType, sal_service_t *pInst) +{ + switch (deviceType) { + case DEVICE_C62X: + case DEVICE_C62XVF: + case DEVICE_DH895XCC: + case DEVICE_DH895XCCVF: + case DEVICE_C3XXX: + case DEVICE_C3XXXVF: + case DEVICE_200XX: + case DEVICE_200XXVF: + pInst->gen = GEN2; + break; + + case DEVICE_C4XXX: + case DEVICE_C4XXXVF: + pInst->gen = GEN3; + break; + + case DEVICE_GEN4: + pInst->gen = GEN4; + break; + + default: + QAT_UTILS_LOG("deviceType not initialised\n"); + return CPA_STATUS_FAIL; + } + return CPA_STATUS_SUCCESS; +} + /************************************************************************* * @ingroup SalCtrl * @description @@ -523,7 +554,12 @@ } pInst->debug_parent_dir = debug_dir; pInst->capabilitiesMask = device->accelCapabilitiesMask; - status = SalList_add(services, &tail_list, pInst); + + status = selectGeneration(device->deviceType, pInst); + if (CPA_STATUS_SUCCESS == status) { + status = + SalList_add(services, &tail_list, pInst); + } if (CPA_STATUS_SUCCESS != status) { free(pInst, M_QAT); } diff --git a/sys/dev/qat/qat_api/common/include/lac_common.h b/sys/dev/qat/qat_api/common/include/lac_common.h --- a/sys/dev/qat/qat_api/common/include/lac_common.h +++ b/sys/dev/qat/qat_api/common/include/lac_common.h @@ -756,17 +756,14 @@ #define LAC_SPINLOCK(lock) \ ({ \ (void)qatUtilsLock(lock); \ - CPA_STATUS_SUCCESS; \ }) #define LAC_SPINUNLOCK(lock) \ ({ \ (void)qatUtilsUnlock(lock); \ - CPA_STATUS_SUCCESS; \ }) #define LAC_SPINLOCK_DESTROY(lock) \ ({ \ (void)qatUtilsLockDestroy(lock); \ - CPA_STATUS_SUCCESS; \ }) #define LAC_CONST_PTR_CAST(castee) ((void *)(LAC_ARCH_UINT)(castee)) diff --git a/sys/dev/qat/qat_api/common/include/lac_sal.h b/sys/dev/qat/qat_api/common/include/lac_sal.h --- a/sys/dev/qat/qat_api/common/include/lac_sal.h +++ b/sys/dev/qat/qat_api/common/include/lac_sal.h @@ -54,8 +54,7 @@ Cpa32U instance_num, sal_service_t **pObj); -/** -******************************************************************************* +/****************************************************************************** * @ingroup SalCtl * @description * This macro goes through the 'list' passed in as a parameter. For each diff --git a/sys/dev/qat/qat_api/common/include/lac_sal_types.h b/sys/dev/qat/qat_api/common/include/lac_sal_types.h --- a/sys/dev/qat/qat_api/common/include/lac_sal_types.h +++ b/sys/dev/qat/qat_api/common/include/lac_sal_types.h @@ -67,6 +67,17 @@ SAL_SERVICE_TYPE_QAT = 32 } sal_service_type_t; +/** + ***************************************************************************** + * @ingroup SalCtrl + * Device generations + * + * @description + * List in an enum all the QAT device generations. + * + *****************************************************************************/ +typedef enum { GEN2, GEN3, GEN4 } sal_generation_t; + /** ***************************************************************************** * @ingroup SalCtrl @@ -128,6 +139,9 @@ CpaBoolean integrityCrcCheck; /** < True if the device supports end to end data integrity checks */ + + sal_generation_t gen; + /** Generation of devices */ } sal_service_t; /** diff --git a/sys/dev/qat/qat_api/common/include/lac_sal_types_crypto.h b/sys/dev/qat/qat_api/common/include/lac_sal_types_crypto.h --- a/sys/dev/qat/qat_api/common/include/lac_sal_types_crypto.h +++ b/sys/dev/qat/qat_api/common/include/lac_sal_types_crypto.h @@ -16,6 +16,7 @@ #define LAC_SAL_TYPES_CRYPTO_H_ #include "lac_sym_qat_hash_defs_lookup.h" +#include "lac_sym_qat_constants_table.h" #include "lac_sym_key.h" #include "cpa_cy_sym_dp.h" @@ -84,6 +85,8 @@ QatUtilsAtomic *pLacDrbgStatsArr; /**< pointer to an array of atomic stats for DRBG */ + icp_qat_hw_auth_mode_t qatHmacMode; + /**< Hmac Mode */ Cpa32U pkeFlowId; /**< Flow ID for all pke requests from this instance - identifies @@ -105,6 +108,8 @@ Cpa16U acceleratorNum; Cpa16U bankNum; + Cpa16U bankNumAsym; + Cpa16U bankNumSym; Cpa16U pkgID; Cpa8U isPolled; Cpa8U executionEngine; @@ -119,6 +124,9 @@ /**< table of pointers to standard defined information for all hash algorithms. We support an extra hash algo that is not exported by cy api which is why we need the extra +1 */ + + lac_sym_qat_constants_t constantsLookupTables; + Cpa8U **ppHmacContentDesc; /**< table of pointers to CD for Hmac precomputes - used at session init */ @@ -137,6 +145,10 @@ debug_file_info_t *debug_file; /**< Statistics handler */ + + CpaBoolean forceAEADMacVerify; + /**< internal flag to enable/disable forcing HW digest verification for + GCM and CCM algorithms */ } sal_crypto_service_t; /************************************************************************* diff --git a/sys/dev/qat/qat_api/common/include/lac_sync.h b/sys/dev/qat/qat_api/common/include/lac_sync.h --- a/sys/dev/qat/qat_api/common/include/lac_sync.h +++ b/sys/dev/qat/qat_api/common/include/lac_sync.h @@ -61,7 +61,7 @@ * Timeout for wait for init messages response in msecs */ -#define DC_SYNC_CALLBACK_TIMEOUT (1000) +#define DC_SYNC_CALLBACK_TIMEOUT (2000) /**< @ingroup LacSyn * Timeout for wait for compression response in msecs */ diff --git a/sys/dev/qat/qat_api/common/include/sal_hw_gen.h b/sys/dev/qat/qat_api/common/include/sal_hw_gen.h new file mode 100644 --- /dev/null +++ b/sys/dev/qat/qat_api/common/include/sal_hw_gen.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2007-2022 Intel Corporation */ +/* $FreeBSD$ */ +/** + *************************************************************************** + * @file sal_hw_gen.h + * + * @ingroup SalHwGen + * + * @description + * Functions which return a value corresponding to qat device generation + * + ***************************************************************************/ + +#ifndef SAL_HW_GEN_H +#define SAL_HW_GEN_H + +#include "cpa.h" +#include "sal_types_compression.h" +#include "lac_sal_types_crypto.h" + +/** + *************************************************************************** + * @ingroup SalHwGen + * + * @description This function returns whether qat device is gen 4 or not + * + * @param[in] pService pointer to compression service + * + ***************************************************************************/ + +static inline CpaBoolean +isDcGen4x(const sal_compression_service_t *pService) +{ + return (pService->generic_service_info.gen == GEN4); +} + +/** + *************************************************************************** + * @ingroup SalHwGen + * + * @description This function returns whether qat device is gen 2/3 or not + * + * @param[in] pService pointer to compression service + * + ***************************************************************************/ + +static inline CpaBoolean +isDcGen2x(const sal_compression_service_t *pService) +{ + return ((pService->generic_service_info.gen == GEN2) || + (pService->generic_service_info.gen == GEN3)); +} + +/** + *************************************************************************** + * @ingroup SalHwGen + * + * @description This function returns whether qat device is gen 4 or not + * + * @param[in] pService pointer to crypto service + * + ***************************************************************************/ + +static inline CpaBoolean +isCyGen4x(const sal_crypto_service_t *pService) +{ + return (pService->generic_service_info.gen == GEN4); +} + +/** + *************************************************************************** + * @ingroup SalHwGen + * + * @description This function returns whether qat device is gen 2/3 or not + * + * @param[in] pService pointer to crypto service + * + ***************************************************************************/ + +static inline CpaBoolean +isCyGen2x(const sal_crypto_service_t *pService) +{ + return ((pService->generic_service_info.gen == GEN2) || + (pService->generic_service_info.gen == GEN3)); +} + +#endif /* SAL_HW_GEN_H */ diff --git a/sys/dev/qat/qat_api/common/include/sal_types_compression.h b/sys/dev/qat/qat_api/common/include/sal_types_compression.h --- a/sys/dev/qat/qat_api/common/include/sal_types_compression.h +++ b/sys/dev/qat/qat_api/common/include/sal_types_compression.h @@ -23,6 +23,7 @@ #include "icp_adf_transport.h" #define DC_NUM_RX_RINGS (1) +#define DC_NUM_COMPRESSION_LEVELS (CPA_DC_L9) /** ***************************************************************************** @@ -37,6 +38,9 @@ /* Device specific minimum output buffer size for static compression */ Cpa32U minOutputBuffSize; + /* Device specific minimum output buffer size for dynamic compression */ + Cpa32U minOutputBuffSizeDynamic; + /* Enable/disable secureRam/acceleratorRam for intermediate buffers*/ Cpa8U useDevRam; @@ -62,6 +66,11 @@ /* Mask that reports supported window sizes for comp/decomp */ Cpa8U windowSizeMask; + /* List representing compression levels that are the first to have + a unique search depth. */ + CpaBoolean uniqueCompressionLevels[DC_NUM_COMPRESSION_LEVELS + 1]; + Cpa8U numCompressionLevels; + /* Flag to indicate CompressAndVerifyAndRecover feature support */ CpaBoolean cnvnrSupported; } sal_compression_device_data_t; diff --git a/sys/dev/qat/qat_api/firmware/include/icp_qat_fw.h b/sys/dev/qat/qat_api/firmware/include/icp_qat_fw.h --- a/sys/dev/qat/qat_api/firmware/include/icp_qat_fw.h +++ b/sys/dev/qat/qat_api/firmware/include/icp_qat_fw.h @@ -486,12 +486,12 @@ /* ========================================================================= */ /* Common QAT FW request header - structure of LW0 - * + ===== + ---- + ----------- + ----------- + ----------- + ----------- + - * | Bit | 31 | 30 - 24 | 21 - 16 | 15 - 8 | 7 - 0 | - * + ===== + ---- + ----------- + ----------- + ----------- + ----------- + - * | Flags | V | Reserved | Serv Type | Serv Cmd Id | Reserved | - * + ===== + ---- + ----------- + ----------- + ----------- + ----------- + -*/ + * + ===== + ------- + ----------- + ----------- + ----------- + -------- + + * | Bit | 31/30 | 29 - 24 | 21 - 16 | 15 - 8 | 7 - 0 | + * + ===== + ------- + ----------- + ----------- + ----------- + -------- + + * | Flags | V/Gen | Reserved | Serv Type | Serv Cmd Id | Rsv | + * + ===== + ------- + ----------- + ----------- + ----------- + -------- + + */ /**< @ingroup icp_qat_fw_comn * Definition of the setting of the header's valid flag */ @@ -505,6 +505,20 @@ * hdr_flags field of LW0 (service request and response) */ #define ICP_QAT_FW_COMN_VALID_FLAG_BITPOS 7 #define ICP_QAT_FW_COMN_VALID_FLAG_MASK 0x1 + +/**< @ingroup icp_qat_fw_comn + * Macros defining the bit position and mask of the 'generation' flag, within + * the hdr_flags field of LW0 (service request and response) */ +#define ICP_QAT_FW_COMN_GEN_FLAG_BITPOS 6 +#define ICP_QAT_FW_COMN_GEN_FLAG_MASK 0x1 +/**< @ingroup icp_qat_fw_comn + * The request is targeted for QAT2.0 */ +#define ICP_QAT_FW_COMN_GEN_2 1 +/**< @ingroup icp_qat_fw_comn +* The request is targeted for QAT1.x. QAT2.0 FW will return + 'unsupported request' if GEN1 request type is sent to QAT2.0 FW */ +#define ICP_QAT_FW_COMN_GEN_1 0 + #define ICP_QAT_FW_COMN_HDR_RESRVD_FLD_MASK 0x7F /* Common QAT FW response header - structure of LW0 @@ -525,6 +539,13 @@ #define ICP_QAT_FW_COMN_CNVNR_FLAG_BITPOS 5 #define ICP_QAT_FW_COMN_CNVNR_FLAG_MASK 0x1 +/**< @ingroup icp_qat_fw_comn + * Macros defining the bit position and mask of Stored Blocks flag + * within the hdr_flags field of LW0 (service response only) + */ +#define ICP_QAT_FW_COMN_ST_BLK_FLAG_BITPOS 4 +#define ICP_QAT_FW_COMN_ST_BLK_FLAG_MASK 0x1 + /** ****************************************************************************** * @ingroup icp_qat_fw_comn @@ -660,6 +681,89 @@ ICP_QAT_FW_COMN_VALID_FLAG_BITPOS, \ ICP_QAT_FW_COMN_VALID_FLAG_MASK) +/** + ****************************************************************************** + * @ingroup icp_qat_fw_comn + * + * @description + * Extract the Stored Block flag from the header flags in the + * response only. + * + * @param hdr_flags Response 'hdr' structure to extract the + * Stored Block bit from the 'hdr_flags' field. + * + *****************************************************************************/ +#define ICP_QAT_FW_COMN_HDR_ST_BLK_FLAG_GET(hdr_flags) \ + QAT_FIELD_GET(hdr_flags, \ + ICP_QAT_FW_COMN_ST_BLK_FLAG_BITPOS, \ + ICP_QAT_FW_COMN_ST_BLK_FLAG_MASK) + +/** + ****************************************************************************** + * @ingroup icp_qat_fw_comn + * + * @description + * Set the Stored Block bit in the response's header flags. + * + * @param hdr_t Response 'hdr_t' structure to set the ST_BLK bit + * @param val Value of the ST_BLK bit flag. + * + *****************************************************************************/ +#define ICP_QAT_FW_COMN_HDR_ST_BLK_FLAG_SET(hdr_t, val) \ + QAT_FIELD_SET((hdr_t.hdr_flags), \ + (val), \ + ICP_QAT_FW_COMN_ST_BLK_FLAG_BITPOS, \ + ICP_QAT_FW_COMN_ST_BLK_FLAG_MASK) + +/** + ****************************************************************************** + * @ingroup icp_qat_fw_comn + * + * @description + * Set the generation bit in the request's header flags. + * + * @param hdr_t Request or Response 'hdr_t' structure to set the gen bit + * @param val Value of the generation bit flag. + * + *****************************************************************************/ +#define ICP_QAT_FW_COMN_HDR_GENERATION_FLAG_SET(hdr_t, val) \ + ICP_QAT_FW_COMN_GENERATION_FLAG_SET(hdr_t, val) + +/** +****************************************************************************** +* @ingroup icp_qat_fw_comn +* +* @description +* Common macro to set the generation bit in the common header +* +* @param hdr_t Structure (request or response) containing the header +* flags field, to allow the generation bit to be set. +* @param val Value of the generation bit flag. +* +*****************************************************************************/ +#define ICP_QAT_FW_COMN_GENERATION_FLAG_SET(hdr_t, val) \ + QAT_FIELD_SET((hdr_t.hdr_flags), \ + (val), \ + ICP_QAT_FW_COMN_GEN_FLAG_BITPOS, \ + ICP_QAT_FW_COMN_GEN_FLAG_MASK) + +/** +****************************************************************************** +* @ingroup icp_qat_fw_comn +* +* @description +* Common macro to extract the generation flag from the header flags field +* within the header structure (request or response). +* +* @param hdr_t Structure (request or response) to extract the +* generation bit from the 'hdr_flags' field. +* +*****************************************************************************/ + +#define ICP_QAT_FW_COMN_HDR_GENERATION_FLAG_GET(hdr_flags) \ + QAT_FIELD_GET(hdr_flags, \ + ICP_QAT_FW_COMN_GEN_FLAG_BITPOS, \ + ICP_QAT_FW_COMN_GEN_FLAG_MASK) /** ****************************************************************************** * @ingroup icp_qat_fw_comn diff --git a/sys/dev/qat/qat_api/firmware/include/icp_qat_fw_comp.h b/sys/dev/qat/qat_api/firmware/include/icp_qat_fw_comp.h --- a/sys/dev/qat/qat_api/firmware/include/icp_qat_fw_comp.h +++ b/sys/dev/qat/qat_api/firmware/include/icp_qat_fw_comp.h @@ -61,6 +61,8 @@ * | | |as intmd| | | | | | | | * | | | buf | | | | | | | | * + ===== + ------ + ----- + --- + ------ + ----- + ----- + -- + ---- + --- + + * Note: For QAT 2.0 Disable Secure Ram, DisType0 Header and Enhanced ASB bits + * are don't care. i.e., these features are removed from QAT 2.0. */ /** Flag usage */ @@ -183,6 +185,28 @@ ((secure_ram & ICP_QAT_FW_COMP_DISABLE_SECURE_RAM_AS_INTMD_BUF_MASK) \ << ICP_QAT_FW_COMP_DISABLE_SECURE_RAM_AS_INTMD_BUF_BITPOS)) +/** +****************************************************************************** +* @ingroup icp_qat_fw_comp +* +* @description +* Macro used for the generation of the command flags for Compression Request. +* This should always be used for the generation of the flags. No direct sets or +* masks should be performed on the flags data +* +* @param sesstype Session Type +* @param autoselect AutoSelectBest +* Selects between compressed and uncompressed output. +* No distinction made between static and dynamic +* compressed data. +* +*********************************************************************************/ +#define ICP_QAT_FW_COMP_20_FLAGS_BUILD(sesstype, autoselect) \ + (((sesstype & ICP_QAT_FW_COMP_SESSION_TYPE_MASK) \ + << ICP_QAT_FW_COMP_SESSION_TYPE_BITPOS) | \ + ((autoselect & ICP_QAT_FW_COMP_AUTO_SELECT_BEST_MASK) \ + << ICP_QAT_FW_COMP_AUTO_SELECT_BEST_BITPOS)) + /** ****************************************************************************** * @ingroup icp_qat_fw_comp @@ -375,14 +399,16 @@ * *****************************************************************************/ #define ICP_QAT_FW_COMP_REQ_PARAM_FLAGS_BUILD( \ - sop, eop, bfinal, cnv, cnvnr, crc) \ + sop, eop, bfinal, cnv, cnvnr, cnvdfx, crc) \ (((sop & ICP_QAT_FW_COMP_SOP_MASK) << ICP_QAT_FW_COMP_SOP_BITPOS) | \ ((eop & ICP_QAT_FW_COMP_EOP_MASK) << ICP_QAT_FW_COMP_EOP_BITPOS) | \ ((bfinal & ICP_QAT_FW_COMP_BFINAL_MASK) \ << ICP_QAT_FW_COMP_BFINAL_BITPOS) | \ ((cnv & ICP_QAT_FW_COMP_CNV_MASK) << ICP_QAT_FW_COMP_CNV_BITPOS) | \ - ((cnvnr & ICP_QAT_FW_COMP_CNV_RECOVERY_MASK) \ - << ICP_QAT_FW_COMP_CNV_RECOVERY_BITPOS) | \ + ((cnvnr & ICP_QAT_FW_COMP_CNVNR_MASK) \ + << ICP_QAT_FW_COMP_CNVNR_BITPOS) | \ + ((cnvdfx & ICP_QAT_FW_COMP_CNV_DFX_MASK) \ + << ICP_QAT_FW_COMP_CNV_DFX_BITPOS) | \ ((crc & ICP_QAT_FW_COMP_CRC_MODE_MASK) \ << ICP_QAT_FW_COMP_CRC_MODE_BITPOS)) @@ -443,6 +469,14 @@ /**< @ingroup icp_qat_fw_comp * Flag indicating that a cnv recovery is to be performed on the request */ +#define ICP_QAT_FW_COMP_NO_CNV_DFX 0 +/**< @ingroup icp_qat_fw_comp + * Flag indicating that NO CNV inject error is to be performed on the request */ + +#define ICP_QAT_FW_COMP_CNV_DFX 1 +/**< @ingroup icp_qat_fw_comp + * Flag indicating that CNV inject error is to be performed on the request */ + #define ICP_QAT_FW_COMP_CRC_MODE_LEGACY 0 /**< @ingroup icp_qat_fw_comp * Flag representing to use the legacy CRC mode */ @@ -491,6 +525,22 @@ /**< @ingroup icp_qat_fw_comp * Starting bit position for the CNV Recovery bit */ +#define ICP_QAT_FW_COMP_CNVNR_MASK 0x1 +/**< @ingroup icp_qat_fw_comp + * One bit mask for the CNV Recovery bit */ + +#define ICP_QAT_FW_COMP_CNVNR_BITPOS 17 +/**< @ingroup icp_qat_fw_comp + * Starting bit position for the CNV Recovery bit */ + +#define ICP_QAT_FW_COMP_CNV_DFX_BITPOS 18 +/**< @ingroup icp_qat_fw_comp + * Starting bit position for the CNV DFX bit */ + +#define ICP_QAT_FW_COMP_CNV_DFX_MASK 0x1 +/**< @ingroup icp_qat_fw_comp + * One bit mask for the CNV DFX bit */ + #define ICP_QAT_FW_COMP_CRC_MODE_BITPOS 19 /**< @ingroup icp_qat_fw_comp * Starting bit position for CRC mode */ @@ -499,6 +549,14 @@ /**< @ingroup icp_qat_fw_comp * One bit mask used to determine CRC mode */ +#define ICP_QAT_FW_COMP_XXHASH_ACC_MODE_BITPOS 20 +/**< @ingroup icp_qat_fw_comp + * Starting bit position for xxHash accumulate mode */ + +#define ICP_QAT_FW_COMP_XXHASH_ACC_MODE_MASK 0x1 +/**< @ingroup icp_qat_fw_comp + * One bit mask used to determine xxHash accumulate mode */ + /** ****************************************************************************** * @ingroup icp_qat_fw_comp @@ -574,6 +632,38 @@ ICP_QAT_FW_COMP_CRC_MODE_BITPOS, \ ICP_QAT_FW_COMP_CRC_MODE_MASK) +/** + ****************************************************************************** + * @ingroup icp_qat_fw_comp + * + * @description + * Macro for extraction of the xxHash accumulate mode bit + * + * @param flags Flags to extract the xxHash accumulate mode bit from + * + *****************************************************************************/ +#define ICP_QAT_FW_COMP_XXHASH_ACC_MODE_GET(flags) \ + QAT_FIELD_GET(flags, \ + ICP_QAT_FW_COMP_XXHASH_ACC_MODE_BITPOS, \ + ICP_QAT_FW_COMP_XXHASH_ACC_MODE_MASK) + +/** + ****************************************************************************** + * @ingroup icp_qat_fw_comp + * + * @description + * Macro for setting of the xxHash accumulate mode bit + * + * @param flags Flags to set the xxHash accumulate mode bit to + * @param val xxHash accumulate mode to set + * + *****************************************************************************/ +#define ICP_QAT_FW_COMP_XXHASH_ACC_MODE_SET(flags, val) \ + QAT_FIELD_SET(flags, \ + val, \ + ICP_QAT_FW_COMP_XXHASH_ACC_MODE_BITPOS, \ + ICP_QAT_FW_COMP_XXHASH_ACC_MODE_MASK) + /** ****************************************************************************** * @ingroup icp_qat_fw_comp @@ -589,10 +679,11 @@ /**< LWs 20-21 */ uint64_t inter_buff_ptr; /**< This field specifies the physical address of an intermediate - * buffer SGL array. The array contains a pair of 64-bit - * intermediate buffer pointers to SGL buffer descriptors, one pair - * per CPM. Please refer to the CPM1.6 Firmware Interface HLD - * specification for more details. */ + * buffer SGL array. The array contains a pair of 64-bit + * intermediate buffer pointers to SGL buffer descriptors, one pair + * per CPM. Please refer to the CPM1.6 Firmware Interface HLD + * specification for more details. + * Placeholder for QAT2.0. */ } icp_qat_fw_xlt_req_params_t; /** @@ -1026,4 +1117,31 @@ (((bank_a_enable)&QAT_FW_COMP_BANK_FLAG_MASK) \ << QAT_FW_COMP_BANK_A_BITPOS)) +/** + ***************************************************************************** + * @ingroup icp_qat_fw_comp + * Definition of the xxhash32 acc state buffer + * @description + * This is data structure used in stateful lite for xxhash32 + * + *****************************************************************************/ +typedef struct xxhash_acc_state_buff_s { + /**< LW 0 */ + uint32_t in_counter; + /**< Accumulated (total) consumed bytes. As oppose to the per request + * IBC in the response.*/ + + /**< LW 1 */ + uint32_t out_counter; + /**< OBC as in the response.*/ + + /**< LW 2-5 */ + uint32_t xxhash_state[4]; + /**< Initial value is set by IA to the values stated in HAS.*/ + + /**< LW 6-9 */ + uint32_t clear_txt[4]; + /**< Set to 0 for the first request.*/ +} xxhash_acc_state_buff_t; + #endif /* _ICP_QAT_FW_COMP_H_ */ diff --git a/sys/dev/qat/qat_api/firmware/include/icp_qat_fw_la.h b/sys/dev/qat/qat_api/firmware/include/icp_qat_fw_la.h --- a/sys/dev/qat/qat_api/firmware/include/icp_qat_fw_la.h +++ b/sys/dev/qat/qat_api/firmware/include/icp_qat_fw_la.h @@ -92,6 +92,44 @@ /**< Delimiter type */ } icp_qat_fw_la_cmd_id_t; +typedef struct icp_qat_fw_la_cipher_20_req_params_s { + /**< LW 14 */ + uint32_t cipher_offset; + /**< Cipher offset long word. */ + + /**< LW 15 */ + uint32_t cipher_length; + /**< Cipher length long word. */ + + /**< LWs 16-19 */ + union { + uint32_t cipher_IV_array[ICP_QAT_FW_NUM_LONGWORDS_4]; + /**< Cipher IV array */ + + struct { + uint64_t cipher_IV_ptr; + /**< Cipher IV pointer or Partial State Pointer */ + + uint64_t resrvd1; + /**< reserved */ + + } s; + + } u; + /**< LW 20 */ + uint32_t spc_aad_offset; + /**< LW 21 */ + uint32_t spc_aad_sz; + /**< LW 22 - 23 */ + uint64_t spc_aad_addr; + /**< LW 24 - 25 */ + uint64_t spc_auth_res_addr; + /**< LW 26 */ + uint8_t reserved[3]; + uint8_t spc_auth_res_sz; + +} icp_qat_fw_la_cipher_20_req_params_t; + /* For the definitions of the bits in the status field of the common * response, refer to icp_qat_fw.h. * The return values specific to Lookaside service are given below. @@ -165,6 +203,34 @@ /* Private defines */ +/* bits 15:14 */ +#define ICP_QAT_FW_LA_USE_WIRELESS_SLICE_TYPE 2 +/**< @ingroup icp_qat_fw_la + * FW Selects Wireless Cipher Slice + * Cipher Algorithms: AES-{F8}, Snow3G, ZUC + * Auth Algorithms : Snow3G, ZUC */ + +#define ICP_QAT_FW_LA_USE_UCS_SLICE_TYPE 1 +/**< @ingroup icp_qat_fw_la + * FW Selects UCS Cipher Slice + * Cipher Algorithms: AES-{CTR/XTS}, Single Pass AES-GCM + * Auth Algorithms : SHA1/ SHA{2/3}-{224/256/384/512} */ + +#define ICP_QAT_FW_LA_USE_LEGACY_SLICE_TYPE 0 +/**< @ingroup icp_qat_fw_la + * FW Selects Legacy Cipher/Auth Slice + * Cipher Algorithms: AES-{CBC/ECB}, SM4, Single Pass AES-CCM + * Auth Algorithms : SHA1/ SHA{2/3}-{224/256/384/512} */ + +#define QAT_LA_SLICE_TYPE_BITPOS 14 +/**< @ingroup icp_qat_fw_la + * Starting bit position for the slice type selection. + * Refer to HAS for Slice type assignment details on QAT2.0 */ + +#define QAT_LA_SLICE_TYPE_MASK 0x3 +/**< @ingroup icp_qat_fw_la + * Two bit mask used to determine the Slice type */ + /* bit 11 */ #define ICP_QAT_FW_LA_GCM_IV_LEN_12_OCTETS 1 /**< @ingroup icp_qat_fw_la @@ -482,7 +548,7 @@ * * @description * Macro for extraction of the Cipher IV field contents (bit 2) - * + * * @param flags Flags to extract the Cipher IV field contents * *****************************************************************************/ @@ -496,7 +562,7 @@ * @description * Macro for extraction of the Cipher/Auth Config * offset type (bit 3) - * + * * @param flags Flags to extract the Cipher/Auth Config * offset type * @@ -640,6 +706,19 @@ QAT_LA_USE_EXTENDED_PROTOCOL_FLAGS_BITPOS, \ QAT_LA_USE_EXTENDED_PROTOCOL_FLAGS_MASK) +/** + ****************************************************************************** + * @ingroup icp_qat_fw_la + * + * @description + * Macro for extraction of the slice type information from the flags. + * + * @param flags Flags to extract the protocol state + * + *****************************************************************************/ +#define ICP_QAT_FW_LA_SLICE_TYPE_GET(flags) \ + QAT_FIELD_GET(flags, QAT_LA_SLICE_TYPE_BITPOS, QAT_LA_SLICE_TYPE_MASK) + /* Macros for setting field bits */ /** ****************************************************************************** @@ -647,7 +726,7 @@ * * @description * Macro for setting the Cipher IV field contents - * + * * @param flags Flags to set with the Cipher IV field contents * @param val Field contents indicator value * @@ -665,7 +744,7 @@ * @description * Macro for setting the Cipher/Auth Config * offset type - * + * * @param flags Flags to set the Cipher/Auth Config offset type * @param val Offset type value * @@ -840,6 +919,23 @@ QAT_LA_USE_EXTENDED_PROTOCOL_FLAGS_BITPOS, \ QAT_LA_USE_EXTENDED_PROTOCOL_FLAGS_MASK) +/** +****************************************************************************** +* @ingroup icp_qat_fw_la +* +* @description +* Macro for setting the "slice type" field in la flags +* +* @param flags Flags to set the slice type +* @param val Value of the slice type to be set. +* +*****************************************************************************/ +#define ICP_QAT_FW_LA_SLICE_TYPE_SET(flags, val) \ + QAT_FIELD_SET(flags, \ + val, \ + QAT_LA_SLICE_TYPE_BITPOS, \ + QAT_LA_SLICE_TYPE_MASK) + /** ***************************************************************************** * @ingroup icp_qat_fw_la @@ -860,14 +956,10 @@ uint8_t content_desc_params_sz; /**< Size of the content descriptor parameters in quad words. - * These - * parameters describe the session setup configuration info for - * the - * slices that this request relies upon i.e. the configuration - * word and - * cipher key needed by the cipher slice if there is a request - * for - * cipher processing. */ + * These parameters describe the session setup configuration + * info for the slices that this request relies upon i.e. the + * configuration word and cipher key needed by the cipher slice + * if there is a request for cipher processing. */ uint8_t content_desc_hdr_resrvd2; /**< Content descriptor reserved field */ @@ -916,14 +1008,10 @@ uint8_t content_desc_params_sz; /**< Size of the content descriptor parameters in quad words. - * These - * parameters describe the session setup configuration info for - * the - * slices that this request relies upon i.e. the configuration - * word and - * cipher key needed by the cipher slice if there is a request - * for - * cipher processing. */ + * These parameters describe the session setup configuration + * info for the slices that this request relies upon i.e. the + * configuration word and cipher key needed by the cipher slice + * if there is a request for cipher processing. */ uint8_t content_desc_hdr_resrvd2; /**< Content descriptor reserved field */ @@ -955,8 +1043,7 @@ /**< LW 27 */ uint8_t cipher_state_sz; /**< State size in quad words of the cipher algorithm used in this - * session. - * Set to zero if the algorithm doesnt provide any state */ + * session. Set to zero if the algorithm doesnt provide any state */ uint8_t cipher_key_sz; /**< Key size in quad words of the cipher algorithm used in this session @@ -964,17 +1051,16 @@ uint8_t cipher_cfg_offset; /**< Quad word offset from the content descriptor parameters address - * i.e. - * (content_address + (cd_hdr_sz << 3)) to the parameters for the cipher - * processing */ + * i.e. (content_address + (cd_hdr_sz << 3)) to the parameters for the + * cipher processing */ uint8_t next_curr_id; /**< This field combines the next and current id (each four bits) - - * the next id is the most significant nibble. - * Next Id: Set to the next slice to pass the ciphered data through. - * Set to ICP_QAT_FW_SLICE_DRAM_WR if the data is not to go through - * any more slices after cipher. - * Current Id: Initialised with the cipher slice type */ + * the next id is the most significant nibble. + * Next Id: Set to the next slice to pass the ciphered data through. + * Set to ICP_QAT_FW_SLICE_DRAM_WR if the data is not to go through + * any more slices after cipher. + * Current Id: Initialised with the cipher slice type */ /**< LW 28 */ uint8_t cipher_padding_sz; @@ -1021,17 +1107,15 @@ uint8_t hash_cfg_offset; /**< Quad word offset from the content descriptor parameters address to - * the - * parameters for the auth processing */ + * the parameters for the auth processing */ uint8_t next_curr_id; /**< This field combines the next and current id (each four bits) - - * the next id is the most significant nibble. - * Next Id: Set to the next slice to pass the authentication data - * through. - * Set to ICP_QAT_FW_SLICE_DRAM_WR if the data is not to go through - * any more slices after authentication. - * Current Id: Initialised with the authentication slice type */ + * the next id is the most significant nibble. + * Next Id: Set to the next slice to pass the authentication data + * through. Set to ICP_QAT_FW_SLICE_DRAM_WR if the data is not to go + * through any more slices after authentication. + * Current Id: Initialised with the authentication slice type */ /**< LW 29 */ uint8_t resrvd3; @@ -1057,8 +1141,7 @@ uint8_t inner_state2_offset; /**< Quad word offset from the content descriptor parameters pointer to - * the - * inner state2 value */ + * the inner state2 value */ uint8_t inner_state2_sz; /**< Size in bytes of inner hash state2 data. Must be a qword multiple @@ -1067,8 +1150,7 @@ /**< LW 31 */ uint8_t outer_config_offset; /**< Quad word offset from the content descriptor parameters pointer to - * the - * outer configuration information */ + * the outer configuration information */ uint8_t outer_state1_sz; /**< Size in bytes of the outer state1 value */ @@ -1078,10 +1160,8 @@ uint8_t outer_prefix_offset; /**< Quad word offset from the start of the inner prefix data to the - * outer - * prefix information. Should equal the rounded inner prefix size, - * converted - * to qwords */ + * outer prefix information. Should equal the rounded inner prefix size, + * converted to qwords */ } icp_qat_fw_auth_cd_ctrl_hdr_t; @@ -1100,8 +1180,7 @@ /**< LW 27 */ uint8_t cipher_state_sz; /**< State size in quad words of the cipher algorithm used in this - * session. - * Set to zero if the algorithm doesnt provide any state */ + * session. Set to zero if the algorithm doesnt provide any state */ uint8_t cipher_key_sz; /**< Key size in quad words of the cipher algorithm used in this session @@ -1109,17 +1188,16 @@ uint8_t cipher_cfg_offset; /**< Quad word offset from the content descriptor parameters address - * i.e. - * (content_address + (cd_hdr_sz << 3)) to the parameters for the cipher - * processing */ + * i.e. (content_address + (cd_hdr_sz << 3)) to the parameters for the + * cipher processing */ uint8_t next_curr_id_cipher; /**< This field combines the next and current id (each four bits) - - * the next id is the most significant nibble. - * Next Id: Set to the next slice to pass the ciphered data through. - * Set to ICP_QAT_FW_SLICE_DRAM_WR if the data is not to go through - * any more slices after cipher. - * Current Id: Initialised with the cipher slice type */ + * the next id is the most significant nibble. + * Next Id: Set to the next slice to pass the ciphered data through. + * Set to ICP_QAT_FW_SLICE_DRAM_WR if the data is not to go through + * any more slices after cipher. + * Current Id: Initialised with the cipher slice type */ /**< LW 28 */ uint8_t cipher_padding_sz; @@ -1134,16 +1212,14 @@ uint8_t hash_cfg_offset; /**< Quad word offset from the content descriptor parameters address to - * the - * parameters for the auth processing */ + * the parameters for the auth processing */ uint8_t next_curr_id_auth; /**< This field combines the next and current id (each four bits) - * the next id is the most significant nibble. * Next Id: Set to the next slice to pass the authentication data - * through. - * Set to ICP_QAT_FW_SLICE_DRAM_WR if the data is not to go through - * any more slices after authentication. + * through. Set to ICP_QAT_FW_SLICE_DRAM_WR if the data is not to go + * through any more slices after authentication. * Current Id: Initialised with the authentication slice type */ /**< LW 29 */ @@ -1170,8 +1246,7 @@ uint8_t inner_state2_offset; /**< Quad word offset from the content descriptor parameters pointer to - * the - * inner state2 value */ + * the inner state2 value */ uint8_t inner_state2_sz; /**< Size in bytes of inner hash state2 data. Must be a qword multiple @@ -1180,8 +1255,7 @@ /**< LW 31 */ uint8_t outer_config_offset; /**< Quad word offset from the content descriptor parameters pointer to - * the - * outer configuration information */ + * the outer configuration information */ uint8_t outer_state1_sz; /**< Size in bytes of the outer state1 value */ @@ -1191,10 +1265,8 @@ uint8_t outer_prefix_offset; /**< Quad word offset from the start of the inner prefix data to the - * outer - * prefix information. Should equal the rounded inner prefix size, - * converted - * to qwords */ + * outer prefix information. Should equal the rounded inner prefix size, + * converted to qwords */ } icp_qat_fw_cipher_auth_cd_ctrl_hdr_t; @@ -1204,9 +1276,9 @@ * + ===== + --- + --- + --- + --- + --- + --- + --- + ---- + * | Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | * + ===== + --- + --- + --- + --- + --- + --- + --- + ---- + - * | Flags | Rsv | Rsv | Rsv | ZUC |SNOW | Rsv | Rsv |NESTED| - * | | | | |EIA3 | 3G | | | | - * | | | | | |UIA2 | | | | + * | Flags | Rsv | Rsv | Rsv | ZUC |SNOW |SKIP |SKIP |NESTED| + * | | | | |EIA3 | 3G |LOAD |LOAD | | + * | | | | | |UIA2 |OUTER|INNER| | * + ===== + --- + --- + --- + --- + --- + --- + --- + ---- + */ @@ -1233,6 +1305,42 @@ * requires nested hashing */ +/* Bit 1 */ + +#define QAT_FW_LA_SKIP_INNER_STATE1_LOAD_BITPOS 1 +/**< @ingroup icp_qat_fw_comn + * Bit position of the Skipping Inner State1 Load bit */ + +#define QAT_FW_LA_SKIP_INNER_STATE1_LOAD 1 +/**< @ingroup icp_qat_fw_comn + * Value indicating the skipping of inner hash state load */ + +#define QAT_FW_LA_NO_SKIP_INNER_STATE1_LOAD 0 +/**< @ingroup icp_qat_fw_comn + * Value indicating the no skipping of inner hash state load */ + +#define QAT_FW_LA_SKIP_INNER_STATE1_LOAD_MASK 0x1 +/**< @ingroup icp_qat_fw_comn + * Bit mask of Skipping Inner State1 Load bit */ + +/* Bit 2 */ + +#define QAT_FW_LA_SKIP_OUTER_STATE1_LOAD_BITPOS 2 +/**< @ingroup icp_qat_fw_comn + * Bit position of the Skipping Outer State1 Load bit */ + +#define QAT_FW_LA_SKIP_OUTER_STATE1_LOAD 1 +/**< @ingroup icp_qat_fw_comn + * Value indicating the skipping of outer hash state load */ + +#define QAT_FW_LA_NO_SKIP_OUTER_STATE1_LOAD 0 +/**< @ingroup icp_qat_fw_comn + * Value indicating the no skipping of outer hash state load */ + +#define QAT_FW_LA_SKIP_OUTER_STATE1_LOAD_MASK 0x1 +/**< @ingroup icp_qat_fw_comn + * Bit mask of Skipping Outer State1 Load bit */ + /* Bit 3 */ #define QAT_FW_LA_SNOW3G_UIA2_BITPOS 3 @@ -1261,6 +1369,24 @@ /**< @ingroup icp_qat_fw_la * One bit mask used to determine the use of hash algorithm ZUC-EIA3 */ +/* Bit 5 */ + +#define QAT_FW_LA_MODE2_BITPOS 5 +/**< @ingroup icp_qat_fw_comn + * Bit position of the Mode 2 bit */ + +#define QAT_FW_LA_MODE2 1 +/**< @ingroup icp_qat_fw_comn + * Value indicating the Mode 2*/ + +#define QAT_FW_LA_NO_MODE2 0 +/**< @ingroup icp_qat_fw_comn + * Value indicating the no Mode 2*/ + +#define QAT_FW_LA_MODE2_MASK 0x1 +/**< @ingroup icp_qat_fw_comn + * Bit mask of Mode 2 */ + /* Macros for extracting hash flags */ /** @@ -1279,6 +1405,67 @@ QAT_FW_LA_AUTH_HDR_NESTED_BITPOS, \ QAT_FW_LA_AUTH_HDR_NESTED_MASK) +/** + ****************************************************************************** + * @ingroup icp_qat_fw_la + * + * @description + * Macro for extraction of the "Skipping Inner State1 Load state" hash flag + * + * @param flags Hash Flags + * + *****************************************************************************/ +#define ICP_QAT_FW_HASH_FLAG_SKIP_INNER_STATE1_LOAD_GET(flags) \ + QAT_FIELD_GET(flags, \ + QAT_FW_LA_SKIP_INNER_STATE1_LOAD_BITPOS, \ + QAT_FW_LA_INNER_STATE1_LOAD_MASK) + +/** + ****************************************************************************** + * Macro for setting the "Skipping Inner State1 Load" hash flag + * + * @param flags Hash Flags + * @param val Value of the flag + * + *****************************************************************************/ +#define ICP_QAT_FW_HASH_FLAG_SKIP_INNER_STATE1_LOAD_SET(flags, val) \ + QAT_FIELD_SET(flags, \ + val, \ + QAT_FW_LA_SKIP_INNER_STATE1_LOAD_BITPOS, \ + QAT_FW_LA_SKIP_INNER_STATE1_LOAD_MASK) + +/** + ****************************************************************************** + * @ingroup icp_qat_fw_la + * + * @description + * Macro for extraction of the "Skipping Outer State1 Load state" hash flag + * + * @param flags Hash Flags + * + *****************************************************************************/ +#define ICP_QAT_FW_HASH_FLAG_SKIP_OUTER_STATE1_LOAD_GET(flags) \ + QAT_FIELD_GET(flags, \ + QAT_FW_LA_SKIP_OUTER_STATE1_LOAD_BITPOS, \ + QAT_FW_LA_SKIP_OUTER_STATE1_LOAD_MASK) + +/** + ****************************************************************************** + * @ingroup icp_qat_fw_la + * + * @description + * Macro for setting the "Skipping Outer State1 Load" hash flag + * + * @param flags Hash Flags + * @param val Value of the flag + * + *****************************************************************************/ +#define ICP_QAT_FW_HASH_FLAG_SKIP_OUTER_STATE1_LOAD_SET(flags, val) \ + QAT_FIELD_SET(flags, \ + val, \ + QAT_FW_LA_SKIP_OUTER_STATE1_LOAD_BITPOS, \ + QAT_FW_LA_SKIP_OUTER_STATE1_LOAD_MASK) + /** ****************************************************************************** * @ingroup icp_qat_fw_la @@ -1328,6 +1515,40 @@ QAT_FW_LA_AUTH_HDR_NESTED_BITPOS, \ QAT_FW_LA_AUTH_HDR_NESTED_MASK) +/** + ****************************************************************************** + * @ingroup icp_qat_fw_la + * + * @description + * Macro for setting the "Skipping Inner State1 Load" hash flag + * + * @param flags Hash Flags + * @param val Value of the flag + * + *****************************************************************************/ +#define ICP_QAT_FW_HASH_FLAG_SKIP_INNER_STATE1_LOAD_SET(flags, val) \ + QAT_FIELD_SET(flags, \ + val, \ + QAT_FW_LA_SKIP_INNER_STATE1_LOAD_BITPOS, \ + QAT_FW_LA_SKIP_INNER_STATE1_LOAD_MASK) + +/** + ****************************************************************************** + * @ingroup icp_qat_fw_la + * + * @description + * Macro for setting the "Skipping Outer State1 Load" hash flag + * + * @param flags Hash Flags + * @param val Value of the flag + * + *****************************************************************************/ +#define ICP_QAT_FW_HASH_FLAG_SKIP_OUTER_STATE1_LOAD_SET(flags, val) \ + QAT_FIELD_SET(flags, \ + val, \ + QAT_FW_LA_SKIP_OUTER_STATE1_LOAD_BITPOS, \ + QAT_FW_LA_SKIP_OUTER_STATE1_LOAD_MASK) + /** ****************************************************************************** * @ingroup icp_qat_fw_la @@ -1362,6 +1583,20 @@ QAT_FW_LA_ZUC_EIA3_BITPOS, \ QAT_FW_LA_ZUC_EIA3_MASK) +/** + ****************************************************************************** + * @ingroup icp_qat_fw_la + * + * @description + * Macro for setting the "Mode 2" hash flag + * + * @param flags Hash Flags + * @param val Value of the flag + * + *****************************************************************************/ +#define ICP_QAT_FW_HASH_FLAG_MODE2_SET(flags, val) \ + QAT_FIELD_SET(flags, val, QAT_FW_LA_MODE2_BITPOS, QAT_FW_LA_MODE2_MASK) + #define ICP_QAT_FW_CCM_GCM_AAD_SZ_MAX 240 #define ICP_QAT_FW_SPC_AAD_SZ_MAX 0x3FFF @@ -1494,8 +1729,7 @@ uint8_t aad_sz; /**< Size in bytes of padded AAD data to prefix to the packet - * for CCM - * or GCM processing */ + * for CCM or GCM processing */ } u2; uint8_t resrvd1; @@ -1535,8 +1769,7 @@ uint8_t aad_sz; /**< Size in bytes of padded AAD data to prefix to the packet - * for CCM - * or GCM processing */ + * for CCM or GCM processing */ } u2; uint8_t resrvd1; @@ -1565,8 +1798,7 @@ /**< SSL3 */ uint16_t secret_lgth_ssl; /**< Length of Secret information for SSL. In the case of TLS - * the - * secret is supplied in the content descriptor */ + * the secret is supplied in the content descriptor */ /**< MGF */ uint16_t mask_length; @@ -1692,8 +1924,7 @@ uint8_t aad_sz; /**< Size in bytes of padded AAD data to prefix to the packet - * for CCM - * or GCM processing */ + * for CCM or GCM processing */ } u2; uint8_t resrvd1; @@ -1731,8 +1962,7 @@ uint8_t aad_sz; /**< Size in bytes of padded AAD data to prefix to the packet - * for CCM - * or GCM processing */ + * for CCM or GCM processing */ } u2; uint8_t resrvd1; @@ -1779,16 +2009,14 @@ /**< LWs 6-13 */ uint64_t opaque_data; /**< Opaque data passed unmodified from the request to response messages - * by - * firmware (fw) */ + * by firmware (fw) */ uint64_t resrvd1; /**< Reserved, unused for TRNG */ uint64_t dest_data_addr; /**< Generic definition of the destination data supplied to the QAT AE. - * The - * common flags are used to further describe the attributes of this + * The common flags are used to further describe the attributes of this * field */ uint32_t resrvd2; @@ -1796,7 +2024,7 @@ uint32_t entropy_length; /**< Size of the data in bytes to process. Used by the get_random - * command. Set to 0 for commands that dont need a length parameter */ + * command. Set to 0 for commands that dont need a length parameter */ } icp_qat_fw_la_trng_req_mid_t; @@ -2235,10 +2463,8 @@ union { uint8_t label_flags; /**< For first-level labels: each bit in [0..3] will trigger a - * child - * Expand-Label operation on the corresponding sublabel. Bits - * [4..7] - * are reserved. + * child Expand-Label operation on the corresponding sublabel. + * Bits [4..7] are reserved. */ uint8_t sublabel_flags; diff --git a/sys/dev/qat/qat_api/firmware/include/icp_qat_hw.h b/sys/dev/qat/qat_api/firmware/include/icp_qat_hw.h --- a/sys/dev/qat/qat_api/firmware/include/icp_qat_hw.h +++ b/sys/dev/qat/qat_api/firmware/include/icp_qat_hw.h @@ -25,22 +25,22 @@ /* ========================================================================= */ typedef enum { - ICP_QAT_HW_AE_0 = 0, /*!< ID of AE0 */ - ICP_QAT_HW_AE_1 = 1, /*!< ID of AE1 */ - ICP_QAT_HW_AE_2 = 2, /*!< ID of AE2 */ - ICP_QAT_HW_AE_3 = 3, /*!< ID of AE3 */ - ICP_QAT_HW_AE_4 = 4, /*!< ID of AE4 */ - ICP_QAT_HW_AE_5 = 5, /*!< ID of AE5 */ - ICP_QAT_HW_AE_6 = 6, /*!< ID of AE6 */ - ICP_QAT_HW_AE_7 = 7, /*!< ID of AE7 */ - ICP_QAT_HW_AE_8 = 8, /*!< ID of AE8 */ - ICP_QAT_HW_AE_9 = 9, /*!< ID of AE9 */ - ICP_QAT_HW_AE_10 = 10, /*!< ID of AE10 */ - ICP_QAT_HW_AE_11 = 11, /*!< ID of AE11 */ - ICP_QAT_HW_AE_12 = 12, /*!< ID of AE12 */ - ICP_QAT_HW_AE_13 = 13, /*!< ID of AE13 */ - ICP_QAT_HW_AE_14 = 14, /*!< ID of AE14 */ - ICP_QAT_HW_AE_15 = 15, /*!< ID of AE15 */ + ICP_QAT_HW_AE_0 = 0, /*!< ID of AE0 */ + ICP_QAT_HW_AE_1 = 1, /*!< ID of AE1 */ + ICP_QAT_HW_AE_2 = 2, /*!< ID of AE2 */ + ICP_QAT_HW_AE_3 = 3, /*!< ID of AE3 */ + ICP_QAT_HW_AE_4 = 4, /*!< ID of AE4 */ + ICP_QAT_HW_AE_5 = 5, /*!< ID of AE5 */ + ICP_QAT_HW_AE_6 = 6, /*!< ID of AE6 */ + ICP_QAT_HW_AE_7 = 7, /*!< ID of AE7 */ + ICP_QAT_HW_AE_8 = 8, /*!< ID of AE8 */ + ICP_QAT_HW_AE_9 = 9, /*!< ID of AE9 */ + ICP_QAT_HW_AE_10 = 10, /*!< ID of AE10 */ + ICP_QAT_HW_AE_11 = 11, /*!< ID of AE11 */ + ICP_QAT_HW_AE_12 = 12, /*!< ID of AE12 */ + ICP_QAT_HW_AE_13 = 13, /*!< ID of AE13 */ + ICP_QAT_HW_AE_14 = 14, /*!< ID of AE14 */ + ICP_QAT_HW_AE_15 = 15, /*!< ID of AE15 */ ICP_QAT_HW_AE_DELIMITER = 16 /**< Delimiter type */ } icp_qat_hw_ae_id_t; @@ -49,12 +49,12 @@ /* ========================================================================= */ typedef enum { - ICP_QAT_HW_QAT_0 = 0, /*!< ID of QAT0 */ - ICP_QAT_HW_QAT_1 = 1, /*!< ID of QAT1 */ - ICP_QAT_HW_QAT_2 = 2, /*!< ID of QAT2 */ - ICP_QAT_HW_QAT_3 = 3, /*!< ID of QAT3 */ - ICP_QAT_HW_QAT_4 = 4, /*!< ID of QAT4 */ - ICP_QAT_HW_QAT_5 = 5, /*!< ID of QAT5 */ + ICP_QAT_HW_QAT_0 = 0, /*!< ID of QAT0 */ + ICP_QAT_HW_QAT_1 = 1, /*!< ID of QAT1 */ + ICP_QAT_HW_QAT_2 = 2, /*!< ID of QAT2 */ + ICP_QAT_HW_QAT_3 = 3, /*!< ID of QAT3 */ + ICP_QAT_HW_QAT_4 = 4, /*!< ID of QAT4 */ + ICP_QAT_HW_QAT_5 = 5, /*!< ID of QAT5 */ ICP_QAT_HW_QAT_DELIMITER = 6 /**< Delimiter type */ } icp_qat_hw_qat_id_t; @@ -79,24 +79,24 @@ ICP_QAT_HW_AUTH_ALGO_SHA256 = 4, /*!< SHA-256 hashing */ ICP_QAT_HW_AUTH_ALGO_SHA384 = 5, /*!< SHA-384 hashing */ ICP_QAT_HW_AUTH_ALGO_SHA512 = 6, /*!< SHA-512 hashing */ - ICP_QAT_HW_AUTH_ALGO_AES_XCBC_MAC = 7, /*!< AES-XCBC-MAC hashing */ - ICP_QAT_HW_AUTH_ALGO_AES_CBC_MAC = 8, /*!< AES-CBC-MAC hashing */ + ICP_QAT_HW_AUTH_ALGO_AES_XCBC_MAC = 7, /*!< AES-XCBC-MAC hashing */ + ICP_QAT_HW_AUTH_ALGO_AES_CBC_MAC = 8, /*!< AES-CBC-MAC hashing */ ICP_QAT_HW_AUTH_ALGO_AES_F9 = 9, /*!< AES F9 hashing */ - ICP_QAT_HW_AUTH_ALGO_GALOIS_128 = 10, /*!< Galois 128 bit hashing */ - ICP_QAT_HW_AUTH_ALGO_GALOIS_64 = 11, /*!< Galois 64 hashing */ - ICP_QAT_HW_AUTH_ALGO_KASUMI_F9 = 12, /*!< Kasumi F9 hashing */ + ICP_QAT_HW_AUTH_ALGO_GALOIS_128 = 10, /*!< Galois 128 bit hashing */ + ICP_QAT_HW_AUTH_ALGO_GALOIS_64 = 11, /*!< Galois 64 hashing */ + ICP_QAT_HW_AUTH_ALGO_KASUMI_F9 = 12, /*!< Kasumi F9 hashing */ ICP_QAT_HW_AUTH_ALGO_SNOW_3G_UIA2 = 13, /*!< UIA2/SNOW_3G F9 hashing */ ICP_QAT_HW_AUTH_ALGO_ZUC_3G_128_EIA3 = - 14, /*!< 128_EIA3/ZUC_3G hashing */ - ICP_QAT_HW_AUTH_ALGO_SM3 = 15, /*!< SM3 hashing */ - ICP_QAT_HW_AUTH_ALGO_SHA3_224 = 16, /*!< SHA3-224 hashing */ - ICP_QAT_HW_AUTH_ALGO_SHA3_256 = 17, /*!< SHA3-256 hashing */ - ICP_QAT_HW_AUTH_ALGO_SHA3_384 = 18, /*!< SHA3-384 hashing */ - ICP_QAT_HW_AUTH_ALGO_SHA3_512 = 19, /*!< SHA3-512 hashing */ - ICP_QAT_HW_AUTH_ALGO_SHAKE_128 = 20, /*!< SHAKE-128 hashing */ - ICP_QAT_HW_AUTH_ALGO_SHAKE_256 = 21, /*!< SHAKE-256 hashing */ - ICP_QAT_HW_AUTH_ALGO_POLY = 22, /*!< POLY hashing */ - ICP_QAT_HW_AUTH_ALGO_DELIMITER = 23 /**< Delimiter type */ + 14, /*!< 128_EIA3/ZUC_3G hashing */ + ICP_QAT_HW_AUTH_ALGO_SM3 = 15, /*!< SM3 hashing */ + ICP_QAT_HW_AUTH_ALGO_SHA3_224 = 16, /*!< SHA3-224 hashing */ + ICP_QAT_HW_AUTH_ALGO_SHA3_256 = 17, /*!< SHA3-256 hashing */ + ICP_QAT_HW_AUTH_ALGO_SHA3_384 = 18, /*!< SHA3-384 hashing */ + ICP_QAT_HW_AUTH_ALGO_SHA3_512 = 19, /*!< SHA3-512 hashing */ + ICP_QAT_HW_AUTH_RESERVED_4 = 20, /*!< Reserved */ + ICP_QAT_HW_AUTH_RESERVED_5 = 21, /*!< Reserved */ + ICP_QAT_HW_AUTH_ALGO_POLY = 22, /*!< POLY hashing */ + ICP_QAT_HW_AUTH_ALGO_DELIMITER = 23 /**< Delimiter type */ } icp_qat_hw_auth_algo_t; /** @@ -118,9 +118,9 @@ *****************************************************************************/ typedef enum { - ICP_QAT_HW_AUTH_MODE0 = 0, /*!< QAT Auth Mode0 configuration */ - ICP_QAT_HW_AUTH_MODE1 = 1, /*!< QAT Auth Mode1 configuration */ - ICP_QAT_HW_AUTH_MODE2 = 2, /*!< QAT AuthMode2 configuration */ + ICP_QAT_HW_AUTH_MODE0 = 0, /*!< QAT Auth Mode0 configuration */ + ICP_QAT_HW_AUTH_MODE1 = 1, /*!< QAT Auth Mode1 configuration */ + ICP_QAT_HW_AUTH_MODE2 = 2, /*!< QAT AuthMode2 configuration */ ICP_QAT_HW_AUTH_MODE_DELIMITER = 3 /**< Delimiter type */ } icp_qat_hw_auth_mode_t; @@ -269,7 +269,7 @@ /**< Flag usage - see additional notes @description for * ICP_QAT_HW_AUTH_CONFIG_BUILD and * ICP_QAT_HW_AUTH_CONFIG_BUILD_UPPER macros. -*/ + */ #define QAT_AUTH_SHA3_HW_PADDING_ENABLE 0 /**< @ingroup icp_qat_hw_defs @@ -461,7 +461,7 @@ #define QAT_HW_ROUND_UP(val, n) (((val) + ((n)-1)) & (~(n - 1))) /* State1 */ -#define ICP_QAT_HW_NULL_STATE1_SZ 64 +#define ICP_QAT_HW_NULL_STATE1_SZ 32 /**< @ingroup icp_qat_hw_defs * State1 block size for NULL hashing */ #define ICP_QAT_HW_MD5_STATE1_SZ 16 @@ -474,7 +474,7 @@ #define ICP_QAT_HW_SHA224_STATE1_SZ 32 /**< @ingroup icp_qat_hw_defs * State1 block size for SHA24 */ -#define ICP_QAT_HW_SHA3_224_STATE1_SZ 32 +#define ICP_QAT_HW_SHA3_224_STATE1_SZ 28 /**< @ingroup icp_qat_hw_defs * State1 block size for SHA3_224 */ #define ICP_QAT_HW_SHA256_STATE1_SZ 32 @@ -486,7 +486,7 @@ #define ICP_QAT_HW_SHA384_STATE1_SZ 64 /**< @ingroup icp_qat_hw_defs * State1 block size for SHA384 */ -#define ICP_QAT_HW_SHA3_384_STATE1_SZ 64 +#define ICP_QAT_HW_SHA3_384_STATE1_SZ 48 /**< @ingroup icp_qat_hw_defs * State1 block size for SHA3_384 */ #define ICP_QAT_HW_SHA512_STATE1_SZ 64 @@ -516,15 +516,15 @@ #define ICP_QAT_HW_ZUC_3G_EIA3_STATE1_SZ 8 /**< @ingroup icp_cpm_hw_defs * State1 block size for EIA3 */ +#define ICP_QAT_HW_SM3_STATE1_SZ 32 +/**< @ingroup icp_qat_hw_defs + * State1 block size for SM3 */ #define ICP_QAT_HW_SHA3_STATEFUL_STATE1_SZ 200 /** <@ingroup icp_cpm_hw_defs * State1 block size for stateful SHA3 processing*/ -#define ICP_QAT_HW_SM3_STATE1_SZ 32 -/**< @ingroup icp_cpm_hw_defs - * State1 block size for SM3 */ /* State2 */ -#define ICP_QAT_HW_NULL_STATE2_SZ 64 +#define ICP_QAT_HW_NULL_STATE2_SZ 32 /**< @ingroup icp_qat_hw_defs * State2 block size for NULL hashing */ #define ICP_QAT_HW_MD5_STATE2_SZ 16 @@ -537,25 +537,25 @@ #define ICP_QAT_HW_SHA224_STATE2_SZ 32 /**< @ingroup icp_qat_hw_defs * State2 block size for SHA224 */ -#define ICP_QAT_HW_SHA3_224_STATE2_SZ 32 +#define ICP_QAT_HW_SHA3_224_STATE2_SZ 0 /**< @ingroup icp_qat_hw_defs * State2 block size for SHA3_224 */ #define ICP_QAT_HW_SHA256_STATE2_SZ 32 /**< @ingroup icp_qat_hw_defs * State2 block size for SHA256 */ -#define ICP_QAT_HW_SHA3_256_STATE2_SZ 32 +#define ICP_QAT_HW_SHA3_256_STATE2_SZ 0 /**< @ingroup icp_qat_hw_defs * State2 block size for SHA3_256 */ #define ICP_QAT_HW_SHA384_STATE2_SZ 64 /**< @ingroup icp_qat_hw_defs * State2 block size for SHA384 */ -#define ICP_QAT_HW_SHA3_384_STATE2_SZ 64 +#define ICP_QAT_HW_SHA3_384_STATE2_SZ 0 /**< @ingroup icp_qat_hw_defs * State2 block size for SHA3_384 */ #define ICP_QAT_HW_SHA512_STATE2_SZ 64 /**< @ingroup icp_qat_hw_defs * State2 block size for SHA512 */ -#define ICP_QAT_HW_SHA3_512_STATE2_SZ 64 +#define ICP_QAT_HW_SHA3_512_STATE2_SZ 0 /**< @ingroup icp_qat_hw_defs * State2 block size for SHA3_512 */ #define ICP_QAT_HW_AES_XCBC_MAC_KEY_SZ 16 @@ -598,6 +598,9 @@ #define ICP_QAT_HW_SM3_STATE2_SZ 32 /**< @ingroup icp_qat_hw_defs * State2 block size for SM3 */ +#define ICP_QAT_HW_SHA3_STATEFUL_STATE2_SZ 208 +/** <@ingroup icp_cpm_hw_defs + * State2 block size for stateful SHA3 processing*/ /* ************************************************************************* */ /* ************************************************************************* */ @@ -647,10 +650,33 @@ icp_qat_hw_auth_setup_t outer_setup; /**< Outer configuration word for the slice */ - /* State2 size is zero - this may change for future implementations */ - uint8_t state2[ICP_QAT_HW_SHA3_512_STATE2_SZ]; } icp_qat_hw_auth_sha3_512_t; +/** + ***************************************************************************** + * @ingroup icp_qat_hw_defs + * Definition of stateful SHA3 auth algorithm processing struct + * @description + * This structs described the parameters to pass to the slice for + * configuring it for stateful SHA3 processing. This is the largest + * possible setup block for authentication + * + *****************************************************************************/ +typedef struct icp_qat_hw_auth_sha3_stateful_s { + icp_qat_hw_auth_setup_t inner_setup; + /**< Inner loop configuration word for the slice */ + + uint8_t inner_state1[ICP_QAT_HW_SHA3_STATEFUL_STATE1_SZ]; + /**< Inner hash block */ + + icp_qat_hw_auth_setup_t outer_setup; + /**< Outer configuration word for the slice */ + + uint8_t outer_state1[ICP_QAT_HW_SHA3_STATEFUL_STATE1_SZ]; + /**< Outer hash block */ + +} icp_qat_hw_auth_sha3_stateful_t; + /** ***************************************************************************** * @ingroup icp_qat_hw_defs @@ -662,6 +688,8 @@ typedef union icp_qat_hw_auth_algo_blk_u { icp_qat_hw_auth_sha512_t sha512; /**< SHA512 Hashing */ + icp_qat_hw_auth_sha3_stateful_t sha3_stateful; + /**< Stateful SHA3 Hashing */ } icp_qat_hw_auth_algo_blk_t; @@ -691,11 +719,11 @@ ICP_QAT_HW_CIPHER_ALGO_NULL = 0, /*!< Null ciphering */ ICP_QAT_HW_CIPHER_ALGO_DES = 1, /*!< DES ciphering */ ICP_QAT_HW_CIPHER_ALGO_3DES = 2, /*!< 3DES ciphering */ - ICP_QAT_HW_CIPHER_ALGO_AES128 = 3, /*!< AES-128 ciphering */ - ICP_QAT_HW_CIPHER_ALGO_AES192 = 4, /*!< AES-192 ciphering */ - ICP_QAT_HW_CIPHER_ALGO_AES256 = 5, /*!< AES-256 ciphering */ + ICP_QAT_HW_CIPHER_ALGO_AES128 = 3, /*!< AES-128 ciphering */ + ICP_QAT_HW_CIPHER_ALGO_AES192 = 4, /*!< AES-192 ciphering */ + ICP_QAT_HW_CIPHER_ALGO_AES256 = 5, /*!< AES-256 ciphering */ ICP_QAT_HW_CIPHER_ALGO_ARC4 = 6, /*!< ARC4 ciphering */ - ICP_QAT_HW_CIPHER_ALGO_KASUMI = 7, /*!< Kasumi */ + ICP_QAT_HW_CIPHER_ALGO_KASUMI = 7, /*!< Kasumi */ ICP_QAT_HW_CIPHER_ALGO_SNOW_3G_UEA2 = 8, /*!< Snow_3G */ ICP_QAT_HW_CIPHER_ALGO_ZUC_3G_128_EEA3 = 9, /*!< ZUC_3G */ ICP_QAT_HW_CIPHER_ALGO_SM4 = 10, /*!< SM4 ciphering */ @@ -723,7 +751,7 @@ ICP_QAT_HW_CIPHER_CTR_MODE = 2, /*!< CTR mode */ ICP_QAT_HW_CIPHER_F8_MODE = 3, /*!< F8 mode */ ICP_QAT_HW_CIPHER_AEAD_MODE = 4, /*!< AES-GCM SPC AEAD mode */ - ICP_QAT_HW_CIPHER_RESERVED_MODE = 5, /*!< Reserved */ + ICP_QAT_HW_CIPHER_CCM_MODE = 5, /*!< AES-CCM SPC AEAD mode */ ICP_QAT_HW_CIPHER_XTS_MODE = 6, /*!< XTS mode */ ICP_QAT_HW_CIPHER_MODE_DELIMITER = 7 /**< Delimiter type */ } icp_qat_hw_cipher_mode_t; @@ -746,6 +774,23 @@ /**< Reserved */ } icp_qat_hw_cipher_config_t; +/** + ***************************************************************************** + * @ingroup icp_qat_hw_defs + * Cipher Configuration Struct + * + * @description + * Configuration data used for setting up the QAT UCS Cipher Slice + * + *****************************************************************************/ +typedef struct icp_qat_hw_ucs_cipher_config_s { + uint32_t val; + /**< Cipher slice configuration */ + + uint32_t reserved[3]; + /**< Reserved */ +} icp_qat_hw_ucs_cipher_config_t; + /** ***************************************************************************** * @ingroup icp_qat_hw_defs @@ -851,6 +896,10 @@ /**< @ingroup icp_qat_hw_defs * Define for the cipher XTS mode key size */ +#define QAT_CIPHER_MODE_UCS_XTS_KEY_SZ_MULT 1 +/**< @ingroup icp_qat_hw_defs + * Define for the UCS cipher XTS mode key size */ + /** ****************************************************************************** * @ingroup icp_qat_hw_defs @@ -931,6 +980,16 @@ #define ICP_QAT_HW_AES_256_KEY_SZ 32 /**< @ingroup icp_qat_hw_defs * Define the key size for AES256 */ +/* AES UCS */ +#define ICP_QAT_HW_UCS_AES_128_KEY_SZ ICP_QAT_HW_AES_128_KEY_SZ +/**< @ingroup icp_qat_hw_defs + * Define the key size for AES128 for UCS slice*/ +#define ICP_QAT_HW_UCS_AES_192_KEY_SZ 32 +/**< @ingroup icp_qat_hw_defs + * Define the key size for AES192 for UCS slice*/ +#define ICP_QAT_HW_UCS_AES_256_KEY_SZ ICP_QAT_HW_AES_256_KEY_SZ +/**< @ingroup icp_qat_hw_defs + * Define the key size for AES256 for UCS slice*/ #define ICP_QAT_HW_AES_128_F8_KEY_SZ \ (ICP_QAT_HW_AES_128_KEY_SZ * QAT_CIPHER_MODE_F8_KEY_SZ_MULT) /**< @ingroup icp_qat_hw_defs @@ -951,6 +1010,14 @@ (ICP_QAT_HW_AES_256_KEY_SZ * QAT_CIPHER_MODE_XTS_KEY_SZ_MULT) /**< @ingroup icp_qat_hw_defs * Define the key size for AES256 XTS */ +#define ICP_QAT_HW_UCS_AES_128_XTS_KEY_SZ \ + (ICP_QAT_HW_UCS_AES_128_KEY_SZ * QAT_CIPHER_MODE_UCS_XTS_KEY_SZ_MULT) +/**< @ingroup icp_qat_hw_defs + * Define the key size for AES128 XTS for the UCS Slice*/ +#define ICP_QAT_HW_UCS_AES_256_XTS_KEY_SZ \ + (ICP_QAT_HW_UCS_AES_256_KEY_SZ * QAT_CIPHER_MODE_UCS_XTS_KEY_SZ_MULT) +/**< @ingroup icp_qat_hw_defs + * Define the key size for AES256 XTS for the UCS Slice*/ #define ICP_QAT_HW_KASUMI_KEY_SZ 16 /**< @ingroup icp_qat_hw_defs * Define the key size for Kasumi */ @@ -1090,10 +1157,10 @@ *****************************************************************************/ typedef enum { - ICP_QAT_HW_TRNG_NEG_0 = 0, /*!< TRNG Neg Zero Test */ - ICP_QAT_HW_TRNG_NEG_1 = 1, /*!< TRNG Neg One Test */ + ICP_QAT_HW_TRNG_NEG_0 = 0, /*!< TRNG Neg Zero Test */ + ICP_QAT_HW_TRNG_NEG_1 = 1, /*!< TRNG Neg One Test */ ICP_QAT_HW_TRNG_POS = 2, /*!< TRNG POS Test */ - ICP_QAT_HW_TRNG_POS_VNC = 3, /*!< TRNG POS VNC Test */ + ICP_QAT_HW_TRNG_POS_VNC = 3, /*!< TRNG POS VNC Test */ ICP_QAT_HW_TRNG_KAT_DELIMITER = 4 /**< Delimiter type */ } icp_qat_hw_trng_kat_mode_t; @@ -1388,7 +1455,7 @@ typedef enum { ICP_QAT_HW_COMPRESSION_ALGO_DEFLATE = 0, /*!< Deflate compression */ - ICP_QAT_HW_COMPRESSION_DEPRECATED = 1, /*!< Deprecated */ + ICP_QAT_HW_COMPRESSION_DEPRECATED = 1, /*!< Deprecated */ ICP_QAT_HW_COMPRESSION_ALGO_DELIMITER = 2 /**< Delimiter type */ } icp_qat_hw_compression_algo_t; @@ -1470,11 +1537,11 @@ *****************************************************************************/ typedef struct icp_qat_hw_compression_config_s { - uint32_t val; - /**< Compression slice configuration */ + uint32_t lower_val; + /**< Compression slice configuration lower LW */ - uint32_t reserved; - /**< Reserved */ + uint32_t upper_val; + /**< Compression slice configuration upper LW */ } icp_qat_hw_compression_config_t; /* Private defines */ diff --git a/sys/dev/qat/qat_api/firmware/include/icp_qat_hw_20_comp.h b/sys/dev/qat/qat_api/firmware/include/icp_qat_hw_20_comp.h new file mode 100644 --- /dev/null +++ b/sys/dev/qat/qat_api/firmware/include/icp_qat_hw_20_comp.h @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2007-2022 Intel Corporation */ +/* $FreeBSD$ */ +/** + ***************************************************************************** + * @file icp_qat_hw_2x_comp.h + * @defgroup ICP QAT HW accessors for using the for 2.x Compression Slice + * definitions + * @ingroup icp_qat_hw_2x_comp + * @description + * This file documents definitions for the QAT HW COMP SLICE + * + *****************************************************************************/ + +#ifndef _ICP_QAT_HW_20_COMP_H_ +#define _ICP_QAT_HW_20_COMP_H_ + +#include "icp_qat_hw_20_comp_defs.h" // For HW definitions +#include "icp_qat_fw.h" //For Set Field Macros. + +#ifdef WIN32 +#include // built in support for _byteswap_ulong +#define BYTE_SWAP_32 _byteswap_ulong +#else +#define BYTE_SWAP_32 __builtin_bswap32 +#endif + +/** +***************************************************************************** +* @ingroup icp_qat_fw_comn +* +* @description +* Definition of the hw config csr. This representation has to be further +* processed by the corresponding config build function. +* +*****************************************************************************/ +typedef struct icp_qat_hw_comp_20_config_csr_lower_s { + // Fields programmable directly by the SW. + icp_qat_hw_comp_20_extended_delay_match_mode_t edmm; + icp_qat_hw_comp_20_hw_comp_format_t algo; + icp_qat_hw_comp_20_search_depth_t sd; + icp_qat_hw_comp_20_hbs_control_t hbs; + // Fields programmable directly by the FW. + // Block Drop enable. (Set by FW) + icp_qat_hw_comp_20_abd_t abd; + icp_qat_hw_comp_20_lllbd_ctrl_t lllbd; + // Advanced HW control (Set to default vals) + icp_qat_hw_comp_20_skip_hash_collision_t hash_col; + icp_qat_hw_comp_20_skip_hash_update_t hash_update; + icp_qat_hw_comp_20_byte_skip_t skip_ctrl; + +} icp_qat_hw_comp_20_config_csr_lower_t; + +/** +***************************************************************************** +* @ingroup icp_qat_fw_comn +* +* @description +* Build the longword as expected by the HW +* +*****************************************************************************/ +static inline uint32_t +ICP_QAT_FW_COMP_20_BUILD_CONFIG_LOWER(icp_qat_hw_comp_20_config_csr_lower_t csr) +{ + uint32_t val32 = 0; + // Programmable values + QAT_FIELD_SET(val32, + csr.algo, + ICP_QAT_HW_COMP_20_CONFIG_CSR_HW_COMP_FORMAT_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_HW_COMP_FORMAT_MASK); + + QAT_FIELD_SET(val32, + csr.sd, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SEARCH_DEPTH_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SEARCH_DEPTH_MASK); + + QAT_FIELD_SET( + val32, + csr.edmm, + ICP_QAT_HW_COMP_20_CONFIG_CSR_EXTENDED_DELAY_MATCH_MODE_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_EXTENDED_DELAY_MATCH_MODE_MASK); + + QAT_FIELD_SET(val32, + csr.hbs, + ICP_QAT_HW_COMP_20_CONFIG_CSR_HBS_CONTROL_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_HBS_CONTROL_MASK); + + QAT_FIELD_SET(val32, + csr.lllbd, + ICP_QAT_HW_COMP_20_CONFIG_CSR_LLLBD_CTRL_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_LLLBD_CTRL_MASK); + + QAT_FIELD_SET(val32, + csr.hash_col, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_COLLISION_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_COLLISION_MASK); + + QAT_FIELD_SET(val32, + csr.hash_update, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_UPDATE_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_UPDATE_MASK); + + QAT_FIELD_SET(val32, + csr.skip_ctrl, + ICP_QAT_HW_COMP_20_CONFIG_CSR_BYTE_SKIP_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_BYTE_SKIP_MASK); + // Default values. + + QAT_FIELD_SET(val32, + csr.abd, + ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_MASK); + + QAT_FIELD_SET(val32, + csr.lllbd, + ICP_QAT_HW_COMP_20_CONFIG_CSR_LLLBD_CTRL_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_LLLBD_CTRL_MASK); + + return BYTE_SWAP_32(val32); +} + +/** +***************************************************************************** +* @ingroup icp_qat_fw_comn +* +* @description +* Definition of the hw config csr. This representation has to be further +* processed by the corresponding config build function. +* +*****************************************************************************/ +typedef struct icp_qat_hw_comp_20_config_csr_upper_s { + icp_qat_hw_comp_20_scb_control_t scb_ctrl; + icp_qat_hw_comp_20_rmb_control_t rmb_ctrl; + icp_qat_hw_comp_20_som_control_t som_ctrl; + icp_qat_hw_comp_20_skip_hash_rd_control_t skip_hash_ctrl; + icp_qat_hw_comp_20_scb_unload_control_t scb_unload_ctrl; + icp_qat_hw_comp_20_disable_token_fusion_control_t + disable_token_fusion_ctrl; + icp_qat_hw_comp_20_scb_mode_reset_mask_t scb_mode_reset; + uint16_t lazy; + uint16_t nice; +} icp_qat_hw_comp_20_config_csr_upper_t; + +/** +***************************************************************************** +* @ingroup icp_qat_fw_comn +* +* @description +* Build the longword as expected by the HW +* +*****************************************************************************/ +static inline uint32_t +ICP_QAT_FW_COMP_20_BUILD_CONFIG_UPPER(icp_qat_hw_comp_20_config_csr_upper_t csr) +{ + uint32_t val32 = 0; + + QAT_FIELD_SET(val32, + csr.scb_ctrl, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_CONTROL_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_CONTROL_MASK); + + QAT_FIELD_SET(val32, + csr.rmb_ctrl, + ICP_QAT_HW_COMP_20_CONFIG_CSR_RMB_CONTROL_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_RMB_CONTROL_MASK); + + QAT_FIELD_SET(val32, + csr.som_ctrl, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SOM_CONTROL_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SOM_CONTROL_MASK); + + QAT_FIELD_SET(val32, + csr.skip_hash_ctrl, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_RD_CONTROL_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_RD_CONTROL_MASK); + + QAT_FIELD_SET(val32, + csr.scb_unload_ctrl, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_UNLOAD_CONTROL_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_UNLOAD_CONTROL_MASK); + + QAT_FIELD_SET( + val32, + csr.disable_token_fusion_ctrl, + ICP_QAT_HW_COMP_20_CONFIG_CSR_DISABLE_TOKEN_FUSION_CONTROL_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_DISABLE_TOKEN_FUSION_CONTROL_MASK); + + QAT_FIELD_SET(val32, + csr.scb_mode_reset, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_MODE_RESET_MASK_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_MODE_RESET_MASK_MASK); + + QAT_FIELD_SET(val32, + csr.lazy, + ICP_QAT_HW_COMP_20_CONFIG_CSR_LAZY_PARAM_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_LAZY_PARAM_MASK); + + QAT_FIELD_SET(val32, + csr.nice, + ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_MASK); + + return BYTE_SWAP_32(val32); +} + +/** +***************************************************************************** +* @ingroup icp_qat_fw_comn +* +* @description +* Definition of the hw config csr. This representation has to be further +* processed by the corresponding config build function. +* +*****************************************************************************/ +typedef struct icp_qat_hw_decomp_20_config_csr_lower_s { + /* Fields programmable directly by the SW. */ + icp_qat_hw_decomp_20_hbs_control_t hbs; + /* Advanced HW control (Set to default vals) */ + icp_qat_hw_decomp_20_hw_comp_format_t algo; +} icp_qat_hw_decomp_20_config_csr_lower_t; + +/** +***************************************************************************** +* @ingroup icp_qat_fw_comn +* +* @description +* Build the longword as expected by the HW +* +*****************************************************************************/ +static inline uint32_t +ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_LOWER( + icp_qat_hw_decomp_20_config_csr_lower_t csr) +{ + uint32_t val32 = 0; + + QAT_FIELD_SET(val32, + csr.hbs, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_HBS_CONTROL_BITPOS, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_HBS_CONTROL_MASK); + + QAT_FIELD_SET(val32, + csr.algo, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_HW_DECOMP_FORMAT_BITPOS, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_HW_DECOMP_FORMAT_MASK); + + return BYTE_SWAP_32(val32); +} + +/** +***************************************************************************** +* @ingroup icp_qat_fw_comn +* +* @description +* Definition of the hw config csr. This representation has to be further +* processed by the corresponding config build function. +* +*****************************************************************************/ +typedef struct icp_qat_hw_decomp_20_config_csr_upper_s { + /* Advanced HW control (Set to default vals) */ + icp_qat_hw_decomp_20_speculative_decoder_control_t sdc; + icp_qat_hw_decomp_20_mini_cam_control_t mcc; +} icp_qat_hw_decomp_20_config_csr_upper_t; + +/** +***************************************************************************** +* @ingroup icp_qat_fw_comn +* +* @description +* Build the longword as expected by the HW +* +*****************************************************************************/ +static inline uint32_t +ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_UPPER( + icp_qat_hw_decomp_20_config_csr_upper_t csr) +{ + uint32_t val32 = 0; + + QAT_FIELD_SET( + val32, + csr.sdc, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_SPECULATIVE_DECODER_CONTROL_BITPOS, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_SPECULATIVE_DECODER_CONTROL_MASK); + + QAT_FIELD_SET(val32, + csr.mcc, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_BITPOS, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_MASK); + + return BYTE_SWAP_32(val32); +} + +#endif /* ICP_QAT_HW__2X_COMP_H_ */ diff --git a/sys/dev/qat/qat_api/firmware/include/icp_qat_hw_20_comp_defs.h b/sys/dev/qat/qat_api/firmware/include/icp_qat_hw_20_comp_defs.h new file mode 100644 --- /dev/null +++ b/sys/dev/qat/qat_api/firmware/include/icp_qat_hw_20_comp_defs.h @@ -0,0 +1,443 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2007-2022 Intel Corporation */ +/* $FreeBSD$ */ +/* + **************************************************************************** + * @file icp_qat_hw_20_comp_defs.h, (autogenerated at 04-19-18 16:06) + * @defgroup icp_qat_hw_comp_20 + * @ingroup icp_qat_hw_comp_20 + * @description + * This file represents the HW configuration CSR definitions + **************************************************************************** + */ + +#ifndef _ICP_QAT_HW_20_COMP_DEFS_H +#define _ICP_QAT_HW_20_COMP_DEFS_H + +/*****************************************************************************/ +/* SCB Disabled - Set by FW, located in upper 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_CONTROL_BITPOS 31 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_CONTROL_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible SCB_CONTROL field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_SCB_CONTROL_ENABLE = 0x0, + /* Normal Mode using SCB (Default) */ + ICP_QAT_HW_COMP_20_SCB_CONTROL_DISABLE = 0x1, + /* Legacy CPM1.x Mode with SCB disabled. */ +} icp_qat_hw_comp_20_scb_control_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_CONTROL_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_SCB_CONTROL_DISABLE + +/*****************************************************************************/ +/* Reset Bit Mask Disabled - Set by FW , located in upper 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_RMB_CONTROL_BITPOS 30 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_RMB_CONTROL_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible RMB_CONTROL field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_RMB_CONTROL_RESET_ALL = 0x0, + /* Reset all data structures with a set_config command. (Set by FW) */ + ICP_QAT_HW_COMP_20_RMB_CONTROL_RESET_FC_ONLY = 0x1, + /* Reset only the Frequency Counters (LFCT) with a set_config command. + */ +} icp_qat_hw_comp_20_rmb_control_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_RMB_CONTROL_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_RMB_CONTROL_RESET_ALL + +/*****************************************************************************/ +/* Slice Operation Mode (SOM) - Set By FW, located in upper 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SOM_CONTROL_BITPOS 28 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SOM_CONTROL_MASK 0x3 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible SOM_CONTROL field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_SOM_CONTROL_NORMAL_MODE = 0x0, + /* Normal mode. */ + ICP_QAT_HW_COMP_20_SOM_CONTROL_REPLAY_MODE = 0x1, + /* Replay mode */ + ICP_QAT_HW_COMP_20_SOM_CONTROL_INPUT_CRC = 0x2, + /* Input CRC Mode */ + ICP_QAT_HW_COMP_20_SOM_CONTROL_RESERVED_MODE = 0x3, + /* Reserved. */ +} icp_qat_hw_comp_20_som_control_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SOM_CONTROL_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_SOM_CONTROL_NORMAL_MODE + +/*****************************************************************************/ +/* Skip Hash Read (Set By FW) , located in upper 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_RD_CONTROL_BITPOS 27 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_RD_CONTROL_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible SKIP_HASH_RD_CONTROL field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_SKIP_HASH_RD_CONTROL_NO_SKIP = 0x0, + /* When set to 0, hash reads are not skipped. */ + ICP_QAT_HW_COMP_20_SKIP_HASH_RD_CONTROL_SKIP_HASH_READS = 0x1, + /* Hash reads are skipped. */ +} icp_qat_hw_comp_20_skip_hash_rd_control_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_RD_CONTROL_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_SKIP_HASH_RD_CONTROL_NO_SKIP + +/*****************************************************************************/ +/* SCB Unload Disable, located in upper 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_UNLOAD_CONTROL_BITPOS 26 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_UNLOAD_CONTROL_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible SCB_UNLOAD_CONTROL field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_SCB_UNLOAD_CONTROL_UNLOAD = 0x0, + /* Unloads the LFCT and flushes the State Registers. */ + ICP_QAT_HW_COMP_20_SCB_UNLOAD_CONTROL_NO_UNLOAD = 0x1, + /* Does not unload the LFCT, but flushes the State Registers. */ +} icp_qat_hw_comp_20_scb_unload_control_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_UNLOAD_CONTROL_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_SCB_UNLOAD_CONTROL_UNLOAD + +/*****************************************************************************/ +/* Disable token fusion, located in upper 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_DISABLE_TOKEN_FUSION_CONTROL_BITPOS 21 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_DISABLE_TOKEN_FUSION_CONTROL_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible DISABLE_TOKEN_FUSION_CONTROL field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_DISABLE_TOKEN_FUSION_CONTROL_ENABLE = 0x0, + /* Enables token fusion. */ + ICP_QAT_HW_COMP_20_DISABLE_TOKEN_FUSION_CONTROL_DISABLE = 0x1, + /* Disables token fusion. */ +} icp_qat_hw_comp_20_disable_token_fusion_control_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_DISABLE_TOKEN_FUSION_CONTROL_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_DISABLE_TOKEN_FUSION_CONTROL_ENABLE + +/*****************************************************************************/ +/* SCB Mode Reset Mask (Set By FW) , located in upper 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_MODE_RESET_MASK_BITPOS 18 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_MODE_RESET_MASK_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible SCB_MODE_RESET_MASK field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_SCB_MODE_RESET_MASK_RESET_COUNTERS = 0x0, + /* iLZ77 mode: Reset LFCT, OBC */ + ICP_QAT_HW_COMP_20_SCB_MODE_RESET_MASK_RESET_COUNTERS_AND_HISTORY = 0x1, + /* iLZ77 mode: Reset LFCT, OBC, HB, HT */ +} icp_qat_hw_comp_20_scb_mode_reset_mask_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SCB_MODE_RESET_MASK_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_SCB_MODE_RESET_MASK_RESET_COUNTERS + +/*****************************************************************************/ +/* Lazy - For iLZ77 and Static DEFLATE, Lazy = 102h , located in upper + * 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_LAZY_PARAM_BITPOS 9 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_LAZY_PARAM_MASK 0x1ff +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_LAZY_PARAM_DEFAULT_VAL 258 + +/*****************************************************************************/ +/* Nice - For iLZ77 and Static DEFLATE, Nice = 103h , located in upper + * 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_BITPOS 0 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_MASK 0x1ff +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_DEFAULT_VAL 259 + +/*****************************************************************************/ +/* History Buffer Size (Set By the Driver/ Application), located in lower 32bit + */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_HBS_CONTROL_BITPOS 14 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_HBS_CONTROL_MASK 0x7 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible HBS_CONTROL field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_HBS_CONTROL_HBS_IS_32KB = 0x0, + /* 000b - 32KB */ + ICP_QAT_HW_COMP_20_HBS_CONTROL_HBS_IS_64KB = 0x1, + /* 001b - 64KB */ +} icp_qat_hw_comp_20_hbs_control_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_HBS_CONTROL_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_HBS_CONTROL_HBS_IS_32KB + +/*****************************************************************************/ +/* Adaptive Block Drop (Set By FW if Dynamic), located in lower 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_BITPOS 13 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible ABD field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_ABD_ABD_ENABLED = 0x0, + /* 0b - Feature enabled. */ + ICP_QAT_HW_COMP_20_ABD_ABD_DISABLED = 0x1, + /* 1b - Feature disabled. */ +} icp_qat_hw_comp_20_abd_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_ABD_ABD_ENABLED + +/*****************************************************************************/ +/* Literal+Length Limit Block Drop Block Drop, (Set By FW if Dynamic) , located + * in lower 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_LLLBD_CTRL_BITPOS 12 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_LLLBD_CTRL_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible LLLBD_CTRL field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_LLLBD_CTRL_LLLBD_ENABLED = 0x0, + /* 0b - Feature enabled. */ + ICP_QAT_HW_COMP_20_LLLBD_CTRL_LLLBD_DISABLED = 0x1, + /* 1b - Feature disabled. */ +} icp_qat_hw_comp_20_lllbd_ctrl_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_LLLBD_CTRL_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_LLLBD_CTRL_LLLBD_ENABLED + +/*****************************************************************************/ +/* Search Depth (SD) (Set By Driver/Application), located in lower 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SEARCH_DEPTH_BITPOS 8 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SEARCH_DEPTH_MASK 0xf +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible SEARCH_DEPTH field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_SEARCH_DEPTH_LEVEL_1 = 0x1, + /* 0001b - Level 1 (search depth = 2^1 = 2) */ + ICP_QAT_HW_COMP_20_SEARCH_DEPTH_LEVEL_6 = 0x3, + /* 0011b - Level 6 (search depth = 2^3 = 8) */ + ICP_QAT_HW_COMP_20_SEARCH_DEPTH_LEVEL_9 = 0x4, + /* 0100b - Level 9 (search depth = 2^4 = 16) */ +} icp_qat_hw_comp_20_search_depth_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SEARCH_DEPTH_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_SEARCH_DEPTH_LEVEL_1 + +/*****************************************************************************/ +/* Compression Format (Set By Driver/Application. Also See CMD ID), located in + * lower 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_HW_COMP_FORMAT_BITPOS 5 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_HW_COMP_FORMAT_MASK 0x7 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible HW_COMP_FORMAT field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_HW_COMP_FORMAT_ILZ77 = 0x0, + /* 000 - iLZ77. (Must set Min_Match = 3 bytes and HB size = 32KB.) */ + ICP_QAT_HW_COMP_20_HW_COMP_FORMAT_DEFLATE = 0x1, + /* 001 - Static DEFLATE. (Must set Min_Match = 3 bytes and HB size = + 32KB.) */ +} icp_qat_hw_comp_20_hw_comp_format_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_HW_COMP_FORMAT_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_HW_COMP_FORMAT_DEFLATE + +/*****************************************************************************/ +/* Skip Hash Collision (Set By FW to default value), located in lower 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_COLLISION_BITPOS 3 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_COLLISION_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible SKIP_HASH_COLLISION field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_SKIP_HASH_COLLISION_ALLOW = 0x0, + /* When set to 0, hash collisions are allowed. */ + ICP_QAT_HW_COMP_20_SKIP_HASH_COLLISION_DONT_ALLOW = 0x1, + /* When set to 0, hash collisions are allowed. */ +} icp_qat_hw_comp_20_skip_hash_collision_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_COLLISION_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_SKIP_HASH_COLLISION_ALLOW + +/*****************************************************************************/ +/* Skip Hash Update (Set By FW to default value) , located in lower 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_UPDATE_BITPOS 2 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_UPDATE_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible SKIP_HASH_UPDATE field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_SKIP_HASH_UPDATE_ALLOW = 0x0, + /* 0 - hash updates are not skipped. */ + ICP_QAT_HW_COMP_20_SKIP_HASH_UPDATE_DONT_ALLOW = 0x1, + /* 1 - hash updates are skipped. */ +} icp_qat_hw_comp_20_skip_hash_update_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_SKIP_HASH_UPDATE_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_SKIP_HASH_UPDATE_ALLOW + +/*****************************************************************************/ +/* 3-Byte Match Skip (Set By FW to default value), located in lower 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_BYTE_SKIP_BITPOS 1 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_BYTE_SKIP_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible BYTE_SKIP field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_BYTE_SKIP_3BYTE_TOKEN = 0x0, + /* 0 - Use 3-byte token */ + ICP_QAT_HW_COMP_20_BYTE_SKIP_3BYTE_LITERAL = 0x1, + /* 0 - Use 3-byte literal */ +} icp_qat_hw_comp_20_byte_skip_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_BYTE_SKIP_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_BYTE_SKIP_3BYTE_TOKEN + +/*****************************************************************************/ +/* Extended Delayed Match Mode enabled (Set By the Driver), located in lower + * 32bit */ +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_EXTENDED_DELAY_MATCH_MODE_BITPOS 0 +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_EXTENDED_DELAY_MATCH_MODE_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible EXTENDED_DELAY_MATCH_MODE field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_COMP_20_EXTENDED_DELAY_MATCH_MODE_EDMM_DISABLED = 0x0, + /* 0 - EXTENDED_DELAY_MATCH_MODE disabled */ + ICP_QAT_HW_COMP_20_EXTENDED_DELAY_MATCH_MODE_EDMM_ENABLED = 0x1, + /* 1 - EXTENDED_DELAY_MATCH_MODE enabled */ +} icp_qat_hw_comp_20_extended_delay_match_mode_t; + +#define ICP_QAT_HW_COMP_20_CONFIG_CSR_EXTENDED_DELAY_MATCH_MODE_DEFAULT_VAL \ + ICP_QAT_HW_COMP_20_EXTENDED_DELAY_MATCH_MODE_EDMM_DISABLED + +/*****************************************************************************/ +/* Speculative Decoder Disable (Set By the Driver/ Application), located in + * upper 32bit */ +#define ICP_QAT_HW_DECOMP_20_CONFIG_CSR_SPECULATIVE_DECODER_CONTROL_BITPOS 31 +#define ICP_QAT_HW_DECOMP_20_CONFIG_CSR_SPECULATIVE_DECODER_CONTROL_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible SPECULATIVE_DECODER_CONTROL field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_DECOMP_20_SPECULATIVE_DECODER_CONTROL_ENABLE = 0x0, + /* 0b - Enabled */ + ICP_QAT_HW_DECOMP_20_SPECULATIVE_DECODER_CONTROL_DISABLE = 0x1, + /* 1b - Disabled */ +} icp_qat_hw_decomp_20_speculative_decoder_control_t; + +#define ICP_QAT_HW_DECOMP_20_CONFIG_CSR_SPECULATIVE_DECODER_CONTROL_DEFAULT_VAL \ + ICP_QAT_HW_DECOMP_20_SPECULATIVE_DECODER_CONTROL_ENABLE + +/*****************************************************************************/ +/* Mini CAM Disable (Set By the Driver/ Application), located in upper 32bit */ +#define ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_BITPOS 30 +#define ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_MASK 0x1 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible MINI_CAM_CONTROL field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_DECOMP_20_MINI_CAM_CONTROL_ENABLE = 0x0, + /* 0b - Enabled */ + ICP_QAT_HW_DECOMP_20_MINI_CAM_CONTROL_DISABLE = 0x1, + /* 1b - Disabled */ +} icp_qat_hw_decomp_20_mini_cam_control_t; + +#define ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_DEFAULT_VAL \ + ICP_QAT_HW_DECOMP_20_MINI_CAM_CONTROL_ENABLE + +/*****************************************************************************/ +/* History Buffer Size (Set By the Driver/ Application), located in lower 32bit + */ +#define ICP_QAT_HW_DECOMP_20_CONFIG_CSR_HBS_CONTROL_BITPOS 14 +#define ICP_QAT_HW_DECOMP_20_CONFIG_CSR_HBS_CONTROL_MASK 0x7 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible HBS_CONTROL field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_DECOMP_20_HBS_CONTROL_HBS_IS_32KB = 0x0, + /* 000b - 32KB */ +} icp_qat_hw_decomp_20_hbs_control_t; + +#define ICP_QAT_HW_DECOMP_20_CONFIG_CSR_HBS_CONTROL_DEFAULT_VAL \ + ICP_QAT_HW_DECOMP_20_HBS_CONTROL_HBS_IS_32KB + +/*****************************************************************************/ +/* Decompression Format (Set By Driver/Application. Also See CMD ID), located in + * lower 32bit */ +#define ICP_QAT_HW_DECOMP_20_CONFIG_CSR_HW_DECOMP_FORMAT_BITPOS 5 +#define ICP_QAT_HW_DECOMP_20_CONFIG_CSR_HW_DECOMP_FORMAT_MASK 0x7 +/* + **************************************************************************** + * @ingroup icp_qat_hw_defs + * @description + * Enumeration of possible HW_DECOMP_FORMAT field values + *****************************************************************************/ +typedef enum { + ICP_QAT_HW_DECOMP_20_HW_DECOMP_FORMAT_DEFLATE = 0x1, + /* 001 - Static DEFLATE. (Must set Min_Match = 3 bytes and HB size = + 32KB.) */ +} icp_qat_hw_decomp_20_hw_comp_format_t; + +#define ICP_QAT_HW_DECOMP_20_CONFIG_CSR_HW_DECOMP_FORMAT_DEFAULT_VAL \ + ICP_QAT_HW_DECOMP_20_HW_DECOMP_FORMAT_DEFLATE + +#endif //_ICP_QAT_HW_20_COMP_DEFS_H diff --git a/sys/dev/qat/qat_api/include/icp_sal_user.h b/sys/dev/qat/qat_api/include/icp_sal_user.h --- a/sys/dev/qat/qat_api/include/icp_sal_user.h +++ b/sys/dev/qat/qat_api/include/icp_sal_user.h @@ -868,4 +868,41 @@ * *****************************************************************************/ CpaStatus icp_sal_AsymPerformOpNow(CpaInstanceHandle instanceHandle); + +/** + ***************************************************************************** + * @ingroup icp_sal_setForceAEADMACVerify + * Sets forceAEADMacVerify for particular instance to force HW MAC + * validation. + * + * @description + * By default HW MAC verification is set to CPA_TRUE - this utility + * function allows to change default behavior. + * + * @assumptions + * None + * @sideEffects + * None + * @blocking + * None + * @reentrant + * No + * @threadSafe + * No + * + * @param[in] instanceHandle Crypto API instance handle. + * @param[in] forceAEADMacVerify new value + * + * @retval CPA_STATUS_SUCCESS Function executed successfully. + * @retval CPA_STATUS_FAIL Function failed. + * @pre + * None + * @post + * None + * @see + * None + * + *****************************************************************************/ +CpaStatus icp_sal_setForceAEADMACVerify(CpaInstanceHandle instanceHandle, + CpaBoolean forceAEADMacVerify); #endif diff --git a/sys/dev/qat/qat_api/include/icp_sal_versions.h b/sys/dev/qat/qat_api/include/icp_sal_versions.h --- a/sys/dev/qat/qat_api/include/icp_sal_versions.h +++ b/sys/dev/qat/qat_api/include/icp_sal_versions.h @@ -26,8 +26,8 @@ /**< Max length of hardware version string */ /* Part name and number of the accelerator device */ -#define SAL_INFO2_DRIVER_SW_VERSION_MAJ_NUMBER 3 -#define SAL_INFO2_DRIVER_SW_VERSION_MIN_NUMBER 11 +#define SAL_INFO2_DRIVER_SW_VERSION_MAJ_NUMBER 3 +#define SAL_INFO2_DRIVER_SW_VERSION_MIN_NUMBER 12 #define SAL_INFO2_DRIVER_SW_VERSION_PATCH_NUMBER 0 /** diff --git a/sys/dev/qat/qat_api/qat_direct/include/icp_accel_devices.h b/sys/dev/qat/qat_api/qat_direct/include/icp_accel_devices.h --- a/sys/dev/qat/qat_api/qat_direct/include/icp_accel_devices.h +++ b/sys/dev/qat/qat_api/qat_direct/include/icp_accel_devices.h @@ -97,7 +97,8 @@ DEVICE_200XX, DEVICE_200XXVF, DEVICE_C4XXX, - DEVICE_C4XXXVF + DEVICE_C4XXXVF, + DEVICE_GEN4 } device_type_t; /* diff --git a/sys/dev/qat/qat_api/qat_kernel/src/qat_transport.c b/sys/dev/qat/qat_api/qat_kernel/src/qat_transport.c --- a/sys/dev/qat/qat_api/qat_kernel/src/qat_transport.c +++ b/sys/dev/qat/qat_api/qat_kernel/src/qat_transport.c @@ -372,13 +372,20 @@ icp_adf_updateQueueTail(icp_comms_trans_handle trans_handle) { struct adf_etr_ring_data *ring = trans_handle; + struct adf_hw_csr_ops *csr_ops; ICP_CHECK_FOR_NULL_PARAM_VOID(ring); + ICP_CHECK_FOR_NULL_PARAM_VOID(ring->bank); + ICP_CHECK_FOR_NULL_PARAM_VOID(ring->bank->accel_dev); - WRITE_CSR_RING_TAIL(ring->bank->csr_addr, - ring->bank->bank_number, - ring->ring_number, - ring->tail); + csr_ops = GET_CSR_OPS(ring->bank->accel_dev); + + ICP_CHECK_FOR_NULL_PARAM_VOID(csr_ops); + + csr_ops->write_csr_ring_tail(ring->bank->csr_addr, + ring->bank->bank_number, + ring->ring_number, + ring->tail); ring->csr_tail_offset = ring->tail; } diff --git a/sys/dev/qat/qat_api/qat_utils/include/qat_utils.h b/sys/dev/qat/qat_api/qat_utils/include/qat_utils.h --- a/sys/dev/qat/qat_api/qat_utils/include/qat_utils.h +++ b/sys/dev/qat/qat_api/qat_utils/include/qat_utils.h @@ -848,4 +848,25 @@ uint32_t keyLenInBytes, uint8_t *in, uint8_t *out); + +/** + * @ingroup QatUtils + * + * @brief Converts AES forward key to reverse key + * + * @param key - pointer to symetric key. + * keyLenInBytes - key length + * out - pointer to output buffer for reversed key + * The in and out buffers need to be at least AES block size long + * as defined in rfc3686 (16 bytes) + * + * @li Reentrant: yes + * @li IRQ safe: yes + * + * @return - CPA_STATUS_SUCCESS/CPA_STATUS_FAIL + * + */ +CpaStatus qatUtilsAESKeyExpansionForward(uint8_t *key, + uint32_t keyLenInBytes, + uint32_t *out); #endif diff --git a/sys/dev/qat/qat_api/qat_utils/src/QatUtilsCrypto.c b/sys/dev/qat/qat_api/qat_utils/src/QatUtilsCrypto.c --- a/sys/dev/qat/qat_api/qat_utils/src/QatUtilsCrypto.c +++ b/sys/dev/qat/qat_api/qat_utils/src/QatUtilsCrypto.c @@ -3,6 +3,10 @@ /* $FreeBSD$ */ #include "qat_utils.h" +#define AES_128_KEY_LEN_BYTES 16 +#define AES_192_KEY_LEN_BYTES 24 +#define AES_256_KEY_LEN_BYTES 32 + CpaStatus qatUtilsHashMD5(uint8_t *in, uint8_t *out) { @@ -150,3 +154,38 @@ return CPA_STATUS_SUCCESS; } + +CpaStatus +qatUtilsAESKeyExpansionForward(uint8_t *key, + uint32_t keyLenInBytes, + uint32_t *out) +{ + rijndael_ctx ctx; + uint32_t i = 0, j = 0; + uint32_t lw_per_round = 4; + int32_t lw_left_to_copy = keyLenInBytes / lw_per_round; + uint32_t *key_pointer = NULL; + + /* Error check for wrong input key len */ + if (AES_128_KEY_LEN_BYTES != keyLenInBytes && + AES_192_KEY_LEN_BYTES != keyLenInBytes && + AES_256_KEY_LEN_BYTES != keyLenInBytes) { + return CPA_STATUS_INVALID_PARAM; + } + + rijndael_set_key(&ctx, key, keyLenInBytes << BYTE_TO_BITS_SHIFT); + + /* Pointer to the last round of expanded key. */ + key_pointer = &ctx.ek[lw_per_round * ctx.Nr]; + + while (lw_left_to_copy > 0) { + for (i = 0; i < MIN(lw_left_to_copy, lw_per_round); i++, j++) { + out[j] = __builtin_bswap32(key_pointer[i]); + } + + lw_left_to_copy -= lw_per_round; + key_pointer -= lw_left_to_copy; + } + + return CPA_STATUS_SUCCESS; +} diff --git a/sys/dev/qat/qat_common/adf_accel_engine.c b/sys/dev/qat/qat_common/adf_accel_engine.c --- a/sys/dev/qat/qat_common/adf_accel_engine.c +++ b/sys/dev/qat/qat_common/adf_accel_engine.c @@ -99,11 +99,24 @@ */ if (hw_device->get_obj_name && hw_device->get_obj_cfg_ae_mask) { unsigned long service_mask = hw_device->service_mask; + enum adf_accel_unit_services service_type = + ADF_ACCEL_SERVICE_NULL; - if (hw_device->service_mask && - !(test_bit(i, &service_mask))) + if (hw_device->get_service_type) + service_type = + hw_device->get_service_type(accel_dev, i); + else + service_type = BIT(i); + + if (service_mask && !(service_mask & service_type)) continue; - obj_name = hw_device->get_obj_name(accel_dev, BIT(i)); + + obj_name = + hw_device->get_obj_name(accel_dev, service_type); + cfg_ae_mask = + hw_device->get_obj_cfg_ae_mask(accel_dev, + service_type); + if (!obj_name) { device_printf( GET_DEV(accel_dev), @@ -111,10 +124,8 @@ BIT(i)); goto out_err; } - if (!hw_device->get_obj_cfg_ae_mask(accel_dev, BIT(i))) + if (!cfg_ae_mask) continue; - cfg_ae_mask = - hw_device->get_obj_cfg_ae_mask(accel_dev, BIT(i)); if (qat_uclo_set_cfg_ae_mask(loader_data->fw_loader, cfg_ae_mask)) { device_printf(GET_DEV(accel_dev), @@ -172,17 +183,12 @@ { struct adf_fw_loader_data *loader_data = accel_dev->fw_loader; struct adf_hw_device_data *hw_data = accel_dev->hw_device; - uint32_t ae_ctr, ae, max_aes = GET_MAX_ACCELENGINES(accel_dev); + uint32_t ae_ctr; if (!hw_data->fw_name) return 0; - for (ae = 0, ae_ctr = 0; ae < max_aes; ae++) { - if (hw_data->ae_mask & (1 << ae)) { - qat_hal_start(loader_data->fw_loader, ae, 0xFF); - ae_ctr++; - } - } + ae_ctr = qat_hal_start(loader_data->fw_loader); device_printf(GET_DEV(accel_dev), "qat_dev%d started %d acceleration engines\n", accel_dev->accel_id, diff --git a/sys/dev/qat/qat_common/adf_cfg_bundle.h b/sys/dev/qat/qat_common/adf_cfg_bundle.h --- a/sys/dev/qat/qat_common/adf_cfg_bundle.h +++ b/sys/dev/qat/qat_common/adf_cfg_bundle.h @@ -49,7 +49,29 @@ struct adf_accel_dev *accel_dev); void adf_cfg_init_ring2serv_mapping(struct adf_accel_dev *accel_dev, - struct adf_cfg_bundle *bundle); + struct adf_cfg_bundle *bundle, + struct adf_cfg_device *device); int adf_cfg_rel_ring2serv_mapping(struct adf_cfg_bundle *bundle); + +static inline void +adf_get_ring_svc_map_data(struct adf_hw_device_data *hw_data, + int bundle_num, + int ring_pair_index, + u8 *serv_type, + int *ring_index, + int *num_rings_per_srv) +{ + if (hw_data->get_ring_svc_map_data) + return hw_data->get_ring_svc_map_data(ring_pair_index, + hw_data->ring_to_svc_map, + serv_type, + ring_index, + num_rings_per_srv, + bundle_num); + *serv_type = GET_SRV_TYPE(hw_data->ring_to_svc_map, ring_pair_index); + *num_rings_per_srv = + hw_data->num_rings_per_bank / (2 * ADF_CFG_NUM_SERVICES); + *ring_index = (*num_rings_per_srv) * ring_pair_index; +} #endif diff --git a/sys/dev/qat/qat_common/adf_cfg_bundle.c b/sys/dev/qat/qat_common/adf_cfg_bundle.c --- a/sys/dev/qat/qat_common/adf_cfg_bundle.c +++ b/sys/dev/qat/qat_common/adf_cfg_bundle.c @@ -157,16 +157,23 @@ { struct adf_cfg_instance *cfg_instance = NULL; int ring_pair_index = 0; + int ring_index = 0; int i = 0; u8 serv_type; - int num_req_rings = bundle->num_of_rings / 2; - int num_rings_per_srv = num_req_rings / ADF_CFG_NUM_SERVICES; + int num_rings_per_srv = 0; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; u16 ring_to_svc_map = GET_HW_DATA(accel_dev)->ring_to_svc_map; /* init the bundle with instance information */ - for (ring_pair_index = 0; ring_pair_index < ADF_CFG_NUM_SERVICES; + for (ring_pair_index = 0; ring_pair_index < bundle->max_cfg_svc_num; ring_pair_index++) { - serv_type = GET_SRV_TYPE(ring_to_svc_map, ring_pair_index); + adf_get_ring_svc_map_data(hw_data, + bundle->number, + ring_pair_index, + &serv_type, + &ring_index, + &num_rings_per_srv); + for (i = 0; i < num_rings_per_srv; i++) { cfg_instance = malloc(sizeof(*cfg_instance), M_QAT, @@ -219,8 +226,9 @@ { int i = 0; + bundle->number = bank_num; /* init ring to service mapping for this bundle */ - adf_cfg_init_ring2serv_mapping(accel_dev, bundle); + adf_cfg_init_ring2serv_mapping(accel_dev, bundle, device); /* init the bundle with instance information */ adf_cfg_init_and_insert_inst(bundle, device, bank_num, accel_dev); @@ -229,7 +237,6 @@ bundle->type = FREE; bundle->polling_mode = -1; bundle->section_index = 0; - bundle->number = bank_num; bundle->sections = malloc(sizeof(char *) * bundle->max_section, M_QAT, @@ -262,18 +269,25 @@ } static void -adf_cfg_assign_serv_to_rings(struct adf_cfg_bundle *bundle, u16 ring_to_svc_map) +adf_cfg_assign_serv_to_rings(struct adf_hw_device_data *hw_data, + struct adf_cfg_bundle *bundle, + struct adf_cfg_device *device) { int ring_pair_index = 0; int ring_index = 0; u8 serv_type = 0; int num_req_rings = bundle->num_of_rings / 2; - int num_rings_per_srv = num_req_rings / ADF_CFG_NUM_SERVICES; + int num_rings_per_srv = 0; - for (ring_pair_index = 0; ring_pair_index < ADF_CFG_NUM_SERVICES; + for (ring_pair_index = 0; ring_pair_index < bundle->max_cfg_svc_num; ring_pair_index++) { - serv_type = GET_SRV_TYPE(ring_to_svc_map, ring_pair_index); - ring_index = num_rings_per_srv * ring_pair_index; + adf_get_ring_svc_map_data(hw_data, + bundle->number, + ring_pair_index, + &serv_type, + &ring_index, + &num_rings_per_srv); + switch (serv_type) { case CRYPTO: ASSIGN_SERV_TO_RINGS(bundle, @@ -283,7 +297,7 @@ num_rings_per_srv); ring_pair_index++; ring_index = num_rings_per_srv * ring_pair_index; - if (ring_pair_index == ADF_CFG_NUM_SERVICES) + if (ring_pair_index == bundle->max_cfg_svc_num) break; ASSIGN_SERV_TO_RINGS(bundle, ring_index, @@ -324,7 +338,7 @@ /* unknown service type */ pr_err("Unknown service type %d, mask 0x%x.\n", serv_type, - ring_to_svc_map); + hw_data->ring_to_svc_map); } } @@ -333,13 +347,18 @@ void adf_cfg_init_ring2serv_mapping(struct adf_accel_dev *accel_dev, - struct adf_cfg_bundle *bundle) + struct adf_cfg_bundle *bundle, + struct adf_cfg_device *device) { struct adf_hw_device_data *hw_data = accel_dev->hw_device; struct adf_cfg_ring *ring_in_bundle; int ring_num = 0; bundle->num_of_rings = hw_data->num_rings_per_bank; + if (hw_data->num_rings_per_bank >= (2 * ADF_CFG_NUM_SERVICES)) + bundle->max_cfg_svc_num = ADF_CFG_NUM_SERVICES; + else + bundle->max_cfg_svc_num = 1; bundle->rings = malloc(bundle->num_of_rings * sizeof(struct adf_cfg_ring *), @@ -356,7 +375,7 @@ bundle->rings[ring_num] = ring_in_bundle; } - adf_cfg_assign_serv_to_rings(bundle, hw_data->ring_to_svc_map); + adf_cfg_assign_serv_to_rings(hw_data, bundle, device); return; } diff --git a/sys/dev/qat/qat_common/adf_cfg_device.c b/sys/dev/qat/qat_common/adf_cfg_device.c --- a/sys/dev/qat/qat_common/adf_cfg_device.c +++ b/sys/dev/qat/qat_common/adf_cfg_device.c @@ -249,7 +249,6 @@ int i = 0; int ret = EFAULT; struct adf_cfg_instance *free_inst = NULL; - struct adf_cfg_bundle *first_free_bundle = NULL; enum adf_cfg_bundle_type free_bundle_type; int first_user_bundle = 0; @@ -304,29 +303,25 @@ return ret; - } else if (!first_free_bundle && - adf_cfg_is_free(device->bundles[i])) { - first_free_bundle = device->bundles[i]; } } + for (i = 0; i < device->bundle_num; i++) { + if (adf_cfg_is_free(device->bundles[i])) { + free_inst = adf_cfg_get_free_instance( + device, + device->bundles[i], + inst, + process_name); + if (!free_inst) + continue; - if (first_free_bundle) { - free_inst = adf_cfg_get_free_instance(device, - first_free_bundle, - inst, - process_name); - - if (!free_inst) + ret = adf_cfg_get_ring_pairs_from_bundle( + device->bundles[i], + inst, + process_name, + free_inst); return ret; - - ret = adf_cfg_get_ring_pairs_from_bundle( - first_free_bundle, inst, process_name, free_inst); - - if (free_bundle_type == KERNEL) { - device->max_kernel_bundle_nr = - first_free_bundle->number; } - return ret; } } pr_err("Don't have enough rings for instance %s in process %s\n", diff --git a/sys/dev/qat/qat_common/adf_cfg_section.c b/sys/dev/qat/qat_common/adf_cfg_section.c --- a/sys/dev/qat/qat_common/adf_cfg_section.c +++ b/sys/dev/qat/qat_common/adf_cfg_section.c @@ -286,10 +286,16 @@ key = malloc(ADF_CFG_MAX_KEY_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO); - snprintf(key, - ADF_CFG_MAX_KEY_LEN_IN_BYTES, - ADF_CY_BANK_NUM_FORMAT, - inst_index); + if (adf_cy_inst_cross_banks(accel_dev)) + snprintf(key, + ADF_CFG_MAX_KEY_LEN_IN_BYTES, + ADF_CY_ASYM_BANK_NUM_FORMAT, + inst_index); + else + snprintf(key, + ADF_CFG_MAX_KEY_LEN_IN_BYTES, + ADF_CY_BANK_NUM_FORMAT, + inst_index); bank_number = asym_inst->bundle; adf_cfg_add_key_value_param( accel_dev, derived_sec, key, (void *)&bank_number, ADF_DEC); @@ -337,10 +343,17 @@ key = malloc(ADF_CFG_MAX_KEY_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO); - snprintf(key, - ADF_CFG_MAX_KEY_LEN_IN_BYTES, - ADF_CY_BANK_NUM_FORMAT, - inst_index); + if (adf_cy_inst_cross_banks(accel_dev)) + snprintf(key, + ADF_CFG_MAX_KEY_LEN_IN_BYTES, + ADF_CY_SYM_BANK_NUM_FORMAT, + inst_index); + else + snprintf(key, + ADF_CFG_MAX_KEY_LEN_IN_BYTES, + ADF_CY_BANK_NUM_FORMAT, + inst_index); + bank_number = sym_inst->bundle; adf_cfg_add_key_value_param( accel_dev, derived_sec, key, (void *)&bank_number, ADF_DEC); diff --git a/sys/dev/qat/qat_common/adf_freebsd_admin.c b/sys/dev/qat/qat_common/adf_freebsd_admin.c --- a/sys/dev/qat/qat_common/adf_freebsd_admin.c +++ b/sys/dev/qat/qat_common/adf_freebsd_admin.c @@ -27,10 +27,7 @@ #define ADF_CONST_TABLE_VERSION (1) /* Admin Messages Registers */ -#define ADF_DH895XCC_ADMINMSGUR_OFFSET (0x3A000 + 0x574) -#define ADF_DH895XCC_ADMINMSGLR_OFFSET (0x3A000 + 0x578) -#define ADF_DH895XCC_MAILBOX_BASE_OFFSET 0x20970 -#define ADF_DH895XCC_MAILBOX_STRIDE 0x1000 +#define ADF_MAILBOX_STRIDE 0x1000 #define ADF_ADMINMSG_LEN 32 #define FREEBSD_ALLIGNMENT_SIZE 64 #define ADF_INIT_CONFIG_SIZE 1024 @@ -146,7 +143,7 @@ hw_data->get_admin_info(&admin_csrs_info); int offset = ae * ADF_ADMINMSG_LEN * 2; int mb_offset = - ae * ADF_DH895XCC_MAILBOX_STRIDE + admin_csrs_info.mailbox_offset; + ae * ADF_MAILBOX_STRIDE + admin_csrs_info.mailbox_offset; int times, received; struct icp_qat_fw_init_admin_req *request = in; @@ -294,7 +291,7 @@ struct icp_qat_fw_init_admin_req req; struct icp_qat_fw_init_admin_resp resp; struct adf_hw_device_data *hw_device = accel_dev->hw_device; - u32 ae_mask = hw_device->ae_mask; + u32 ae_mask = hw_device->admin_ae_mask; explicit_bzero(&req, sizeof(req)); req.cmd_id = ICP_QAT_FW_CONSTANTS_CFG; diff --git a/sys/dev/qat/qat_common/adf_freebsd_transport_debug.c b/sys/dev/qat/qat_common/adf_freebsd_transport_debug.c --- a/sys/dev/qat/qat_common/adf_freebsd_transport_debug.c +++ b/sys/dev/qat/qat_common/adf_freebsd_transport_debug.c @@ -20,6 +20,7 @@ { struct adf_etr_ring_data *ring = arg1; struct adf_etr_bank_data *bank = ring->bank; + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(bank->accel_dev); struct resource *csr = ring->bank->csr_addr; struct sbuf sb; int error, word; @@ -29,13 +30,13 @@ { int head, tail, empty; - head = READ_CSR_RING_HEAD(csr, - bank->bank_number, - ring->ring_number); - tail = READ_CSR_RING_TAIL(csr, - bank->bank_number, - ring->ring_number); - empty = READ_CSR_E_STAT(csr, bank->bank_number); + head = csr_ops->read_csr_ring_head(csr, + bank->bank_number, + ring->ring_number); + tail = csr_ops->read_csr_ring_tail(csr, + bank->bank_number, + ring->ring_number); + empty = csr_ops->read_csr_e_stat(csr, bank->bank_number); sbuf_cat(&sb, "\n------- Ring configuration -------\n"); sbuf_printf(&sb, @@ -119,6 +120,7 @@ { struct adf_etr_bank_data *bank; struct adf_accel_dev *accel_dev = NULL; + struct adf_hw_csr_ops *csr_ops = NULL; struct adf_hw_device_data *hw_data = NULL; u8 num_rings_per_bank = 0; struct sbuf sb; @@ -127,6 +129,7 @@ sbuf_new_for_sysctl(&sb, NULL, 128, req); bank = arg1; accel_dev = bank->accel_dev; + csr_ops = GET_CSR_OPS(bank->accel_dev); hw_data = accel_dev->hw_device; num_rings_per_bank = hw_data->num_rings_per_bank; sbuf_printf(&sb, @@ -140,13 +143,13 @@ if (!(bank->ring_mask & 1 << ring_id)) continue; - head = READ_CSR_RING_HEAD(csr, - bank->bank_number, - ring->ring_number); - tail = READ_CSR_RING_TAIL(csr, - bank->bank_number, - ring->ring_number); - empty = READ_CSR_E_STAT(csr, bank->bank_number); + head = csr_ops->read_csr_ring_head(csr, + bank->bank_number, + ring->ring_number); + tail = csr_ops->read_csr_ring_tail(csr, + bank->bank_number, + ring->ring_number); + empty = csr_ops->read_csr_e_stat(csr, bank->bank_number); sbuf_printf(&sb, "ring num %02d, head %04x, tail %04x, empty: %d\n", diff --git a/sys/dev/qat/qat_common/adf_gen2_hw_data.c b/sys/dev/qat/qat_common/adf_gen2_hw_data.c new file mode 100644 --- /dev/null +++ b/sys/dev/qat/qat_common/adf_gen2_hw_data.c @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2021 Intel Corporation */ +/* $FreeBSD$ */ +#include "adf_gen2_hw_data.h" +#include "icp_qat_hw.h" + +static u64 +build_csr_ring_base_addr(dma_addr_t addr, u32 size) +{ + return BUILD_RING_BASE_ADDR(addr, size); +} + +static u32 +read_csr_ring_head(struct resource *csr_base_addr, u32 bank, u32 ring) +{ + return READ_CSR_RING_HEAD(csr_base_addr, bank, ring); +} + +static void +write_csr_ring_head(struct resource *csr_base_addr, + u32 bank, + u32 ring, + u32 value) +{ + WRITE_CSR_RING_HEAD(csr_base_addr, bank, ring, value); +} + +static u32 +read_csr_ring_tail(struct resource *csr_base_addr, u32 bank, u32 ring) +{ + return READ_CSR_RING_TAIL(csr_base_addr, bank, ring); +} + +static void +write_csr_ring_tail(struct resource *csr_base_addr, + u32 bank, + u32 ring, + u32 value) +{ + WRITE_CSR_RING_TAIL(csr_base_addr, bank, ring, value); +} + +static u32 +read_csr_e_stat(struct resource *csr_base_addr, u32 bank) +{ + return READ_CSR_E_STAT(csr_base_addr, bank); +} + +static void +write_csr_ring_config(struct resource *csr_base_addr, + u32 bank, + u32 ring, + u32 value) +{ + WRITE_CSR_RING_CONFIG(csr_base_addr, bank, ring, value); +} + +static void +write_csr_ring_base(struct resource *csr_base_addr, + u32 bank, + u32 ring, + dma_addr_t addr) +{ + WRITE_CSR_RING_BASE(csr_base_addr, bank, ring, addr); +} + +static void +write_csr_int_flag(struct resource *csr_base_addr, u32 bank, u32 value) +{ + WRITE_CSR_INT_FLAG(csr_base_addr, bank, value); +} + +static void +write_csr_int_srcsel(struct resource *csr_base_addr, u32 bank) +{ + WRITE_CSR_INT_SRCSEL(csr_base_addr, bank); +} + +static void +write_csr_int_col_en(struct resource *csr_base_addr, u32 bank, u32 value) +{ + WRITE_CSR_INT_COL_EN(csr_base_addr, bank, value); +} + +static void +write_csr_int_col_ctl(struct resource *csr_base_addr, u32 bank, u32 value) +{ + WRITE_CSR_INT_COL_CTL(csr_base_addr, bank, value); +} + +static void +write_csr_int_flag_and_col(struct resource *csr_base_addr, u32 bank, u32 value) +{ + WRITE_CSR_INT_FLAG_AND_COL(csr_base_addr, bank, value); +} + +static u32 +read_csr_ring_srv_arb_en(struct resource *csr_base_addr, u32 bank) +{ + return READ_CSR_RING_SRV_ARB_EN(csr_base_addr, bank); +} + +static void +write_csr_ring_srv_arb_en(struct resource *csr_base_addr, u32 bank, u32 value) +{ + WRITE_CSR_RING_SRV_ARB_EN(csr_base_addr, bank, value); +} + +void +adf_gen2_init_hw_csr_info(struct adf_hw_csr_info *csr_info) +{ + struct adf_hw_csr_ops *csr_ops = &csr_info->csr_ops; + + csr_info->arb_enable_mask = 0xFF; + + csr_ops->build_csr_ring_base_addr = build_csr_ring_base_addr; + csr_ops->read_csr_ring_head = read_csr_ring_head; + csr_ops->write_csr_ring_head = write_csr_ring_head; + csr_ops->read_csr_ring_tail = read_csr_ring_tail; + csr_ops->write_csr_ring_tail = write_csr_ring_tail; + csr_ops->read_csr_e_stat = read_csr_e_stat; + csr_ops->write_csr_ring_config = write_csr_ring_config; + csr_ops->write_csr_ring_base = write_csr_ring_base; + csr_ops->write_csr_int_flag = write_csr_int_flag; + csr_ops->write_csr_int_srcsel = write_csr_int_srcsel; + csr_ops->write_csr_int_col_en = write_csr_int_col_en; + csr_ops->write_csr_int_col_ctl = write_csr_int_col_ctl; + csr_ops->write_csr_int_flag_and_col = write_csr_int_flag_and_col; + csr_ops->read_csr_ring_srv_arb_en = read_csr_ring_srv_arb_en; + csr_ops->write_csr_ring_srv_arb_en = write_csr_ring_srv_arb_en; +} +EXPORT_SYMBOL_GPL(adf_gen2_init_hw_csr_info); diff --git a/sys/dev/qat/qat_common/adf_gen4_hw_data.c b/sys/dev/qat/qat_common/adf_gen4_hw_data.c new file mode 100644 --- /dev/null +++ b/sys/dev/qat/qat_common/adf_gen4_hw_data.c @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2021 Intel Corporation */ +/* $FreeBSD$ */ +#include "adf_accel_devices.h" +#include "adf_gen4_hw_data.h" + +static u64 +build_csr_ring_base_addr(bus_addr_t addr, u32 size) +{ + return BUILD_RING_BASE_ADDR(addr, size); +} + +static u32 +read_csr_ring_head(struct resource *csr_base_addr, u32 bank, u32 ring) +{ + return READ_CSR_RING_HEAD(csr_base_addr, bank, ring); +} + +static void +write_csr_ring_head(struct resource *csr_base_addr, + u32 bank, + u32 ring, + u32 value) +{ + WRITE_CSR_RING_HEAD(csr_base_addr, bank, ring, value); +} + +static u32 +read_csr_ring_tail(struct resource *csr_base_addr, u32 bank, u32 ring) +{ + return READ_CSR_RING_TAIL(csr_base_addr, bank, ring); +} + +static void +write_csr_ring_tail(struct resource *csr_base_addr, + u32 bank, + u32 ring, + u32 value) +{ + WRITE_CSR_RING_TAIL(csr_base_addr, bank, ring, value); +} + +static u32 +read_csr_e_stat(struct resource *csr_base_addr, u32 bank) +{ + return READ_CSR_E_STAT(csr_base_addr, bank); +} + +static void +write_csr_ring_config(struct resource *csr_base_addr, + u32 bank, + u32 ring, + u32 value) +{ + WRITE_CSR_RING_CONFIG(csr_base_addr, bank, ring, value); +} + +static void +write_csr_ring_base(struct resource *csr_base_addr, + u32 bank, + u32 ring, + bus_addr_t addr) +{ + WRITE_CSR_RING_BASE(csr_base_addr, bank, ring, addr); +} + +static void +write_csr_int_flag(struct resource *csr_base_addr, u32 bank, u32 value) +{ + WRITE_CSR_INT_FLAG(csr_base_addr, bank, value); +} + +static void +write_csr_int_srcsel(struct resource *csr_base_addr, u32 bank) +{ + WRITE_CSR_INT_SRCSEL(csr_base_addr, bank); +} + +static void +write_csr_int_col_en(struct resource *csr_base_addr, u32 bank, u32 value) +{ + WRITE_CSR_INT_COL_EN(csr_base_addr, bank, value); +} + +static void +write_csr_int_col_ctl(struct resource *csr_base_addr, u32 bank, u32 value) +{ + WRITE_CSR_INT_COL_CTL(csr_base_addr, bank, value); +} + +static void +write_csr_int_flag_and_col(struct resource *csr_base_addr, u32 bank, u32 value) +{ + WRITE_CSR_INT_FLAG_AND_COL(csr_base_addr, bank, value); +} + +static u32 +read_csr_ring_srv_arb_en(struct resource *csr_base_addr, u32 bank) +{ + return READ_CSR_RING_SRV_ARB_EN(csr_base_addr, bank); +} + +static void +write_csr_ring_srv_arb_en(struct resource *csr_base_addr, u32 bank, u32 value) +{ + WRITE_CSR_RING_SRV_ARB_EN(csr_base_addr, bank, value); +} + +void +adf_gen4_init_hw_csr_info(struct adf_hw_csr_info *csr_info) +{ + struct adf_hw_csr_ops *csr_ops = &csr_info->csr_ops; + + csr_info->arb_enable_mask = 0x1; + + csr_ops->build_csr_ring_base_addr = build_csr_ring_base_addr; + csr_ops->read_csr_ring_head = read_csr_ring_head; + csr_ops->write_csr_ring_head = write_csr_ring_head; + csr_ops->read_csr_ring_tail = read_csr_ring_tail; + csr_ops->write_csr_ring_tail = write_csr_ring_tail; + csr_ops->read_csr_e_stat = read_csr_e_stat; + csr_ops->write_csr_ring_config = write_csr_ring_config; + csr_ops->write_csr_ring_base = write_csr_ring_base; + csr_ops->write_csr_int_flag = write_csr_int_flag; + csr_ops->write_csr_int_srcsel = write_csr_int_srcsel; + csr_ops->write_csr_int_col_en = write_csr_int_col_en; + csr_ops->write_csr_int_col_ctl = write_csr_int_col_ctl; + csr_ops->write_csr_int_flag_and_col = write_csr_int_flag_and_col; + csr_ops->read_csr_ring_srv_arb_en = read_csr_ring_srv_arb_en; + csr_ops->write_csr_ring_srv_arb_en = write_csr_ring_srv_arb_en; +} +EXPORT_SYMBOL_GPL(adf_gen4_init_hw_csr_info); + +static inline void +adf_gen4_unpack_ssm_wdtimer(u64 value, u32 *upper, u32 *lower) +{ + *lower = lower_32_bits(value); + *upper = upper_32_bits(value); +} + +int +adf_gen4_set_ssm_wdtimer(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u64 timer_val_pke = ADF_SSM_WDT_PKE_DEFAULT_VALUE; + u64 timer_val = ADF_SSM_WDT_DEFAULT_VALUE; + u32 ssm_wdt_pke_high = 0; + u32 ssm_wdt_pke_low = 0; + u32 ssm_wdt_high = 0; + u32 ssm_wdt_low = 0; + struct resource *pmisc_addr; + struct adf_bar *pmisc; + int pmisc_id; + + pmisc_id = hw_data->get_misc_bar_id(hw_data); + pmisc = &GET_BARS(accel_dev)[pmisc_id]; + pmisc_addr = pmisc->virt_addr; + + /* Convert 64bit WDT timer value into 32bit values for + * mmio write to 32bit CSRs. + */ + adf_gen4_unpack_ssm_wdtimer(timer_val, &ssm_wdt_high, &ssm_wdt_low); + adf_gen4_unpack_ssm_wdtimer(timer_val_pke, + &ssm_wdt_pke_high, + &ssm_wdt_pke_low); + + /* Enable WDT for sym and dc */ + ADF_CSR_WR(pmisc_addr, ADF_SSMWDTL_OFFSET, ssm_wdt_low); + ADF_CSR_WR(pmisc_addr, ADF_SSMWDTH_OFFSET, ssm_wdt_high); + /* Enable WDT for pke */ + ADF_CSR_WR(pmisc_addr, ADF_SSMWDTPKEL_OFFSET, ssm_wdt_pke_low); + ADF_CSR_WR(pmisc_addr, ADF_SSMWDTPKEH_OFFSET, ssm_wdt_pke_high); + + return 0; +} +EXPORT_SYMBOL_GPL(adf_gen4_set_ssm_wdtimer); diff --git a/sys/dev/qat/qat_common/adf_heartbeat.c b/sys/dev/qat/qat_common/adf_heartbeat.c --- a/sys/dev/qat/qat_common/adf_heartbeat.c +++ b/sys/dev/qat/qat_common/adf_heartbeat.c @@ -68,10 +68,14 @@ unsigned int timer_val = ADF_CFG_HB_DEFAULT_VALUE; u32 clk_per_sec = 0; - if (!hw_data->get_ae_clock) + /* HB clock may be different than AE clock */ + if (hw_data->get_hb_clock) { + clk_per_sec = (u32)hw_data->get_hb_clock(hw_data); + } else if (hw_data->get_ae_clock) { + clk_per_sec = (u32)hw_data->get_ae_clock(hw_data); + } else { return EINVAL; - - clk_per_sec = (u32)hw_data->get_ae_clock(hw_data); + } /* Get Heartbeat Timer value from the configuration */ if (!adf_cfg_get_param_value(accel_dev, @@ -99,24 +103,19 @@ return 0; } -struct adf_hb_count { - u16 ae_thread[ADF_NUM_HB_CNT_PER_AE]; -}; - int adf_get_heartbeat_status(struct adf_accel_dev *accel_dev) { + struct icp_qat_fw_init_admin_hb_cnt *live_s, *last_s, *curr_s; struct adf_hw_device_data *hw_device = accel_dev->hw_device; - struct icp_qat_fw_init_admin_hb_stats *live_s = - (struct icp_qat_fw_init_admin_hb_stats *) - accel_dev->admin->virt_hb_addr; const size_t max_aes = hw_device->get_num_aes(hw_device); + const size_t hb_ctrs = hw_device->heartbeat_ctr_num; const size_t stats_size = - max_aes * sizeof(struct icp_qat_fw_init_admin_hb_stats); + max_aes * hb_ctrs * sizeof(struct icp_qat_fw_init_admin_hb_cnt); int ret = 0; size_t ae, thr; + u16 *count_s; unsigned long ae_mask = 0; - int num_threads_per_ae = ADF_NUM_HB_CNT_PER_AE; /* * Memory layout of Heartbeat @@ -127,13 +126,19 @@ * \_______________/\_______________/\________/ * ^ ^ ^ * | | | - * | | max_aes * sizeof(adf_hb_count) - * | max_aes * sizeof(icp_qat_fw_init_admin_hb_stats) - * max_aes * sizeof(icp_qat_fw_init_admin_hb_stats) + * | | max_aes * hb_ctrs * + * | | sizeof(u16) + * | | + * | max_aes * hb_ctrs * + * | sizeof(icp_qat_fw_init_admin_hb_cnt) + * | + * max_aes * hb_ctrs * + * sizeof(icp_qat_fw_init_admin_hb_cnt) */ - struct icp_qat_fw_init_admin_hb_stats *curr_s; - struct icp_qat_fw_init_admin_hb_stats *last_s = live_s + max_aes; - struct adf_hb_count *count = (struct adf_hb_count *)(last_s + max_aes); + live_s = (struct icp_qat_fw_init_admin_hb_cnt *) + accel_dev->admin->virt_hb_addr; + last_s = live_s + (max_aes * hb_ctrs); + count_s = (u16 *)(last_s + (max_aes * hb_ctrs)); curr_s = malloc(stats_size, M_QAT, M_WAITOK | M_ZERO); @@ -142,23 +147,25 @@ for_each_set_bit(ae, &ae_mask, max_aes) { - for (thr = 0; thr < num_threads_per_ae; ++thr) { - struct icp_qat_fw_init_admin_hb_cnt *curr = - &curr_s[ae].stats[thr]; - struct icp_qat_fw_init_admin_hb_cnt *prev = - &last_s[ae].stats[thr]; - u16 req = curr->req_heartbeat_cnt; - u16 resp = curr->resp_heartbeat_cnt; - u16 last = prev->resp_heartbeat_cnt; + struct icp_qat_fw_init_admin_hb_cnt *curr = + curr_s + ae * hb_ctrs; + struct icp_qat_fw_init_admin_hb_cnt *prev = + last_s + ae * hb_ctrs; + u16 *count = count_s + ae * hb_ctrs; + + for (thr = 0; thr < hb_ctrs; ++thr) { + u16 req = curr[thr].req_heartbeat_cnt; + u16 resp = curr[thr].resp_heartbeat_cnt; + u16 last = prev[thr].resp_heartbeat_cnt; if ((thr == ADF_AE_ADMIN_THREAD || req != resp) && resp == last) { - u16 retry = ++count[ae].ae_thread[thr]; + u16 retry = ++count[thr]; if (retry >= ADF_CFG_HB_COUNT_THRESHOLD) ret = EIO; } else { - count[ae].ae_thread[thr] = 0; + count[thr] = 0; } } } diff --git a/sys/dev/qat/qat_common/adf_hw_arbiter.c b/sys/dev/qat/qat_common/adf_hw_arbiter.c --- a/sys/dev/qat/qat_common/adf_hw_arbiter.c +++ b/sys/dev/qat/qat_common/adf_hw_arbiter.c @@ -97,14 +97,30 @@ void adf_update_ring_arb(struct adf_etr_ring_data *ring) { - WRITE_CSR_ARB_RINGSRVARBEN(ring->bank->csr_addr, - ring->bank->bank_number, - ring->bank->ring_mask & 0xFF); + int shift; + u32 arben, arben_tx, arben_rx, arb_mask; + struct adf_accel_dev *accel_dev = ring->bank->accel_dev; + struct adf_hw_csr_info *csr_info = &accel_dev->hw_device->csr_info; + struct adf_hw_csr_ops *csr_ops = &csr_info->csr_ops; + + arb_mask = csr_info->arb_enable_mask; + shift = hweight32(arb_mask); + + arben_tx = ring->bank->ring_mask & arb_mask; + arben_rx = (ring->bank->ring_mask >> shift) & arb_mask; + arben = arben_tx & arben_rx; + csr_ops->write_csr_ring_srv_arb_en(ring->bank->csr_addr, + ring->bank->bank_number, + arben); } void -adf_enable_ring_arb(void *csr_addr, unsigned int bank_nr, unsigned int mask) +adf_enable_ring_arb(struct adf_accel_dev *accel_dev, + void *csr_addr, + unsigned int bank_nr, + unsigned int mask) { + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(accel_dev); struct resource *csr = csr_addr; u32 arbenable; @@ -112,16 +128,20 @@ return; mutex_lock(&csr_arb_lock); - arbenable = READ_CSR_ARB_RINGSRVARBEN(csr, bank_nr); + arbenable = csr_ops->read_csr_ring_srv_arb_en(csr, bank_nr); arbenable |= mask & 0xFF; - WRITE_CSR_ARB_RINGSRVARBEN(csr, bank_nr, arbenable); + csr_ops->write_csr_ring_srv_arb_en(csr, bank_nr, arbenable); mutex_unlock(&csr_arb_lock); } void -adf_disable_ring_arb(void *csr_addr, unsigned int bank_nr, unsigned int mask) +adf_disable_ring_arb(struct adf_accel_dev *accel_dev, + void *csr_addr, + unsigned int bank_nr, + unsigned int mask) { + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(accel_dev); struct resource *csr = csr_addr; u32 arbenable; @@ -129,15 +149,16 @@ return; mutex_lock(&csr_arb_lock); - arbenable = READ_CSR_ARB_RINGSRVARBEN(csr, bank_nr); + arbenable = csr_ops->read_csr_ring_srv_arb_en(csr, bank_nr); arbenable &= ~mask & 0xFF; - WRITE_CSR_ARB_RINGSRVARBEN(csr, bank_nr, arbenable); + csr_ops->write_csr_ring_srv_arb_en(csr, bank_nr, arbenable); mutex_unlock(&csr_arb_lock); } void adf_exit_arb(struct adf_accel_dev *accel_dev) { + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(accel_dev); struct adf_hw_device_data *hw_data = accel_dev->hw_device; struct arb_info info; struct resource *csr; @@ -166,12 +187,13 @@ /* Disable arbitration on all rings */ for (i = 0; i < GET_MAX_BANKS(accel_dev); i++) - WRITE_CSR_ARB_RINGSRVARBEN(csr, i, 0); + csr_ops->write_csr_ring_srv_arb_en(csr, i, 0); } void adf_disable_arb(struct adf_accel_dev *accel_dev) { + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(accel_dev); struct resource *csr; unsigned int i; @@ -182,5 +204,5 @@ /* Disable arbitration on all rings */ for (i = 0; i < GET_MAX_BANKS(accel_dev); i++) - WRITE_CSR_ARB_RINGSRVARBEN(csr, i, 0); + csr_ops->write_csr_ring_srv_arb_en(csr, i, 0); } diff --git a/sys/dev/qat/qat_common/adf_init.c b/sys/dev/qat/qat_common/adf_init.c --- a/sys/dev/qat/qat_common/adf_init.c +++ b/sys/dev/qat/qat_common/adf_init.c @@ -213,7 +213,7 @@ unsigned int mask; u32 clk_per_sec = hw_data->get_clock_speed(hw_data); u32 timer_val = ADF_WDT_TIMER_SYM_COMP_MS * (clk_per_sec / 1000); - u32 timer_val_pke = ADF_SSM_WDT_PKE_DEFAULT_VALUE; + u32 timer_val_pke = ADF_GEN2_SSM_WDT_PKE_DEFAULT_VALUE; char timer_str[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 }; /* Get Watch Dog Timer for CySym+Comp from the configuration */ @@ -289,6 +289,12 @@ return EFAULT; } + if (hw_data->init_device && hw_data->init_device(accel_dev)) { + device_printf(GET_DEV(accel_dev), + "Failed to initialize device\n"); + return EFAULT; + } + if (hw_data->init_accel_units && hw_data->init_accel_units(accel_dev)) { device_printf(GET_DEV(accel_dev), "Failed initialize accel_units\n"); @@ -343,7 +349,8 @@ hw_data->enable_error_correction(accel_dev); - if (hw_data->enable_vf2pf_comms(accel_dev)) { + if (hw_data->enable_vf2pf_comms && + hw_data->enable_vf2pf_comms(accel_dev)) { device_printf(GET_DEV(accel_dev), "QAT: Failed to enable vf2pf comms\n"); return EFAULT; diff --git a/sys/dev/qat/qat_common/adf_isr.c b/sys/dev/qat/qat_common/adf_isr.c --- a/sys/dev/qat/qat_common/adf_isr.c +++ b/sys/dev/qat/qat_common/adf_isr.c @@ -38,6 +38,9 @@ int num_vectors = 0; u_int *vectors; + if (hw_data->set_msix_rttable) + hw_data->set_msix_rttable(accel_dev); + /* If SR-IOV is disabled, add entries for each bank */ if (!accel_dev->u1.pf.vf_info) { msix_num_entries += hw_data->num_banks; @@ -90,8 +93,11 @@ { struct adf_etr_bank_data *bank = bank_ptr; struct adf_etr_data *priv_data = bank->accel_dev->transport; + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(bank->accel_dev); - WRITE_CSR_INT_FLAG_AND_COL(bank->csr_addr, bank->bank_number, 0); + csr_ops->write_csr_int_flag_and_col(bank->csr_addr, + bank->bank_number, + 0); adf_response_handler((uintptr_t)&priv_data->banks[bank->bank_number]); return; } diff --git a/sys/dev/qat/qat_common/adf_transport.c b/sys/dev/qat/qat_common/adf_transport.c --- a/sys/dev/qat/qat_common/adf_transport.c +++ b/sys/dev/qat/qat_common/adf_transport.c @@ -73,27 +73,36 @@ static void adf_enable_ring_irq(struct adf_etr_bank_data *bank, u32 ring) { + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(bank->accel_dev); + mtx_lock(&bank->lock); bank->irq_mask |= (1 << ring); mtx_unlock(&bank->lock); - WRITE_CSR_INT_COL_EN(bank->csr_addr, bank->bank_number, bank->irq_mask); - WRITE_CSR_INT_COL_CTL(bank->csr_addr, - bank->bank_number, - bank->irq_coalesc_timer); + csr_ops->write_csr_int_col_en(bank->csr_addr, + bank->bank_number, + bank->irq_mask); + csr_ops->write_csr_int_col_ctl(bank->csr_addr, + bank->bank_number, + bank->irq_coalesc_timer); } static void adf_disable_ring_irq(struct adf_etr_bank_data *bank, u32 ring) { + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(bank->accel_dev); + mtx_lock(&bank->lock); bank->irq_mask &= ~(1 << ring); mtx_unlock(&bank->lock); - WRITE_CSR_INT_COL_EN(bank->csr_addr, bank->bank_number, bank->irq_mask); + csr_ops->write_csr_int_col_en(bank->csr_addr, + bank->bank_number, + bank->irq_mask); } int adf_send_message(struct adf_etr_ring_data *ring, u32 *msg) { + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(ring->bank->accel_dev); u32 msg_size = 0; if (atomic_add_return(1, ring->inflights) > ring->max_inflights) { @@ -110,10 +119,10 @@ ring->tail = adf_modulo(ring->tail + msg_size, ADF_RING_SIZE_MODULO(ring->ring_size)); - WRITE_CSR_RING_TAIL(ring->bank->csr_addr, - ring->bank->bank_number, - ring->ring_number, - ring->tail); + csr_ops->write_csr_ring_tail(ring->bank->csr_addr, + ring->bank->bank_number, + ring->ring_number, + ring->tail); ring->csr_tail_offset = ring->tail; mtx_unlock(&ring->lock); return 0; @@ -122,6 +131,7 @@ int adf_handle_response(struct adf_etr_ring_data *ring, u32 quota) { + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(ring->bank->accel_dev); u32 msg_counter = 0; u32 *msg = (u32 *)((uintptr_t)ring->base_addr + ring->head); @@ -139,10 +149,10 @@ msg = (u32 *)((uintptr_t)ring->base_addr + ring->head); } if (msg_counter > 0) - WRITE_CSR_RING_HEAD(ring->bank->csr_addr, - ring->bank->bank_number, - ring->ring_number, - ring->head); + csr_ops->write_csr_ring_head(ring->bank->csr_addr, + ring->bank->bank_number, + ring->ring_number, + ring->head); return msg_counter; } @@ -154,6 +164,7 @@ struct adf_etr_data *trans_data; struct adf_etr_bank_data *bank; struct adf_etr_ring_data *ring; + struct adf_hw_csr_ops *csr_ops; u32 rings_not_empty; u32 ring_num; u32 resp_total = 0; @@ -168,12 +179,14 @@ return EINVAL; } + csr_ops = GET_CSR_OPS(accel_dev); trans_data = accel_dev->transport; bank = &trans_data->banks[bank_num]; mtx_lock(&bank->lock); /* Read the ring status CSR to determine which rings are empty. */ - rings_not_empty = READ_CSR_E_STAT(bank->csr_addr, bank->bank_number); + rings_not_empty = + csr_ops->read_csr_e_stat(bank->csr_addr, bank->bank_number); /* Complement to find which rings have data to be processed. */ rings_not_empty = (~rings_not_empty) & bank->ring_mask; @@ -265,25 +278,27 @@ static void adf_configure_tx_ring(struct adf_etr_ring_data *ring) { + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(ring->bank->accel_dev); u32 ring_config = BUILD_RING_CONFIG(ring->ring_size); - WRITE_CSR_RING_CONFIG(ring->bank->csr_addr, - ring->bank->bank_number, - ring->ring_number, - ring_config); + csr_ops->write_csr_ring_config(ring->bank->csr_addr, + ring->bank->bank_number, + ring->ring_number, + ring_config); } static void adf_configure_rx_ring(struct adf_etr_ring_data *ring) { + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(ring->bank->accel_dev); u32 ring_config = BUILD_RESP_RING_CONFIG(ring->ring_size, ADF_RING_NEAR_WATERMARK_512, ADF_RING_NEAR_WATERMARK_0); - WRITE_CSR_RING_CONFIG(ring->bank->csr_addr, - ring->bank->bank_number, - ring->ring_number, - ring_config); + csr_ops->write_csr_ring_config(ring->bank->csr_addr, + ring->bank->bank_number, + ring->ring_number, + ring_config); } static int @@ -292,6 +307,7 @@ struct adf_etr_bank_data *bank = ring->bank; struct adf_accel_dev *accel_dev = bank->accel_dev; struct adf_hw_device_data *hw_data = accel_dev->hw_device; + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(accel_dev); u64 ring_base; u32 ring_size_bytes = ADF_SIZE_TO_RING_SIZE_IN_BYTES(ring->ring_size); @@ -323,11 +339,12 @@ else adf_configure_rx_ring(ring); - ring_base = BUILD_RING_BASE_ADDR(ring->dma_addr, ring->ring_size); - WRITE_CSR_RING_BASE(ring->bank->csr_addr, - ring->bank->bank_number, - ring->ring_number, - ring_base); + ring_base = + csr_ops->build_csr_ring_base_addr(ring->dma_addr, ring->ring_size); + csr_ops->write_csr_ring_base(ring->bank->csr_addr, + ring->bank->bank_number, + ring->ring_number, + ring_base); mtx_init(&ring->lock, "adf bank", NULL, MTX_DEF); return 0; } @@ -443,19 +460,20 @@ adf_remove_ring(struct adf_etr_ring_data *ring) { struct adf_etr_bank_data *bank = ring->bank; + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(bank->accel_dev); /* Disable interrupts for the given ring */ adf_disable_ring_irq(bank, ring->ring_number); /* Clear PCI config space */ - WRITE_CSR_RING_CONFIG(bank->csr_addr, - bank->bank_number, - ring->ring_number, - 0); - WRITE_CSR_RING_BASE(bank->csr_addr, - bank->bank_number, - ring->ring_number, - 0); + csr_ops->write_csr_ring_config(bank->csr_addr, + bank->bank_number, + ring->ring_number, + 0); + csr_ops->write_csr_ring_base(bank->csr_addr, + bank->bank_number, + ring->ring_number, + 0); adf_ring_debugfs_rm(ring); adf_unreserve_ring(bank, ring->ring_number); /* Disable HW arbitration for the given ring */ @@ -468,10 +486,12 @@ { struct adf_accel_dev *accel_dev = bank->accel_dev; struct adf_hw_device_data *hw_data = accel_dev->hw_device; + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(accel_dev); u8 num_rings_per_bank = hw_data->num_rings_per_bank; u32 empty_rings, i; - empty_rings = READ_CSR_E_STAT(bank->csr_addr, bank->bank_number); + empty_rings = + csr_ops->read_csr_e_stat(bank->csr_addr, bank->bank_number); empty_rings = ~empty_rings & bank->irq_mask; for (i = 0; i < num_rings_per_bank; ++i) { @@ -484,12 +504,13 @@ adf_response_handler(uintptr_t bank_addr) { struct adf_etr_bank_data *bank = (void *)bank_addr; + struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(bank->accel_dev); /* Handle all the responses and re-enable IRQs */ adf_ring_response_handler(bank); - WRITE_CSR_INT_FLAG_AND_COL(bank->csr_addr, - bank->bank_number, - bank->irq_mask); + csr_ops->write_csr_int_flag_and_col(bank->csr_addr, + bank->bank_number, + bank->irq_mask); } static inline int @@ -548,10 +569,12 @@ struct resource *csr_addr) { struct adf_hw_device_data *hw_data = accel_dev->hw_device; + struct adf_hw_csr_ops *csr_ops = &hw_data->csr_info.csr_ops; struct adf_etr_ring_data *ring; struct adf_etr_ring_data *tx_ring; u32 i, coalesc_enabled = 0; u8 num_rings_per_bank = hw_data->num_rings_per_bank; + u32 irq_mask = BIT(num_rings_per_bank) - 1; u32 size = 0; explicit_bzero(bank, sizeof(*bank)); @@ -580,8 +603,8 @@ bank->irq_coalesc_timer = ADF_COALESCING_MIN_TIME; for (i = 0; i < num_rings_per_bank; i++) { - WRITE_CSR_RING_CONFIG(csr_addr, bank_num, i, 0); - WRITE_CSR_RING_BASE(csr_addr, bank_num, i, 0); + csr_ops->write_csr_ring_config(csr_addr, bank_num, i, 0); + csr_ops->write_csr_ring_base(csr_addr, bank_num, i, 0); ring = &bank->rings[i]; if (hw_data->tx_rings_mask & (1 << i)) { ring->inflights = @@ -605,8 +628,8 @@ goto err; } - WRITE_CSR_INT_FLAG(csr_addr, bank_num, ADF_BANK_INT_FLAG_CLEAR_MASK); - WRITE_CSR_INT_SRCSEL(csr_addr, bank_num); + csr_ops->write_csr_int_flag(csr_addr, bank_num, irq_mask); + csr_ops->write_csr_int_srcsel(csr_addr, bank_num); return 0; err: for (i = 0; i < num_rings_per_bank; i++) { diff --git a/sys/dev/qat/qat_common/qat_hal.c b/sys/dev/qat/qat_common/qat_hal.c --- a/sys/dev/qat/qat_common/qat_hal.c +++ b/sys/dev/qat/qat_common/qat_hal.c @@ -75,6 +75,29 @@ 0x0D81581C010ull, 0x0E000010000ull, 0x0E000010000ull, }; +static const uint64_t inst_CPM2X[] = { + 0x0F0000C0000ull, 0x0D802C00011ull, 0x0F0000C0001ull, 0x0FC066C0001ull, + 0x0F0000C0300ull, 0x0F0000C0300ull, 0x0F0000C0300ull, 0x0F000500300ull, + 0x0A0610C0000ull, 0x0BAC0000301ull, 0x0D802000101ull, 0x0A0580C0000ull, + 0x0A0581C0000ull, 0x0A0582C0000ull, 0x0A0583C0000ull, 0x0A0584C0000ull, + 0x0A0585C0000ull, 0x0A0586C0000ull, 0x0A0587C0000ull, 0x0A0588C0000ull, + 0x0A0589C0000ull, 0x0A058AC0000ull, 0x0A058BC0000ull, 0x0A058CC0000ull, + 0x0A058DC0000ull, 0x0A058EC0000ull, 0x0A058FC0000ull, 0x0A05C0C0000ull, + 0x0A05C1C0000ull, 0x0A05C2C0000ull, 0x0A05C3C0000ull, 0x0A05C4C0000ull, + 0x0A05C5C0000ull, 0x0A05C6C0000ull, 0x0A05C7C0000ull, 0x0A05C8C0000ull, + 0x0A05C9C0000ull, 0x0A05CAC0000ull, 0x0A05CBC0000ull, 0x0A05CCC0000ull, + 0x0A05CDC0000ull, 0x0A05CEC0000ull, 0x0A05CFC0000ull, 0x0A0400C0000ull, + 0x0B0400C0000ull, 0x0A0401C0000ull, 0x0B0401C0000ull, 0x0A0402C0000ull, + 0x0B0402C0000ull, 0x0A0403C0000ull, 0x0B0403C0000ull, 0x0A0404C0000ull, + 0x0B0404C0000ull, 0x0A0405C0000ull, 0x0B0405C0000ull, 0x0A0406C0000ull, + 0x0B0406C0000ull, 0x0A0407C0000ull, 0x0B0407C0000ull, 0x0A0408C0000ull, + 0x0B0408C0000ull, 0x0A0409C0000ull, 0x0B0409C0000ull, 0x0A040AC0000ull, + 0x0B040AC0000ull, 0x0A040BC0000ull, 0x0B040BC0000ull, 0x0A040CC0000ull, + 0x0B040CC0000ull, 0x0A040DC0000ull, 0x0B040DC0000ull, 0x0A040EC0000ull, + 0x0B040EC0000ull, 0x0A040FC0000ull, 0x0B040FC0000ull, 0x0D81341C010ull, + 0x0E000000001ull, 0x0E000010000ull, +}; + void qat_hal_set_live_ctx(struct icp_qat_fw_loader_handle *handle, unsigned char ae, @@ -206,6 +229,11 @@ { unsigned int csr, new_csr; + if (IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { + pr_err("QAT: No next neigh for CPM2X\n"); + return EINVAL; + } + qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &csr); csr &= IGNORE_W1C_MASK; @@ -339,6 +367,21 @@ return reg_addr; } +static u32 +qat_hal_get_ae_mask_gen4(struct icp_qat_fw_loader_handle *handle) +{ + u32 tg = 0, ae; + u32 valid_ae_mask = 0; + + for (ae = 0; ae < handle->hal_handle->ae_max_num; ae++) { + if (handle->hal_handle->ae_mask & (1 << ae)) { + tg = ae / 4; + valid_ae_mask |= (1 << (tg * 2)); + } + } + return valid_ae_mask; +} + void qat_hal_reset(struct icp_qat_fw_loader_handle *handle) { @@ -353,15 +396,26 @@ ae_reset_csr[1] = ICP_RESET_CPP1; if (handle->hal_handle->ae_mask > 0xffff) ++cpp_num; + } else if (IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { + ae_reset_csr[0] = ICP_RESET_CPP0; } else { ae_reset_csr[0] = ICP_RESET; } for (i = 0; i < cpp_num; i++) { if (i == 0) { - valid_ae_mask = handle->hal_handle->ae_mask & 0xFFFF; - valid_slice_mask = - handle->hal_handle->slice_mask & 0x3F; + if (IS_QAT_GEN4( + pci_get_device(GET_DEV(handle->accel_dev)))) { + valid_ae_mask = + qat_hal_get_ae_mask_gen4(handle); + valid_slice_mask = + handle->hal_handle->slice_mask; + } else { + valid_ae_mask = + handle->hal_handle->ae_mask & 0xFFFF; + valid_slice_mask = + handle->hal_handle->slice_mask & 0x3F; + } } else { valid_ae_mask = (handle->hal_handle->ae_mask >> AES_PER_CPP) & @@ -509,7 +563,7 @@ unsigned long ae_mask = handle->hal_handle->ae_mask; misc_ctl_csr = - (IS_QAT_GEN3(pci_get_device(GET_DEV(handle->accel_dev)))) ? + (IS_QAT_GEN3_OR_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) ? MISC_CONTROL_C4XXX : MISC_CONTROL; /* stop the timestamp timers */ @@ -586,6 +640,9 @@ clk_csr[1] = ICP_GLOBAL_CLK_ENABLE_CPP1; if (handle->hal_handle->ae_mask > 0xffff) ++cpp_num; + } else if (IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { + ae_reset_csr[0] = ICP_RESET_CPP0; + clk_csr[0] = ICP_GLOBAL_CLK_ENABLE_CPP0; } else { ae_reset_csr[0] = ICP_RESET; clk_csr[0] = ICP_GLOBAL_CLK_ENABLE; @@ -593,9 +650,18 @@ for (i = 0; i < cpp_num; i++) { if (i == 0) { - valid_ae_mask = handle->hal_handle->ae_mask & 0xFFFF; - valid_slice_mask = - handle->hal_handle->slice_mask & 0x3F; + if (IS_QAT_GEN4( + pci_get_device(GET_DEV(handle->accel_dev)))) { + valid_ae_mask = + qat_hal_get_ae_mask_gen4(handle); + valid_slice_mask = + handle->hal_handle->slice_mask; + } else { + valid_ae_mask = + handle->hal_handle->ae_mask & 0xFFFF; + valid_slice_mask = + handle->hal_handle->slice_mask & 0x3F; + } } else { valid_ae_mask = (handle->hal_handle->ae_mask >> AES_PER_CPP) & @@ -714,7 +780,24 @@ const uint64_t *uword) { unsigned int ustore_addr; - unsigned int i; + unsigned int i, ae_in_group; + + if (IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { + ae_in_group = ae / 4 * 4; + + for (i = 0; i < AE_TG_NUM_CPM2X; i++) { + if (ae_in_group + i == ae) + continue; + if (ae_in_group + i >= handle->hal_handle->ae_max_num) + break; + if (qat_hal_check_ae_active(handle, ae_in_group + i)) { + pr_err( + "ae%d in T_group is active, cannot write to ustore!\n", + ae_in_group + i); + return; + } + } + } qat_hal_rd_ae_csr(handle, ae, USTORE_ADDRESS, &ustore_addr); uaddr |= UA_ECS; @@ -826,10 +909,25 @@ qat_hal_wr_ae_csr(handle, ae, AE_MISC_CONTROL, csr_val); qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &csr_val); csr_val &= IGNORE_W1C_MASK; - csr_val |= CE_NN_MODE; + if (!IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { + csr_val |= CE_NN_MODE; + } qat_hal_wr_ae_csr(handle, ae, CTX_ENABLES, csr_val); - qat_hal_wr_uwords( - handle, ae, 0, ARRAY_SIZE(inst), (const uint64_t *)inst); + + if (IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { + if (ae % 4 == 0) + qat_hal_wr_uwords(handle, + ae, + 0, + ARRAY_SIZE(inst_CPM2X), + (const uint64_t *)inst_CPM2X); + } else { + qat_hal_wr_uwords(handle, + ae, + 0, + ARRAY_SIZE(inst), + (const uint64_t *)inst); + } qat_hal_wr_indr_csr(handle, ae, ctx_mask, @@ -971,6 +1069,7 @@ malloc(sizeof(*handle->hal_handle), M_QAT, M_WAITOK | M_ZERO); handle->hal_handle->revision_id = accel_dev->accel_pci_dev.revid; handle->hal_handle->ae_mask = hw_data->ae_mask; + handle->hal_handle->admin_ae_mask = hw_data->admin_ae_mask; handle->hal_handle->slice_mask = hw_data->accel_mask; handle->cfg_ae_mask = 0xFFFFFFFF; /* create AE objects */ @@ -1038,17 +1137,23 @@ free(handle, M_QAT); } -void -qat_hal_start(struct icp_qat_fw_loader_handle *handle, - unsigned char ae, - unsigned int ctx_mask) +int +qat_hal_start(struct icp_qat_fw_loader_handle *handle) { + unsigned char ae = 0; int retry = 0; unsigned int fcu_sts = 0; unsigned int fcu_ctl_csr, fcu_sts_csr; + unsigned long ae_mask = handle->hal_handle->ae_mask; + u32 ae_ctr = 0; if (handle->fw_auth) { - if (IS_QAT_GEN3(pci_get_device(GET_DEV(handle->accel_dev)))) { + for_each_set_bit(ae, &ae_mask, handle->hal_handle->ae_max_num) + { + ae_ctr++; + } + if (IS_QAT_GEN3_OR_GEN4( + pci_get_device(GET_DEV(handle->accel_dev)))) { fcu_ctl_csr = FCU_CONTROL_C4XXX; fcu_sts_csr = FCU_STATUS_C4XXX; @@ -1061,17 +1166,27 @@ pause_ms("adfstop", FW_AUTH_WAIT_PERIOD); fcu_sts = GET_FCU_CSR(handle, fcu_sts_csr); if (((fcu_sts >> FCU_STS_DONE_POS) & 0x1)) - return; + return ae_ctr; } while (retry++ < FW_AUTH_MAX_RETRY); pr_err("QAT: start error (AE 0x%x FCU_STS = 0x%x)\n", ae, fcu_sts); + return 0; } else { - qat_hal_put_wakeup_event(handle, - ae, - (~ctx_mask) & ICP_QAT_UCLO_AE_ALL_CTX, - 0x10000); - qat_hal_enable_ctx(handle, ae, ctx_mask); + for_each_set_bit(ae, &ae_mask, handle->hal_handle->ae_max_num) + { + qat_hal_put_wakeup_event(handle, + ae, + 0, + IS_QAT_GEN4( + pci_get_device(GET_DEV( + handle->accel_dev))) ? + 0x80000000 : + 0x10000); + qat_hal_enable_ctx(handle, ae, ICP_QAT_UCLO_AE_ALL_CTX); + ae_ctr++; + } + return ae_ctr; } } @@ -1193,7 +1308,7 @@ handle, ae, ctx, INDIRECT_LM_ADDR_0_BYTE_INDEX, &ind_lm_addr_byte0); qat_hal_rd_indr_csr( handle, ae, ctx, INDIRECT_LM_ADDR_1_BYTE_INDEX, &ind_lm_addr_byte1); - if (IS_QAT_GEN3(pci_get_device(GET_DEV(handle->accel_dev)))) { + if (IS_QAT_GEN3_OR_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { qat_hal_rd_indr_csr( handle, ae, ctx, LM_ADDR_2_INDIRECT, &ind_lm_addr2); qat_hal_rd_indr_csr( @@ -1286,7 +1401,7 @@ (1 << ctx), INDIRECT_LM_ADDR_1_BYTE_INDEX, ind_lm_addr_byte1); - if (IS_QAT_GEN3(pci_get_device(GET_DEV(handle->accel_dev)))) { + if (IS_QAT_GEN3_OR_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { qat_hal_wr_indr_csr( handle, ae, (1 << ctx), LM_ADDR_2_INDIRECT, ind_lm_addr2); qat_hal_wr_indr_csr( @@ -1832,6 +1947,11 @@ int stat = 0; unsigned char ctx; + if (IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { + pr_err("QAT: No next neigh for CPM2X\n"); + return EINVAL; + } + if (ctx_mask == 0) return EINVAL; diff --git a/sys/dev/qat/qat_common/qat_uclo.c b/sys/dev/qat/qat_common/qat_uclo.c --- a/sys/dev/qat/qat_common/qat_uclo.c +++ b/sys/dev/qat/qat_common/qat_uclo.c @@ -46,9 +46,13 @@ encap_image->img_ptr->ctx_assigned; ae_data->shareable_ustore = ICP_QAT_SHARED_USTORE_MODE(encap_image->img_ptr->ae_mode); - ae_data->eff_ustore_size = ae_data->shareable_ustore ? - (obj_handle->ustore_phy_size << 1) : - obj_handle->ustore_phy_size; + if (obj_handle->prod_type == ICP_QAT_AC_4XXX_A_DEV_TYPE) + ae_data->eff_ustore_size = obj_handle->ustore_phy_size; + else { + ae_data->eff_ustore_size = ae_data->shareable_ustore ? + (obj_handle->ustore_phy_size << 1) : + obj_handle->ustore_phy_size; + } } else { ae_slice->ctx_mask_assigned = 0; } @@ -324,9 +328,13 @@ { struct icp_qat_uclo_objhandle *obj_handle = handle->obj_handle; unsigned int ae; + unsigned int lmem; + + lmem = IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev))) ? + ICP_QAT_UCLO_MAX_LMEM_REG_2X : + ICP_QAT_UCLO_MAX_LMEM_REG; - if (qat_uclo_fetch_initmem_ae( - handle, init_mem, ICP_QAT_UCLO_MAX_LMEM_REG, &ae)) + if (qat_uclo_fetch_initmem_ae(handle, init_mem, lmem, &ae)) return EINVAL; if (qat_uclo_create_batch_init_list( handle, init_mem, ae, &obj_handle->lm_init_tab[ae])) @@ -411,6 +419,8 @@ { unsigned long cfg_ae_mask = handle->cfg_ae_mask; unsigned long ae_assigned = uof_image->ae_assigned; + const bool gen4 = + IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev))); if (!test_bit(ae, &cfg_ae_mask)) continue; @@ -418,7 +428,8 @@ if (!test_bit(ae, &ae_assigned)) continue; - if (obj_handle->ae_data[ae].shareable_ustore && (ae & 1)) { + if (obj_handle->ae_data[ae].shareable_ustore && (ae & 1) && + !gen4) { qat_hal_get_scs_neigh_ae(ae, &neigh_ae); if (test_bit(neigh_ae, &ae_assigned)) @@ -427,7 +438,7 @@ ustore_size = obj_handle->ae_data[ae].eff_ustore_size; patt_pos = page->beg_addr_p + page->micro_words_num; - if (obj_handle->ae_data[ae].shareable_ustore) { + if (obj_handle->ae_data[ae].shareable_ustore && !gen4) { qat_hal_get_scs_neigh_ae(ae, &neigh_ae); if (init[ae] == 0 && page->beg_addr_p != 0) { qat_hal_wr_coalesce_uwords(handle, @@ -445,6 +456,9 @@ init[ae] = 1; init[neigh_ae] = 1; } else { + if (gen4 && (ae % 4 != 0)) + continue; + qat_hal_wr_uwords(handle, (unsigned char)ae, 0, @@ -727,6 +741,61 @@ return 0; } +static int +UcLo_checkTGroupList2X(struct icp_qat_fw_loader_handle *handle) +{ + int i; + unsigned int swAe = 0; + unsigned int ii, jj; + struct icp_qat_uclo_aedata *ae_data0, *ae_datax; + struct icp_qat_uclo_objhandle *obj_handle = handle->obj_handle; + + for (i = 0; i < obj_handle->uimage_num; i++) { + struct icp_qat_uof_image *image = + obj_handle->ae_uimage[i].img_ptr; + if (image->numpages > 1) { + pr_err( + "Only 1 page is allowed in a UOF for CPM2X; We found %d in %s\n", + image->numpages, + qat_uclo_get_string(&obj_handle->str_table, + image->img_name)); + return EINVAL; + } + } + + for (swAe = 0; + (swAe < obj_handle->ae_num) && (swAe < ICP_QAT_UCLO_MAX_AE); + swAe += AE_TG_NUM_CPM2X) { + if (!qat_hal_check_ae_active(handle, swAe)) { + continue; + } + + for (ii = swAe; ii < (swAe + AE_TG_NUM_CPM2X); ii++) { + ae_data0 = &obj_handle->ae_data[ii]; + if (ae_data0->slice_num != 1) // not assigned + continue; + + for (jj = ii + 1; jj < (swAe + AE_TG_NUM_CPM2X); jj++) { + ae_datax = &obj_handle->ae_data[jj]; + if (ae_datax->slice_num != 1) // not assigned + continue; + if (ae_data0->ae_slices[0] + .encap_image->img_ptr != + ae_datax->ae_slices[0] + .encap_image->img_ptr) { + pr_err("Only 1 list is allowed in a "); + pr_err("Tgroup for CPM2X;\n"); + pr_err("ME%d, %d is assigned", ii, jj); + pr_err(" different list files\n"); + return EINVAL; + } + } + } + } + + return 0; +} + static int qat_uclo_map_ae(struct icp_qat_fw_loader_handle *handle, int max_ae) { @@ -752,6 +821,11 @@ return EINVAL; } } + if (IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { + if (UcLo_checkTGroupList2X(handle)) { + return EINVAL; + } + } if (!mflag) { pr_err("QAT: uimage uses AE not set"); return EINVAL; @@ -817,6 +891,9 @@ return ICP_QAT_AC_200XX_DEV_TYPE; case ADF_C4XXX_PCI_DEVICE_ID: return ICP_QAT_AC_C4XXX_DEV_TYPE; + case ADF_4XXX_PCI_DEVICE_ID: + case ADF_401XX_PCI_DEVICE_ID: + return ICP_QAT_AC_4XXX_A_DEV_TYPE; default: pr_err("QAT: unsupported device 0x%x\n", pci_get_device(GET_DEV(handle->accel_dev))); @@ -1001,11 +1078,13 @@ ae_mode = (char)ICP_QAT_SHARED_USTORE_MODE(uof_image->ae_mode); qat_hal_set_ae_scs_mode(handle, ae, ae_mode); - nn_mode = ICP_QAT_NN_MODE(uof_image->ae_mode); + if (!IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { + nn_mode = ICP_QAT_NN_MODE(uof_image->ae_mode); - if (qat_hal_set_ae_nn_mode(handle, ae, nn_mode)) { - pr_err("QAT: qat_hal_set_ae_nn_mode error\n"); - return EFAULT; + if (qat_hal_set_ae_nn_mode(handle, ae, nn_mode)) { + pr_err("QAT: qat_hal_set_ae_nn_mode error\n"); + return EFAULT; + } } ae_mode = (char)ICP_QAT_LOC_MEM0_MODE(uof_image->ae_mode); if (qat_hal_set_ae_lm_mode(handle, ae, ICP_LMEM0, ae_mode)) { @@ -1017,7 +1096,7 @@ pr_err("QAT: qat_hal_set_ae_lm_mode LMEM1 error\n"); return EFAULT; } - if (obj_handle->prod_type == ICP_QAT_AC_C4XXX_DEV_TYPE) { + if (IS_QAT_GEN3_OR_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { ae_mode = (char)ICP_QAT_LOC_MEM2_MODE(uof_image->ae_mode); if (qat_hal_set_ae_lm_mode(handle, ae, ICP_LMEM2, ae_mode)) { pr_err("QAT: qat_hal_set_ae_lm_mode LMEM2 error\n"); @@ -1168,12 +1247,14 @@ } static void -qat_uclo_map_simg(struct icp_qat_suof_handle *suof_handle, +qat_uclo_map_simg(struct icp_qat_fw_loader_handle *handle, struct icp_qat_suof_img_hdr *suof_img_hdr, struct icp_qat_suof_chunk_hdr *suof_chunk_hdr) { + struct icp_qat_suof_handle *suof_handle = handle->sobj_handle; const struct icp_qat_simg_ae_mode *ae_mode; struct icp_qat_suof_objhdr *suof_objhdr; + unsigned int device_id = pci_get_device(GET_DEV(handle->accel_dev)); suof_img_hdr->simg_buf = (suof_handle->suof_buf + suof_chunk_hdr->offset + @@ -1187,9 +1268,10 @@ suof_img_hdr->css_key = (suof_img_hdr->css_header + sizeof(struct icp_qat_css_hdr)); suof_img_hdr->css_signature = suof_img_hdr->css_key + - ICP_QAT_CSS_FWSK_MODULUS_LEN + ICP_QAT_CSS_FWSK_EXPONENT_LEN; + ICP_QAT_CSS_FWSK_MODULUS_LEN(device_id) + + ICP_QAT_CSS_FWSK_EXPONENT_LEN(device_id); suof_img_hdr->css_simg = - suof_img_hdr->css_signature + ICP_QAT_CSS_SIGNATURE_LEN; + suof_img_hdr->css_signature + ICP_QAT_CSS_SIGNATURE_LEN(device_id); ae_mode = (const struct icp_qat_simg_ae_mode *)(suof_img_hdr->css_simg); suof_img_hdr->ae_mask = ae_mode->ae_mask; @@ -1277,7 +1359,8 @@ struct icp_qat_suof_handle *suof_handle = handle->sobj_handle; struct icp_qat_suof_chunk_hdr *suof_chunk_hdr = NULL; struct icp_qat_suof_img_hdr *suof_img_hdr = NULL; - int ret = 0, ae0_img = ICP_QAT_UCLO_MAX_AE; + int ret = 0, ae0_img = ICP_QAT_UCLO_MAX_AE, + aeMax_img = ICP_QAT_UCLO_MAX_AE; unsigned int i = 0; struct icp_qat_suof_img_hdr img_header; @@ -1305,7 +1388,7 @@ } for (i = 0; i < suof_handle->img_table.num_simgs; i++) { - qat_uclo_map_simg(handle->sobj_handle, + qat_uclo_map_simg(handle, &suof_img_hdr[i], &suof_chunk_hdr[1 + i]); ret = qat_uclo_check_simg_compat(handle, &suof_img_hdr[i]); @@ -1315,9 +1398,29 @@ if ((suof_img_hdr[i].ae_mask & 0x1) != 0) ae0_img = i; } - qat_uclo_tail_img(suof_img_hdr, - ae0_img, - suof_handle->img_table.num_simgs); + + if (!IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { + qat_uclo_tail_img(suof_img_hdr, + ae0_img, + suof_handle->img_table.num_simgs); + } else { + if (suof_handle->img_table.num_simgs == 1) + return 0; + qat_uclo_tail_img(suof_img_hdr, + ae0_img, + suof_handle->img_table.num_simgs - 1); + for (i = 0; i < suof_handle->img_table.num_simgs; i++) { + if ((suof_img_hdr[i].ae_mask & + (0x1 << (handle->hal_handle->ae_max_num - 1))) != + 0) { + aeMax_img = i; + break; + } + } + qat_uclo_tail_img(suof_img_hdr, + aeMax_img, + suof_handle->img_table.num_simgs); + } return 0; } @@ -1335,7 +1438,7 @@ bus_addr = ADD_ADDR(desc->css_hdr_high, desc->css_hdr_low) - sizeof(struct icp_qat_auth_chunk); - if (IS_QAT_GEN3(pci_get_device(GET_DEV(handle->accel_dev)))) { + if (IS_QAT_GEN3_OR_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { fcu_ctl_csr = FCU_CONTROL_C4XXX; fcu_sts_csr = FCU_STATUS_C4XXX; fcu_dram_hi_csr = FCU_DRAM_ADDR_HI_C4XXX; @@ -1372,6 +1475,103 @@ return EINVAL; } +static int +qat_uclo_is_broadcast(struct icp_qat_fw_loader_handle *handle, int imgid) +{ + struct icp_qat_suof_handle *sobj_handle; + + if (!IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) + return 0; + + sobj_handle = (struct icp_qat_suof_handle *)handle->sobj_handle; + if (handle->hal_handle->admin_ae_mask & + sobj_handle->img_table.simg_hdr[imgid].ae_mask) + return 0; + + return 1; +} + +static int +qat_uclo_broadcast_load_fw(struct icp_qat_fw_loader_handle *handle, + struct icp_qat_fw_auth_desc *desc) +{ + unsigned int i = 0; + unsigned int fcuSts = 0, fcuAeBroadcastMask = 0; + unsigned int retry = 0; + unsigned int fcuStsCsr = 0; + unsigned int fcuCtlCsr = 0; + unsigned int loadedAes = 0; + unsigned int device_id = pci_get_device(GET_DEV(handle->accel_dev)); + + if (IS_QAT_GEN4(device_id)) { + fcuCtlCsr = FCU_CONTROL_4XXX; + fcuStsCsr = FCU_STATUS_4XXX; + } else { + pr_err("Uclo_BroadcastLoadFW only applicable for CPM20\n"); + return EINVAL; + } + + for (i = 0; i < ICP_QAT_UCLO_MAX_AE; i++) { + if (!test_bit(i, (unsigned long *)&handle->hal_handle->ae_mask)) + continue; + + if (qat_hal_check_ae_active(handle, (unsigned char)i)) { + pr_err( + "Uclo_BroadcastLoadFW error (invalid AE status)\n"); + return EINVAL; + } + + if ((desc->ae_mask >> i) & 0x1) { + fcuAeBroadcastMask |= 1 << i; + } + } + + if (fcuAeBroadcastMask) { + retry = 0; + SET_FCU_CSR(handle, + FCU_ME_BROADCAST_MASK_TYPE, + fcuAeBroadcastMask); + SET_FCU_CSR(handle, fcuCtlCsr, FCU_CTRL_CMD_LOAD); + do { + msleep(FW_AUTH_WAIT_PERIOD); + fcuSts = GET_FCU_CSR(handle, fcuStsCsr); + + if ((fcuSts & FCU_AUTH_STS_MASK) == FCU_STS_LOAD_FAIL) { + pr_err( + "Uclo_BroadcastLoadFW fail (fcu_status = 0x%x)\n", + fcuSts & FCU_AUTH_STS_MASK); + return EINVAL; + } else if ((fcuSts & FCU_AUTH_STS_MASK) == + FCU_STS_LOAD_DONE) { + if (IS_QAT_GEN4(device_id)) + loadedAes = + GET_FCU_CSR(handle, + FCU_AE_LOADED_4XXX); + else + loadedAes = + (fcuSts >> FCU_LOADED_AE_POS); + + if ((loadedAes & fcuAeBroadcastMask) == + fcuAeBroadcastMask) + break; + } else if ((fcuSts & FCU_AUTH_STS_MASK) == + FCU_STS_VERI_DONE) { + SET_FCU_CSR(handle, + fcuCtlCsr, + FCU_CTRL_CMD_LOAD); + } + } while (retry++ < FW_BROADCAST_MAX_RETRY); + if (retry > FW_BROADCAST_MAX_RETRY) { + pr_err( + "Uclo_BroadcastLoadFW fail(fcu_status = 0x%x),retry = %d\n", + fcuSts & FCU_AUTH_STS_MASK, + retry); + return EINVAL; + } + } + return 0; +} + static int qat_uclo_simg_alloc(struct icp_qat_fw_loader_handle *handle, struct icp_firml_dram_desc *dram_desc, @@ -1417,14 +1617,16 @@ struct icp_qat_auth_chunk *auth_chunk; u64 virt_addr, bus_addr, virt_base; unsigned int length, simg_offset = sizeof(*auth_chunk); + unsigned int device_id = pci_get_device(GET_DEV(handle->accel_dev)); - if (size > (ICP_QAT_AE_IMG_OFFSET + ICP_QAT_CSS_MAX_IMAGE_LEN)) { + if (size > + (ICP_QAT_AE_IMG_OFFSET(device_id) + ICP_QAT_CSS_MAX_IMAGE_LEN)) { pr_err("QAT: error, input image size overflow %d\n", size); return EINVAL; } length = (css_hdr->fw_type == CSS_AE_FIRMWARE) ? - ICP_QAT_CSS_AE_SIMG_LEN + simg_offset : - size + ICP_QAT_CSS_FWSK_PAD_LEN + simg_offset; + ICP_QAT_CSS_AE_SIMG_LEN(device_id) + simg_offset : + size + ICP_QAT_CSS_FWSK_PAD_LEN(device_id) + simg_offset; if (qat_uclo_simg_alloc(handle, img_desc, length)) { pr_err("QAT: error, allocate continuous dram fail\n"); return -ENOMEM; @@ -1451,42 +1653,43 @@ memcpy((void *)(uintptr_t)virt_addr, (const void *)(image + sizeof(*css_hdr)), - ICP_QAT_CSS_FWSK_MODULUS_LEN); + ICP_QAT_CSS_FWSK_MODULUS_LEN(device_id)); /* padding */ - explicit_bzero((void *)(uintptr_t)(virt_addr + - ICP_QAT_CSS_FWSK_MODULUS_LEN), - ICP_QAT_CSS_FWSK_PAD_LEN); + explicit_bzero((void *)(uintptr_t)( + virt_addr + ICP_QAT_CSS_FWSK_MODULUS_LEN(device_id)), + ICP_QAT_CSS_FWSK_PAD_LEN(device_id)); /* exponent */ - memcpy((void *)(uintptr_t)(virt_addr + ICP_QAT_CSS_FWSK_MODULUS_LEN + - ICP_QAT_CSS_FWSK_PAD_LEN), + memcpy((void *)(uintptr_t)(virt_addr + + ICP_QAT_CSS_FWSK_MODULUS_LEN(device_id) + + ICP_QAT_CSS_FWSK_PAD_LEN(device_id)), (const void *)(image + sizeof(*css_hdr) + - ICP_QAT_CSS_FWSK_MODULUS_LEN), + ICP_QAT_CSS_FWSK_MODULUS_LEN(device_id)), sizeof(unsigned int)); /* signature */ bus_addr = ADD_ADDR(auth_desc->fwsk_pub_high, auth_desc->fwsk_pub_low) + - ICP_QAT_CSS_FWSK_PUB_LEN; - virt_addr = virt_addr + ICP_QAT_CSS_FWSK_PUB_LEN; + ICP_QAT_CSS_FWSK_PUB_LEN(device_id); + virt_addr = virt_addr + ICP_QAT_CSS_FWSK_PUB_LEN(device_id); auth_desc->signature_high = (unsigned int)(bus_addr >> BITS_IN_DWORD); auth_desc->signature_low = (unsigned int)bus_addr; memcpy((void *)(uintptr_t)virt_addr, (const void *)(image + sizeof(*css_hdr) + - ICP_QAT_CSS_FWSK_MODULUS_LEN + - ICP_QAT_CSS_FWSK_EXPONENT_LEN), - ICP_QAT_CSS_SIGNATURE_LEN); + ICP_QAT_CSS_FWSK_MODULUS_LEN(device_id) + + ICP_QAT_CSS_FWSK_EXPONENT_LEN(device_id)), + ICP_QAT_CSS_SIGNATURE_LEN(device_id)); bus_addr = ADD_ADDR(auth_desc->signature_high, auth_desc->signature_low) + - ICP_QAT_CSS_SIGNATURE_LEN; - virt_addr += ICP_QAT_CSS_SIGNATURE_LEN; + ICP_QAT_CSS_SIGNATURE_LEN(device_id); + virt_addr += ICP_QAT_CSS_SIGNATURE_LEN(device_id); auth_desc->img_high = (unsigned int)(bus_addr >> BITS_IN_DWORD); auth_desc->img_low = (unsigned int)bus_addr; - auth_desc->img_len = size - ICP_QAT_AE_IMG_OFFSET; + auth_desc->img_len = size - ICP_QAT_AE_IMG_OFFSET(device_id); memcpy((void *)(uintptr_t)virt_addr, - (const void *)(image + ICP_QAT_AE_IMG_OFFSET), + (const void *)(image + ICP_QAT_AE_IMG_OFFSET(device_id)), auth_desc->img_len); virt_addr = virt_base; /* AE firmware */ @@ -1506,7 +1709,8 @@ (unsigned int)(bus_addr >> BITS_IN_DWORD); auth_desc->img_ae_insts_low = (unsigned int)bus_addr; virt_addr += sizeof(struct icp_qat_css_hdr) + - ICP_QAT_CSS_FWSK_PUB_LEN + ICP_QAT_CSS_SIGNATURE_LEN; + ICP_QAT_CSS_FWSK_PUB_LEN(device_id) + + ICP_QAT_CSS_SIGNATURE_LEN(device_id); auth_desc->ae_mask = ((struct icp_qat_simg_ae_mode *)virt_addr)->ae_mask & handle->cfg_ae_mask; @@ -1528,7 +1732,7 @@ unsigned int loaded_aes = FCU_LOADED_AE_POS; unsigned long ae_mask = handle->hal_handle->ae_mask; - if (IS_QAT_GEN3(pci_get_device(GET_DEV(handle->accel_dev)))) { + if (IS_QAT_GEN3_OR_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { fcu_ctl_csr = FCU_CONTROL_C4XXX; fcu_sts_csr = FCU_STATUS_C4XXX; @@ -1549,14 +1753,19 @@ } SET_FCU_CSR(handle, fcu_ctl_csr, - (FCU_CTRL_CMD_LOAD | (i << FCU_CTRL_AE_POS))); + (FCU_CTRL_CMD_LOAD | + (IS_QAT_GEN4( + pci_get_device(GET_DEV(handle->accel_dev))) ? + (1 << FCU_CTRL_BROADCAST_POS) : + 0) | + (i << FCU_CTRL_AE_POS))); do { pause_ms("adfstop", FW_AUTH_WAIT_PERIOD); fcu_sts = GET_FCU_CSR(handle, fcu_sts_csr); if ((fcu_sts & FCU_AUTH_STS_MASK) == FCU_STS_LOAD_DONE) { - loaded_aes = IS_QAT_GEN3(pci_get_device( + loaded_aes = IS_QAT_GEN3_OR_GEN4(pci_get_device( GET_DEV(handle->accel_dev))) ? GET_FCU_CSR(handle, FCU_AE_LOADED_C4XXX) : (fcu_sts >> FCU_LOADED_AE_POS); @@ -1606,6 +1815,16 @@ qat_uclo_simg_free(handle, &img_desc); } else { + if (IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) { + device_printf( + NULL, "QAT: PKE service is not allowed because "); + device_printf(NULL, "MMP fw will not be loaded for "); + device_printf(NULL, + "device 0x%x", + pci_get_device( + GET_DEV(handle->accel_dev))); + return status; + } if (pci_get_device(GET_DEV(handle->accel_dev)) == ADF_C3XXX_PCI_DEVICE_ID) { pr_err("QAT: C3XXX doesn't support unsigned MMP\n"); @@ -2044,7 +2263,8 @@ uw_relative_addr + i, fill_pat); - if (obj_handle->ae_data[ae].shareable_ustore) + if (obj_handle->ae_data[ae].shareable_ustore && + !IS_QAT_GEN4(pci_get_device(GET_DEV(handle->accel_dev)))) /* copy the buffer to ustore */ qat_hal_wr_coalesce_uwords(handle, (unsigned char)ae, @@ -2140,10 +2360,16 @@ goto wr_err; if (qat_uclo_auth_fw(handle, desc)) goto wr_err; - if (qat_uclo_load_fw(handle, desc)) - goto wr_err; + if (qat_uclo_is_broadcast(handle, i)) { + if (qat_uclo_broadcast_load_fw(handle, desc)) + goto wr_err; + } else { + if (qat_uclo_load_fw(handle, desc)) + goto wr_err; + } qat_uclo_simg_free(handle, &img_desc); } + return 0; wr_err: qat_uclo_simg_free(handle, &img_desc); diff --git a/sys/dev/qat/qat_hw/qat_200xx/adf_200xx_hw_data.c b/sys/dev/qat/qat_hw/qat_200xx/adf_200xx_hw_data.c --- a/sys/dev/qat/qat_hw/qat_200xx/adf_200xx_hw_data.c +++ b/sys/dev/qat/qat_hw/qat_200xx/adf_200xx_hw_data.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "adf_200xx_hw_data.h" #include "icp_qat_hw.h" #include "adf_heartbeat.h" @@ -495,6 +496,7 @@ hw_data->get_errsou_offset = get_errsou_offset; hw_data->get_clock_speed = get_clock_speed; hw_data->get_sku = get_sku; + hw_data->heartbeat_ctr_num = ADF_NUM_HB_CNT_PER_AE; hw_data->fw_name = ADF_200XX_FW; hw_data->fw_mmp_name = ADF_200XX_MMP; hw_data->init_admin_comms = adf_init_admin_comms; @@ -532,6 +534,8 @@ hw_data->ring_to_svc_map = ADF_DEFAULT_RING_TO_SRV_MAP; hw_data->pre_reset = adf_dev_pre_reset; hw_data->post_reset = adf_dev_post_reset; + + adf_gen2_init_hw_csr_info(&hw_data->csr_info); } void diff --git a/sys/dev/qat/qat_hw/qat_200xx/adf_drv.c b/sys/dev/qat/qat_hw/qat_200xx/adf_drv.c --- a/sys/dev/qat/qat_hw/qat_200xx/adf_drv.c +++ b/sys/dev/qat/qat_hw/qat_200xx/adf_drv.c @@ -145,6 +145,7 @@ /* Get Accelerators and Accelerators Engines masks */ hw_data->accel_mask = hw_data->get_accel_mask(accel_dev); hw_data->ae_mask = hw_data->get_ae_mask(accel_dev); + hw_data->admin_ae_mask = hw_data->ae_mask; accel_pci_dev->sku = hw_data->get_sku(hw_data); /* If the device has no acceleration engines then ignore it. */ diff --git a/sys/dev/qat/qat_hw/qat_4xxx/adf_4xxx_hw_data.h b/sys/dev/qat/qat_hw/qat_4xxx/adf_4xxx_hw_data.h new file mode 100644 --- /dev/null +++ b/sys/dev/qat/qat_hw/qat_4xxx/adf_4xxx_hw_data.h @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2007 - 2022 Intel Corporation */ +/* $FreeBSD$ */ +#ifndef ADF_4XXX_HW_DATA_H_ +#define ADF_4XXX_HW_DATA_H_ + +#include + +/* PCIe configuration space */ +#define ADF_4XXX_SRAM_BAR 0 +#define ADF_4XXX_PMISC_BAR 1 +#define ADF_4XXX_ETR_BAR 2 +#define ADF_4XXX_RX_RINGS_OFFSET 1 +#define ADF_4XXX_TX_RINGS_MASK 0x1 +#define ADF_4XXX_MAX_ACCELERATORS 1 +#define ADF_4XXX_MAX_ACCELENGINES 9 +#define ADF_4XXX_BAR_MASK (BIT(0) | BIT(2) | BIT(4)) + +/* 2 Accel units dedicated to services and */ +/* 1 Accel unit dedicated to Admin AE */ +#define ADF_4XXX_MAX_ACCELUNITS 3 + +/* Physical function fuses */ +#define ADF_4XXX_FUSECTL0_OFFSET (0x2C8) +#define ADF_4XXX_FUSECTL1_OFFSET (0x2CC) +#define ADF_4XXX_FUSECTL2_OFFSET (0x2D0) +#define ADF_4XXX_FUSECTL3_OFFSET (0x2D4) +#define ADF_4XXX_FUSECTL4_OFFSET (0x2D8) +#define ADF_4XXX_FUSECTL5_OFFSET (0x2DC) + +#define ADF_4XXX_ACCELERATORS_MASK (0x1) +#define ADF_4XXX_ACCELENGINES_MASK (0x1FF) +#define ADF_4XXX_ADMIN_AE_MASK (0x100) + +#define ADF_4XXX_ETR_MAX_BANKS 64 + +/* MSIX interrupt */ +#define ADF_4XXX_SMIAPF_RP_X0_MASK_OFFSET (0x41A040) +#define ADF_4XXX_SMIAPF_RP_X1_MASK_OFFSET (0x41A044) +#define ADF_4XXX_SMIAPF_MASK_OFFSET (0x41A084) +#define ADF_4XXX_MSIX_RTTABLE_OFFSET(i) (0x409000 + ((i)*0x04)) + +/* Bank and ring configuration */ +#define ADF_4XXX_NUM_RINGS_PER_BANK 2 + +/* Error source registers */ +#define ADF_4XXX_ERRSOU0 (0x41A200) +#define ADF_4XXX_ERRSOU1 (0x41A204) +#define ADF_4XXX_ERRSOU2 (0x41A208) +#define ADF_4XXX_ERRSOU3 (0x41A20C) + +/* Error source mask registers */ +#define ADF_4XXX_ERRMSK0 (0x41A210) +#define ADF_4XXX_ERRMSK1 (0x41A214) +#define ADF_4XXX_ERRMSK2 (0x41A218) +#define ADF_4XXX_ERRMSK3 (0x41A21C) + +#define ADF_4XXX_VFLNOTIFY BIT(7) + +/* Arbiter configuration */ +#define ADF_4XXX_ARB_CONFIG (BIT(31) | BIT(6) | BIT(0)) +#define ADF_4XXX_ARB_OFFSET (0x0) +#define ADF_4XXX_ARB_WRK_2_SER_MAP_OFFSET (0x400) + +/* Admin Interface Reg Offset */ +#define ADF_4XXX_ADMINMSGUR_OFFSET (0x500574) +#define ADF_4XXX_ADMINMSGLR_OFFSET (0x500578) +#define ADF_4XXX_MAILBOX_BASE_OFFSET (0x600970) + +/* Power management */ +#define ADF_4XXX_PM_POLL_DELAY_US 20 +#define ADF_4XXX_PM_POLL_TIMEOUT_US USEC_PER_SEC +#define ADF_4XXX_PM_STATUS (0x50A00C) +#define ADF_4XXX_PM_INTERRUPT (0x50A028) +#define ADF_4XXX_PM_DRV_ACTIVE BIT(20) +#define ADF_4XXX_PM_INIT_STATE BIT(21) +/* Power management source in ERRSOU2 and ERRMSK2 */ +#define ADF_4XXX_PM_SOU BIT(18) + +/* Firmware Binaries */ +#define ADF_4XXX_FW "qat_4xxx_fw" +#define ADF_4XXX_MMP "qat_4xxx_mmp_fw" +#define ADF_4XXX_DC_OBJ "qat_4xxx_dc.bin" +#define ADF_4XXX_SYM_OBJ "qat_4xxx_sym.bin" +#define ADF_4XXX_ASYM_OBJ "qat_4xxx_asym.bin" +#define ADF_4XXX_ADMIN_OBJ "qat_4xxx_admin.bin" + +/* Only 3 types of images can be loaded including the admin image */ +#define ADF_4XXX_MAX_OBJ 3 + +#define ADF_4XXX_AE_FREQ (1000 * 1000000) +#define ADF_4XXX_KPT_COUNTER_FREQ (100 * 1000000) + +#define ADF_4XXX_MIN_AE_FREQ (9 * 1000000) +#define ADF_4XXX_MAX_AE_FREQ (1100 * 1000000) + +/* qat_4xxx fuse bits are different from old GENs, redefine them */ +enum icp_qat_4xxx_slice_mask { + ICP_ACCEL_4XXX_MASK_CIPHER_SLICE = BIT(0), + ICP_ACCEL_4XXX_MASK_AUTH_SLICE = BIT(1), + ICP_ACCEL_4XXX_MASK_PKE_SLICE = BIT(2), + ICP_ACCEL_4XXX_MASK_COMPRESS_SLICE = BIT(3), + ICP_ACCEL_4XXX_MASK_UCS_SLICE = BIT(4), + ICP_ACCEL_4XXX_MASK_EIA3_SLICE = BIT(5), + ICP_ACCEL_4XXX_MASK_SMX_SLICE = BIT(6), +}; + +void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data); +void adf_clean_hw_data_4xxx(struct adf_hw_device_data *hw_data); + +#endif diff --git a/sys/dev/qat/qat_hw/qat_4xxx/adf_4xxx_hw_data.c b/sys/dev/qat/qat_hw/qat_4xxx/adf_4xxx_hw_data.c new file mode 100644 --- /dev/null +++ b/sys/dev/qat/qat_hw/qat_4xxx/adf_4xxx_hw_data.c @@ -0,0 +1,973 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2007-2022 Intel Corporation */ +/* $FreeBSD$ */ +#include +#include +#include +#include +#include +#include +#include +#include "adf_4xxx_hw_data.h" +#include "adf_heartbeat.h" +#include "icp_qat_fw_init_admin.h" +#include "icp_qat_hw.h" + +#define ADF_CONST_TABLE_SIZE 1024 + +struct adf_fw_config { + u32 ae_mask; + char *obj_name; +}; + +/* Accel unit information */ +static const struct adf_accel_unit adf_4xxx_au_a_ae[] = { + { 0x1, 0x1, 0xF, 0x1B, 4, ADF_ACCEL_SERVICE_NULL }, + { 0x2, 0x1, 0xF0, 0x6C0, 4, ADF_ACCEL_SERVICE_NULL }, + { 0x4, 0x1, 0x100, 0xF000, 1, ADF_ACCEL_ADMIN }, +}; + +/* Worker thread to service arbiter mappings */ +static u32 thrd_to_arb_map[ADF_4XXX_MAX_ACCELENGINES] = { 0x5555555, 0x5555555, + 0x5555555, 0x5555555, + 0xAAAAAAA, 0xAAAAAAA, + 0xAAAAAAA, 0xAAAAAAA, + 0x0 }; + +/* Masks representing ME thread-service mappings. + * Thread 7 carries out Admin work and is thus + * left out. + */ +static u8 default_active_thd_mask = 0x7F; +static u8 dc_me_active_thd_mask = 0x03; + +static u32 thrd_to_arb_map_gen[ADF_4XXX_MAX_ACCELENGINES] = { 0 }; + +#define ADF_4XXX_ASYM_SYM \ + (ASYM | SYM << ADF_CFG_SERV_RING_PAIR_1_SHIFT | \ + ASYM << ADF_CFG_SERV_RING_PAIR_2_SHIFT | \ + SYM << ADF_CFG_SERV_RING_PAIR_3_SHIFT) + +#define ADF_4XXX_DC \ + (COMP | COMP << ADF_CFG_SERV_RING_PAIR_1_SHIFT | \ + COMP << ADF_CFG_SERV_RING_PAIR_2_SHIFT | \ + COMP << ADF_CFG_SERV_RING_PAIR_3_SHIFT) + +#define ADF_4XXX_SYM \ + (SYM | SYM << ADF_CFG_SERV_RING_PAIR_1_SHIFT | \ + SYM << ADF_CFG_SERV_RING_PAIR_2_SHIFT | \ + SYM << ADF_CFG_SERV_RING_PAIR_3_SHIFT) + +#define ADF_4XXX_ASYM \ + (ASYM | ASYM << ADF_CFG_SERV_RING_PAIR_1_SHIFT | \ + ASYM << ADF_CFG_SERV_RING_PAIR_2_SHIFT | \ + ASYM << ADF_CFG_SERV_RING_PAIR_3_SHIFT) + +#define ADF_4XXX_ASYM_DC \ + (ASYM | ASYM << ADF_CFG_SERV_RING_PAIR_1_SHIFT | \ + COMP << ADF_CFG_SERV_RING_PAIR_2_SHIFT | \ + COMP << ADF_CFG_SERV_RING_PAIR_3_SHIFT) + +#define ADF_4XXX_SYM_DC \ + (SYM | SYM << ADF_CFG_SERV_RING_PAIR_1_SHIFT | \ + COMP << ADF_CFG_SERV_RING_PAIR_2_SHIFT | \ + COMP << ADF_CFG_SERV_RING_PAIR_3_SHIFT) + +#define ADF_4XXX_NA \ + (NA | NA << ADF_CFG_SERV_RING_PAIR_1_SHIFT | \ + NA << ADF_CFG_SERV_RING_PAIR_2_SHIFT | \ + NA << ADF_CFG_SERV_RING_PAIR_3_SHIFT) + +#define ADF_4XXX_DEFAULT_RING_TO_SRV_MAP ADF_4XXX_ASYM_SYM + +struct adf_enabled_services { + const char svcs_enabled[ADF_CFG_MAX_VAL_LEN_IN_BYTES]; + u16 rng_to_svc_msk; +}; + +static struct adf_enabled_services adf_4xxx_svcs[] = { + { "dc", ADF_4XXX_DC }, + { "sym", ADF_4XXX_SYM }, + { "asym", ADF_4XXX_ASYM }, + { "dc;asym", ADF_4XXX_ASYM_DC }, + { "asym;dc", ADF_4XXX_ASYM_DC }, + { "sym;dc", ADF_4XXX_SYM_DC }, + { "dc;sym", ADF_4XXX_SYM_DC }, + { "asym;sym", ADF_4XXX_ASYM_SYM }, + { "sym;asym", ADF_4XXX_ASYM_SYM }, +}; + +static struct adf_hw_device_class adf_4xxx_class = { + .name = ADF_4XXX_DEVICE_NAME, + .type = DEV_4XXX, + .instances = 0, +}; + +static u32 +get_accel_mask(struct adf_accel_dev *accel_dev) +{ + return ADF_4XXX_ACCELERATORS_MASK; +} + +static u32 +get_ae_mask(struct adf_accel_dev *accel_dev) +{ + u32 fusectl4 = accel_dev->hw_device->fuses; + + return ~fusectl4 & ADF_4XXX_ACCELENGINES_MASK; +} + +static int +get_ring_to_svc_map(struct adf_accel_dev *accel_dev, u16 *ring_to_svc_map) +{ + char key[ADF_CFG_MAX_KEY_LEN_IN_BYTES]; + char val[ADF_CFG_MAX_KEY_LEN_IN_BYTES]; + u32 i = 0; + + *ring_to_svc_map = 0; + /* Get the services enabled by user */ + snprintf(key, sizeof(key), ADF_SERVICES_ENABLED); + if (adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, key, val)) + return EFAULT; + + for (i = 0; i < ARRAY_SIZE(adf_4xxx_svcs); i++) { + if (!strncmp(val, + adf_4xxx_svcs[i].svcs_enabled, + ADF_CFG_MAX_KEY_LEN_IN_BYTES)) { + *ring_to_svc_map = adf_4xxx_svcs[i].rng_to_svc_msk; + return 0; + } + } + + device_printf(GET_DEV(accel_dev), + "Invalid services enabled: %s\n", + val); + return EFAULT; +} + +static u32 +get_num_accels(struct adf_hw_device_data *self) +{ + return ADF_4XXX_MAX_ACCELERATORS; +} + +static u32 +get_num_aes(struct adf_hw_device_data *self) +{ + if (!self || !self->ae_mask) + return 0; + + return hweight32(self->ae_mask); +} + +static u32 +get_misc_bar_id(struct adf_hw_device_data *self) +{ + return ADF_4XXX_PMISC_BAR; +} + +static u32 +get_etr_bar_id(struct adf_hw_device_data *self) +{ + return ADF_4XXX_ETR_BAR; +} + +static u32 +get_sram_bar_id(struct adf_hw_device_data *self) +{ + return ADF_4XXX_SRAM_BAR; +} + +/* + * The vector routing table is used to select the MSI-X entry to use for each + * interrupt source. + * The first ADF_4XXX_ETR_MAX_BANKS entries correspond to ring interrupts. + * The final entry corresponds to VF2PF or error interrupts. + * This vector table could be used to configure one MSI-X entry to be shared + * between multiple interrupt sources. + * + * The default routing is set to have a one to one correspondence between the + * interrupt source and the MSI-X entry used. + */ +static void +set_msix_default_rttable(struct adf_accel_dev *accel_dev) +{ + struct resource *csr; + int i; + + csr = (&GET_BARS(accel_dev)[ADF_4XXX_PMISC_BAR])->virt_addr; + for (i = 0; i <= ADF_4XXX_ETR_MAX_BANKS; i++) + ADF_CSR_WR(csr, ADF_4XXX_MSIX_RTTABLE_OFFSET(i), i); +} + +static u32 +adf_4xxx_get_hw_cap(struct adf_accel_dev *accel_dev) +{ + device_t pdev = accel_dev->accel_pci_dev.pci_dev; + u32 fusectl1; + u32 capabilities; + + /* Read accelerator capabilities mask */ + fusectl1 = pci_read_config(pdev, ADF_4XXX_FUSECTL1_OFFSET, 4); + capabilities = ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC | + ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC | + ICP_ACCEL_CAPABILITIES_CIPHER | + ICP_ACCEL_CAPABILITIES_AUTHENTICATION | + ICP_ACCEL_CAPABILITIES_COMPRESSION | + ICP_ACCEL_CAPABILITIES_LZ4_COMPRESSION | + ICP_ACCEL_CAPABILITIES_LZ4S_COMPRESSION | + ICP_ACCEL_CAPABILITIES_HKDF | ICP_ACCEL_CAPABILITIES_SHA3_EXT | + ICP_ACCEL_CAPABILITIES_SM3 | ICP_ACCEL_CAPABILITIES_SM4 | + ICP_ACCEL_CAPABILITIES_CHACHA_POLY | + ICP_ACCEL_CAPABILITIES_AESGCM_SPC | + ICP_ACCEL_CAPABILITIES_AES_V2 | ICP_ACCEL_CAPABILITIES_RL; + + if (fusectl1 & ICP_ACCEL_4XXX_MASK_CIPHER_SLICE) { + capabilities &= ~ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC; + capabilities &= ~ICP_ACCEL_CAPABILITIES_CIPHER; + } + if (fusectl1 & ICP_ACCEL_4XXX_MASK_AUTH_SLICE) + capabilities &= ~ICP_ACCEL_CAPABILITIES_AUTHENTICATION; + if (fusectl1 & ICP_ACCEL_4XXX_MASK_PKE_SLICE) + capabilities &= ~ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC; + if (fusectl1 & ICP_ACCEL_4XXX_MASK_COMPRESS_SLICE) { + capabilities &= ~ICP_ACCEL_CAPABILITIES_COMPRESSION; + capabilities &= ~ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY64; + } + if (fusectl1 & ICP_ACCEL_4XXX_MASK_SMX_SLICE) { + capabilities &= ~ICP_ACCEL_CAPABILITIES_SM3; + capabilities &= ~ICP_ACCEL_CAPABILITIES_SM4; + } + return capabilities; +} + +static u32 +get_hb_clock(struct adf_hw_device_data *self) +{ + /* + * 4XXX uses KPT counter for HB + */ + return ADF_4XXX_KPT_COUNTER_FREQ; +} + +static u32 +get_ae_clock(struct adf_hw_device_data *self) +{ + /* + * Clock update interval is <16> ticks for qat_4xxx. + */ + return self->clock_frequency / 16; +} + +static int +measure_clock(struct adf_accel_dev *accel_dev) +{ + u32 frequency; + int ret = 0; + + ret = adf_dev_measure_clock(accel_dev, + &frequency, + ADF_4XXX_MIN_AE_FREQ, + ADF_4XXX_MAX_AE_FREQ); + if (ret) + return ret; + + accel_dev->hw_device->clock_frequency = frequency; + return 0; +} + +static int +adf_4xxx_configure_accel_units(struct adf_accel_dev *accel_dev) +{ + char key[ADF_CFG_MAX_KEY_LEN_IN_BYTES] = { 0 }; + char val_str[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 }; + + if (adf_cfg_section_add(accel_dev, ADF_GENERAL_SEC)) + goto err; + + snprintf(key, sizeof(key), ADF_SERVICES_ENABLED); + snprintf(val_str, + sizeof(val_str), + ADF_CFG_ASYM ADF_SERVICES_SEPARATOR ADF_CFG_SYM); + + if (adf_cfg_add_key_value_param( + accel_dev, ADF_GENERAL_SEC, key, (void *)val_str, ADF_STR)) + goto err; + + return 0; +err: + device_printf(GET_DEV(accel_dev), "Failed to configure accel units\n"); + return EINVAL; +} + +static u32 +get_num_accel_units(struct adf_hw_device_data *self) +{ + return ADF_4XXX_MAX_ACCELUNITS; +} + +static void +get_accel_unit(struct adf_hw_device_data *self, + struct adf_accel_unit **accel_unit) +{ + memcpy(*accel_unit, adf_4xxx_au_a_ae, sizeof(adf_4xxx_au_a_ae)); +} + +static void +adf_exit_accel_unit_services(struct adf_accel_dev *accel_dev) +{ + if (accel_dev->au_info) { + kfree(accel_dev->au_info->au); + accel_dev->au_info->au = NULL; + kfree(accel_dev->au_info); + accel_dev->au_info = NULL; + } +} + +static int +get_accel_unit_config(struct adf_accel_dev *accel_dev, + u8 *num_sym_au, + u8 *num_dc_au, + u8 *num_asym_au) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + char key[ADF_CFG_MAX_KEY_LEN_IN_BYTES]; + char val[ADF_CFG_MAX_VAL_LEN_IN_BYTES]; + u32 num_au = hw_data->get_num_accel_units(hw_data); + /* One AU will be allocated by default if a service enabled */ + u32 alloc_au = 1; + /* There's always one AU that is used for Admin AE */ + u32 service_mask = ADF_ACCEL_ADMIN; + char *token, *cur_str; + u32 disabled_caps = 0; + + /* Get the services enabled by user */ + snprintf(key, sizeof(key), ADF_SERVICES_ENABLED); + if (adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, key, val)) + return EFAULT; + cur_str = val; + token = strsep(&cur_str, ADF_SERVICES_SEPARATOR); + while (token) { + if (!strncmp(token, ADF_CFG_SYM, strlen(ADF_CFG_SYM))) + service_mask |= ADF_ACCEL_CRYPTO; + if (!strncmp(token, ADF_CFG_ASYM, strlen(ADF_CFG_ASYM))) + service_mask |= ADF_ACCEL_ASYM; + + /* cy means both asym & crypto should be enabled + * Hardware resources allocation check will be done later + */ + if (!strncmp(token, ADF_CFG_CY, strlen(ADF_CFG_CY))) + service_mask |= ADF_ACCEL_ASYM | ADF_ACCEL_CRYPTO; + if (!strncmp(token, ADF_SERVICE_DC, strlen(ADF_SERVICE_DC))) + service_mask |= ADF_ACCEL_COMPRESSION; + + token = strsep(&cur_str, ADF_SERVICES_SEPARATOR); + } + + /* Ensure the user won't enable more services than it can support */ + if (hweight32(service_mask) > num_au) { + device_printf(GET_DEV(accel_dev), + "Can't enable more services than "); + device_printf(GET_DEV(accel_dev), "%d!\n", num_au); + return EFAULT; + } else if (hweight32(service_mask) == 2) { + /* Due to limitation, besides AU for Admin AE + * only 2 more AUs can be allocated + */ + alloc_au = 2; + } + + if (service_mask & ADF_ACCEL_CRYPTO) + *num_sym_au = alloc_au; + if (service_mask & ADF_ACCEL_ASYM) + *num_asym_au = alloc_au; + if (service_mask & ADF_ACCEL_COMPRESSION) + *num_dc_au = alloc_au; + + /*update capability*/ + if (!*num_sym_au || !(service_mask & ADF_ACCEL_CRYPTO)) { + disabled_caps = ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC | + ICP_ACCEL_CAPABILITIES_CIPHER | + ICP_ACCEL_CAPABILITIES_SHA3_EXT | + ICP_ACCEL_CAPABILITIES_SM3 | ICP_ACCEL_CAPABILITIES_SM4 | + ICP_ACCEL_CAPABILITIES_CHACHA_POLY | + ICP_ACCEL_CAPABILITIES_AESGCM_SPC | + ICP_ACCEL_CAPABILITIES_AES_V2; + } + if (!*num_asym_au || !(service_mask & ADF_ACCEL_ASYM)) { + disabled_caps |= ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC | + ICP_ACCEL_CAPABILITIES_AUTHENTICATION; + } + if (!*num_dc_au || !(service_mask & ADF_ACCEL_COMPRESSION)) { + disabled_caps |= ICP_ACCEL_CAPABILITIES_COMPRESSION | + ICP_ACCEL_CAPABILITIES_LZ4_COMPRESSION | + ICP_ACCEL_CAPABILITIES_LZ4S_COMPRESSION | + ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY64; + accel_dev->hw_device->extended_dc_capabilities = 0; + } + accel_dev->hw_device->accel_capabilities_mask = + adf_4xxx_get_hw_cap(accel_dev) & ~disabled_caps; + + hw_data->service_mask = service_mask; + hw_data->service_to_load_mask = service_mask; + + return 0; +} + +static int +adf_init_accel_unit_services(struct adf_accel_dev *accel_dev) +{ + u8 num_sym_au = 0, num_dc_au = 0, num_asym_au = 0; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u32 num_au = hw_data->get_num_accel_units(hw_data); + u32 au_size = num_au * sizeof(struct adf_accel_unit); + u8 i; + + if (get_accel_unit_config( + accel_dev, &num_sym_au, &num_dc_au, &num_asym_au)) + return EFAULT; + + accel_dev->au_info = kzalloc(sizeof(*accel_dev->au_info), GFP_KERNEL); + if (!accel_dev->au_info) + return ENOMEM; + + accel_dev->au_info->au = kzalloc(au_size, GFP_KERNEL); + if (!accel_dev->au_info->au) { + kfree(accel_dev->au_info); + accel_dev->au_info = NULL; + return ENOMEM; + } + + accel_dev->au_info->num_cy_au = num_sym_au; + accel_dev->au_info->num_dc_au = num_dc_au; + accel_dev->au_info->num_asym_au = num_asym_au; + + get_accel_unit(hw_data, &accel_dev->au_info->au); + + /* Enable ASYM accel units */ + for (i = 0; i < num_au && num_asym_au > 0; i++) { + if (accel_dev->au_info->au[i].services == + ADF_ACCEL_SERVICE_NULL) { + accel_dev->au_info->au[i].services = ADF_ACCEL_ASYM; + num_asym_au--; + } + } + /* Enable SYM accel units */ + for (i = 0; i < num_au && num_sym_au > 0; i++) { + if (accel_dev->au_info->au[i].services == + ADF_ACCEL_SERVICE_NULL) { + accel_dev->au_info->au[i].services = ADF_ACCEL_CRYPTO; + num_sym_au--; + } + } + /* Enable compression accel units */ + for (i = 0; i < num_au && num_dc_au > 0; i++) { + if (accel_dev->au_info->au[i].services == + ADF_ACCEL_SERVICE_NULL) { + accel_dev->au_info->au[i].services = + ADF_ACCEL_COMPRESSION; + num_dc_au--; + } + } + accel_dev->au_info->dc_ae_msk |= + hw_data->get_obj_cfg_ae_mask(accel_dev, ADF_ACCEL_COMPRESSION); + + return 0; +} + +static int +adf_init_accel_units(struct adf_accel_dev *accel_dev) +{ + return adf_init_accel_unit_services(accel_dev); +} + +static void +adf_exit_accel_units(struct adf_accel_dev *accel_dev) +{ + /* reset the AU service */ + adf_exit_accel_unit_services(accel_dev); +} + +static const char * +get_obj_name(struct adf_accel_dev *accel_dev, + enum adf_accel_unit_services service) +{ + switch (service) { + case ADF_ACCEL_ASYM: + return ADF_4XXX_ASYM_OBJ; + case ADF_ACCEL_CRYPTO: + return ADF_4XXX_SYM_OBJ; + case ADF_ACCEL_COMPRESSION: + return ADF_4XXX_DC_OBJ; + case ADF_ACCEL_ADMIN: + return ADF_4XXX_ADMIN_OBJ; + default: + return NULL; + } +} + +static uint32_t +get_objs_num(struct adf_accel_dev *accel_dev) +{ + return ADF_4XXX_MAX_OBJ; +} + +static uint32_t +get_obj_cfg_ae_mask(struct adf_accel_dev *accel_dev, + enum adf_accel_unit_services service) +{ + u32 ae_mask = 0; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u32 num_au = hw_data->get_num_accel_units(hw_data); + struct adf_accel_unit *accel_unit = accel_dev->au_info->au; + u32 i = 0; + + if (service == ADF_ACCEL_SERVICE_NULL) + return 0; + + for (i = 0; i < num_au; i++) { + if (accel_unit[i].services == service) + ae_mask |= accel_unit[i].ae_mask; + } + + return ae_mask; +} + +static enum adf_accel_unit_services +adf_4xxx_get_service_type(struct adf_accel_dev *accel_dev, s32 obj_num) +{ + struct adf_accel_unit *accel_unit; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u8 num_au = hw_data->get_num_accel_units(hw_data); + int i; + + if (!hw_data->service_to_load_mask) + return ADF_ACCEL_SERVICE_NULL; + + if (accel_dev->au_info && accel_dev->au_info->au) + accel_unit = accel_dev->au_info->au; + else + return ADF_ACCEL_SERVICE_NULL; + + for (i = num_au - 2; i >= 0; i--) { + if (hw_data->service_to_load_mask & accel_unit[i].services) { + hw_data->service_to_load_mask &= + ~accel_unit[i].services; + return accel_unit[i].services; + } + } + + /* admin AE should be loaded last */ + if (hw_data->service_to_load_mask & accel_unit[num_au - 1].services) { + hw_data->service_to_load_mask &= + ~accel_unit[num_au - 1].services; + return accel_unit[num_au - 1].services; + } + + return ADF_ACCEL_SERVICE_NULL; +} + +static void +get_ring_svc_map_data(int ring_pair_index, + u16 ring_to_svc_map, + u8 *serv_type, + int *ring_index, + int *num_rings_per_srv, + int bundle_num) +{ + *serv_type = + GET_SRV_TYPE(ring_to_svc_map, bundle_num % ADF_CFG_NUM_SERVICES); + *ring_index = 0; + *num_rings_per_srv = ADF_4XXX_NUM_RINGS_PER_BANK / 2; +} + +static int +adf_get_dc_extcapabilities(struct adf_accel_dev *accel_dev, u32 *capabilities) +{ + struct icp_qat_fw_init_admin_req req; + struct icp_qat_fw_init_admin_resp resp; + u8 i; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u8 num_au = hw_data->get_num_accel_units(hw_data); + u32 first_dc_ae = 0; + + for (i = 0; i < num_au; i++) { + if (accel_dev->au_info->au[i].services & + ADF_ACCEL_COMPRESSION) { + first_dc_ae = accel_dev->au_info->au[i].ae_mask; + first_dc_ae &= ~(first_dc_ae - 1); + } + } + + memset(&req, 0, sizeof(req)); + memset(&resp, 0, sizeof(resp)); + req.cmd_id = ICP_QAT_FW_COMP_CAPABILITY_GET; + + if (likely(first_dc_ae)) { + if (adf_send_admin(accel_dev, &req, &resp, first_dc_ae) || + resp.status) { + *capabilities = 0; + return EFAULT; + } + + *capabilities = resp.extended_features; + } + + return 0; +} + +static int +adf_get_fw_status(struct adf_accel_dev *accel_dev, + u8 *major, + u8 *minor, + u8 *patch) +{ + struct icp_qat_fw_init_admin_req req; + struct icp_qat_fw_init_admin_resp resp; + u32 ae_mask = 1; + + memset(&req, 0, sizeof(req)); + memset(&resp, 0, sizeof(resp)); + req.cmd_id = ICP_QAT_FW_STATUS_GET; + + if (adf_send_admin(accel_dev, &req, &resp, ae_mask)) + return EFAULT; + + *major = resp.version_major_num; + *minor = resp.version_minor_num; + *patch = resp.version_patch_num; + + return 0; +} + +static int +adf_4xxx_send_admin_init(struct adf_accel_dev *accel_dev) +{ + int ret = 0; + struct icp_qat_fw_init_admin_req req; + struct icp_qat_fw_init_admin_resp resp; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u32 ae_mask = hw_data->ae_mask; + u32 admin_ae_mask = hw_data->admin_ae_mask; + u8 num_au = hw_data->get_num_accel_units(hw_data); + u8 i; + u32 dc_capabilities = 0; + + for (i = 0; i < num_au; i++) { + if (accel_dev->au_info->au[i].services == + ADF_ACCEL_SERVICE_NULL) + ae_mask &= ~accel_dev->au_info->au[i].ae_mask; + + if (accel_dev->au_info->au[i].services != ADF_ACCEL_ADMIN) + admin_ae_mask &= ~accel_dev->au_info->au[i].ae_mask; + } + + if (!accel_dev->admin) { + device_printf(GET_DEV(accel_dev), "adf_admin not available\n"); + return EFAULT; + } + + memset(&req, 0, sizeof(req)); + memset(&resp, 0, sizeof(resp)); + + req.cmd_id = ICP_QAT_FW_CONSTANTS_CFG; + req.init_cfg_sz = ADF_CONST_TABLE_SIZE; + req.init_cfg_ptr = accel_dev->admin->const_tbl_addr; + if (adf_send_admin(accel_dev, &req, &resp, admin_ae_mask)) { + device_printf(GET_DEV(accel_dev), + "Error sending constants config message\n"); + return EFAULT; + } + + memset(&req, 0, sizeof(req)); + memset(&resp, 0, sizeof(resp)); + req.cmd_id = ICP_QAT_FW_INIT_ME; + if (adf_send_admin(accel_dev, &req, &resp, ae_mask)) { + device_printf(GET_DEV(accel_dev), + "Error sending init message\n"); + return EFAULT; + } + + memset(&req, 0, sizeof(req)); + memset(&resp, 0, sizeof(resp)); + req.cmd_id = ICP_QAT_FW_HEARTBEAT_TIMER_SET; + req.init_cfg_ptr = accel_dev->admin->phy_hb_addr; + if (adf_get_hb_timer(accel_dev, &req.heartbeat_ticks)) + return EINVAL; + + if (adf_send_admin(accel_dev, &req, &resp, ae_mask)) + device_printf(GET_DEV(accel_dev), + "Heartbeat is not supported\n"); + + ret = adf_get_dc_extcapabilities(accel_dev, &dc_capabilities); + if (unlikely(ret)) { + device_printf(GET_DEV(accel_dev), + "Could not get FW ext. capabilities\n"); + } + + accel_dev->hw_device->extended_dc_capabilities = dc_capabilities; + + adf_get_fw_status(accel_dev, + &accel_dev->fw_versions.fw_version_major, + &accel_dev->fw_versions.fw_version_minor, + &accel_dev->fw_versions.fw_version_patch); + + device_printf(GET_DEV(accel_dev), + "FW version: %d.%d.%d\n", + accel_dev->fw_versions.fw_version_major, + accel_dev->fw_versions.fw_version_minor, + accel_dev->fw_versions.fw_version_patch); + + return ret; +} + +static enum dev_sku_info +get_sku(struct adf_hw_device_data *self) +{ + return DEV_SKU_1; +} + +static struct adf_accel_unit * +get_au_by_ae(struct adf_accel_dev *accel_dev, int ae_num) +{ + int i = 0; + struct adf_accel_unit *accel_unit = accel_dev->au_info->au; + + if (!accel_unit) + return NULL; + + for (i = 0; i < ADF_4XXX_MAX_ACCELUNITS; i++) + if (accel_unit[i].ae_mask & BIT(ae_num)) + return &accel_unit[i]; + + return NULL; +} + +static bool +check_accel_unit_service(enum adf_accel_unit_services au_srv, + enum adf_cfg_service_type ring_srv) +{ + if ((au_srv & ADF_ACCEL_SERVICE_NULL) && ring_srv == NA) + return true; + if ((au_srv & ADF_ACCEL_COMPRESSION) && ring_srv == COMP) + return true; + if ((au_srv & ADF_ACCEL_ASYM) && ring_srv == ASYM) + return true; + if ((au_srv & ADF_ACCEL_CRYPTO) && ring_srv == SYM) + return true; + + return false; +} + +static void +adf_4xxx_cfg_gen_dispatch_arbiter(struct adf_accel_dev *accel_dev, + u32 *thrd_to_arb_map_gen) +{ + struct adf_accel_unit *au = NULL; + int engine = 0; + int thread = 0; + int service; + u16 ena_srv_mask; + u16 service_type; + u32 service_mask; + unsigned long thd_srv_mask = default_active_thd_mask; + + ena_srv_mask = accel_dev->hw_device->ring_to_svc_map; + /* If ring_to_svc_map is not changed, return default arbiter value */ + if (ena_srv_mask == ADF_4XXX_DEFAULT_RING_TO_SRV_MAP) { + memcpy(thrd_to_arb_map_gen, + thrd_to_arb_map, + sizeof(thrd_to_arb_map_gen[0]) * + ADF_4XXX_MAX_ACCELENGINES); + return; + } + + for (engine = 0; engine < ADF_4XXX_MAX_ACCELENGINES - 1; engine++) { + thrd_to_arb_map_gen[engine] = 0; + service_mask = 0; + au = get_au_by_ae(accel_dev, engine); + if (!au) + continue; + + for (service = 0; service < ADF_CFG_MAX_SERVICES; service++) { + service_type = GET_SRV_TYPE(ena_srv_mask, service); + if (check_accel_unit_service(au->services, + service_type)) + service_mask |= BIT(service); + } + + if (au->services == ADF_ACCEL_COMPRESSION) + thd_srv_mask = dc_me_active_thd_mask; + else + thd_srv_mask = default_active_thd_mask; + + for_each_set_bit(thread, &thd_srv_mask, 8) + { + thrd_to_arb_map_gen[engine] |= + (service_mask << (ADF_CFG_MAX_SERVICES * thread)); + } + } +} + +static void +adf_get_arbiter_mapping(struct adf_accel_dev *accel_dev, + u32 const **arb_map_config) +{ + int i; + struct adf_hw_device_data *hw_device = accel_dev->hw_device; + + for (i = 1; i < ADF_4XXX_MAX_ACCELENGINES; i++) { + if (~hw_device->ae_mask & (1 << i)) + thrd_to_arb_map[i] = 0; + } + adf_4xxx_cfg_gen_dispatch_arbiter(accel_dev, thrd_to_arb_map_gen); + *arb_map_config = thrd_to_arb_map_gen; +} + +static void +get_arb_info(struct arb_info *arb_info) +{ + arb_info->wrk_cfg_offset = ADF_4XXX_ARB_CONFIG; + arb_info->arbiter_offset = ADF_4XXX_ARB_OFFSET; + arb_info->wrk_thd_2_srv_arb_map = ADF_4XXX_ARB_WRK_2_SER_MAP_OFFSET; +} + +static void +get_admin_info(struct admin_info *admin_csrs_info) +{ + admin_csrs_info->mailbox_offset = ADF_4XXX_MAILBOX_BASE_OFFSET; + admin_csrs_info->admin_msg_ur = ADF_4XXX_ADMINMSGUR_OFFSET; + admin_csrs_info->admin_msg_lr = ADF_4XXX_ADMINMSGLR_OFFSET; +} + +static void +adf_enable_error_correction(struct adf_accel_dev *accel_dev) +{ + struct adf_bar *misc_bar = &GET_BARS(accel_dev)[ADF_4XXX_PMISC_BAR]; + struct resource *csr = misc_bar->virt_addr; + + /* Enable all in errsou3 except VFLR notification on host */ + ADF_CSR_WR(csr, ADF_4XXX_ERRMSK3, ADF_4XXX_VFLNOTIFY); +} + +static void +adf_enable_ints(struct adf_accel_dev *accel_dev) +{ + struct resource *addr; + + addr = (&GET_BARS(accel_dev)[ADF_4XXX_PMISC_BAR])->virt_addr; + + /* Enable bundle interrupts */ + ADF_CSR_WR(addr, ADF_4XXX_SMIAPF_RP_X0_MASK_OFFSET, 0); + ADF_CSR_WR(addr, ADF_4XXX_SMIAPF_RP_X1_MASK_OFFSET, 0); + + /* Enable misc interrupts */ + ADF_CSR_WR(addr, ADF_4XXX_SMIAPF_MASK_OFFSET, 0); +} + +static int +adf_init_device(struct adf_accel_dev *accel_dev) +{ + struct resource *addr; + u32 status; + u32 csr; + int ret; + + addr = (&GET_BARS(accel_dev)[ADF_4XXX_PMISC_BAR])->virt_addr; + + /* Temporarily mask PM interrupt */ + csr = ADF_CSR_RD(addr, ADF_4XXX_ERRMSK2); + csr |= ADF_4XXX_PM_SOU; + ADF_CSR_WR(addr, ADF_4XXX_ERRMSK2, csr); + + /* Set DRV_ACTIVE bit to power up the device */ + ADF_CSR_WR(addr, ADF_4XXX_PM_INTERRUPT, ADF_4XXX_PM_DRV_ACTIVE); + + /* Poll status register to make sure the device is powered up */ + status = 0; + ret = read_poll_timeout(ADF_CSR_RD, + status, + status & ADF_4XXX_PM_INIT_STATE, + ADF_4XXX_PM_POLL_DELAY_US, + ADF_4XXX_PM_POLL_TIMEOUT_US, + true, + addr, + ADF_4XXX_PM_STATUS); + if (ret) + device_printf(GET_DEV(accel_dev), + "Failed to power up the device\n"); + + return ret; +} + +void +adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data) +{ + hw_data->dev_class = &adf_4xxx_class; + hw_data->instance_id = adf_4xxx_class.instances++; + hw_data->num_banks = ADF_4XXX_ETR_MAX_BANKS; + hw_data->num_rings_per_bank = ADF_4XXX_NUM_RINGS_PER_BANK; + hw_data->num_accel = ADF_4XXX_MAX_ACCELERATORS; + hw_data->num_engines = ADF_4XXX_MAX_ACCELENGINES; + hw_data->num_logical_accel = 1; + hw_data->tx_rx_gap = ADF_4XXX_RX_RINGS_OFFSET; + hw_data->tx_rings_mask = ADF_4XXX_TX_RINGS_MASK; + hw_data->alloc_irq = adf_isr_resource_alloc; + hw_data->free_irq = adf_isr_resource_free; + hw_data->enable_error_correction = adf_enable_error_correction; + hw_data->get_accel_mask = get_accel_mask; + hw_data->get_ae_mask = get_ae_mask; + hw_data->get_num_accels = get_num_accels; + hw_data->get_num_aes = get_num_aes; + hw_data->get_sram_bar_id = get_sram_bar_id; + hw_data->get_etr_bar_id = get_etr_bar_id; + hw_data->get_misc_bar_id = get_misc_bar_id; + hw_data->get_arb_info = get_arb_info; + hw_data->get_admin_info = get_admin_info; + hw_data->get_accel_cap = adf_4xxx_get_hw_cap; + hw_data->clock_frequency = ADF_4XXX_AE_FREQ; + hw_data->get_sku = get_sku; + hw_data->heartbeat_ctr_num = ADF_NUM_HB_CNT_PER_AE; + hw_data->fw_name = ADF_4XXX_FW; + hw_data->fw_mmp_name = ADF_4XXX_MMP; + hw_data->init_admin_comms = adf_init_admin_comms; + hw_data->exit_admin_comms = adf_exit_admin_comms; + hw_data->send_admin_init = adf_4xxx_send_admin_init; + hw_data->init_arb = adf_init_gen2_arb; + hw_data->exit_arb = adf_exit_arb; + hw_data->get_arb_mapping = adf_get_arbiter_mapping; + hw_data->enable_ints = adf_enable_ints; + hw_data->init_device = adf_init_device; + hw_data->reset_device = adf_reset_flr; + hw_data->restore_device = adf_dev_restore; + hw_data->init_accel_units = adf_init_accel_units; + hw_data->exit_accel_units = adf_exit_accel_units; + hw_data->get_num_accel_units = get_num_accel_units; + hw_data->configure_accel_units = adf_4xxx_configure_accel_units; + hw_data->get_ring_to_svc_map = get_ring_to_svc_map; + hw_data->get_ring_svc_map_data = get_ring_svc_map_data; + hw_data->admin_ae_mask = ADF_4XXX_ADMIN_AE_MASK; + hw_data->get_objs_num = get_objs_num; + hw_data->get_obj_name = get_obj_name; + hw_data->get_obj_cfg_ae_mask = get_obj_cfg_ae_mask; + hw_data->get_service_type = adf_4xxx_get_service_type; + hw_data->set_msix_rttable = set_msix_default_rttable; + hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer; + hw_data->disable_iov = adf_disable_sriov; + hw_data->min_iov_compat_ver = ADF_PFVF_COMPATIBILITY_VERSION; + hw_data->config_device = adf_config_device; + hw_data->set_asym_rings_mask = adf_cfg_set_asym_rings_mask; + hw_data->get_hb_clock = get_hb_clock; + hw_data->get_heartbeat_status = adf_get_heartbeat_status; + hw_data->get_ae_clock = get_ae_clock; + hw_data->measure_clock = measure_clock; + hw_data->query_storage_cap = 1; + + adf_gen4_init_hw_csr_info(&hw_data->csr_info); +} + +void +adf_clean_hw_data_4xxx(struct adf_hw_device_data *hw_data) +{ + hw_data->dev_class->instances--; +} diff --git a/sys/dev/qat/qat_hw/qat_c4xxx/adf_drv.c b/sys/dev/qat/qat_hw/qat_4xxx/adf_drv.c copy from sys/dev/qat/qat_hw/qat_c4xxx/adf_drv.c copy to sys/dev/qat/qat_hw/qat_4xxx/adf_drv.c --- a/sys/dev/qat/qat_hw/qat_c4xxx/adf_drv.c +++ b/sys/dev/qat/qat_hw/qat_4xxx/adf_drv.c @@ -1,11 +1,12 @@ /* SPDX-License-Identifier: BSD-3-Clause */ -/* Copyright(c) 2007-2022 Intel Corporation */ +/* Copyright(c) 2007 - 2022 Intel Corporation */ /* $FreeBSD$ */ #include "qat_freebsd.h" #include "adf_cfg.h" #include "adf_common_drv.h" #include "adf_accel_devices.h" -#include "adf_c4xxx_hw_data.h" +#include "adf_4xxx_hw_data.h" +#include "adf_gen4_hw_data.h" #include "adf_fw_counters.h" #include "adf_cfg_device.h" #include @@ -16,7 +17,7 @@ #include "adf_heartbeat_dbg.h" #include "adf_cnvnr_freq_counters.h" -static MALLOC_DEFINE(M_QAT_C4XXX, "qat_c4xx", "qat_c4xx"); +static MALLOC_DEFINE(M_QAT_4XXX, "qat_4xxx", "qat_4xxx"); #define ADF_SYSTEM_DEVICE(device_id) \ { \ @@ -24,7 +25,8 @@ } static const struct pci_device_id adf_pci_tbl[] = - { ADF_SYSTEM_DEVICE(ADF_C4XXX_PCI_DEVICE_ID), + { ADF_SYSTEM_DEVICE(ADF_4XXX_PCI_DEVICE_ID), + ADF_SYSTEM_DEVICE(ADF_401XX_PCI_DEVICE_ID), { 0, } }; @@ -38,7 +40,7 @@ if (pci_get_vendor(dev) == id->vendor && pci_get_device(dev) == id->device) { device_set_desc(dev, - "Intel " ADF_C4XXX_DEVICE_NAME + "Intel " ADF_4XXX_DEVICE_NAME " QuickAssist"); return BUS_PROBE_GENERIC; } @@ -65,13 +67,14 @@ if (accel_dev->hw_device) { switch (pci_get_device(accel_pci_dev->pci_dev)) { - case ADF_C4XXX_PCI_DEVICE_ID: - adf_clean_hw_data_c4xxx(accel_dev->hw_device); + case ADF_4XXX_PCI_DEVICE_ID: + case ADF_401XX_PCI_DEVICE_ID: + adf_clean_hw_data_4xxx(accel_dev->hw_device); break; default: break; } - free(accel_dev->hw_device, M_QAT_C4XXX); + free(accel_dev->hw_device, M_QAT_4XXX); accel_dev->hw_device = NULL; } adf_cfg_dev_remove(accel_dev); @@ -104,8 +107,6 @@ if (bus_get_domain(dev, &accel_pci_dev->node) != 0) accel_pci_dev->node = 0; - /* XXX: Revisit if we actually need a devmgr table at all. */ - /* Add accel device to accel table. * This should be called before adf_cleanup_accel is called */ @@ -115,12 +116,17 @@ } /* Allocate and configure device configuration structure */ - hw_data = malloc(sizeof(*hw_data), M_QAT_C4XXX, M_WAITOK | M_ZERO); + hw_data = malloc(sizeof(*hw_data), M_QAT_4XXX, M_WAITOK | M_ZERO); accel_dev->hw_device = hw_data; - adf_init_hw_data_c4xxx(accel_dev->hw_device); + adf_init_hw_data_4xxx(accel_dev->hw_device); accel_pci_dev->revid = pci_get_revid(dev); - hw_data->fuses = pci_read_config(dev, ADF_DEVICE_FUSECTL_OFFSET, 4); + hw_data->fuses = pci_read_config(dev, ADF_4XXX_FUSECTL4_OFFSET, 4); + if (accel_pci_dev->revid == 0x00) { + device_printf(dev, "A0 stepping is not supported.\n"); + ret = ENODEV; + goto out_err; + } /* Get PPAERUCM values and store */ ret = adf_aer_store_ppaerucm_reg(dev, hw_data); @@ -131,6 +137,7 @@ hw_data->accel_mask = hw_data->get_accel_mask(accel_dev); hw_data->ae_mask = hw_data->get_ae_mask(accel_dev); + accel_pci_dev->sku = hw_data->get_sku(hw_data); /* If the device has no acceleration engines then ignore it. */ if (!hw_data->accel_mask || !hw_data->ae_mask || (~hw_data->ae_mask & 0x01)) { @@ -143,7 +150,6 @@ ret = adf_cfg_dev_add(accel_dev); if (ret) goto out_err; - ret = adf_clock_debugfs_add(accel_dev); if (ret) goto out_err; @@ -158,7 +164,7 @@ NULL, NULL, BUS_SPACE_MAXSIZE, - /*BUS_SPACE_UNRESTRICTED*/ 1, + /* BUS_SPACE_UNRESTRICTED */ 1, BUS_SPACE_MAXSIZE, 0, NULL, @@ -172,19 +178,12 @@ hw_data->get_accel_cap(accel_dev); } - accel_pci_dev->sku = hw_data->get_sku(hw_data); - /* Find and map all the device's BARS */ i = 0; for (bar_nr = 0; i < ADF_PCI_MAX_BARS && bar_nr < PCIR_MAX_BAR_0; bar_nr++) { struct adf_bar *bar; - /* - * XXX: This isn't quite right as it will ignore a BAR - * that wasn't assigned a valid resource range by the - * firmware. - */ rid = PCIR_BAR(bar_nr); if (bus_get_resource(dev, SYS_RES_MEMORY, rid, NULL, NULL) != 0) continue; @@ -199,7 +198,7 @@ goto out_err; } bar->base_addr = rman_get_start(bar->virt_addr); - bar->size = rman_get_start(bar->virt_addr); + bar->size = rman_get_size(bar->virt_addr); } pci_enable_busmaster(dev); @@ -261,8 +260,8 @@ adf_methods, sizeof(struct adf_accel_dev) }; -DRIVER_MODULE_ORDERED(qat_c4xxx, pci, adf_driver, NULL, NULL, SI_ORDER_THIRD); -MODULE_VERSION(qat_c4xxx, 1); -MODULE_DEPEND(qat_c4xxx, qat_common, 1, 1, 1); -MODULE_DEPEND(qat_c4xxx, qat_api, 1, 1, 1); -MODULE_DEPEND(qat_c4xxx, linuxkpi, 1, 1, 1); +DRIVER_MODULE_ORDERED(qat_4xxx, pci, adf_driver, NULL, NULL, SI_ORDER_THIRD); +MODULE_VERSION(qat_4xxx, 1); +MODULE_DEPEND(qat_4xxx, qat_common, 1, 1, 1); +MODULE_DEPEND(qat_4xxx, qat_api, 1, 1, 1); +MODULE_DEPEND(qat_4xxx, linuxkpi, 1, 1, 1); diff --git a/sys/dev/qat/qat_hw/qat_c3xxx/adf_c3xxx_hw_data.c b/sys/dev/qat/qat_hw/qat_c3xxx/adf_c3xxx_hw_data.c --- a/sys/dev/qat/qat_hw/qat_c3xxx/adf_c3xxx_hw_data.c +++ b/sys/dev/qat/qat_hw/qat_c3xxx/adf_c3xxx_hw_data.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "adf_c3xxx_hw_data.h" #include "icp_qat_hw.h" #include "adf_heartbeat.h" @@ -368,6 +369,7 @@ hw_data->get_errsou_offset = get_errsou_offset; hw_data->get_clock_speed = get_clock_speed; hw_data->get_sku = get_sku; + hw_data->heartbeat_ctr_num = ADF_NUM_HB_CNT_PER_AE; hw_data->fw_name = ADF_C3XXX_FW; hw_data->fw_mmp_name = ADF_C3XXX_MMP; hw_data->init_admin_comms = adf_init_admin_comms; @@ -406,6 +408,8 @@ hw_data->ring_to_svc_map = ADF_DEFAULT_RING_TO_SRV_MAP; hw_data->pre_reset = adf_dev_pre_reset; hw_data->post_reset = adf_dev_post_reset; + + adf_gen2_init_hw_csr_info(&hw_data->csr_info); } void diff --git a/sys/dev/qat/qat_hw/qat_c3xxx/adf_drv.c b/sys/dev/qat/qat_hw/qat_c3xxx/adf_drv.c --- a/sys/dev/qat/qat_hw/qat_c3xxx/adf_drv.c +++ b/sys/dev/qat/qat_hw/qat_c3xxx/adf_drv.c @@ -133,6 +133,7 @@ /* Get Accelerators and Accelerators Engines masks */ hw_data->accel_mask = hw_data->get_accel_mask(accel_dev); hw_data->ae_mask = hw_data->get_ae_mask(accel_dev); + hw_data->admin_ae_mask = hw_data->ae_mask; accel_pci_dev->sku = hw_data->get_sku(hw_data); /* If the device has no acceleration engines then ignore it. */ diff --git a/sys/dev/qat/qat_hw/qat_c4xxx/adf_c4xxx_hw_data.c b/sys/dev/qat/qat_hw/qat_c4xxx/adf_c4xxx_hw_data.c --- a/sys/dev/qat/qat_hw/qat_c4xxx/adf_c4xxx_hw_data.c +++ b/sys/dev/qat/qat_hw/qat_c4xxx/adf_c4xxx_hw_data.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "adf_c4xxx_hw_data.h" #include "adf_c4xxx_reset.h" #include "adf_c4xxx_inline.h" @@ -754,7 +755,6 @@ ICP_ACCEL_CAPABILITIES_SM3 | ICP_ACCEL_CAPABILITIES_SM4 | ICP_ACCEL_CAPABILITIES_CHACHA_POLY | ICP_ACCEL_CAPABILITIES_AESGCM_SPC | - ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY | ICP_ACCEL_CAPABILITIES_ECEDMONT; if (legfuses & ICP_ACCEL_MASK_CIPHER_SLICE) { @@ -2128,74 +2128,6 @@ } } -static int -adf_get_heartbeat_status_c4xxx(struct adf_accel_dev *accel_dev) -{ - struct adf_hw_device_data *hw_device = accel_dev->hw_device; - struct icp_qat_fw_init_c4xxx_admin_hb_stats *live_s = - (struct icp_qat_fw_init_c4xxx_admin_hb_stats *) - accel_dev->admin->virt_hb_addr; - const size_t max_aes = hw_device->get_num_aes(hw_device); - const size_t stats_size = - max_aes * sizeof(struct icp_qat_fw_init_c4xxx_admin_hb_stats); - int ret = 0; - size_t ae = 0, thr; - unsigned long ae_mask = 0; - int num_threads_per_ae = ADF_NUM_THREADS_PER_AE; - - /* - * Memory layout of Heartbeat - * - * +----------------+----------------+---------+ - * | Live value | Last value | Count | - * +----------------+----------------+---------+ - * \_______________/\_______________/\________/ - * ^ ^ ^ - * | | | - * | | max_aes * sizeof(adf_hb_count) - * | max_aes * - * sizeof(icp_qat_fw_init_c4xxx_admin_hb_stats) - * max_aes * sizeof(icp_qat_fw_init_c4xxx_admin_hb_stats) - */ - struct icp_qat_fw_init_c4xxx_admin_hb_stats *curr_s; - struct icp_qat_fw_init_c4xxx_admin_hb_stats *last_s = live_s + max_aes; - struct adf_hb_count *count = (struct adf_hb_count *)(last_s + max_aes); - - curr_s = malloc(stats_size, M_QAT, M_WAITOK | M_ZERO); - - memcpy(curr_s, live_s, stats_size); - ae_mask = hw_device->ae_mask; - - for_each_set_bit(ae, &ae_mask, max_aes) - { - for (thr = 0; thr < num_threads_per_ae; ++thr) { - struct icp_qat_fw_init_admin_hb_cnt *curr = - &curr_s[ae].stats[thr]; - struct icp_qat_fw_init_admin_hb_cnt *prev = - &last_s[ae].stats[thr]; - u16 req = curr->req_heartbeat_cnt; - u16 resp = curr->resp_heartbeat_cnt; - u16 last = prev->resp_heartbeat_cnt; - - if ((thr == ADF_AE_ADMIN_THREAD || req != resp) && - resp == last) { - u16 retry = ++count[ae].ae_thread[thr]; - - if (retry >= ADF_CFG_HB_COUNT_THRESHOLD) - ret = EIO; - } else { - count[ae].ae_thread[thr] = 0; - } - } - } - - /* Copy current stats for the next iteration */ - memcpy(last_s, curr_s, stats_size); - free(curr_s, M_QAT); - - return ret; -} - void adf_init_hw_data_c4xxx(struct adf_hw_device_data *hw_data) { @@ -2230,6 +2162,7 @@ hw_data->get_clock_speed = get_clock_speed; hw_data->get_eth_doorbell_msg = get_eth_doorbell_msg; hw_data->get_sku = get_sku; + hw_data->heartbeat_ctr_num = ADF_NUM_THREADS_PER_AE; hw_data->check_prod_sku = c4xxx_check_prod_sku; hw_data->fw_name = ADF_C4XXX_FW; hw_data->fw_mmp_name = ADF_C4XXX_MMP; @@ -2256,7 +2189,7 @@ hw_data->reset_hw_units = adf_c4xxx_reset_hw_units; hw_data->exit_accel_units = adf_exit_accel_units; hw_data->ring_to_svc_map = ADF_DEFAULT_RING_TO_SRV_MAP; - hw_data->get_heartbeat_status = adf_get_heartbeat_status_c4xxx; + hw_data->get_heartbeat_status = adf_get_heartbeat_status; hw_data->get_ae_clock = get_ae_clock; hw_data->clock_frequency = ADF_C4XXX_AE_FREQ; hw_data->measure_clock = measure_clock; @@ -2275,6 +2208,9 @@ hw_data->count_ras_event = adf_fw_count_ras_event; hw_data->config_device = adf_config_device; hw_data->set_asym_rings_mask = adf_cfg_set_asym_rings_mask; + + adf_gen2_init_hw_csr_info(&hw_data->csr_info); + hw_data->csr_info.arb_enable_mask = 0xF; } void diff --git a/sys/dev/qat/qat_hw/qat_c4xxx/adf_drv.c b/sys/dev/qat/qat_hw/qat_c4xxx/adf_drv.c --- a/sys/dev/qat/qat_hw/qat_c4xxx/adf_drv.c +++ b/sys/dev/qat/qat_hw/qat_c4xxx/adf_drv.c @@ -130,6 +130,7 @@ /* Get Accelerators and Accelerators Engines masks */ hw_data->accel_mask = hw_data->get_accel_mask(accel_dev); hw_data->ae_mask = hw_data->get_ae_mask(accel_dev); + hw_data->admin_ae_mask = hw_data->ae_mask; /* If the device has no acceleration engines then ignore it. */ if (!hw_data->accel_mask || !hw_data->ae_mask || diff --git a/sys/dev/qat/qat_hw/qat_c62x/adf_c62x_hw_data.c b/sys/dev/qat/qat_hw/qat_c62x/adf_c62x_hw_data.c --- a/sys/dev/qat/qat_hw/qat_c62x/adf_c62x_hw_data.c +++ b/sys/dev/qat/qat_hw/qat_c62x/adf_c62x_hw_data.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "adf_c62x_hw_data.h" #include "icp_qat_hw.h" #include "adf_cfg.h" @@ -373,6 +374,7 @@ hw_data->get_errsou_offset = get_errsou_offset; hw_data->get_clock_speed = get_clock_speed; hw_data->get_sku = get_sku; + hw_data->heartbeat_ctr_num = ADF_NUM_HB_CNT_PER_AE; hw_data->fw_name = ADF_C62X_FW; hw_data->fw_mmp_name = ADF_C62X_MMP; hw_data->init_admin_comms = adf_init_admin_comms; @@ -411,6 +413,8 @@ hw_data->ring_to_svc_map = ADF_DEFAULT_RING_TO_SRV_MAP; hw_data->pre_reset = adf_dev_pre_reset; hw_data->post_reset = adf_dev_post_reset; + + adf_gen2_init_hw_csr_info(&hw_data->csr_info); } void diff --git a/sys/dev/qat/qat_hw/qat_c62x/adf_drv.c b/sys/dev/qat/qat_hw/qat_c62x/adf_drv.c --- a/sys/dev/qat/qat_hw/qat_c62x/adf_drv.c +++ b/sys/dev/qat/qat_hw/qat_c62x/adf_drv.c @@ -133,6 +133,7 @@ /* Get Accelerators and Accelerators Engines masks */ hw_data->accel_mask = hw_data->get_accel_mask(accel_dev); hw_data->ae_mask = hw_data->get_ae_mask(accel_dev); + hw_data->admin_ae_mask = hw_data->ae_mask; accel_pci_dev->sku = hw_data->get_sku(hw_data); /* If the device has no acceleration engines then ignore it. */ if (!hw_data->accel_mask || !hw_data->ae_mask || diff --git a/sys/dev/qat/qat_hw/qat_dh895xcc/adf_dh895xcc_hw_data.c b/sys/dev/qat/qat_hw/qat_dh895xcc/adf_dh895xcc_hw_data.c --- a/sys/dev/qat/qat_hw/qat_dh895xcc/adf_dh895xcc_hw_data.c +++ b/sys/dev/qat/qat_hw/qat_dh895xcc/adf_dh895xcc_hw_data.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "adf_dh895xcc_hw_data.h" #include "icp_qat_hw.h" #include "adf_heartbeat.h" @@ -361,6 +362,7 @@ hw_data->get_clock_speed = get_clock_speed; hw_data->get_sram_bar_id = get_sram_bar_id; hw_data->get_sku = get_sku; + hw_data->heartbeat_ctr_num = ADF_NUM_HB_CNT_PER_AE; hw_data->fw_name = ADF_DH895XCC_FW; hw_data->fw_mmp_name = ADF_DH895XCC_MMP; hw_data->init_admin_comms = adf_init_admin_comms; @@ -396,6 +398,8 @@ hw_data->ring_to_svc_map = ADF_DEFAULT_RING_TO_SRV_MAP; hw_data->pre_reset = adf_dev_pre_reset; hw_data->post_reset = adf_dev_post_reset; + + adf_gen2_init_hw_csr_info(&hw_data->csr_info); } void diff --git a/sys/dev/qat/qat_hw/qat_dh895xcc/adf_drv.c b/sys/dev/qat/qat_hw/qat_dh895xcc/adf_drv.c --- a/sys/dev/qat/qat_hw/qat_dh895xcc/adf_drv.c +++ b/sys/dev/qat/qat_hw/qat_dh895xcc/adf_drv.c @@ -126,6 +126,7 @@ /* Get Accelerators and Accelerators Engines masks */ hw_data->accel_mask = hw_data->get_accel_mask(accel_dev); hw_data->ae_mask = hw_data->get_ae_mask(accel_dev); + hw_data->admin_ae_mask = hw_data->ae_mask; accel_pci_dev->sku = hw_data->get_sku(hw_data); /* If the device has no acceleration engines then ignore it. */ if (!hw_data->accel_mask || !hw_data->ae_mask || diff --git a/sys/modules/qat/qat_api/Makefile b/sys/modules/qat/qat_api/Makefile --- a/sys/modules/qat/qat_api/Makefile +++ b/sys/modules/qat/qat_api/Makefile @@ -44,6 +44,7 @@ SRCS+= common/crypto/sym/qat/lac_sym_qat_hash.c SRCS+= common/crypto/sym/qat/lac_sym_qat_hash_defs_lookup.c SRCS+= common/crypto/sym/qat/lac_sym_qat_cipher.c +SRCS+= common/crypto/sym/qat/lac_sym_qat_constants_table.c SRCS+= common/crypto/sym/qat/lac_sym_qat_key.c SRCS+= common/crypto/sym/key/lac_sym_key.c SRCS+= common/stubs/lac_stubs.c diff --git a/sys/modules/qat/qat_common/Makefile b/sys/modules/qat/qat_common/Makefile --- a/sys/modules/qat/qat_common/Makefile +++ b/sys/modules/qat/qat_common/Makefile @@ -9,6 +9,8 @@ SRCS+= adf_heartbeat.c adf_freebsd_heartbeat_dbg.c SRCS+= adf_dev_mgr.c adf_hw_arbiter.c SRCS+= adf_init.c adf_transport.c adf_isr.c adf_fw_counters.c adf_dev_err.c +SRCS+= adf_gen2_hw_data.c +SRCS+= adf_gen4_hw_data.c SRCS+= qat_freebsd.c SRCS+= adf_freebsd_cfg_dev_dbg.c adf_freebsd_ver_dbg.c SRCS+= adf_cfg_device.c adf_cfg_section.c adf_cfg_instance.c adf_cfg_bundle.c diff --git a/sys/modules/qat/qat_hw/Makefile b/sys/modules/qat/qat_hw/Makefile --- a/sys/modules/qat/qat_hw/Makefile +++ b/sys/modules/qat/qat_hw/Makefile @@ -6,6 +6,7 @@ KMOD= qat_hw SRCS+= qat_c62x/adf_c62x_hw_data.c qat_c62x/adf_drv.c SRCS+= qat_200xx/adf_200xx_hw_data.c qat_200xx/adf_drv.c +SRCS+= qat_4xxx/adf_4xxx_hw_data.c qat_4xxx/adf_drv.c SRCS+= qat_c3xxx/adf_c3xxx_hw_data.c qat_c3xxx/adf_drv.c SRCS+= qat_dh895xcc/adf_dh895xcc_hw_data.c qat_dh895xcc/adf_drv.c SRCS+= qat_c4xxx/adf_c4xxx_hw_data.c qat_c4xxx/adf_drv.c qat_c4xxx/adf_c4xxx_ae_config.c qat_c4xxx/adf_c4xxx_misc_error_stats.c diff --git a/sys/modules/qatfw/Makefile b/sys/modules/qatfw/Makefile --- a/sys/modules/qatfw/Makefile +++ b/sys/modules/qatfw/Makefile @@ -5,6 +5,7 @@ qat_200xx \ qat_c3xxx \ qat_c4xxx \ - qat_dh895xcc + qat_dh895xcc \ + qat_4xxx .include diff --git a/sys/modules/qatfw/qat_4xxx/Makefile b/sys/modules/qatfw/qat_4xxx/Makefile new file mode 100644 --- /dev/null +++ b/sys/modules/qatfw/qat_4xxx/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2007-2022 Intel Corporation +# $FreeBSD$ +.PATH: ${SRCTOP}/sys/contrib/dev/qat + +KMOD= qat_4xxx_fw + +FIRMWS= ${SRCTOP}/sys/contrib/dev/qat/qat_4xxx.bin:qat_4xxx_fw:111 ${SRCTOP}/sys/contrib/dev/qat/qat_4xxx_mmp.bin:qat_4xxx_mmp_fw:111 + +.include