xref: /freebsd/sys/contrib/ncsw/Peripherals/FM/Pcd/fm_kg.c (revision 8ef24a0d4b28fe230e20637f56869cc4148cd2ca)
1 /* Copyright (c) 2008-2011 Freescale Semiconductor, Inc.
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *     * Redistributions of source code must retain the above copyright
7  *       notice, this list of conditions and the following disclaimer.
8  *     * Redistributions in binary form must reproduce the above copyright
9  *       notice, this list of conditions and the following disclaimer in the
10  *       documentation and/or other materials provided with the distribution.
11  *     * Neither the name of Freescale Semiconductor nor the
12  *       names of its contributors may be used to endorse or promote products
13  *       derived from this software without specific prior written permission.
14  *
15  *
16  * ALTERNATIVELY, this software may be distributed under the terms of the
17  * GNU General Public License ("GPL") as published by the Free Software
18  * Foundation, either version 2 of that License or (at your option) any
19  * later version.
20  *
21  * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
22  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /******************************************************************************
34  @File          fm_kg.c
35 
36  @Description   FM PCD ...
37 *//***************************************************************************/
38 #include "std_ext.h"
39 #include "error_ext.h"
40 #include "string_ext.h"
41 #include "debug_ext.h"
42 #include "net_ext.h"
43 #include "fm_port_ext.h"
44 
45 #include "fm_common.h"
46 #include "fm_pcd.h"
47 #include "fm_hc.h"
48 
49 #include "fm_pcd_ipc.h"
50 
51 
52 static t_Error WriteKgarWait(t_FmPcd *p_FmPcd, uint32_t kgar)
53 {
54     WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgar, kgar);
55     /* Wait for GO to be idle and read error */
56     while ((kgar = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgar)) & FM_PCD_KG_KGAR_GO) ;
57     if (kgar & FM_PCD_KG_KGAR_ERR)
58         RETURN_ERROR(MINOR, E_INVALID_STATE, ("Keygen scheme access violation"));
59     return E_OK;
60 }
61 
62 static e_FmPcdKgExtractDfltSelect GetGenericSwDefault(t_FmPcdKgExtractDflt swDefaults[], uint8_t numOfSwDefaults, uint8_t code)
63 {
64     int i;
65 
66     switch(code)
67     {
68         case( KG_SCH_GEN_PARSE_RESULT_N_FQID):
69         case( KG_SCH_GEN_DEFAULT):
70         case( KG_SCH_GEN_NEXTHDR):
71             for(i=0 ; i<numOfSwDefaults ; i++)
72                 if(swDefaults[i].type == e_FM_PCD_KG_GENERIC_NOT_FROM_DATA)
73                     return swDefaults[i].dfltSelect;
74             ASSERT_COND(FALSE);
75         case( KG_SCH_GEN_SHIM1):
76         case( KG_SCH_GEN_SHIM2):
77         case( KG_SCH_GEN_IP_PID_NO_V):
78         case( KG_SCH_GEN_ETH_NO_V):
79         case( KG_SCH_GEN_SNAP_NO_V):
80         case( KG_SCH_GEN_VLAN1_NO_V):
81         case( KG_SCH_GEN_VLAN2_NO_V):
82         case( KG_SCH_GEN_ETH_TYPE_NO_V):
83         case( KG_SCH_GEN_PPP_NO_V):
84         case( KG_SCH_GEN_MPLS1_NO_V):
85         case( KG_SCH_GEN_MPLS_LAST_NO_V):
86         case( KG_SCH_GEN_L3_NO_V):
87         case( KG_SCH_GEN_IP2_NO_V):
88         case( KG_SCH_GEN_GRE_NO_V):
89         case( KG_SCH_GEN_L4_NO_V):
90             for(i=0 ; i<numOfSwDefaults ; i++)
91                 if(swDefaults[i].type == e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V)
92                     return swDefaults[i].dfltSelect;
93 
94         case( KG_SCH_GEN_START_OF_FRM):
95         case( KG_SCH_GEN_ETH):
96         case( KG_SCH_GEN_SNAP):
97         case( KG_SCH_GEN_VLAN1):
98         case( KG_SCH_GEN_VLAN2):
99         case( KG_SCH_GEN_ETH_TYPE):
100         case( KG_SCH_GEN_PPP):
101         case( KG_SCH_GEN_MPLS1):
102         case( KG_SCH_GEN_MPLS2):
103         case( KG_SCH_GEN_MPLS3):
104         case( KG_SCH_GEN_MPLS_LAST):
105         case( KG_SCH_GEN_IPV4):
106         case( KG_SCH_GEN_IPV6):
107         case( KG_SCH_GEN_IPV4_TUNNELED):
108         case( KG_SCH_GEN_IPV6_TUNNELED):
109         case( KG_SCH_GEN_MIN_ENCAP):
110         case( KG_SCH_GEN_GRE):
111         case( KG_SCH_GEN_TCP):
112         case( KG_SCH_GEN_UDP):
113         case( KG_SCH_GEN_IPSEC_AH):
114         case( KG_SCH_GEN_SCTP):
115         case( KG_SCH_GEN_DCCP):
116         case( KG_SCH_GEN_IPSEC_ESP):
117             for(i=0 ; i<numOfSwDefaults ; i++)
118                 if(swDefaults[i].type == e_FM_PCD_KG_GENERIC_FROM_DATA)
119                     return swDefaults[i].dfltSelect;
120         default:
121             return e_FM_PCD_KG_DFLT_ILLEGAL;
122     }
123 }
124 
125 static uint8_t GetGenCode(e_FmPcdExtractFrom src, uint8_t *p_Offset)
126 {
127     *p_Offset = 0;
128 
129     switch(src)
130     {
131         case(e_FM_PCD_EXTRACT_FROM_FRAME_START):
132             return KG_SCH_GEN_START_OF_FRM;
133         case(e_FM_PCD_EXTRACT_FROM_DFLT_VALUE):
134             return KG_SCH_GEN_DEFAULT;
135         case(e_FM_PCD_EXTRACT_FROM_PARSE_RESULT):
136             return KG_SCH_GEN_PARSE_RESULT_N_FQID;
137         case(e_FM_PCD_EXTRACT_FROM_ENQ_FQID):
138             *p_Offset = 32;
139             return KG_SCH_GEN_PARSE_RESULT_N_FQID;
140         case(e_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE):
141             return KG_SCH_GEN_NEXTHDR;
142         default:
143             REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src"));
144             return 0;
145     }
146 }
147 
148 static uint8_t GetGenHdrCode(e_NetHeaderType hdr, e_FmPcdHdrIndex hdrIndex, bool ignoreProtocolValidation)
149 {
150     if(!ignoreProtocolValidation)
151         switch(hdr)
152         {
153             case(HEADER_TYPE_NONE):
154                 ASSERT_COND(FALSE);
155             case(HEADER_TYPE_ETH):
156                 return KG_SCH_GEN_ETH;
157             case(HEADER_TYPE_LLC_SNAP):
158                 return KG_SCH_GEN_SNAP;
159             case(HEADER_TYPE_PPPoE):
160                 return KG_SCH_GEN_PPP;
161             case(HEADER_TYPE_MPLS):
162                 if((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
163                     return KG_SCH_GEN_MPLS1;
164                 if(hdrIndex == e_FM_PCD_HDR_INDEX_2)
165                     return KG_SCH_GEN_MPLS2;
166                 if(hdrIndex == e_FM_PCD_HDR_INDEX_3)
167                     return KG_SCH_GEN_MPLS3;
168                 if(hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
169                     return KG_SCH_GEN_MPLS_LAST;
170                 REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index"));
171                 return 0;
172             case(HEADER_TYPE_IPv4):
173                 if((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
174                     return KG_SCH_GEN_IPV4;
175                 if(hdrIndex == e_FM_PCD_HDR_INDEX_2)
176                     return KG_SCH_GEN_IPV4_TUNNELED;
177                 REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 header index"));
178                 return 0;
179             case(HEADER_TYPE_IPv6):
180                 if((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
181                     return KG_SCH_GEN_IPV6;
182                 if(hdrIndex == e_FM_PCD_HDR_INDEX_2)
183                     return KG_SCH_GEN_IPV6_TUNNELED;
184                 REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 header index"));
185                 return 0;
186             case(HEADER_TYPE_GRE):
187                 return KG_SCH_GEN_GRE;
188             case(HEADER_TYPE_TCP):
189                 return KG_SCH_GEN_TCP;
190             case(HEADER_TYPE_UDP):
191                 return KG_SCH_GEN_UDP;
192             case(HEADER_TYPE_IPSEC_AH):
193                 return KG_SCH_GEN_IPSEC_AH;
194             case(HEADER_TYPE_IPSEC_ESP):
195                 return KG_SCH_GEN_IPSEC_ESP;
196             case(HEADER_TYPE_SCTP):
197                 return KG_SCH_GEN_SCTP;
198             case(HEADER_TYPE_DCCP):
199                 return KG_SCH_GEN_DCCP;
200             default:
201                 REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
202                 return 0;
203         }
204     else
205         switch(hdr)
206         {
207             case(HEADER_TYPE_NONE):
208                 ASSERT_COND(FALSE);
209             case(HEADER_TYPE_ETH):
210                 return KG_SCH_GEN_ETH_NO_V;
211             case(HEADER_TYPE_LLC_SNAP):
212                 return KG_SCH_GEN_SNAP_NO_V;
213             case(HEADER_TYPE_PPPoE):
214                 return KG_SCH_GEN_PPP_NO_V;
215             case(HEADER_TYPE_MPLS):
216                  if((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
217                     return KG_SCH_GEN_MPLS1_NO_V;
218                 if(hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
219                     return KG_SCH_GEN_MPLS_LAST_NO_V;
220                 if((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_3) )
221                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Indexed MPLS Extraction not supported"));
222                 else
223                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index"));
224                 return 0;
225             case(HEADER_TYPE_IPv4):
226             case(HEADER_TYPE_IPv6):
227               if((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
228                     return KG_SCH_GEN_L3_NO_V;
229                 if(hdrIndex == e_FM_PCD_HDR_INDEX_2)
230                     return KG_SCH_GEN_IP2_NO_V;
231                 REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header index"));
232             case(HEADER_TYPE_MINENCAP):
233                 return KG_SCH_GEN_IP2_NO_V;
234             case(HEADER_TYPE_USER_DEFINED_L3):
235                 return KG_SCH_GEN_L3_NO_V;
236             case(HEADER_TYPE_GRE):
237                 return KG_SCH_GEN_GRE_NO_V;
238             case(HEADER_TYPE_TCP):
239             case(HEADER_TYPE_UDP):
240             case(HEADER_TYPE_IPSEC_AH):
241             case(HEADER_TYPE_IPSEC_ESP):
242             case(HEADER_TYPE_SCTP):
243             case(HEADER_TYPE_DCCP):
244                 return KG_SCH_GEN_L4_NO_V;
245             case(HEADER_TYPE_USER_DEFINED_SHIM1):
246                 return KG_SCH_GEN_SHIM1;
247             case(HEADER_TYPE_USER_DEFINED_SHIM2):
248                 return KG_SCH_GEN_SHIM2;
249             default:
250                 REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
251                 return 0;
252         }
253 }
254 static t_GenericCodes GetGenFieldCode(e_NetHeaderType hdr, t_FmPcdFields field, bool ignoreProtocolValidation, e_FmPcdHdrIndex hdrIndex)
255 {
256     if (!ignoreProtocolValidation)
257         switch(hdr)
258         {
259             case(HEADER_TYPE_NONE):
260                 ASSERT_COND(FALSE);
261             case(HEADER_TYPE_ETH):
262                 switch(field.eth)
263                 {
264                     case(NET_HEADER_FIELD_ETH_TYPE):
265                         return KG_SCH_GEN_ETH_TYPE;
266                     default:
267                         REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
268                         return 0;
269                 }
270             case(HEADER_TYPE_VLAN):
271                 switch(field.vlan)
272                 {
273                     case(NET_HEADER_FIELD_VLAN_TCI):
274                         if((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
275                             return KG_SCH_GEN_VLAN1;
276                         if(hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
277                             return KG_SCH_GEN_VLAN2;
278                         REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal VLAN header index"));
279                         return 0;
280                 }
281             case(HEADER_TYPE_MPLS):
282             case(HEADER_TYPE_IPSEC_AH):
283             case(HEADER_TYPE_IPSEC_ESP):
284             case(HEADER_TYPE_LLC_SNAP):
285             case(HEADER_TYPE_PPPoE):
286             case(HEADER_TYPE_IPv4):
287             case(HEADER_TYPE_IPv6):
288             case(HEADER_TYPE_GRE):
289             case(HEADER_TYPE_MINENCAP):
290             case(HEADER_TYPE_USER_DEFINED_L3):
291             case(HEADER_TYPE_TCP):
292             case(HEADER_TYPE_UDP):
293             case(HEADER_TYPE_SCTP):
294             case(HEADER_TYPE_DCCP):
295             case(HEADER_TYPE_USER_DEFINED_L4):
296                 REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
297             default:
298                 REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Header not supported"));
299                 return 0;
300         }
301         else
302             switch(hdr)
303             {
304                 case(HEADER_TYPE_NONE):
305                     ASSERT_COND(FALSE);
306                 case(HEADER_TYPE_ETH):
307                 switch(field.eth)
308                 {
309                     case(NET_HEADER_FIELD_ETH_TYPE):
310                         return KG_SCH_GEN_ETH_TYPE_NO_V;
311                     default:
312                         REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
313                         return 0;
314                 }
315                 case(HEADER_TYPE_VLAN):
316                     switch(field.vlan)
317                     {
318                         case(NET_HEADER_FIELD_VLAN_TCI) :
319                             if((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
320                                 return KG_SCH_GEN_VLAN1_NO_V;
321                             if(hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
322                                 return KG_SCH_GEN_VLAN2_NO_V;
323                             REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal VLAN header index"));
324                             return 0;
325                     }
326                 case(HEADER_TYPE_IPv4):
327                     switch(field.ipv4)
328                     {
329                         case(NET_HEADER_FIELD_IPv4_PROTO):
330                             return KG_SCH_GEN_IP_PID_NO_V;
331                         default:
332                             REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
333                             return 0;
334                     }
335                 case(HEADER_TYPE_IPv6):
336                    switch(field.ipv6)
337                     {
338                         case(NET_HEADER_FIELD_IPv6_NEXT_HDR):
339                             return KG_SCH_GEN_IP_PID_NO_V;
340                         default:
341                             REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
342                             return 0;
343                     }
344                 case(HEADER_TYPE_MPLS):
345                 case(HEADER_TYPE_LLC_SNAP):
346                 case(HEADER_TYPE_PPPoE):
347                 case(HEADER_TYPE_GRE):
348                 case(HEADER_TYPE_MINENCAP):
349                 case(HEADER_TYPE_USER_DEFINED_L3):
350                 case(HEADER_TYPE_TCP):
351                 case(HEADER_TYPE_UDP):
352                 case(HEADER_TYPE_IPSEC_AH):
353                 case(HEADER_TYPE_IPSEC_ESP):
354                 case(HEADER_TYPE_SCTP):
355                 case(HEADER_TYPE_DCCP):
356                 case(HEADER_TYPE_USER_DEFINED_L4):
357                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
358                     return 0;
359                 default:
360                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Header not supported"));
361                     return 0;
362             }
363 }
364 
365 static t_KnownFieldsMasks GetKnownProtMask(e_NetHeaderType hdr, e_FmPcdHdrIndex index, t_FmPcdFields field)
366 {
367     switch(hdr)
368     {
369         case(HEADER_TYPE_NONE):
370             ASSERT_COND(FALSE);
371         case(HEADER_TYPE_ETH):
372             switch(field.eth)
373             {
374                 case(NET_HEADER_FIELD_ETH_DA):
375                     return KG_SCH_KN_MACDST;
376                 case(NET_HEADER_FIELD_ETH_SA):
377                     return KG_SCH_KN_MACSRC;
378                 case(NET_HEADER_FIELD_ETH_TYPE):
379                     return KG_SCH_KN_ETYPE;
380                 default:
381                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
382                     return 0;
383            }
384         case(HEADER_TYPE_LLC_SNAP):
385             switch(field.llcSnap)
386             {
387                 case(NET_HEADER_FIELD_LLC_SNAP_TYPE):
388                     return KG_SCH_KN_ETYPE;
389                 default:
390                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
391                     return 0;
392            }
393         case(HEADER_TYPE_VLAN):
394             switch(field.vlan)
395             {
396                 case(NET_HEADER_FIELD_VLAN_TCI):
397                     if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
398                         return KG_SCH_KN_TCI1;
399                     if(index == e_FM_PCD_HDR_INDEX_LAST)
400                         return KG_SCH_KN_TCI2;
401                     else
402                     {
403                         REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
404                         return 0;
405                     }
406                 default:
407                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
408                     return 0;
409             }
410         case(HEADER_TYPE_MPLS):
411             switch(field.mpls)
412             {
413                 case(NET_HEADER_FIELD_MPLS_LABEL_STACK):
414                     if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
415                         return KG_SCH_KN_MPLS1;
416                     if(index == e_FM_PCD_HDR_INDEX_2)
417                         return KG_SCH_KN_MPLS2;
418                     if(index == e_FM_PCD_HDR_INDEX_LAST)
419                         return KG_SCH_KN_MPLS_LAST;
420                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS index"));
421                     return 0;
422                 default:
423                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
424                     return 0;
425             }
426         case(HEADER_TYPE_IPv4):
427             switch(field.ipv4)
428             {
429                 case(NET_HEADER_FIELD_IPv4_SRC_IP):
430                     if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
431                         return KG_SCH_KN_IPSRC1;
432                     if(index == e_FM_PCD_HDR_INDEX_2)
433                         return KG_SCH_KN_IPSRC2;
434                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
435                     return 0;
436                 case(NET_HEADER_FIELD_IPv4_DST_IP):
437                     if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
438                         return KG_SCH_KN_IPDST1;
439                     if(index == e_FM_PCD_HDR_INDEX_2)
440                         return KG_SCH_KN_IPDST2;
441                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
442                     return 0;
443                 case(NET_HEADER_FIELD_IPv4_PROTO):
444                     if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
445                         return KG_SCH_KN_PTYPE1;
446                     if(index == e_FM_PCD_HDR_INDEX_2)
447                         return KG_SCH_KN_PTYPE2;
448                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
449                     return 0;
450                 case(NET_HEADER_FIELD_IPv4_TOS):
451                     if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
452                         return KG_SCH_KN_IPTOS_TC1;
453                     if(index == e_FM_PCD_HDR_INDEX_2)
454                         return KG_SCH_KN_IPTOS_TC2;
455                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
456                     return 0;
457                 default:
458                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
459                     return 0;
460             }
461         case(HEADER_TYPE_IPv6):
462              switch(field.ipv6)
463             {
464                 case(NET_HEADER_FIELD_IPv6_SRC_IP):
465                     if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
466                         return KG_SCH_KN_IPSRC1;
467                     if(index == e_FM_PCD_HDR_INDEX_2)
468                         return KG_SCH_KN_IPSRC2;
469                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
470                     return 0;
471                 case(NET_HEADER_FIELD_IPv6_DST_IP):
472                     if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
473                         return KG_SCH_KN_IPDST1;
474                     if(index == e_FM_PCD_HDR_INDEX_2)
475                         return KG_SCH_KN_IPDST2;
476                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
477                     return 0;
478                 case(NET_HEADER_FIELD_IPv6_NEXT_HDR):
479                     if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
480                         return KG_SCH_KN_PTYPE1;
481                     if(index == e_FM_PCD_HDR_INDEX_2)
482                         return KG_SCH_KN_PTYPE2;
483                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
484                     return 0;
485                 case(NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL | NET_HEADER_FIELD_IPv6_TC):
486                     if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
487                         return (KG_SCH_KN_IPV6FL1 | KG_SCH_KN_IPTOS_TC1);
488                     if(index == e_FM_PCD_HDR_INDEX_2)
489                         return (KG_SCH_KN_IPV6FL2 | KG_SCH_KN_IPTOS_TC2);
490                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
491                     return 0;
492                 default:
493                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
494                     return 0;
495             }
496         case(HEADER_TYPE_GRE):
497             switch(field.gre)
498             {
499                 case(NET_HEADER_FIELD_GRE_TYPE):
500                     return KG_SCH_KN_GREPTYPE;
501                 default:
502                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
503                     return 0;
504            }
505         case(HEADER_TYPE_MINENCAP):
506             switch(field.minencap)
507             {
508                 case(NET_HEADER_FIELD_MINENCAP_SRC_IP):
509                     return KG_SCH_KN_IPSRC2;
510                 case(NET_HEADER_FIELD_MINENCAP_DST_IP):
511                     return KG_SCH_KN_IPDST2;
512                 case(NET_HEADER_FIELD_MINENCAP_TYPE):
513                     return KG_SCH_KN_PTYPE2;
514                 default:
515                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
516                     return 0;
517            }
518         case(HEADER_TYPE_TCP):
519             switch(field.tcp)
520             {
521                 case(NET_HEADER_FIELD_TCP_PORT_SRC):
522                     return KG_SCH_KN_L4PSRC;
523                 case(NET_HEADER_FIELD_TCP_PORT_DST):
524                     return KG_SCH_KN_L4PDST;
525                 case(NET_HEADER_FIELD_TCP_FLAGS):
526                     return KG_SCH_KN_TFLG;
527                 default:
528                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
529                     return 0;
530             }
531         case(HEADER_TYPE_UDP):
532             switch(field.udp)
533             {
534                 case(NET_HEADER_FIELD_UDP_PORT_SRC):
535                     return KG_SCH_KN_L4PSRC;
536                 case(NET_HEADER_FIELD_UDP_PORT_DST):
537                     return KG_SCH_KN_L4PDST;
538                 default:
539                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
540                     return 0;
541             }
542         case(HEADER_TYPE_IPSEC_AH):
543             switch(field.ipsecAh)
544             {
545                 case(NET_HEADER_FIELD_IPSEC_AH_SPI):
546                     return KG_SCH_KN_IPSEC_SPI;
547                 case(NET_HEADER_FIELD_IPSEC_AH_NH):
548                     return KG_SCH_KN_IPSEC_NH;
549                 default:
550                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
551                     return 0;
552             }
553         case(HEADER_TYPE_IPSEC_ESP):
554             switch(field.ipsecEsp)
555             {
556                 case(NET_HEADER_FIELD_IPSEC_ESP_SPI):
557                     return KG_SCH_KN_IPSEC_SPI;
558                 default:
559                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
560                     return 0;
561             }
562         case(HEADER_TYPE_SCTP):
563             switch(field.sctp)
564             {
565                 case(NET_HEADER_FIELD_SCTP_PORT_SRC):
566                     return KG_SCH_KN_L4PSRC;
567                 case(NET_HEADER_FIELD_SCTP_PORT_DST):
568                     return KG_SCH_KN_L4PDST;
569                 default:
570                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
571                     return 0;
572             }
573         case(HEADER_TYPE_DCCP):
574             switch(field.dccp)
575             {
576                 case(NET_HEADER_FIELD_DCCP_PORT_SRC):
577                     return KG_SCH_KN_L4PSRC;
578                 case(NET_HEADER_FIELD_DCCP_PORT_DST):
579                     return KG_SCH_KN_L4PDST;
580                 default:
581                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
582                     return 0;
583             }
584         case(HEADER_TYPE_PPPoE):
585             switch(field.pppoe)
586             {
587                 case(NET_HEADER_FIELD_PPPoE_PID):
588                     return KG_SCH_KN_PPPID;
589                 case(NET_HEADER_FIELD_PPPoE_SID):
590                     return KG_SCH_KN_PPPSID;
591                 default:
592                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
593                     return 0;
594             }
595         default:
596             REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
597             return 0;
598     }
599 }
600 
601 
602 static uint8_t GetKnownFieldId(uint32_t bitMask)
603 {
604     uint8_t cnt = 0;
605 
606     while (bitMask)
607         if(bitMask & 0x80000000)
608             break;
609         else
610         {
611             cnt++;
612             bitMask <<= 1;
613         }
614     return cnt;
615 
616 }
617 
618 static uint8_t GetExtractedOrMask(uint8_t bitOffset, bool fqid)
619 {
620     uint8_t i, mask, numOfOnesToClear, walking1Mask = 1;
621 
622     /* bitOffset 1-7 --> mask 0x1-0x7F */
623     if(bitOffset<8)
624     {
625         mask = 0;
626         for(i = 0 ; i < bitOffset ; i++, walking1Mask <<= 1)
627             mask |= walking1Mask;
628     }
629     else
630     {
631        mask = 0xFF;
632        numOfOnesToClear = 0;
633        if(fqid && bitOffset>24)
634            /* bitOffset 25-31 --> mask 0xFE-0x80 */
635            numOfOnesToClear = (uint8_t)(bitOffset-24);
636        else
637           /* bitOffset 9-15 --> mask 0xFE-0x80 */
638           if(!fqid && bitOffset>8)
639                numOfOnesToClear = (uint8_t)(bitOffset-8);
640        for(i = 0 ; i < numOfOnesToClear ; i++, walking1Mask <<= 1)
641            mask &= ~walking1Mask;
642        /* bitOffset 8-24 for FQID, 8 for PP --> no mask (0xFF)*/
643     }
644     return mask;
645 }
646 
647 
648 t_Error FmPcdKgBuildClsPlanGrp(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_Grp, t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet)
649 {
650     t_FmPcd                         *p_FmPcd = (t_FmPcd*)h_FmPcd;
651     t_FmPcdKgClsPlanGrp             *p_ClsPlanGrp;
652     t_FmPcdIpcKgClsPlanParams       kgAlloc;
653     t_Error                         err = E_OK;
654     uint32_t                        oredVectors = 0;
655     uint32_t                        intFlags;
656     int                             i, j;
657 
658     if (p_Grp->numOfOptions >= FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS))
659         RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Too many classification plan basic options selected."));
660 
661     intFlags = FmPcdLock(p_FmPcd);
662 
663     /* find a new clsPlan group */
664     for(i = 0;i<FM_MAX_NUM_OF_PORTS;i++)
665         if(!p_FmPcd->p_FmPcdKg->clsPlanGrps[i].used)
666             break;
667     if(i== FM_MAX_NUM_OF_PORTS)
668     {
669         FmPcdUnlock(p_FmPcd, intFlags);
670         RETURN_ERROR(MAJOR, E_FULL,("No classification plan groups available."));
671     }
672     p_FmPcd->p_FmPcdKg->clsPlanGrps[i].used = TRUE;
673     p_Grp->clsPlanGrpId = (uint8_t)i;
674 
675     if(p_Grp->numOfOptions == 0)
676         p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId = (uint8_t)i;
677 
678     if (!TRY_LOCK(NULL, &p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock))
679     {
680         FmPcdUnlock(p_FmPcd, intFlags);
681         return ERROR_CODE(E_BUSY);
682     }
683     FmPcdUnlock(p_FmPcd, intFlags);
684 
685     p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[i];
686     p_ClsPlanGrp->netEnvId = p_Grp->netEnvId;
687     p_ClsPlanGrp->owners = 0;
688     FmPcdSetClsPlanGrpId(p_FmPcd, p_Grp->netEnvId, p_Grp->clsPlanGrpId);
689     FmPcdIncNetEnvOwners(p_FmPcd, p_Grp->netEnvId);
690 
691     p_ClsPlanGrp->sizeOfGrp = (uint16_t)(1<<p_Grp->numOfOptions);
692     /* a minimal group of 8 is required */
693     if(p_ClsPlanGrp->sizeOfGrp < CLS_PLAN_NUM_PER_GRP)
694         p_ClsPlanGrp->sizeOfGrp = CLS_PLAN_NUM_PER_GRP;
695     if(p_FmPcd->guestId == NCSW_MASTER_ID)
696     {
697         err = KgAllocClsPlanEntries(h_FmPcd, p_ClsPlanGrp->sizeOfGrp, p_FmPcd->guestId, &p_ClsPlanGrp->baseEntry);
698 
699         if(err)
700         {
701             RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock);
702             RETURN_ERROR(MINOR, E_INVALID_STATE, NO_MSG);
703         }
704 
705     }
706     else
707     {
708         t_FmPcdIpcMsg   msg;
709         uint32_t        replyLength;
710         t_FmPcdIpcReply reply;
711 
712         /* in GUEST_PARTITION, we use the IPC, to also set a private driver group if required */
713         memset(&reply, 0, sizeof(reply));
714         memset(&msg, 0, sizeof(msg));
715         memset(&kgAlloc, 0, sizeof(kgAlloc));
716         kgAlloc.guestId = p_FmPcd->guestId;
717         kgAlloc.numOfClsPlanEntries = p_ClsPlanGrp->sizeOfGrp;
718         msg.msgId = FM_PCD_ALLOC_KG_CLSPLAN;
719         memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc));
720         replyLength = (sizeof(uint32_t) + sizeof(p_ClsPlanGrp->baseEntry));
721         if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
722                                      (uint8_t*)&msg,
723                                      sizeof(msg.msgId) + sizeof(kgAlloc),
724                                      (uint8_t*)&reply,
725                                      &replyLength,
726                                      NULL,
727                                      NULL)) != E_OK)
728         {
729             RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock);
730             RETURN_ERROR(MAJOR, err, NO_MSG);
731         }
732 
733         if (replyLength != (sizeof(uint32_t) + sizeof(p_ClsPlanGrp->baseEntry)))
734         {
735             RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock);
736             RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
737         }
738         if ((t_Error)reply.error != E_OK)
739         {
740             RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock);
741             RETURN_ERROR(MINOR, (t_Error)reply.error, NO_MSG);
742         }
743 
744         p_ClsPlanGrp->baseEntry = *(uint8_t*)(reply.replyBody);
745     }
746 
747     /* build classification plan entries parameters */
748     p_ClsPlanSet->baseEntry = p_ClsPlanGrp->baseEntry;
749     p_ClsPlanSet->numOfClsPlanEntries = p_ClsPlanGrp->sizeOfGrp;
750 
751     oredVectors = 0;
752     for(i = 0; i<p_Grp->numOfOptions; i++)
753     {
754         oredVectors |= p_Grp->optVectors[i];
755         /* save an array of used options - the indexes represent the power of 2 index */
756         p_ClsPlanGrp->optArray[i] = p_Grp->options[i];
757     }
758     /* set the classification plan relevant entries so that all bits
759      * relevant to the list of options is cleared
760      */
761     for(j = 0; j<p_ClsPlanGrp->sizeOfGrp; j++)
762         p_ClsPlanSet->vectors[j] = ~oredVectors;
763 
764     for(i = 0; i<p_Grp->numOfOptions; i++)
765     {
766        /* option i got the place 2^i in the clsPlan array. all entries that
767          * have bit i set, should have the vector bit cleared. So each option
768          * has one location that it is exclusive (1,2,4,8...) and represent the
769          * presence of that option only, and other locations that represent a
770          * combination of options.
771          * e.g:
772          * If ethernet-BC is option 1 it gets entry 2 in the table. Entry 2
773          * now represents a frame with ethernet-BC header - so the bit
774          * representing ethernet-BC should be set and all other option bits
775          * should be cleared.
776          * Entries 2,3,6,7,10... also have ethernet-BC and therefore have bit
777          * vector[1] set, but they also have other bits set:
778          * 3=1+2, options 0 and 1
779          * 6=2+4, options 1 and 2
780          * 7=1+2+4, options 0,1,and 2
781          * 10=2+8, options 1 and 3
782          * etc.
783          * */
784 
785         /* now for each option (i), we set their bits in all entries (j)
786          * that contain bit 2^i.
787          */
788         for(j = 0; j<p_ClsPlanGrp->sizeOfGrp; j++)
789         {
790             if(j & (1<<i))
791                 p_ClsPlanSet->vectors[j] |= p_Grp->optVectors[i];
792         }
793     }
794 
795     RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock);
796 
797     return E_OK;
798 }
799 
800 void FmPcdKgDestroyClsPlanGrp(t_Handle h_FmPcd, uint8_t grpId)
801 {
802     t_FmPcd                         *p_FmPcd = (t_FmPcd*)h_FmPcd;
803     t_FmPcdIpcKgClsPlanParams       kgAlloc;
804     t_Error                         err;
805     t_FmPcdIpcMsg                   msg;
806     uint32_t                        replyLength;
807     t_FmPcdIpcReply                 reply;
808 
809     /* check that no port is bound to this clsPlan */
810     if(p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].owners)
811     {
812         REPORT_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a clsPlan grp that has ports bound to"));
813         return;
814     }
815 
816     FmPcdDecNetEnvOwners(p_FmPcd, p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].netEnvId);
817 
818     /* free blocks */
819     if(p_FmPcd->guestId == NCSW_MASTER_ID)
820     {
821         KgFreeClsPlanEntries(h_FmPcd,
822                              p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].sizeOfGrp,
823                              p_FmPcd->guestId,
824                              p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].baseEntry);
825     }
826     else    /* in GUEST_PARTITION, we use the IPC, to also set a private driver group if required */
827     {
828         memset(&reply, 0, sizeof(reply));
829         memset(&msg, 0, sizeof(msg));
830         kgAlloc.guestId = p_FmPcd->guestId;
831         kgAlloc.numOfClsPlanEntries = p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].sizeOfGrp;
832         kgAlloc.clsPlanBase = p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].baseEntry;
833         msg.msgId = FM_PCD_FREE_KG_CLSPLAN;
834         memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc));
835         replyLength = sizeof(uint32_t);
836         if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
837                                      (uint8_t*)&msg,
838                                      sizeof(msg.msgId) + sizeof(kgAlloc),
839                                      (uint8_t*)&reply,
840                                      &replyLength,
841                                      NULL,
842                                      NULL)) != E_OK)
843         {
844             REPORT_ERROR(MINOR, err, NO_MSG);
845             return;
846         }
847         if (replyLength != sizeof(uint32_t))
848         {
849             REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
850             return;
851         }
852         if((t_Error)reply.error != E_OK)
853         {
854             REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Free KG clsPlan failed"));
855             return;
856         }
857     }
858 
859     if(grpId == p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId)
860         p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId = ILLEGAL_CLS_PLAN;
861     /* clear clsPlan driver structure */
862     memset(&p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId], 0, sizeof(t_FmPcdKgClsPlanGrp));
863 }
864 
865 t_Error FmPcdKgBuildBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort, uint32_t *p_SpReg, bool add)
866 {
867     t_FmPcd                 *p_FmPcd = (t_FmPcd*)h_FmPcd;
868     uint32_t                j, schemesPerPortVector = 0;
869     t_FmPcdKgScheme         *p_Scheme;
870     uint8_t                 i, relativeSchemeId;
871     uint32_t                tmp, walking1Mask;
872     uint8_t                 swPortIndex = 0;
873 
874     SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
875     SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE);
876     SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
877 
878     /* for each scheme */
879     for(i = 0; i<p_BindPort->numOfSchemes; i++)
880     {
881         relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]);
882         if(relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES)
883             RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
884 
885         if(add)
886         {
887             if (!FmPcdKgIsSchemeValidSw(h_FmPcd, relativeSchemeId))
888                 RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Requested scheme is invalid."));
889 
890             p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId];
891             /* check netEnvId  of the port against the scheme netEnvId */
892             if((p_Scheme->netEnvId != p_BindPort->netEnvId) && (p_Scheme->netEnvId != ILLEGAL_NETENV))
893                 RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port may not be bound to requested scheme - differ in netEnvId"));
894 
895             /* if next engine is private port policer profile, we need to check that it is valid */
896             HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, p_BindPort->hardwarePortId);
897             if(p_Scheme->nextRelativePlcrProfile)
898             {
899                 for(j = 0;j<p_Scheme->numOfProfiles;j++)
900                 {
901                     ASSERT_COND(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].h_FmPort);
902                     if(p_Scheme->relativeProfileId+j >= p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles)
903                         RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Relative profile not in range"));
904                      if(!FmPcdPlcrIsProfileValid(p_FmPcd, (uint16_t)(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase + p_Scheme->relativeProfileId + j)))
905                         RETURN_ERROR(MINOR, E_INVALID_STATE, ("Relative profile not valid."));
906                 }
907             }
908             if(!p_BindPort->useClsPlan)
909             {
910                 /* if this port does not use clsPlan, it may not be bound to schemes with units that contain
911                 cls plan options. Schemes that are used only directly, should not be checked.
912                 it also may not be bound to schemes that go to CC with units that are options  - so we OR
913                 the match vector and the grpBits (= ccUnits) */
914                 if ((p_Scheme->matchVector != SCHEME_ALWAYS_DIRECT) || p_Scheme->ccUnits)
915                 {
916                     walking1Mask = 0x80000000;
917                     tmp = (p_Scheme->matchVector == SCHEME_ALWAYS_DIRECT)? 0:p_Scheme->matchVector;
918                     tmp |= p_Scheme->ccUnits;
919                     while (tmp)
920                     {
921                         if(tmp & walking1Mask)
922                         {
923                             tmp &= ~walking1Mask;
924                             if(!PcdNetEnvIsUnitWithoutOpts(p_FmPcd, p_Scheme->netEnvId, walking1Mask))
925                                 RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port (without clsPlan) may not be bound to requested scheme - uses clsPlan options"));
926                         }
927                         walking1Mask >>= 1;
928                     }
929                 }
930             }
931         }
932         /* build vector */
933         schemesPerPortVector |= 1 << (31 - p_BindPort->schemesIds[i]);
934     }
935 
936     *p_SpReg = schemesPerPortVector;
937 
938     return E_OK;
939 }
940 
941 void FmPcdKgIncSchemeOwners(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort)
942 {
943     t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
944     int             i;
945     t_FmPcdKgScheme *p_Scheme;
946 
947     /* for each scheme - update owners counters */
948     for(i = 0; i<p_BindPort->numOfSchemes; i++)
949     {
950         p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[p_BindPort->schemesIds[i]];
951 
952         /* increment owners number */
953         p_Scheme->owners++;
954     }
955 }
956 
957 void FmPcdKgDecSchemeOwners(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort)
958 {
959     t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
960     int             i;
961     t_FmPcdKgScheme *p_Scheme;
962 
963     /* for each scheme - update owners counters */
964     for(i = 0; i<p_BindPort->numOfSchemes; i++)
965     {
966         p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[p_BindPort->schemesIds[i]];
967 
968         /* increment owners number */
969         ASSERT_COND(p_Scheme->owners);
970         p_Scheme->owners--;
971     }
972 }
973 
974 static t_Error KgWriteSp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t spReg, bool add)
975 {
976     t_FmPcdKgPortConfigRegs *p_FmPcdKgPortRegs;
977     uint32_t                tmpKgarReg = 0, tmpKgpeSp, intFlags;
978     t_Error                 err = E_OK;
979 
980     if (p_FmPcd->h_Hc)
981         return FmHcKgWriteSp(p_FmPcd->h_Hc, hardwarePortId, spReg, add);
982 
983     p_FmPcdKgPortRegs = &p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs;
984 
985     tmpKgarReg = FmPcdKgBuildReadPortSchemeBindActionReg(hardwarePortId);
986     intFlags = FmPcdLock(p_FmPcd);
987     err = WriteKgarWait(p_FmPcd, tmpKgarReg);
988     if(err)
989     {
990         FmPcdUnlock(p_FmPcd, intFlags);
991         RETURN_ERROR(MINOR, err, NO_MSG);
992     }
993 
994     tmpKgpeSp = GET_UINT32(p_FmPcdKgPortRegs->kgoe_sp);
995 
996     if(add)
997         tmpKgpeSp |= spReg;
998     else /* clear */
999         tmpKgpeSp &= ~spReg;
1000 
1001     WRITE_UINT32(p_FmPcdKgPortRegs->kgoe_sp, tmpKgpeSp);
1002 
1003     tmpKgarReg = FmPcdKgBuildWritePortSchemeBindActionReg(hardwarePortId);
1004 
1005     err = WriteKgarWait(p_FmPcd, tmpKgarReg);
1006     FmPcdUnlock(p_FmPcd, intFlags);
1007     return err;
1008 }
1009 
1010 static t_Error KgWriteCpp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t cppReg)
1011 {
1012     t_FmPcdKgPortConfigRegs *p_FmPcdKgPortRegs;
1013     uint32_t                tmpKgarReg, intFlags;
1014     t_Error                 err;
1015 
1016     if (p_FmPcd->h_Hc)
1017         return FmHcKgWriteCpp(p_FmPcd->h_Hc, hardwarePortId, cppReg);
1018 
1019     p_FmPcdKgPortRegs = &p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs;
1020     intFlags = FmPcdLock(p_FmPcd);
1021     WRITE_UINT32(p_FmPcdKgPortRegs->kgoe_cpp, cppReg);
1022 
1023     tmpKgarReg = FmPcdKgBuildWritePortClsPlanBindActionReg(hardwarePortId);
1024     err = WriteKgarWait(p_FmPcd, tmpKgarReg);
1025     FmPcdUnlock(p_FmPcd, intFlags);
1026 
1027     return err;
1028 }
1029 
1030 static void FmPcdKgUnbindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId)
1031 {
1032     KgWriteCpp(p_FmPcd, hardwarePortId, 0);
1033 }
1034 
1035 static t_Error KgBindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId)
1036 {
1037     uint32_t                tmpKgpeCpp = 0;
1038 
1039     tmpKgpeCpp = FmPcdKgBuildCppReg(p_FmPcd, clsPlanGrpId);
1040     return KgWriteCpp(p_FmPcd, hardwarePortId, tmpKgpeCpp);
1041 }
1042 
1043 t_Error FmPcdKgBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes  *p_SchemeBind)
1044 {
1045     t_FmPcd                 *p_FmPcd = (t_FmPcd*)h_FmPcd;
1046     uint32_t                spReg;
1047     t_Error                 err = E_OK;
1048 
1049     err = FmPcdKgBuildBindPortToSchemes(h_FmPcd, p_SchemeBind, &spReg, TRUE);
1050     if(err)
1051         RETURN_ERROR(MAJOR, err, NO_MSG);
1052 
1053     err = KgWriteSp(p_FmPcd, p_SchemeBind->hardwarePortId, spReg, TRUE);
1054     if(err)
1055         RETURN_ERROR(MAJOR, err, NO_MSG);
1056 
1057     FmPcdKgIncSchemeOwners(h_FmPcd, p_SchemeBind);
1058 
1059     return E_OK;
1060 }
1061 
1062 t_Error FmPcdKgUnbindPortToSchemes(t_Handle h_FmPcd ,  t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind)
1063 {
1064     t_FmPcd                 *p_FmPcd = (t_FmPcd*)h_FmPcd;
1065     uint32_t                spReg;
1066     t_Error                 err = E_OK;
1067 
1068     err = FmPcdKgBuildBindPortToSchemes(h_FmPcd, p_SchemeBind, &spReg, FALSE);
1069     if(err)
1070         RETURN_ERROR(MAJOR, err, NO_MSG);
1071 
1072     err = KgWriteSp(p_FmPcd, p_SchemeBind->hardwarePortId, spReg, FALSE);
1073     if(err)
1074         RETURN_ERROR(MAJOR, err, NO_MSG);
1075 
1076     FmPcdKgDecSchemeOwners(h_FmPcd, p_SchemeBind);
1077 
1078     return E_OK;
1079 }
1080 
1081 bool     FmPcdKgIsSchemeValidSw(t_Handle h_FmPcd, uint8_t schemeId)
1082 {
1083     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
1084 
1085     return p_FmPcd->p_FmPcdKg->schemes[schemeId].valid;
1086 }
1087 
1088 bool     KgIsSchemeAlwaysDirect(t_Handle h_FmPcd, uint8_t schemeId)
1089 {
1090     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
1091 
1092     if(p_FmPcd->p_FmPcdKg->schemes[schemeId].matchVector == SCHEME_ALWAYS_DIRECT)
1093         return TRUE;
1094     else
1095         return FALSE;
1096 }
1097 
1098 t_Error  FmPcdKgAllocSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds)
1099 {
1100     t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
1101     uint32_t            intFlags;
1102     uint8_t             i,j;
1103 
1104     SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
1105     SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE);
1106 
1107     intFlags = FmPcdLock(p_FmPcd);
1108     for(j=0,i=0;i<FM_PCD_KG_NUM_OF_SCHEMES && j<numOfSchemes;i++)
1109     {
1110         if(!p_FmPcd->p_FmPcdKg->schemesMng[i].allocated)
1111         {
1112             p_FmPcd->p_FmPcdKg->schemesMng[i].allocated = TRUE;
1113             p_FmPcd->p_FmPcdKg->schemesMng[i].ownerId = guestId;
1114             p_SchemesIds[j] = i;
1115             j++;
1116         }
1117     }
1118 
1119     if (j != numOfSchemes)
1120     {
1121         /* roll back */
1122         for(j--; j; j--)
1123         {
1124             p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[j]].allocated = FALSE;
1125             p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[j]].ownerId = 0;
1126             p_SchemesIds[j] = 0;
1127         }
1128         FmPcdUnlock(p_FmPcd, intFlags);
1129         RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("No schemes found"));
1130     }
1131     FmPcdUnlock(p_FmPcd, intFlags);
1132 
1133     return E_OK;
1134 }
1135 
1136 t_Error  FmPcdKgFreeSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds)
1137 {
1138     t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
1139     uint32_t            intFlags;
1140     uint8_t             i;
1141 
1142     SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
1143     SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE);
1144 
1145     intFlags = FmPcdLock(p_FmPcd);
1146 
1147     for(i=0;i<numOfSchemes;i++)
1148     {
1149         if(!p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].allocated)
1150         {
1151             FmPcdUnlock(p_FmPcd, intFlags);
1152             RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Scheme was not previously allocated"));
1153         }
1154         if(p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].ownerId != guestId)
1155         {
1156             FmPcdUnlock(p_FmPcd, intFlags);
1157             RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Scheme is not owned by caller. "));
1158         }
1159         p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].allocated = FALSE;
1160         p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].ownerId = 0;
1161     }
1162 
1163     FmPcdUnlock(p_FmPcd, intFlags);
1164     return E_OK;
1165 }
1166 
1167 t_Error  KgAllocClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t *p_First)
1168 {
1169     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
1170     uint32_t    intFlags;
1171     uint8_t     numOfBlocks, blocksFound=0, first=0;
1172     uint8_t     i, j;
1173 
1174     intFlags = FmPcdLock(p_FmPcd);
1175 
1176     if(!numOfClsPlanEntries)
1177     {
1178         FmPcdUnlock(p_FmPcd, intFlags);
1179         return E_OK;
1180     }
1181 
1182     if ((numOfClsPlanEntries % CLS_PLAN_NUM_PER_GRP) || (!POWER_OF_2(numOfClsPlanEntries)))
1183     {
1184         FmPcdUnlock(p_FmPcd, intFlags);
1185         RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfClsPlanEntries must be a power of 2 and divisible by 8"));
1186     }
1187 
1188     numOfBlocks =  (uint8_t)(numOfClsPlanEntries/CLS_PLAN_NUM_PER_GRP);
1189 
1190     /* try to find consequent blocks */
1191     first = 0;
1192     for(i=0;i<FM_PCD_MAX_NUM_OF_CLS_PLANS/CLS_PLAN_NUM_PER_GRP;)
1193     {
1194         if(!p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].allocated)
1195         {
1196             blocksFound++;
1197             i++;
1198             if(blocksFound == numOfBlocks)
1199                 break;
1200         }
1201         else
1202         {
1203             blocksFound = 0;
1204             /* advance i to the next aligned address */
1205             first = i = (uint8_t)(first + numOfBlocks);
1206         }
1207     }
1208 
1209     if(blocksFound == numOfBlocks)
1210     {
1211         *p_First = (uint8_t)(first*CLS_PLAN_NUM_PER_GRP);
1212         for(j = first; j<first + numOfBlocks; j++)
1213         {
1214             p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[j].allocated = TRUE;
1215             p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[j].ownerId = guestId;
1216         }
1217         FmPcdUnlock(p_FmPcd, intFlags);
1218 
1219         return E_OK;
1220     }
1221     else
1222     {
1223         FmPcdUnlock(p_FmPcd, intFlags);
1224         RETURN_ERROR(MINOR, E_FULL, ("No recources for clsPlan"));
1225     }
1226 }
1227 
1228 void  KgFreeClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t base)
1229 {
1230     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
1231     uint32_t    intFlags;
1232     uint8_t     numOfBlocks;
1233     uint8_t     i, baseBlock;
1234 
1235     UNUSED( guestId);
1236 
1237     intFlags = FmPcdLock(p_FmPcd);
1238 
1239     numOfBlocks =  (uint8_t)(numOfClsPlanEntries/CLS_PLAN_NUM_PER_GRP);
1240     ASSERT_COND(!(base%CLS_PLAN_NUM_PER_GRP));
1241 
1242     baseBlock = (uint8_t)(base/CLS_PLAN_NUM_PER_GRP);
1243     for(i=baseBlock;i<baseBlock+numOfBlocks;i++)
1244     {
1245         ASSERT_COND(p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].allocated);
1246         ASSERT_COND(guestId == p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].ownerId);
1247         p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].allocated = FALSE;
1248         p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].ownerId = 0;
1249     }
1250     FmPcdUnlock(p_FmPcd, intFlags);
1251 }
1252 
1253 void KgEnable(t_FmPcd *p_FmPcd)
1254 {
1255     t_FmPcdKgRegs               *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
1256 
1257     ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
1258     WRITE_UINT32(p_Regs->kggcr,GET_UINT32(p_Regs->kggcr) | FM_PCD_KG_KGGCR_EN);
1259 }
1260 
1261 void KgDisable(t_FmPcd *p_FmPcd)
1262 {
1263     t_FmPcdKgRegs               *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
1264 
1265     ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
1266     WRITE_UINT32(p_Regs->kggcr,GET_UINT32(p_Regs->kggcr) & ~FM_PCD_KG_KGGCR_EN);
1267 }
1268 
1269 void KgSetClsPlan(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanSet *p_Set)
1270 {
1271     t_FmPcd                 *p_FmPcd = (t_FmPcd*)h_FmPcd;
1272     t_FmPcdKgClsPlanRegs    *p_FmPcdKgPortRegs;
1273     uint32_t                tmpKgarReg=0, intFlags;
1274     uint16_t                i, j;
1275 
1276     SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE);
1277     SANITY_CHECK_RETURN(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE);
1278 
1279     ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
1280     p_FmPcdKgPortRegs = &p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.clsPlanRegs;
1281 
1282     intFlags = FmPcdLock(p_FmPcd);
1283     for(i=p_Set->baseEntry;i<p_Set->baseEntry+p_Set->numOfClsPlanEntries;i+=8)
1284     {
1285         tmpKgarReg = FmPcdKgBuildWriteClsPlanBlockActionReg((uint8_t)(i / CLS_PLAN_NUM_PER_GRP));
1286 
1287         for (j = i; j < i+8; j++)
1288         {
1289             ASSERT_COND(IN_RANGE(0, (j - p_Set->baseEntry), FM_PCD_MAX_NUM_OF_CLS_PLANS-1));
1290             WRITE_UINT32(p_FmPcdKgPortRegs->kgcpe[j % CLS_PLAN_NUM_PER_GRP],p_Set->vectors[j - p_Set->baseEntry]);
1291         }
1292 
1293         if(WriteKgarWait(p_FmPcd, tmpKgarReg) != E_OK)
1294         {
1295             REPORT_ERROR(MAJOR, E_INVALID_STATE, ("WriteKgarWait FAILED"));
1296             return;
1297         }
1298     }
1299     FmPcdUnlock(p_FmPcd, intFlags);
1300 }
1301 
1302 static void PcdKgErrorException(t_Handle h_FmPcd)
1303 {
1304     t_FmPcd                 *p_FmPcd = (t_FmPcd *)h_FmPcd;
1305     uint32_t                event, force, schemeIndexes = 0,index = 0, mask = 0;
1306 
1307     ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
1308     event = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgeer);
1309     mask = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgeeer);
1310 
1311     schemeIndexes = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgseer);
1312     schemeIndexes &= GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgseeer);
1313 
1314     event &= mask;
1315 
1316     /* clear the forced events */
1317     force = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgfeer);
1318     if(force & event)
1319         WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgfeer, force & ~event);
1320 
1321     WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgeer, event);
1322     WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgseer, schemeIndexes);
1323 
1324     if(event & FM_PCD_KG_DOUBLE_ECC)
1325         p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC);
1326     if(event & FM_PCD_KG_KEYSIZE_OVERFLOW)
1327     {
1328         if(schemeIndexes)
1329         {
1330             while(schemeIndexes)
1331             {
1332                 if(schemeIndexes & 0x1)
1333                     p_FmPcd->f_FmPcdIndexedException(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, (uint16_t)(31 - index));
1334                 schemeIndexes >>= 1;
1335                 index+=1;
1336             }
1337         }
1338         else /* this should happen only when interrupt is forced. */
1339             p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW);
1340     }
1341 }
1342 
1343 static t_Error KgInitGuest(t_FmPcd *p_FmPcd)
1344 {
1345     t_Error                     err = E_OK;
1346     t_FmPcdIpcKgSchemesParams   kgAlloc;
1347     uint32_t                    replyLength;
1348     t_FmPcdIpcReply             reply;
1349     t_FmPcdIpcMsg               msg;
1350 
1351     ASSERT_COND(p_FmPcd->guestId != NCSW_MASTER_ID);
1352 
1353     /* in GUEST_PARTITION, we use the IPC  */
1354     memset(&reply, 0, sizeof(reply));
1355     memset(&msg, 0, sizeof(msg));
1356     memset(&kgAlloc, 0, sizeof(t_FmPcdIpcKgSchemesParams));
1357     kgAlloc.numOfSchemes = p_FmPcd->p_FmPcdKg->numOfSchemes;
1358     kgAlloc.guestId = p_FmPcd->guestId;
1359     msg.msgId = FM_PCD_ALLOC_KG_SCHEMES;
1360     memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc));
1361     replyLength = sizeof(uint32_t) + p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t);
1362     if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
1363                                  (uint8_t*)&msg,
1364                                  sizeof(msg.msgId) + sizeof(kgAlloc),
1365                                  (uint8_t*)&reply,
1366                                  &replyLength,
1367                                  NULL,
1368                                  NULL)) != E_OK)
1369         RETURN_ERROR(MAJOR, err, NO_MSG);
1370     if(replyLength != (sizeof(uint32_t) + p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t)))
1371         RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
1372     memcpy(p_FmPcd->p_FmPcdKg->schemesIds, (uint8_t*)(reply.replyBody),p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t));
1373 
1374     return (t_Error)reply.error;
1375 }
1376 
1377 static t_Error KgInitMaster(t_FmPcd *p_FmPcd)
1378 {
1379     t_Error                     err = E_OK;
1380     t_FmPcdKgRegs               *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
1381     int                         i;
1382     uint8_t                     hardwarePortId = 0;
1383     uint32_t                    tmpReg;
1384 
1385     ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
1386 
1387     /**********************KGEER******************/
1388     WRITE_UINT32(p_Regs->kgeer, (FM_PCD_KG_DOUBLE_ECC | FM_PCD_KG_KEYSIZE_OVERFLOW));
1389     /**********************KGEER******************/
1390 
1391     /**********************KGEEER******************/
1392     tmpReg = 0;
1393     if(p_FmPcd->exceptions & FM_PCD_EX_KG_DOUBLE_ECC)
1394     {
1395         FmEnableRamsEcc(p_FmPcd->h_Fm);
1396         tmpReg |= FM_PCD_KG_DOUBLE_ECC;
1397     }
1398     if(p_FmPcd->exceptions & FM_PCD_EX_KG_KEYSIZE_OVERFLOW)
1399         tmpReg |= FM_PCD_KG_KEYSIZE_OVERFLOW;
1400     WRITE_UINT32(p_Regs->kgeeer,tmpReg);
1401     /**********************KGEEER******************/
1402 
1403     /**********************KGFDOR******************/
1404     WRITE_UINT32(p_Regs->kgfdor,0);
1405     /**********************KGFDOR******************/
1406 
1407     /**********************KGGDV0R******************/
1408     WRITE_UINT32(p_Regs->kggdv0r,0);
1409     /**********************KGGDV0R******************/
1410 
1411     /**********************KGGDV1R******************/
1412     WRITE_UINT32(p_Regs->kggdv1r,0);
1413     /**********************KGGDV1R******************/
1414 
1415     /**********************KGGCR******************/
1416     WRITE_UINT32(p_Regs->kggcr, NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME);
1417     /**********************KGGCR******************/
1418 
1419     /* register even if no interrupts enabled, to allow future enablement */
1420     FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_KG, 0, e_FM_INTR_TYPE_ERR, PcdKgErrorException, p_FmPcd);
1421 
1422     /* clear binding between ports to schemes so that all ports are not bound to any schemes */
1423     for (i=0;i<FM_MAX_NUM_OF_PORTS;i++)
1424     {
1425         SW_PORT_INDX_TO_HW_PORT_ID(hardwarePortId, i);
1426 
1427         err = KgWriteSp(p_FmPcd, hardwarePortId, 0xffffffff, FALSE);
1428         if(err)
1429             RETURN_ERROR(MINOR, err, NO_MSG);
1430 
1431         err = KgWriteCpp(p_FmPcd, hardwarePortId, 0);
1432         if(err)
1433             RETURN_ERROR(MINOR, err, NO_MSG);
1434     }
1435 
1436     /* enable and enable all scheme interrupts */
1437     WRITE_UINT32(p_Regs->kgseer, 0xFFFFFFFF);
1438     WRITE_UINT32(p_Regs->kgseeer, 0xFFFFFFFF);
1439 
1440     if(p_FmPcd->p_FmPcdKg->numOfSchemes)
1441     {
1442         err = FmPcdKgAllocSchemes(p_FmPcd,
1443                                   p_FmPcd->p_FmPcdKg->numOfSchemes,
1444                                   p_FmPcd->guestId,
1445                                   p_FmPcd->p_FmPcdKg->schemesIds);
1446         if(err)
1447             RETURN_ERROR(MINOR, err, NO_MSG);
1448     }
1449 
1450     return E_OK;
1451 }
1452 
1453 
1454 /****************************************/
1455 /*  API routines                        */
1456 /****************************************/
1457 t_Error FM_PCD_KgSetAdditionalDataAfterParsing(t_Handle h_FmPcd, uint8_t payloadOffset)
1458 {
1459    t_FmPcd              *p_FmPcd = (t_FmPcd*)h_FmPcd;
1460    t_FmPcdKgRegs        *p_Regs;
1461 
1462     SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
1463     SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_NULL_POINTER);
1464     SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_NULL_POINTER);
1465     SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, E_NULL_POINTER);
1466 
1467     p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
1468     if(!FmIsMaster(p_FmPcd->h_Fm))
1469         RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_KgSetAdditionalDataAfterParsing - guest mode!"));
1470 
1471 /* not needed
1472     if(payloadOffset > 256)
1473         RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("data exatraction offset from parseing end can not be more than 256"));
1474 */
1475 
1476     WRITE_UINT32(p_Regs->kgfdor,payloadOffset);
1477 
1478     return E_OK;
1479 }
1480 
1481 t_Error FM_PCD_KgSetDfltValue(t_Handle h_FmPcd, uint8_t valueId, uint32_t value)
1482 {
1483    t_FmPcd              *p_FmPcd = (t_FmPcd*)h_FmPcd;
1484    t_FmPcdKgRegs        *p_Regs;
1485 
1486     SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
1487     SANITY_CHECK_RETURN_ERROR(((valueId == 0) || (valueId == 1)), E_INVALID_VALUE);
1488     SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_NULL_POINTER);
1489     SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_NULL_POINTER);
1490     SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, E_NULL_POINTER);
1491 
1492     p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
1493 
1494     if(!FmIsMaster(p_FmPcd->h_Fm))
1495         RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_KgSetDfltValue - guest mode!"));
1496 
1497     if(valueId == 0)
1498         WRITE_UINT32(p_Regs->kggdv0r,value);
1499     else
1500         WRITE_UINT32(p_Regs->kggdv1r,value);
1501     return E_OK;
1502 }
1503 
1504 #if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
1505 t_Error FM_PCD_KgDumpRegs(t_Handle h_FmPcd)
1506 {
1507     t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
1508     int                 i = 0, j = 0;
1509     uint8_t             hardwarePortId = 0;
1510     uint32_t            tmpKgarReg, intFlags;
1511     t_Error             err = E_OK;
1512     t_FmPcdIpcMsg       msg;
1513 
1514     DECLARE_DUMP;
1515 
1516     SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
1517     SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE);
1518     SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
1519 
1520     if(p_FmPcd->guestId != NCSW_MASTER_ID)
1521     {
1522         memset(&msg, 0, sizeof(msg));
1523         msg.msgId = FM_PCD_KG_DUMP_REGS;
1524         return XX_IpcSendMessage(p_FmPcd->h_IpcSession,
1525                                  (uint8_t*)&msg,
1526                                  sizeof(msg.msgId),
1527                                  NULL,
1528                                  NULL,
1529                                  NULL,
1530                                  NULL);
1531     }
1532     DUMP_SUBTITLE(("\n"));
1533     DUMP_TITLE(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, ("FmPcdKgRegs Regs"));
1534 
1535     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kggcr);
1536     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgeer);
1537     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgeeer);
1538     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgseer);
1539     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgseeer);
1540     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kggsr);
1541     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgtpc);
1542     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgserc);
1543     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgfdor);
1544     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kggdv0r);
1545     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kggdv1r);
1546     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgfer);
1547     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgfeer);
1548     DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgar);
1549 
1550     DUMP_SUBTITLE(("\n"));
1551     intFlags = FmPcdLock(p_FmPcd);
1552     for(j = 0;j<FM_PCD_KG_NUM_OF_SCHEMES;j++)
1553     {
1554         tmpKgarReg = FmPcdKgBuildReadSchemeActionReg((uint8_t)j);
1555         if(WriteKgarWait(p_FmPcd, tmpKgarReg) != E_OK)
1556             RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
1557 
1558         DUMP_TITLE(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs, ("FmPcdKgIndirectAccessSchemeRegs Scheme %d Regs", j));
1559 
1560         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_mode);
1561         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_ekfc);
1562         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_ekdv);
1563         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_bmch);
1564         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_bmcl);
1565         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_fqb);
1566         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_hc);
1567         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_ppc);
1568 
1569         DUMP_TITLE(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_gec, ("kgse_gec"));
1570         DUMP_SUBSTRUCT_ARRAY(i, FM_PCD_KG_NUM_OF_GENERIC_REGS)
1571         {
1572             DUMP_MEMORY(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_gec[i], sizeof(uint32_t));
1573         }
1574 
1575         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_spc);
1576         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_dv0);
1577         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_dv1);
1578         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_ccbs);
1579         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_mv);
1580     }
1581     DUMP_SUBTITLE(("\n"));
1582 
1583     for (i=0;i<FM_MAX_NUM_OF_PORTS;i++)
1584     {
1585         SW_PORT_INDX_TO_HW_PORT_ID(hardwarePortId, i);
1586 
1587         tmpKgarReg = FmPcdKgBuildReadPortSchemeBindActionReg(hardwarePortId);
1588 
1589         err = WriteKgarWait(p_FmPcd, tmpKgarReg);
1590         if(err)
1591             RETURN_ERROR(MINOR, err, NO_MSG);
1592 
1593         DUMP_TITLE(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs, ("FmPcdKgIndirectAccessPortRegs PCD Port %d regs", hardwarePortId));
1594 
1595         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs, kgoe_sp);
1596         DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs, kgoe_cpp);
1597     }
1598 
1599     DUMP_SUBTITLE(("\n"));
1600     for(j=0;j<FM_PCD_MAX_NUM_OF_CLS_PLANS/CLS_PLAN_NUM_PER_GRP;j++)
1601     {
1602         DUMP_TITLE(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.clsPlanRegs, ("FmPcdKgIndirectAccessClsPlanRegs Regs group %d", j));
1603         DUMP_TITLE(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.clsPlanRegs.kgcpe, ("kgcpe"));
1604 
1605         tmpKgarReg = FmPcdKgBuildReadClsPlanBlockActionReg((uint8_t)j);
1606         err = WriteKgarWait(p_FmPcd, tmpKgarReg);
1607         if(err)
1608             RETURN_ERROR(MINOR, err, NO_MSG);
1609         DUMP_SUBSTRUCT_ARRAY(i, 8)
1610             DUMP_MEMORY(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.clsPlanRegs.kgcpe[i], sizeof(uint32_t));
1611     }
1612     FmPcdUnlock(p_FmPcd, intFlags);
1613 
1614     return E_OK;
1615 }
1616 #endif /* (defined(DEBUG_ERRORS) && ... */
1617 
1618 t_Handle KgConfig( t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams)
1619 {
1620     t_FmPcdKg   *p_FmPcdKg;
1621 
1622     UNUSED(p_FmPcd);
1623 
1624     if (p_FmPcdParams->numOfSchemes > FM_PCD_KG_NUM_OF_SCHEMES)
1625     {
1626         REPORT_ERROR(MAJOR, E_INVALID_VALUE,
1627                      ("numOfSchemes should not exceed %d", FM_PCD_KG_NUM_OF_SCHEMES));
1628         return NULL;
1629     }
1630 
1631     p_FmPcdKg = (t_FmPcdKg *)XX_Malloc(sizeof(t_FmPcdKg));
1632     if (!p_FmPcdKg)
1633     {
1634         REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Keygen allocation FAILED"));
1635         return NULL;
1636     }
1637     memset(p_FmPcdKg, 0, sizeof(t_FmPcdKg));
1638 
1639     if(FmIsMaster(p_FmPcd->h_Fm))
1640     {
1641         p_FmPcdKg->p_FmPcdKgRegs  = (t_FmPcdKgRegs *)UINT_TO_PTR(FmGetPcdKgBaseAddr(p_FmPcdParams->h_Fm));
1642         p_FmPcd->exceptions |= DEFAULT_fmPcdKgErrorExceptions;
1643     }
1644 
1645     p_FmPcdKg->numOfSchemes = p_FmPcdParams->numOfSchemes;
1646     if((p_FmPcd->guestId == NCSW_MASTER_ID) && !p_FmPcdKg->numOfSchemes)
1647     {
1648         p_FmPcdKg->numOfSchemes = FM_PCD_KG_NUM_OF_SCHEMES;
1649         DBG(WARNING, ("numOfSchemes was defined 0 by user, re-defined by driver to FM_PCD_KG_NUM_OF_SCHEMES"));
1650     }
1651 
1652     p_FmPcdKg->emptyClsPlanGrpId = ILLEGAL_CLS_PLAN;
1653 
1654     return p_FmPcdKg;
1655 }
1656 
1657 t_Error KgInit(t_FmPcd *p_FmPcd)
1658 {
1659     if (p_FmPcd->guestId == NCSW_MASTER_ID)
1660         return KgInitMaster(p_FmPcd);
1661     else
1662         return KgInitGuest(p_FmPcd);
1663 }
1664 
1665 t_Error KgFree(t_FmPcd *p_FmPcd)
1666 {
1667     t_FmPcdIpcKgSchemesParams       kgAlloc;
1668     t_Error                         err = E_OK;
1669     t_FmPcdIpcMsg                   msg;
1670     uint32_t                        replyLength;
1671     t_FmPcdIpcReply                 reply;
1672 
1673     FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_KG, 0, e_FM_INTR_TYPE_ERR);
1674 
1675     if(p_FmPcd->guestId == NCSW_MASTER_ID)
1676         return FmPcdKgFreeSchemes(p_FmPcd,
1677                                     p_FmPcd->p_FmPcdKg->numOfSchemes,
1678                                     p_FmPcd->guestId,
1679                                     p_FmPcd->p_FmPcdKg->schemesIds);
1680 
1681     /* guest */
1682     memset(&reply, 0, sizeof(reply));
1683     memset(&msg, 0, sizeof(msg));
1684     kgAlloc.numOfSchemes = p_FmPcd->p_FmPcdKg->numOfSchemes;
1685     kgAlloc.guestId = p_FmPcd->guestId;
1686     ASSERT_COND(kgAlloc.numOfSchemes < FM_PCD_KG_NUM_OF_SCHEMES);
1687     memcpy(kgAlloc.schemesIds, p_FmPcd->p_FmPcdKg->schemesIds , (sizeof(uint8_t))*kgAlloc.numOfSchemes);
1688     msg.msgId = FM_PCD_FREE_KG_SCHEMES;
1689     memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc));
1690     replyLength = sizeof(uint32_t);
1691     if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
1692                                  (uint8_t*)&msg,
1693                                  sizeof(msg.msgId) + sizeof(kgAlloc),
1694                                  (uint8_t*)&reply,
1695                                  &replyLength,
1696                                  NULL,
1697                                  NULL)) != E_OK)
1698         RETURN_ERROR(MAJOR, err, NO_MSG);
1699     if (replyLength != sizeof(uint32_t))
1700         RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
1701 
1702     return (t_Error)reply.error;
1703 }
1704 
1705 t_Error FmPcdKgSetOrBindToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t netEnvId, protocolOpt_t *p_OptArray, uint8_t *p_ClsPlanGrpId, bool *p_IsEmptyClsPlanGrp)
1706 {
1707     t_FmPcd                                 *p_FmPcd = (t_FmPcd *)h_FmPcd;
1708     t_FmPcdKgInterModuleClsPlanGrpParams    grpParams, *p_GrpParams;
1709     t_FmPcdKgClsPlanGrp                     *p_ClsPlanGrp;
1710     t_FmPcdKgInterModuleClsPlanSet          *p_ClsPlanSet;
1711     t_Error                                 err;
1712 
1713     memset(&grpParams, 0, sizeof(grpParams));
1714     grpParams.clsPlanGrpId = ILLEGAL_CLS_PLAN;
1715     p_GrpParams = &grpParams;
1716 
1717     p_GrpParams->netEnvId = netEnvId;
1718     err = PcdGetClsPlanGrpParams(h_FmPcd, p_GrpParams);
1719     if(err)
1720         RETURN_ERROR(MINOR,err,NO_MSG);
1721     if(p_GrpParams->grpExists)
1722         *p_ClsPlanGrpId = p_GrpParams->clsPlanGrpId;
1723     else
1724     {
1725         p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet));
1726         if (!p_ClsPlanSet)
1727             RETURN_ERROR(MAJOR, E_NO_MEMORY, ("memory allocation failed for p_ClsPlanSet"));
1728         memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet));
1729         err = FmPcdKgBuildClsPlanGrp(h_FmPcd, p_GrpParams, p_ClsPlanSet);
1730         if (err)
1731         {
1732             XX_Free(p_ClsPlanSet);
1733             RETURN_ERROR(MINOR,err,NO_MSG);
1734         }
1735         *p_ClsPlanGrpId = p_GrpParams->clsPlanGrpId;
1736 
1737         if (p_FmPcd->h_Hc)
1738         {
1739             /* write clsPlan entries to memory */
1740             err = FmHcPcdKgSetClsPlan(p_FmPcd->h_Hc, p_ClsPlanSet);
1741             if (err)
1742             {
1743                 XX_Free(p_ClsPlanSet);
1744                 RETURN_ERROR(MAJOR, err, NO_MSG);
1745             }
1746         }
1747         else
1748             /* write clsPlan entries to memory */
1749             KgSetClsPlan(p_FmPcd, p_ClsPlanSet);
1750 
1751         XX_Free(p_ClsPlanSet);
1752     }
1753 
1754     /* mark if this is an empty classification group */
1755     if(*p_ClsPlanGrpId == p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId)
1756         *p_IsEmptyClsPlanGrp = TRUE;
1757     else
1758         *p_IsEmptyClsPlanGrp = FALSE;
1759 
1760     p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[*p_ClsPlanGrpId];
1761 
1762     /* increment owners number */
1763     p_ClsPlanGrp->owners++;
1764 
1765     /* copy options array for port */
1766     memcpy(p_OptArray, &p_FmPcd->p_FmPcdKg->clsPlanGrps[*p_ClsPlanGrpId].optArray, FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)*sizeof(protocolOpt_t));
1767 
1768     /* bind port to the new or existing group */
1769     err = KgBindPortToClsPlanGrp(p_FmPcd, hardwarePortId, p_GrpParams->clsPlanGrpId);
1770     if(err)
1771         RETURN_ERROR(MINOR, err, NO_MSG);
1772 
1773     return E_OK;
1774 }
1775 
1776 t_Error FmPcdKgDeleteOrUnbindPortToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId)
1777 {
1778     t_FmPcd                         *p_FmPcd = (t_FmPcd *)h_FmPcd;
1779     t_FmPcdKgClsPlanGrp             *p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId];
1780     t_FmPcdKgInterModuleClsPlanSet  *p_ClsPlanSet;
1781 
1782     FmPcdKgUnbindPortToClsPlanGrp(p_FmPcd, hardwarePortId);
1783 
1784     /* decrement owners number */
1785     ASSERT_COND(p_ClsPlanGrp->owners);
1786     p_ClsPlanGrp->owners--;
1787 
1788     if(!p_ClsPlanGrp->owners)
1789     {
1790         if (p_FmPcd->h_Hc)
1791             return FmHcPcdKgDeleteClsPlan(p_FmPcd->h_Hc, clsPlanGrpId);
1792         else
1793         {
1794             /* clear clsPlan entries in memory */
1795             p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet));
1796             if (!p_ClsPlanSet)
1797                 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("memory allocation failed for p_ClsPlanSet"));
1798             memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet));
1799             p_ClsPlanSet->baseEntry = p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].baseEntry;
1800             p_ClsPlanSet->numOfClsPlanEntries = p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].sizeOfGrp;
1801             KgSetClsPlan(p_FmPcd, p_ClsPlanSet);
1802             XX_Free(p_ClsPlanSet);
1803             FmPcdKgDestroyClsPlanGrp(h_FmPcd, clsPlanGrpId);
1804         }
1805     }
1806     return E_OK;
1807 }
1808 
1809 t_Error FmPcdKgBuildScheme(t_Handle h_FmPcd,  t_FmPcdKgSchemeParams *p_Scheme, t_FmPcdKgInterModuleSchemeRegs *p_SchemeRegs)
1810 {
1811     t_FmPcd                             *p_FmPcd = (t_FmPcd *)h_FmPcd;
1812     uint32_t                            grpBits = 0;
1813     uint8_t                             grpBase;
1814     bool                                direct=TRUE, absolute=FALSE;
1815     uint16_t                            profileId=0, numOfProfiles=0, relativeProfileId;
1816     t_Error                             err = E_OK;
1817     int                                 i = 0;
1818     t_NetEnvParams                      netEnvParams;
1819     uint32_t                            tmpReg, fqbTmp = 0, ppcTmp = 0, selectTmp, maskTmp, knownTmp, genTmp;
1820     t_FmPcdKgKeyExtractAndHashParams    *p_KeyAndHash = NULL;
1821     uint8_t                             j, curr, idx;
1822     uint8_t                             id, shift=0, code=0, offset=0, size=0;
1823     t_FmPcdExtractEntry                 *p_Extract = NULL;
1824     t_FmPcdKgExtractedOrParams          *p_ExtractOr;
1825     bool                                generic = FALSE;
1826     t_KnownFieldsMasks                  bitMask;
1827     e_FmPcdKgExtractDfltSelect          swDefault = (e_FmPcdKgExtractDfltSelect)0;
1828     t_FmPcdKgSchemesExtracts            *p_LocalExtractsArray;
1829     uint8_t                             numOfSwDefaults = 0;
1830     t_FmPcdKgExtractDflt                swDefaults[NUM_OF_SW_DEFAULTS];
1831     uint8_t                             currGenId = 0, relativeSchemeId;
1832 
1833     if(!p_Scheme->modify)
1834         relativeSchemeId = p_Scheme->id.relativeSchemeId;
1835     else
1836         relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, (uint8_t)(PTR_TO_UINT(p_Scheme->id.h_Scheme)-1));
1837 
1838     memset(&p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId], 0, sizeof(t_FmPcdKgScheme));
1839     memset(swDefaults, 0, NUM_OF_SW_DEFAULTS*sizeof(t_FmPcdKgExtractDflt));
1840     memset(p_SchemeRegs, 0, sizeof(t_FmPcdKgInterModuleSchemeRegs));
1841 
1842     if (p_Scheme->netEnvParams.numOfDistinctionUnits > FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
1843         RETURN_ERROR(MAJOR, E_INVALID_VALUE,
1844                      ("numOfDistinctionUnits should not exceed %d", FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS));
1845 
1846     /* by netEnv parameters, get match vector */
1847     if(!p_Scheme->alwaysDirect)
1848     {
1849         p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId =
1850             (uint8_t)(PTR_TO_UINT(p_Scheme->netEnvParams.h_NetEnv)-1);
1851         netEnvParams.netEnvId = p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId;
1852         netEnvParams.numOfDistinctionUnits = p_Scheme->netEnvParams.numOfDistinctionUnits;
1853         memcpy(netEnvParams.unitIds, p_Scheme->netEnvParams.unitIds, (sizeof(uint8_t))*p_Scheme->netEnvParams.numOfDistinctionUnits);
1854         err = PcdGetUnitsVector(p_FmPcd, &netEnvParams);
1855         if(err)
1856             RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
1857         p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].matchVector = netEnvParams.vector;
1858     }
1859     else
1860     {
1861         p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].matchVector = SCHEME_ALWAYS_DIRECT;
1862         p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId = ILLEGAL_NETENV;
1863     }
1864 
1865     if(p_Scheme->nextEngine == e_FM_PCD_INVALID)
1866         RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next Engine of the scheme is not Valid"));
1867 
1868     if(p_Scheme->bypassFqidGeneration)
1869     {
1870 #ifdef FM_KG_NO_BYPASS_FQID_GEN
1871         {
1872             t_FmRevisionInfo    revInfo;
1873 
1874             FM_GetRevision(p_FmPcd->h_Fm, &revInfo);
1875             if (revInfo.majorRev != 4)
1876                 RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassFqidGeneration."));
1877         }
1878 #endif /* FM_KG_NO_BYPASS_FQID_GEN */
1879         if(p_Scheme->baseFqid)
1880             RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid set for a scheme that does not generate an FQID"));
1881     }
1882     else
1883         if(!p_Scheme->baseFqid)
1884             DBG(WARNING, ("baseFqid is 0."));
1885 
1886     if(p_Scheme->nextEngine == e_FM_PCD_PLCR)
1887     {
1888         direct = p_Scheme->kgNextEngineParams.plcrProfile.direct;
1889         p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].directPlcr = direct;
1890         absolute = (bool)(p_Scheme->kgNextEngineParams.plcrProfile.sharedProfile ? TRUE : FALSE);
1891         if(!direct && absolute)
1892             RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Indirect policing is not available when profile is shared."));
1893 
1894         if(direct)
1895         {
1896             profileId = p_Scheme->kgNextEngineParams.plcrProfile.profileSelect.directRelativeProfileId;
1897             numOfProfiles = 1;
1898         }
1899         else
1900         {
1901             profileId = p_Scheme->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase;
1902             shift = p_Scheme->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift;
1903             numOfProfiles = p_Scheme->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.numOfProfiles;
1904         }
1905     }
1906 
1907     if(p_Scheme->nextEngine == e_FM_PCD_CC)
1908     {
1909 #ifdef FM_KG_NO_BYPASS_PLCR_PROFILE_GEN
1910         if((p_Scheme->kgNextEngineParams.cc.plcrNext) && (p_Scheme->kgNextEngineParams.cc.bypassPlcrProfileGeneration))
1911         {
1912             t_FmRevisionInfo    revInfo;
1913 
1914             FM_GetRevision(p_FmPcd->h_Fm, &revInfo);
1915             if (revInfo.majorRev != 4)
1916                 RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassPlcrProfileGeneration."));
1917         }
1918 #endif /* FM_KG_NO_BYPASS_PLCR_PROFILE_GEN */
1919 
1920         err = FmPcdCcGetGrpParams(p_Scheme->kgNextEngineParams.cc.h_CcTree,
1921                              p_Scheme->kgNextEngineParams.cc.grpId,
1922                              &grpBits,
1923                              &grpBase);
1924         if(err)
1925             RETURN_ERROR(MAJOR, err, NO_MSG);
1926         p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].ccUnits = grpBits;
1927 
1928         if((p_Scheme->kgNextEngineParams.cc.plcrNext) &&
1929            (!p_Scheme->kgNextEngineParams.cc.bypassPlcrProfileGeneration))
1930         {
1931                 if(p_Scheme->kgNextEngineParams.cc.plcrProfile.sharedProfile)
1932                     RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Shared profile may not be used after Coarse classification."));
1933                 absolute = FALSE;
1934                 direct = p_Scheme->kgNextEngineParams.cc.plcrProfile.direct;
1935                 if(direct)
1936                 {
1937                     profileId = p_Scheme->kgNextEngineParams.cc.plcrProfile.profileSelect.directRelativeProfileId;
1938                     numOfProfiles = 1;
1939                 }
1940                 else
1941                 {
1942                     profileId = p_Scheme->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase;
1943                     shift = p_Scheme->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift;
1944                     numOfProfiles = p_Scheme->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.numOfProfiles;
1945                 }
1946         }
1947     }
1948 
1949     /* if policer is used directly after KG, or after CC */
1950     if((p_Scheme->nextEngine == e_FM_PCD_PLCR)  ||
1951        ((p_Scheme->nextEngine == e_FM_PCD_CC) &&
1952         (p_Scheme->kgNextEngineParams.cc.plcrNext) &&
1953         (!p_Scheme->kgNextEngineParams.cc.bypassPlcrProfileGeneration)))
1954     {
1955         /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */
1956         if(absolute)
1957         {
1958             /* for absolute direct policy only, */
1959             relativeProfileId = profileId;
1960             err = FmPcdPlcrGetAbsoluteProfileId(h_FmPcd,e_FM_PCD_PLCR_SHARED,NULL, relativeProfileId, &profileId);
1961             if(err)
1962                 RETURN_ERROR(MAJOR, err, ("Shared profile not valid offset"));
1963             if(!FmPcdPlcrIsProfileValid(p_FmPcd, profileId))
1964                 RETURN_ERROR(MINOR, E_INVALID_STATE, ("Shared profile not valid."));
1965             p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].relativeProfileId = profileId;
1966         }
1967         else
1968         {
1969             /* save relative profile id's for later check */
1970             p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextRelativePlcrProfile = TRUE;
1971             p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].relativeProfileId = profileId;
1972             p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].numOfProfiles = numOfProfiles;
1973         }
1974     }
1975     else
1976     {
1977         /* if policer is NOT going to be used after KG at all than if bypassFqidGeneration
1978         is set, we do not need numOfUsedExtractedOrs and hashDistributionNumOfFqids */
1979         if(p_Scheme->bypassFqidGeneration && p_Scheme->numOfUsedExtractedOrs)
1980             RETURN_ERROR(MAJOR, E_INVALID_STATE,
1981                     ("numOfUsedExtractedOrs is set in a scheme that does not generate FQID or policer profile ID"));
1982         if(p_Scheme->bypassFqidGeneration &&
1983                 p_Scheme->useHash &&
1984                 p_Scheme->keyExtractAndHashParams.hashDistributionNumOfFqids)
1985             RETURN_ERROR(MAJOR, E_INVALID_STATE,
1986                     ("hashDistributionNumOfFqids is set in a scheme that does not generate FQID or policer profile ID"));
1987     }
1988 
1989     /* configure all 21 scheme registers */
1990     tmpReg =  KG_SCH_MODE_EN;
1991     switch(p_Scheme->nextEngine)
1992     {
1993         case(e_FM_PCD_PLCR):
1994             /* add to mode register - NIA */
1995             tmpReg |= KG_SCH_MODE_NIA_PLCR;
1996             tmpReg |= NIA_ENG_PLCR;
1997             tmpReg |= (uint32_t)(p_Scheme->kgNextEngineParams.plcrProfile.sharedProfile ? NIA_PLCR_ABSOLUTE:0);
1998             /* initialize policer profile command - */
1999             /*  configure kgse_ppc  */
2000             if(direct)
2001             /* use profileId as base, other fields are 0 */
2002                 p_SchemeRegs->kgse_ppc = (uint32_t)profileId;
2003             else
2004             {
2005                 if(shift > MAX_PP_SHIFT)
2006                     RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_PP_SHIFT));
2007 
2008                 if(!numOfProfiles || !POWER_OF_2(numOfProfiles))
2009                     RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2"));
2010 
2011                 ppcTmp = ((uint32_t)shift << KG_SCH_PP_SHIFT_HIGH_SHIFT) & KG_SCH_PP_SHIFT_HIGH;
2012                 ppcTmp |= ((uint32_t)shift << KG_SCH_PP_SHIFT_LOW_SHIFT) & KG_SCH_PP_SHIFT_LOW;
2013                 ppcTmp |= ((uint32_t)(numOfProfiles-1) << KG_SCH_PP_MASK_SHIFT);
2014                 ppcTmp |= (uint32_t)profileId;
2015 
2016                 p_SchemeRegs->kgse_ppc = ppcTmp;
2017             }
2018             break;
2019         case(e_FM_PCD_CC):
2020             /* mode reg - define NIA */
2021             tmpReg |= (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC);
2022 
2023             p_SchemeRegs->kgse_ccbs = grpBits;
2024             tmpReg |= (uint32_t)(grpBase << KG_SCH_MODE_CCOBASE_SHIFT);
2025 
2026             if(p_Scheme->kgNextEngineParams.cc.plcrNext)
2027             {
2028                 if(!p_Scheme->kgNextEngineParams.cc.bypassPlcrProfileGeneration)
2029                 {
2030                     /* find out if absolute or relative */
2031                     if(absolute)
2032                          RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("It is illegal to request a shared profile in a scheme that is in a KG->CC->PLCR flow"));
2033                     if(direct)
2034                     {
2035                         /* mask = 0, base = directProfileId */
2036                         p_SchemeRegs->kgse_ppc = (uint32_t)profileId;
2037                     }
2038                     else
2039                     {
2040                         if(shift > MAX_PP_SHIFT)
2041                             RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_PP_SHIFT));
2042                         if(!numOfProfiles || !POWER_OF_2(numOfProfiles))
2043                             RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2"));
2044 
2045                         ppcTmp = ((uint32_t)shift << KG_SCH_PP_SHIFT_HIGH_SHIFT) & KG_SCH_PP_SHIFT_HIGH;
2046                         ppcTmp |= ((uint32_t)shift << KG_SCH_PP_SHIFT_LOW_SHIFT) & KG_SCH_PP_SHIFT_LOW;
2047                         ppcTmp |= ((uint32_t)(numOfProfiles-1) << KG_SCH_PP_MASK_SHIFT);
2048                         ppcTmp |= (uint32_t)profileId;
2049 
2050                         p_SchemeRegs->kgse_ppc = ppcTmp;
2051                     }
2052                 }
2053                 else
2054                     ppcTmp = KG_SCH_PP_NO_GEN;
2055             }
2056             break;
2057         case(e_FM_PCD_DONE):
2058             if(p_Scheme->kgNextEngineParams.doneAction == e_FM_PCD_DROP_FRAME)
2059                 tmpReg |= (NIA_ENG_BMI | NIA_BMI_AC_DISCARD);
2060             else
2061                 tmpReg |= (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME);
2062             break;
2063         default:
2064              RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine not supported"));
2065     }
2066     p_SchemeRegs->kgse_mode = tmpReg;
2067 
2068     p_SchemeRegs->kgse_mv = p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].matchVector;
2069 
2070     if(p_Scheme->useHash)
2071     {
2072         p_KeyAndHash = &p_Scheme->keyExtractAndHashParams;
2073 
2074         if (p_KeyAndHash->numOfUsedExtracts >= FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY)
2075              RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfUsedExtracts out of range"));
2076 
2077         /*  configure kgse_dv0  */
2078         p_SchemeRegs->kgse_dv0 = p_KeyAndHash->privateDflt0;
2079 
2080         /*  configure kgse_dv1  */
2081         p_SchemeRegs->kgse_dv1 = p_KeyAndHash->privateDflt1;
2082 
2083         if(!p_Scheme->bypassFqidGeneration)
2084         {
2085             if(!p_KeyAndHash->hashDistributionNumOfFqids || !POWER_OF_2(p_KeyAndHash->hashDistributionNumOfFqids))
2086                 RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashDistributionNumOfFqids must not be 0 and must be a power of 2"));
2087             if((p_KeyAndHash->hashDistributionNumOfFqids-1) & p_Scheme->baseFqid)
2088                 DBG(WARNING, ("baseFqid unaligned. Distribution may result in less than hashDistributionNumOfFqids queues."));
2089         }
2090 
2091         /*  configure kgse_ekdv  */
2092         tmpReg = 0;
2093         for( i=0 ;i<p_KeyAndHash->numOfUsedDflts ; i++)
2094         {
2095             switch(p_KeyAndHash->dflts[i].type)
2096             {
2097                 case(e_FM_PCD_KG_MAC_ADDR):
2098                     tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_MAC_ADDR_SHIFT);
2099                     break;
2100                 case(e_FM_PCD_KG_TCI):
2101                     tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_TCI_SHIFT);
2102                     break;
2103                 case(e_FM_PCD_KG_ENET_TYPE):
2104                     tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_ENET_TYPE_SHIFT);
2105                     break;
2106                 case(e_FM_PCD_KG_PPP_SESSION_ID):
2107                     tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PPP_SESSION_ID_SHIFT);
2108                     break;
2109                 case(e_FM_PCD_KG_PPP_PROTOCOL_ID):
2110                     tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PPP_PROTOCOL_ID_SHIFT);
2111                     break;
2112                 case(e_FM_PCD_KG_MPLS_LABEL):
2113                     tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_MPLS_LABEL_SHIFT);
2114                     break;
2115                 case(e_FM_PCD_KG_IP_ADDR):
2116                     tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IP_ADDR_SHIFT);
2117                     break;
2118                 case(e_FM_PCD_KG_PROTOCOL_TYPE):
2119                     tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PROTOCOL_TYPE_SHIFT);
2120                     break;
2121                 case(e_FM_PCD_KG_IP_TOS_TC):
2122                     tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IP_TOS_TC_SHIFT);
2123                     break;
2124                 case(e_FM_PCD_KG_IPV6_FLOW_LABEL):
2125                     tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_L4_PORT_SHIFT);
2126                     break;
2127                 case(e_FM_PCD_KG_IPSEC_SPI):
2128                     tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IPSEC_SPI_SHIFT);
2129                     break;
2130                 case(e_FM_PCD_KG_L4_PORT):
2131                     tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_L4_PORT_SHIFT);
2132                     break;
2133                 case(e_FM_PCD_KG_TCP_FLAG):
2134                     tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_TCP_FLAG_SHIFT);
2135                     break;
2136                 case(e_FM_PCD_KG_GENERIC_FROM_DATA):
2137                     swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_FROM_DATA;
2138                     swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect;
2139                     numOfSwDefaults ++;
2140                     break;
2141                 case(e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V):
2142                     swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V;
2143                     swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect;
2144                     numOfSwDefaults ++;
2145                     break;
2146                 case(e_FM_PCD_KG_GENERIC_NOT_FROM_DATA):
2147                     swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_NOT_FROM_DATA;
2148                     swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect;
2149                     numOfSwDefaults ++;
2150                    break;
2151                 default:
2152                     RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
2153             }
2154         }
2155         p_SchemeRegs->kgse_ekdv = tmpReg;
2156 
2157         p_LocalExtractsArray = (t_FmPcdKgSchemesExtracts *)XX_Malloc(sizeof(t_FmPcdKgSchemesExtracts));
2158         if(!p_LocalExtractsArray)
2159             RETURN_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
2160 
2161         /*  configure kgse_ekfc and  kgse_gec */
2162         knownTmp = 0;
2163         for( i=0 ;i<p_KeyAndHash->numOfUsedExtracts ; i++)
2164         {
2165             p_Extract = &p_KeyAndHash->extractArray[i];
2166             switch(p_Extract->type)
2167             {
2168                 case(e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO):
2169                     knownTmp |= KG_SCH_KN_PORT_ID;
2170                     /* save in driver structure */
2171                     p_LocalExtractsArray->extractsArray[i].id = GetKnownFieldId(KG_SCH_KN_PORT_ID);
2172                     p_LocalExtractsArray->extractsArray[i].known = TRUE;
2173                     break;
2174                 case(e_FM_PCD_EXTRACT_BY_HDR):
2175                     switch(p_Extract->extractByHdr.hdr)
2176                     {
2177                         case(HEADER_TYPE_UDP_ENCAP_ESP):
2178                             switch(p_Extract->extractByHdr.type)
2179                             {
2180                                 case(e_FM_PCD_EXTRACT_FROM_HDR):
2181                                     /* case where extraction from ESP only */
2182                                     if (p_Extract->extractByHdr.extractByHdrType.fromHdr.offset >= UDP_HEADER_SIZE)
2183                                     {
2184                                         p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
2185                                         p_Extract->extractByHdr.extractByHdrType.fromHdr.offset -= UDP_HEADER_SIZE;
2186                                         p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
2187                                     }
2188                                     else
2189                                     {
2190                                         p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP;
2191                                         p_Extract->extractByHdr.ignoreProtocolValidation = FALSE;
2192                                     }
2193                                     break;
2194                                 case(e_FM_PCD_EXTRACT_FROM_FIELD):
2195                                     switch(p_Extract->extractByHdr.extractByHdrType.fromField.field.udpEncapEsp)
2196                                     {
2197                                         case(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC):
2198                                         case(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST):
2199                                         case(NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN):
2200                                         case(NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM):
2201                                             p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP;
2202                                             break;
2203                                         case(NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI):
2204                                             p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR;
2205                                             p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
2206                                             p_Extract->extractByHdr.extractByHdrType.fromField.size = p_Extract->extractByHdr.extractByHdrType.fromField.size;
2207                                             /*p_Extract->extractByHdr.extractByHdrType.fromField.offset += ESP_SPI_OFFSET;*/
2208                                             p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
2209                                             break;
2210                                         case(NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM):
2211                                             p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR;
2212                                             p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
2213                                             p_Extract->extractByHdr.extractByHdrType.fromField.size = p_Extract->extractByHdr.extractByHdrType.fromField.size;
2214                                             p_Extract->extractByHdr.extractByHdrType.fromField.offset += ESP_SEQ_NUM_OFFSET;
2215                                             p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
2216                                             break;
2217                                     }
2218                                     break;
2219                                 case(e_FM_PCD_EXTRACT_FULL_FIELD):
2220                                     switch(p_Extract->extractByHdr.extractByHdrType.fullField.udpEncapEsp)
2221                                     {
2222                                         case(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC):
2223                                         case(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST):
2224                                         case(NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN):
2225                                         case(NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM):
2226                                             p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP;
2227                                             break;
2228                                         case(NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI):
2229                                             p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR;
2230                                             p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
2231                                             p_Extract->extractByHdr.extractByHdrType.fromHdr.size = ESP_SPI_SIZE;
2232                                             p_Extract->extractByHdr.extractByHdrType.fromHdr.offset = ESP_SPI_OFFSET;
2233                                             p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
2234                                             break;
2235                                         case(NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM):
2236                                             p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR;
2237                                             p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
2238                                             p_Extract->extractByHdr.extractByHdrType.fromHdr.size = ESP_SEQ_NUM_SIZE;
2239                                             p_Extract->extractByHdr.extractByHdrType.fromHdr.offset = ESP_SEQ_NUM_OFFSET;
2240                                             p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
2241                                             break;
2242                                     }
2243                                     break;
2244                             }
2245                             break;
2246                         default:
2247                             break;
2248                     }
2249                     switch(p_Extract->extractByHdr.type)
2250                     {
2251                         case(e_FM_PCD_EXTRACT_FROM_HDR):
2252                             generic = TRUE;
2253                             /* get the header code for the generic extract */
2254                             code = GetGenHdrCode(p_Extract->extractByHdr.hdr, p_Extract->extractByHdr.hdrIndex, p_Extract->extractByHdr.ignoreProtocolValidation);
2255                             /* set generic register fields */
2256                             offset = p_Extract->extractByHdr.extractByHdrType.fromHdr.offset;
2257                             size = p_Extract->extractByHdr.extractByHdrType.fromHdr.size;
2258                             break;
2259                         case(e_FM_PCD_EXTRACT_FROM_FIELD):
2260                             generic = TRUE;
2261                             /* get the field code for the generic extract */
2262                             code = GetGenFieldCode(p_Extract->extractByHdr.hdr,
2263                                         p_Extract->extractByHdr.extractByHdrType.fromField.field, p_Extract->extractByHdr.ignoreProtocolValidation,p_Extract->extractByHdr.hdrIndex);
2264                             offset = p_Extract->extractByHdr.extractByHdrType.fromField.offset;
2265                             size = p_Extract->extractByHdr.extractByHdrType.fromField.size;
2266                             break;
2267                         case(e_FM_PCD_EXTRACT_FULL_FIELD):
2268                             if(!p_Extract->extractByHdr.ignoreProtocolValidation)
2269                             {
2270                                 /* if we have a known field for it - use it, otherwise use generic */
2271                                 bitMask = GetKnownProtMask(p_Extract->extractByHdr.hdr, p_Extract->extractByHdr.hdrIndex,
2272                                             p_Extract->extractByHdr.extractByHdrType.fullField);
2273                                 if(bitMask)
2274                                 {
2275                                     knownTmp |= bitMask;
2276                                     /* save in driver structure */
2277                                     p_LocalExtractsArray->extractsArray[i].id = GetKnownFieldId(bitMask);
2278                                     p_LocalExtractsArray->extractsArray[i].known = TRUE;
2279                                 }
2280                                 else
2281                                     generic = TRUE;
2282 
2283                             }
2284                             else
2285                                 generic = TRUE;
2286                             if(generic)
2287                             {
2288                                 /* tmp - till we cover more headers under generic */
2289                                 RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Full header selection not supported"));
2290                             }
2291                             break;
2292                         default:
2293                             RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
2294                     }
2295                     break;
2296                 case(e_FM_PCD_EXTRACT_NON_HDR):
2297                     /* use generic */
2298                     generic = TRUE;
2299                     offset = 0;
2300                     /* get the field code for the generic extract */
2301                     code = GetGenCode(p_Extract->extractNonHdr.src, &offset);
2302                     offset += p_Extract->extractNonHdr.offset;
2303                     size = p_Extract->extractNonHdr.size;
2304                     break;
2305                 default:
2306                     RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
2307             }
2308 
2309             if(generic)
2310             {
2311                 /* set generic register fields */
2312                 if(currGenId >= FM_PCD_KG_NUM_OF_GENERIC_REGS)
2313                     RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used"));
2314                 if(!code)
2315                     RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG);
2316 
2317                 genTmp = KG_SCH_GEN_VALID;
2318                 genTmp |= (uint32_t)(code << KG_SCH_GEN_HT_SHIFT);
2319                 genTmp |= offset;
2320                 if((size > MAX_KG_SCH_SIZE) || (size < 1))
2321                       RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal extraction (size out of range)"));
2322                 genTmp |= (uint32_t)((size - 1) << KG_SCH_GEN_SIZE_SHIFT);
2323                 swDefault = GetGenericSwDefault(swDefaults, numOfSwDefaults, code);
2324                 if(swDefault == e_FM_PCD_KG_DFLT_ILLEGAL)
2325                     DBG(WARNING, ("No sw default configured"));
2326 
2327                 genTmp |= swDefault << KG_SCH_GEN_DEF_SHIFT;
2328                 genTmp |= KG_SCH_GEN_MASK;
2329                 p_SchemeRegs->kgse_gec[currGenId] = genTmp;
2330                 /* save in driver structure */
2331                 p_LocalExtractsArray->extractsArray[i].id = currGenId++;
2332                 p_LocalExtractsArray->extractsArray[i].known = FALSE;
2333                 generic = FALSE;
2334             }
2335         }
2336         p_SchemeRegs->kgse_ekfc = knownTmp;
2337 
2338         selectTmp = 0;
2339         maskTmp = 0xFFFFFFFF;
2340         /*  configure kgse_bmch, kgse_bmcl and kgse_fqb */
2341 
2342         if(p_KeyAndHash->numOfUsedMasks >= FM_PCD_KG_NUM_OF_EXTRACT_MASKS)
2343             RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Only %d masks supported", FM_PCD_KG_NUM_OF_EXTRACT_MASKS));
2344         for( i=0 ;i<p_KeyAndHash->numOfUsedMasks ; i++)
2345         {
2346             /* Get the relative id of the extract (for known 0-0x1f, for generic 0-7) */
2347             id = p_LocalExtractsArray->extractsArray[p_KeyAndHash->masks[i].extractArrayIndex].id;
2348             /* Get the shift of the select field (depending on i) */
2349             GET_MASK_SEL_SHIFT(shift,i);
2350             if (p_LocalExtractsArray->extractsArray[p_KeyAndHash->masks[i].extractArrayIndex].known)
2351                 selectTmp |= id << shift;
2352             else
2353                 selectTmp |= (id + MASK_FOR_GENERIC_BASE_ID) << shift;
2354 
2355             /* Get the shift of the offset field (depending on i) - may
2356                be in  kgse_bmch or in kgse_fqb (depending on i) */
2357             GET_MASK_OFFSET_SHIFT(shift,i);
2358             if (i<=1)
2359                 selectTmp |= p_KeyAndHash->masks[i].offset << shift;
2360             else
2361                 fqbTmp |= p_KeyAndHash->masks[i].offset << shift;
2362 
2363             /* Get the shift of the mask field (depending on i) */
2364             GET_MASK_SHIFT(shift,i);
2365             /* pass all bits */
2366             maskTmp |= KG_SCH_BITMASK_MASK << shift;
2367             /* clear bits that need masking */
2368             maskTmp &= ~(0xFF << shift) ;
2369             /* set mask bits */
2370             maskTmp |= (p_KeyAndHash->masks[i].mask << shift) ;
2371         }
2372         p_SchemeRegs->kgse_bmch = selectTmp;
2373         p_SchemeRegs->kgse_bmcl = maskTmp;
2374         /* kgse_fqb will be written t the end of the routine */
2375 
2376         /*  configure kgse_hc  */
2377         if(p_KeyAndHash->hashShift > MAX_HASH_SHIFT)
2378              RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashShift must not be larger than %d", MAX_HASH_SHIFT));
2379         if(p_KeyAndHash->hashDistributionFqidsShift > MAX_DIST_FQID_SHIFT)
2380              RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashDistributionFqidsShift must not be larger than %d", MAX_DIST_FQID_SHIFT));
2381 
2382         tmpReg = 0;
2383 
2384         tmpReg |= ((p_KeyAndHash->hashDistributionNumOfFqids - 1) << p_KeyAndHash->hashDistributionFqidsShift);
2385         tmpReg |= p_KeyAndHash->hashShift << KG_SCH_HASH_CONFIG_SHIFT_SHIFT;
2386 
2387         if(p_KeyAndHash->symmetricHash)
2388         {
2389             if((!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_MACSRC) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_MACDST)) ||
2390                     (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPSRC1) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPDST1)) ||
2391                     (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPSRC2) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPDST2)) ||
2392                     (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_L4PSRC) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_L4PDST)))
2393                 RETURN_ERROR(MAJOR, E_INVALID_STATE, ("symmetricHash set but src/dest extractions missing"));
2394             tmpReg |= KG_SCH_HASH_CONFIG_SYM;
2395         }
2396         p_SchemeRegs->kgse_hc = tmpReg;
2397 
2398         /* build the return array describing the order of the extractions */
2399 
2400         /* the last currGenId places of the array
2401            are for generic extracts that are always last.
2402            We now sort for the calculation of the order of the known
2403            extractions we sort the known extracts between orderedArray[0] and
2404            orderedArray[p_KeyAndHash->numOfUsedExtracts - currGenId - 1].
2405            for the calculation of the order of the generic extractions we use:
2406            num_of_generic - currGenId
2407            num_of_known - p_KeyAndHash->numOfUsedExtracts - currGenId
2408            first_generic_index = num_of_known */
2409         curr = 0;
2410         for (i=0;i<p_KeyAndHash->numOfUsedExtracts ; i++)
2411         {
2412             if(p_LocalExtractsArray->extractsArray[i].known)
2413             {
2414                 ASSERT_COND(curr<(p_KeyAndHash->numOfUsedExtracts - currGenId));
2415                 j = curr;
2416                 /* id is the extract id (port id = 0, mac src = 1 etc.). the value in the array is the original
2417                 index in the user's extractions array */
2418                 /* we compare the id of the current extract with the id of the extract in the orderedArray[j-1]
2419                 location */
2420                 while((j > 0) && (p_LocalExtractsArray->extractsArray[i].id <
2421                       p_LocalExtractsArray->extractsArray[p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[j-1]].id))
2422                 {
2423                     p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[j] =
2424                         p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[j-1];
2425                     j--;
2426                 }
2427                 p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[j] = (uint8_t)i;
2428                 curr++;
2429             }
2430             else
2431             {
2432                 /* index is first_generic_index + generic index (id) */
2433                 idx = (uint8_t)(p_KeyAndHash->numOfUsedExtracts - currGenId + p_LocalExtractsArray->extractsArray[i].id);
2434                 ASSERT_COND(idx < FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY);
2435                 p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[idx]= (uint8_t)i;
2436             }
2437         }
2438         XX_Free(p_LocalExtractsArray);
2439         p_LocalExtractsArray = NULL;
2440 
2441     }
2442     else
2443     {
2444         /* clear all unused registers: */
2445         p_SchemeRegs->kgse_ekfc = 0;
2446         p_SchemeRegs->kgse_ekdv = 0;
2447         p_SchemeRegs->kgse_bmch = 0;
2448         p_SchemeRegs->kgse_bmcl = 0;
2449         p_SchemeRegs->kgse_hc = 0;
2450         p_SchemeRegs->kgse_dv0 = 0;
2451         p_SchemeRegs->kgse_dv1 = 0;
2452     }
2453 
2454     if(p_Scheme->bypassFqidGeneration)
2455         p_SchemeRegs->kgse_hc |= KG_SCH_HASH_CONFIG_NO_FQID;
2456 
2457     /*  configure kgse_spc  */
2458     if( p_Scheme->schemeCounter.update)
2459         p_SchemeRegs->kgse_spc = p_Scheme->schemeCounter.value;
2460 
2461 
2462     /* check that are enough generic registers */
2463     if(p_Scheme->numOfUsedExtractedOrs + currGenId > FM_PCD_KG_NUM_OF_GENERIC_REGS)
2464         RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used"));
2465 
2466     /* extracted OR mask on Qid */
2467     for( i=0 ;i<p_Scheme->numOfUsedExtractedOrs ; i++)
2468     {
2469 
2470         p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].extractedOrs = TRUE;
2471         /*  configure kgse_gec[i]  */
2472         p_ExtractOr = &p_Scheme->extractedOrs[i];
2473         switch(p_ExtractOr->type)
2474         {
2475             case(e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO):
2476                 code = KG_SCH_GEN_PARSE_RESULT_N_FQID;
2477                 offset = 0;
2478                 break;
2479             case(e_FM_PCD_EXTRACT_BY_HDR):
2480                 /* get the header code for the generic extract */
2481                 code = GetGenHdrCode(p_ExtractOr->extractByHdr.hdr, p_ExtractOr->extractByHdr.hdrIndex, p_ExtractOr->extractByHdr.ignoreProtocolValidation);
2482                 /* set generic register fields */
2483                 offset = p_ExtractOr->extractionOffset;
2484                 break;
2485             case(e_FM_PCD_EXTRACT_NON_HDR):
2486                 /* get the field code for the generic extract */
2487                 offset = 0;
2488                 code = GetGenCode(p_ExtractOr->src, &offset);
2489                 offset += p_ExtractOr->extractionOffset;
2490                 break;
2491             default:
2492                 RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
2493         }
2494 
2495         /* set generic register fields */
2496         if(!code)
2497             RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG);
2498         genTmp = KG_SCH_GEN_EXTRACT_TYPE | KG_SCH_GEN_VALID;
2499         genTmp |= (uint32_t)(code << KG_SCH_GEN_HT_SHIFT);
2500         genTmp |= offset;
2501         if(!!p_ExtractOr->bitOffsetInFqid == !!p_ExtractOr->bitOffsetInPlcrProfile)
2502             RETURN_ERROR(MAJOR, E_INVALID_VALUE, (" extracted byte must effect either FQID or Policer profile"));
2503 
2504         /************************************************************************************
2505             bitOffsetInFqid and bitOffsetInPolicerProfile are translated to rotate parameter
2506             in the following way:
2507 
2508             Driver API and implementation:
2509             ==============================
2510             FQID: extracted OR byte may be shifted right 1-31 bits to effect parts of the FQID.
2511             if shifted less than 8 bits, or more than 24 bits a mask is set on the bits that
2512             are not overlapping FQID.
2513                      ------------------------
2514                     |      FQID (24)         |
2515                      ------------------------
2516             --------
2517            |        |  extracted OR byte
2518             --------
2519 
2520             Policer Profile: extracted OR byte may be shifted right 1-15 bits to effect parts of the
2521             PP id. Unless shifted exactly 8 bits to overlap the PP id, a mask is set on the bits that
2522             are not overlapping PP id.
2523 
2524                      --------
2525                     | PP (8) |
2526                      --------
2527             --------
2528            |        |  extracted OR byte
2529             --------
2530 
2531             HW implementation
2532             =================
2533             FQID and PP construct a 32 bit word in the way describe below. Extracted byte is located
2534             as the highest byte of that word and may be rotated to effect any part os the FQID or
2535             the PP.
2536              ------------------------  --------
2537             |      FQID (24)         || PP (8) |
2538              ------------------------  --------
2539              --------
2540             |        |  extracted OR byte
2541              --------
2542 
2543         ************************************************************************************/
2544 
2545         if(p_ExtractOr->bitOffsetInFqid)
2546         {
2547             if(p_ExtractOr->bitOffsetInFqid > MAX_KG_SCH_FQID_BIT_OFFSET )
2548               RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal extraction (bitOffsetInFqid out of range)"));
2549             if(p_ExtractOr->bitOffsetInFqid<8)
2550                 genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInFqid+24) << KG_SCH_GEN_SIZE_SHIFT);
2551             else
2552                 genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInFqid-8) << KG_SCH_GEN_SIZE_SHIFT);
2553             p_ExtractOr->mask &= GetExtractedOrMask(p_ExtractOr->bitOffsetInFqid, TRUE);
2554         }
2555         else /* effect policer profile */
2556         {
2557             if(p_ExtractOr->bitOffsetInPlcrProfile > MAX_KG_SCH_PP_BIT_OFFSET )
2558               RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal extraction (bitOffsetInPlcrProfile out of range)"));
2559             p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].bitOffsetInPlcrProfile = p_ExtractOr->bitOffsetInPlcrProfile;
2560             genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInPlcrProfile+16) << KG_SCH_GEN_SIZE_SHIFT);
2561             p_ExtractOr->mask &= GetExtractedOrMask(p_ExtractOr->bitOffsetInPlcrProfile, FALSE);
2562         }
2563 
2564         genTmp |= (uint32_t)(p_ExtractOr->extractionOffset << KG_SCH_GEN_DEF_SHIFT);
2565         /* clear bits that need masking */
2566         genTmp &= ~KG_SCH_GEN_MASK ;
2567         /* set mask bits */
2568         genTmp |= (uint32_t)(p_ExtractOr->mask << KG_SCH_GEN_MASK_SHIFT);
2569         p_SchemeRegs->kgse_gec[currGenId++] = genTmp;
2570 
2571     }
2572     /* clear all unused GEC registers */
2573     for( i=currGenId ;i<FM_PCD_KG_NUM_OF_GENERIC_REGS ; i++)
2574         p_SchemeRegs->kgse_gec[i] = 0;
2575 
2576     /* add base Qid for this scheme */
2577     /* add configuration for kgse_fqb */
2578     if(p_Scheme->baseFqid & ~0x00FFFFFF)
2579         RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid must be between 1 and 2^24-1"));
2580 
2581     fqbTmp |= p_Scheme->baseFqid;
2582     p_SchemeRegs->kgse_fqb = fqbTmp;
2583 
2584     p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine = p_Scheme->nextEngine;
2585     p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].doneAction = p_Scheme->kgNextEngineParams.doneAction;
2586     return E_OK;
2587 }
2588 
2589 void  FmPcdKgValidateSchemeSw(t_Handle h_FmPcd, uint8_t schemeId)
2590 {
2591     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2592 
2593     ASSERT_COND(!p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
2594 
2595     if(p_FmPcd->p_FmPcdKg->schemes[schemeId].netEnvId != ILLEGAL_NETENV)
2596         FmPcdIncNetEnvOwners(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[schemeId].netEnvId);
2597     p_FmPcd->p_FmPcdKg->schemes[schemeId].valid = TRUE;
2598 }
2599 
2600 void  FmPcdKgInvalidateSchemeSw(t_Handle h_FmPcd, uint8_t schemeId)
2601 {
2602 
2603     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2604 
2605     if(p_FmPcd->p_FmPcdKg->schemes[schemeId].netEnvId != ILLEGAL_NETENV)
2606         FmPcdDecNetEnvOwners(h_FmPcd, p_FmPcd->p_FmPcdKg->schemes[schemeId].netEnvId);
2607     p_FmPcd->p_FmPcdKg->schemes[schemeId].valid = FALSE;
2608 }
2609 
2610 uint32_t FmPcdKgGetRequiredAction(t_Handle h_FmPcd, uint8_t schemeId)
2611 {
2612     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2613     ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
2614 
2615     return p_FmPcd->p_FmPcdKg->schemes[schemeId].requiredAction;
2616 }
2617 
2618 uint32_t FmPcdKgGetPointedOwners(t_Handle h_FmPcd, uint8_t schemeId)
2619 {
2620     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2621 
2622    ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
2623 
2624     return p_FmPcd->p_FmPcdKg->schemes[schemeId].pointedOwners;
2625 }
2626 
2627 bool FmPcdKgIsDirectPlcr(t_Handle h_FmPcd, uint8_t schemeId)
2628 {
2629     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2630 
2631    ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
2632 
2633     return p_FmPcd->p_FmPcdKg->schemes[schemeId].directPlcr;
2634 }
2635 
2636 
2637 uint16_t FmPcdKgGetRelativeProfileId(t_Handle h_FmPcd, uint8_t schemeId)
2638 {
2639     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2640 
2641    ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
2642 
2643     return p_FmPcd->p_FmPcdKg->schemes[schemeId].relativeProfileId;
2644 }
2645 
2646 
2647 bool FmPcdKgIsDistrOnPlcrProfile(t_Handle h_FmPcd, uint8_t schemeId)
2648 {
2649     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2650 
2651    ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
2652 
2653     if((p_FmPcd->p_FmPcdKg->schemes[schemeId].extractedOrs &&
2654         p_FmPcd->p_FmPcdKg->schemes[schemeId].bitOffsetInPlcrProfile) ||
2655         p_FmPcd->p_FmPcdKg->schemes[schemeId].nextRelativePlcrProfile)
2656         return TRUE;
2657     else
2658         return FALSE;
2659 
2660 }
2661 void FmPcdKgUpatePointedOwner(t_Handle h_FmPcd, uint8_t schemeId, bool add)
2662 {
2663     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2664 
2665    ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
2666 
2667     if(add)
2668         p_FmPcd->p_FmPcdKg->schemes[schemeId].pointedOwners++;
2669     else
2670         p_FmPcd->p_FmPcdKg->schemes[schemeId].pointedOwners--;
2671 }
2672 
2673 e_FmPcdEngine FmPcdKgGetNextEngine(t_Handle h_FmPcd, uint8_t schemeId)
2674 {
2675     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2676 
2677     ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
2678 
2679     return p_FmPcd->p_FmPcdKg->schemes[schemeId].nextEngine;
2680 }
2681 
2682 e_FmPcdDoneAction FmPcdKgGetDoneAction(t_Handle h_FmPcd, uint8_t schemeId)
2683 {
2684     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2685 
2686     ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
2687 
2688     return p_FmPcd->p_FmPcdKg->schemes[schemeId].doneAction;
2689 }
2690 
2691 void FmPcdKgUpdateRequiredAction(t_Handle h_FmPcd, uint8_t schemeId, uint32_t requiredAction)
2692 {
2693     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2694 
2695     ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
2696 
2697     p_FmPcd->p_FmPcdKg->schemes[schemeId].requiredAction = requiredAction;
2698 }
2699 
2700 t_Error FmPcdKgCheckInvalidateSchemeSw(t_Handle h_FmPcd, uint8_t schemeId)
2701 {
2702     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2703 
2704     if(schemeId >= FM_PCD_KG_NUM_OF_SCHEMES)
2705         REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
2706 
2707    /* check that no port is bound to this scheme */
2708     if(p_FmPcd->p_FmPcdKg->schemes[schemeId].owners)
2709        RETURN_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a scheme that has ports bound to"));
2710     if(!p_FmPcd->p_FmPcdKg->schemes[schemeId].valid)
2711        RETURN_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete an invalid scheme"));
2712     return E_OK;
2713 }
2714 
2715 uint32_t FmPcdKgBuildCppReg(t_Handle h_FmPcd, uint8_t clsPlanGrpId)
2716 {
2717     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2718     uint32_t    tmpKgpeCpp;
2719 
2720     tmpKgpeCpp = (uint32_t)(p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].baseEntry / 8);
2721     tmpKgpeCpp |= (uint32_t)(((p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].sizeOfGrp / 8) - 1) << FM_PCD_KG_PE_CPP_MASK_SHIFT);
2722     return tmpKgpeCpp;
2723 }
2724 
2725 bool    FmPcdKgHwSchemeIsValid(uint32_t schemeModeReg)
2726 {
2727 
2728     if(schemeModeReg & KG_SCH_MODE_EN)
2729         return TRUE;
2730     else
2731         return FALSE;
2732 }
2733 
2734 uint32_t    FmPcdKgBuildWriteSchemeActionReg(uint8_t schemeId, bool updateCounter)
2735 {
2736     return     (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT)|
2737                             FM_PCD_KG_KGAR_GO |
2738                             FM_PCD_KG_KGAR_WRITE |
2739                             FM_PCD_KG_KGAR_SEL_SCHEME_ENTRY |
2740                             DUMMY_PORT_ID |
2741                             (updateCounter ? FM_PCD_KG_KGAR_SCHEME_WSEL_UPDATE_CNT:0));
2742 
2743 }
2744 
2745 uint32_t    FmPcdKgBuildReadSchemeActionReg(uint8_t schemeId)
2746 {
2747     return     (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT)|
2748                             FM_PCD_KG_KGAR_GO |
2749                             FM_PCD_KG_KGAR_READ |
2750                             FM_PCD_KG_KGAR_SEL_SCHEME_ENTRY |
2751                             DUMMY_PORT_ID |
2752                             FM_PCD_KG_KGAR_SCHEME_WSEL_UPDATE_CNT);
2753 
2754 }
2755 
2756 
2757 uint32_t    FmPcdKgBuildWriteClsPlanBlockActionReg(uint8_t grpId)
2758 {
2759     return (uint32_t)(FM_PCD_KG_KGAR_GO |
2760                         FM_PCD_KG_KGAR_WRITE |
2761                         FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY |
2762                         DUMMY_PORT_ID |
2763                         ((uint32_t)grpId << FM_PCD_KG_KGAR_NUM_SHIFT) |
2764                         FM_PCD_KG_KGAR_WSEL_MASK);
2765 
2766 
2767         /* if we ever want to write 1 by 1, use:
2768         sel = (uint8_t)(0x01 << (7- (entryId % CLS_PLAN_NUM_PER_GRP)));*/
2769 }
2770 
2771 uint32_t    FmPcdKgBuildReadClsPlanBlockActionReg(uint8_t grpId)
2772 {
2773     return (uint32_t)(FM_PCD_KG_KGAR_GO |
2774                         FM_PCD_KG_KGAR_READ |
2775                         FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY |
2776                         DUMMY_PORT_ID |
2777                         ((uint32_t)grpId << FM_PCD_KG_KGAR_NUM_SHIFT) |
2778                         FM_PCD_KG_KGAR_WSEL_MASK);
2779 
2780 
2781         /* if we ever want to write 1 by 1, use:
2782         sel = (uint8_t)(0x01 << (7- (entryId % CLS_PLAN_NUM_PER_GRP)));*/
2783 }
2784 
2785 uint32_t        FmPcdKgBuildWritePortSchemeBindActionReg(uint8_t hardwarePortId)
2786 {
2787 
2788     return (uint32_t)(FM_PCD_KG_KGAR_GO |
2789                         FM_PCD_KG_KGAR_WRITE |
2790                         FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
2791                         hardwarePortId |
2792                         FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP);
2793 }
2794 
2795 uint32_t        FmPcdKgBuildReadPortSchemeBindActionReg(uint8_t hardwarePortId)
2796 {
2797 
2798     return (uint32_t)(FM_PCD_KG_KGAR_GO |
2799                         FM_PCD_KG_KGAR_READ |
2800                         FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
2801                         hardwarePortId |
2802                         FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP);
2803 }
2804 uint32_t        FmPcdKgBuildWritePortClsPlanBindActionReg(uint8_t hardwarePortId)
2805 {
2806 
2807     return (uint32_t)(FM_PCD_KG_KGAR_GO |
2808                         FM_PCD_KG_KGAR_WRITE |
2809                         FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
2810                         hardwarePortId |
2811                         FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP);
2812 }
2813 
2814 uint8_t FmPcdKgGetClsPlanGrpBase(t_Handle h_FmPcd, uint8_t clsPlanGrp)
2815 {
2816     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2817 
2818     return p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrp].baseEntry;
2819 }
2820 
2821 uint16_t FmPcdKgGetClsPlanGrpSize(t_Handle h_FmPcd, uint8_t clsPlanGrp)
2822 {
2823     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2824 
2825     return p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrp].sizeOfGrp;
2826 }
2827 
2828 uint8_t FmPcdKgGetSchemeSwId(t_Handle h_FmPcd, uint8_t schemeHwId)
2829 {
2830     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2831     uint8_t     i;
2832 
2833     for(i=0;i<p_FmPcd->p_FmPcdKg->numOfSchemes;i++)
2834         if(p_FmPcd->p_FmPcdKg->schemesIds[i] == schemeHwId)
2835             return i;
2836     ASSERT_COND(i!=p_FmPcd->p_FmPcdKg->numOfSchemes);
2837     return FM_PCD_KG_NUM_OF_SCHEMES;
2838 }
2839 
2840 uint8_t FmPcdKgGetNumOfPartitionSchemes(t_Handle h_FmPcd)
2841 {
2842     return ((t_FmPcd*)h_FmPcd)->p_FmPcdKg->numOfSchemes;
2843 }
2844 
2845 uint8_t FmPcdKgGetPhysicalSchemeId(t_Handle h_FmPcd, uint8_t relativeSchemeId)
2846 {
2847     return ((t_FmPcd*)h_FmPcd)->p_FmPcdKg->schemesIds[relativeSchemeId];
2848 }
2849 
2850 uint8_t FmPcdKgGetRelativeSchemeId(t_Handle h_FmPcd, uint8_t schemeId)
2851 {
2852     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2853     uint8_t     i;
2854 
2855     for(i = 0;i<p_FmPcd->p_FmPcdKg->numOfSchemes;i++)
2856         if(p_FmPcd->p_FmPcdKg->schemesIds[i] == schemeId)
2857             return i;
2858 
2859     if(i == p_FmPcd->p_FmPcdKg->numOfSchemes)
2860         REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("Scheme is out of partition range"));
2861 
2862     return FM_PCD_KG_NUM_OF_SCHEMES;
2863 }
2864 
2865 t_Error FmPcdKgCcGetSetParams(t_Handle h_FmPcd, t_Handle  h_Scheme, uint32_t requiredAction)
2866 {
2867     t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
2868     uint8_t             relativeSchemeId, physicalSchemeId;
2869     uint32_t            tmpKgarReg, tmpReg32 = 0, intFlags;
2870     t_Error             err;
2871 
2872     SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0);
2873     SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, 0);
2874     SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0);
2875 
2876     if (p_FmPcd->h_Hc)
2877         return FmHcPcdKgCcGetSetParams(p_FmPcd->h_Hc,  h_Scheme,  requiredAction);
2878 
2879     physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1);
2880 
2881     relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId);
2882     if(relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES)
2883         RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
2884 
2885     if (FmPcdKgSchemeTryLock(p_FmPcd, relativeSchemeId, FALSE))
2886         RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Lock of the scheme FAILED"));
2887 
2888     if(!p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].pointedOwners ||
2889        !(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].requiredAction & requiredAction))
2890     {
2891         if(requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
2892         {
2893             switch(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine)
2894             {
2895                 case(e_FM_PCD_DONE):
2896                     if(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].doneAction == e_FM_PCD_ENQ_FRAME)
2897                     {
2898                         tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
2899                         intFlags = FmPcdLock(p_FmPcd);
2900                         WriteKgarWait(p_FmPcd, tmpKgarReg);
2901                         if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode) & KG_SCH_MODE_EN))
2902                         {
2903                             RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock);
2904                             RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid"));
2905                         }
2906                         tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode);
2907                         ASSERT_COND(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME));
2908                         WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode, tmpReg32 | NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA);
2909                         /* call indirect command for scheme write */
2910                         tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
2911                         WriteKgarWait(p_FmPcd, tmpKgarReg);
2912                         FmPcdUnlock(p_FmPcd, intFlags);
2913                     }
2914                 break;
2915                 case(e_FM_PCD_PLCR):
2916                     if(!p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].directPlcr ||
2917                        (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].extractedOrs &&
2918                         p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].bitOffsetInPlcrProfile) ||
2919                         p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextRelativePlcrProfile)
2920                         {
2921                             RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock);
2922                             RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("In this situation PP can not be with distribution and has to be shared"));
2923                         }
2924                         err = FmPcdPlcrCcGetSetParams(h_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].relativeProfileId, requiredAction);
2925                         if(err)
2926                         {
2927                             RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock);
2928                             RETURN_ERROR(MAJOR, err, NO_MSG);
2929                         }
2930                break;
2931                default:
2932                     RETURN_ERROR(MAJOR, E_INVALID_VALUE,("in this situation the next engine after scheme can be or PLCR or ENQ_FRAME"));
2933             }
2934         }
2935     }
2936     p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].pointedOwners += 1;
2937     p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].requiredAction |= requiredAction;
2938 
2939     RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock);
2940     return E_OK;
2941 }
2942 
2943 t_Error FmPcdKgSchemeTryLock(t_Handle h_FmPcd, uint8_t schemeId, bool intr)
2944 {
2945     t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
2946     bool        ans;
2947 
2948     if (intr)
2949         ans = TRY_LOCK(NULL, &p_FmPcd->p_FmPcdKg->schemes[schemeId].lock);
2950     else
2951         ans = TRY_LOCK(p_FmPcd->h_Spinlock, &p_FmPcd->p_FmPcdKg->schemes[schemeId].lock);
2952     if (ans)
2953         return E_OK;
2954     return ERROR_CODE(E_BUSY);
2955 }
2956 
2957 void FmPcdKgReleaseSchemeLock(t_Handle h_FmPcd, uint8_t schemeId)
2958 {
2959     RELEASE_LOCK(((t_FmPcd*)h_FmPcd)->p_FmPcdKg->schemes[schemeId].lock);
2960 }
2961 
2962 t_Handle FM_PCD_KgSetScheme(t_Handle h_FmPcd,  t_FmPcdKgSchemeParams *p_Scheme)
2963 {
2964     t_FmPcd                             *p_FmPcd = (t_FmPcd*)h_FmPcd;
2965     uint32_t                            tmpReg;
2966     t_FmPcdKgInterModuleSchemeRegs      schemeRegs;
2967     t_FmPcdKgInterModuleSchemeRegs      *p_MemRegs;
2968     uint8_t                             i;
2969     t_Error                             err = E_OK;
2970     uint32_t                            tmpKgarReg;
2971     uint32_t                            intFlags;
2972     uint8_t                             physicalSchemeId, relativeSchemeId;
2973 
2974     SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, NULL);
2975     SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, NULL);
2976     SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL);
2977 
2978     if (p_FmPcd->h_Hc)
2979         return FmHcPcdKgSetScheme(p_FmPcd->h_Hc, p_Scheme);
2980 
2981     /* if not called for modification, check first that this scheme is unused */
2982     if(!p_Scheme->modify)
2983     {
2984         /* check that schemeId is in range */
2985         if(p_Scheme->id.relativeSchemeId >= p_FmPcd->p_FmPcdKg->numOfSchemes)
2986         {
2987             REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("Scheme is out of range"));
2988             return NULL;
2989         }
2990         relativeSchemeId = p_Scheme->id.relativeSchemeId;
2991 
2992         if (FmPcdKgSchemeTryLock(p_FmPcd, relativeSchemeId, FALSE))
2993             return NULL;
2994 
2995         physicalSchemeId = p_FmPcd->p_FmPcdKg->schemesIds[relativeSchemeId];
2996 
2997         /* read specified scheme into scheme registers */
2998         tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
2999         intFlags = FmPcdLock(p_FmPcd);
3000         WriteKgarWait(p_FmPcd, tmpKgarReg);
3001         tmpReg = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode);
3002         FmPcdUnlock(p_FmPcd, intFlags);
3003 
3004         if (tmpReg & KG_SCH_MODE_EN)
3005         {
3006             REPORT_ERROR(MAJOR, E_ALREADY_EXISTS,
3007                          ("Scheme %d(phys %d) is already used", relativeSchemeId, physicalSchemeId));
3008             RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock);
3009             return NULL;
3010         }
3011     }
3012     else
3013     {
3014         SANITY_CHECK_RETURN_VALUE(p_Scheme->id.h_Scheme, E_INVALID_HANDLE, NULL);
3015 
3016         intFlags = FmPcdLock(p_FmPcd);
3017         physicalSchemeId = (uint8_t)(PTR_TO_UINT(p_Scheme->id.h_Scheme)-1);
3018         relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId);
3019 
3020         /* check that schemeId is in range */
3021         if(relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES)
3022         {
3023             REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
3024             FmPcdUnlock(p_FmPcd, intFlags);
3025             return NULL;
3026         }
3027 
3028         err = FmPcdKgSchemeTryLock(p_FmPcd, relativeSchemeId, TRUE);
3029         FmPcdUnlock(p_FmPcd, intFlags);
3030         if (err)
3031             return NULL;
3032     }
3033 
3034     err = FmPcdKgBuildScheme(h_FmPcd, p_Scheme, &schemeRegs);
3035     if(err)
3036     {
3037         REPORT_ERROR(MAJOR, err, NO_MSG);
3038         FmPcdKgInvalidateSchemeSw(h_FmPcd, relativeSchemeId);
3039         RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock);
3040         return NULL;
3041     }
3042 
3043     /* configure all 21 scheme registers */
3044     p_MemRegs = &p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs;
3045     intFlags = FmPcdLock(p_FmPcd);
3046     WRITE_UINT32(p_MemRegs->kgse_ppc, schemeRegs.kgse_ppc);
3047     WRITE_UINT32(p_MemRegs->kgse_ccbs, schemeRegs.kgse_ccbs);
3048     WRITE_UINT32(p_MemRegs->kgse_mode, schemeRegs.kgse_mode);
3049     WRITE_UINT32(p_MemRegs->kgse_mv, schemeRegs.kgse_mv);
3050     WRITE_UINT32(p_MemRegs->kgse_dv0, schemeRegs.kgse_dv0);
3051     WRITE_UINT32(p_MemRegs->kgse_dv1, schemeRegs.kgse_dv1);
3052     WRITE_UINT32(p_MemRegs->kgse_ekdv, schemeRegs.kgse_ekdv);
3053     WRITE_UINT32(p_MemRegs->kgse_ekfc, schemeRegs.kgse_ekfc);
3054     WRITE_UINT32(p_MemRegs->kgse_bmch, schemeRegs.kgse_bmch);
3055     WRITE_UINT32(p_MemRegs->kgse_bmcl, schemeRegs.kgse_bmcl);
3056     WRITE_UINT32(p_MemRegs->kgse_hc, schemeRegs.kgse_hc);
3057     WRITE_UINT32(p_MemRegs->kgse_spc, schemeRegs.kgse_spc);
3058     WRITE_UINT32(p_MemRegs->kgse_fqb, schemeRegs.kgse_fqb);
3059     for(i=0 ; i<FM_PCD_KG_NUM_OF_GENERIC_REGS ; i++)
3060         WRITE_UINT32(p_MemRegs->kgse_gec[i], schemeRegs.kgse_gec[i]);
3061 
3062     /* call indirect command for scheme write */
3063     tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, p_Scheme->schemeCounter.update);
3064 
3065     WriteKgarWait(p_FmPcd, tmpKgarReg);
3066     FmPcdUnlock(p_FmPcd, intFlags);
3067 
3068     FmPcdKgValidateSchemeSw(h_FmPcd, relativeSchemeId);
3069 
3070     RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock);
3071 
3072     return UINT_TO_PTR((uint64_t)physicalSchemeId+1);
3073 }
3074 
3075 t_Error  FM_PCD_KgDeleteScheme(t_Handle h_FmPcd, t_Handle h_Scheme)
3076 {
3077     t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
3078     uint8_t             physicalSchemeId;
3079     uint32_t            tmpKgarReg, intFlags;
3080     t_Error             err = E_OK;
3081     uint8_t             relativeSchemeId;
3082 
3083     SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
3084     SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE);
3085     SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
3086 
3087     if (p_FmPcd->h_Hc)
3088         return FmHcPcdKgDeleteScheme(p_FmPcd->h_Hc, h_Scheme);
3089 
3090     physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1);
3091     relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId);
3092 
3093     if(relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES)
3094         RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
3095 
3096     if ((err = FmPcdKgSchemeTryLock(p_FmPcd, relativeSchemeId, FALSE)) != E_OK)
3097        RETURN_ERROR(MINOR, err, NO_MSG);
3098 
3099     /* check that no port is bound to this scheme */
3100     err = FmPcdKgCheckInvalidateSchemeSw(h_FmPcd, relativeSchemeId);
3101     if(err)
3102        RETURN_ERROR(MINOR, err, NO_MSG);
3103 
3104     intFlags = FmPcdLock(p_FmPcd);
3105     /* clear mode register, including enable bit */
3106     WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode, 0);
3107 
3108     /* call indirect command for scheme write */
3109     tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
3110 
3111     WriteKgarWait(p_FmPcd, tmpKgarReg);
3112     FmPcdUnlock(p_FmPcd, intFlags);
3113 
3114     FmPcdKgInvalidateSchemeSw(h_FmPcd, relativeSchemeId);
3115 
3116     RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock);
3117 
3118     return E_OK;
3119 }
3120 
3121 uint32_t  FM_PCD_KgGetSchemeCounter(t_Handle h_FmPcd, t_Handle h_Scheme)
3122 {
3123     t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
3124     uint32_t            tmpKgarReg, spc, intFlags;
3125     uint8_t             physicalSchemeId;
3126 
3127     SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0);
3128     SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, 0);
3129     SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0);
3130 
3131     if (p_FmPcd->h_Hc)
3132         return FmHcPcdKgGetSchemeCounter(p_FmPcd->h_Hc, h_Scheme);
3133 
3134     physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1);
3135 
3136     if(FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId) == FM_PCD_KG_NUM_OF_SCHEMES)
3137         REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
3138 
3139     tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
3140     intFlags = FmPcdLock(p_FmPcd);
3141     WriteKgarWait(p_FmPcd, tmpKgarReg);
3142     if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode) & KG_SCH_MODE_EN))
3143        REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid"));
3144     spc = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_spc);
3145     FmPcdUnlock(p_FmPcd, intFlags);
3146 
3147     return spc;
3148 }
3149 
3150 t_Error  FM_PCD_KgSetSchemeCounter(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t value)
3151 {
3152     t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
3153     uint32_t            tmpKgarReg, intFlags;
3154     uint8_t             physicalSchemeId;
3155 
3156     SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0);
3157     SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, 0);
3158     SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0);
3159 
3160     if (p_FmPcd->h_Hc)
3161         return FmHcPcdKgSetSchemeCounter(p_FmPcd->h_Hc, h_Scheme, value);
3162 
3163     physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1);
3164     /* check that schemeId is in range */
3165     if(FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId) == FM_PCD_KG_NUM_OF_SCHEMES)
3166         REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
3167 
3168     /* read specified scheme into scheme registers */
3169     tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
3170     intFlags = FmPcdLock(p_FmPcd);
3171     WriteKgarWait(p_FmPcd, tmpKgarReg);
3172     if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode) & KG_SCH_MODE_EN))
3173     {
3174        FmPcdUnlock(p_FmPcd, intFlags);
3175        RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid"));
3176     }
3177 
3178     /* change counter value */
3179     WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_spc, value);
3180 
3181     /* call indirect command for scheme write */
3182     tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE);
3183 
3184     WriteKgarWait(p_FmPcd, tmpKgarReg);
3185     FmPcdUnlock(p_FmPcd, intFlags);
3186 
3187     return E_OK;
3188 }
3189 
3190