Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2008-2016 Freescale Semiconductor Inc.
3 : : * Copyright 2017-2024 NXP
4 : : */
5 : :
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <string.h>
9 : : #include <fcntl.h>
10 : : #include <errno.h>
11 : : #include <unistd.h>
12 : : #include <termios.h>
13 : : #include <sys/ioctl.h>
14 : : #include <stdbool.h>
15 : : #include <rte_common.h>
16 : :
17 : : #include "fm_ext.h"
18 : : #include "fm_pcd_ext.h"
19 : : #include "fm_port_ext.h"
20 : : #include <dpaa_ethdev.h>
21 : :
22 : : #define DEV_TO_ID(p) \
23 : : do { \
24 : : t_device *p_dev = (t_device *)p; \
25 : : p = UINT_TO_PTR(p_dev->id); \
26 : : } while (0)
27 : :
28 : : /* Major and minor are in sync with FMD, respin is for fmlib identification */
29 : : #define FM_LIB_VERSION_MAJOR 21
30 : : #define FM_LIB_VERSION_MINOR 1
31 : : #define FM_LIB_VERSION_RESPIN 0
32 : :
33 : : #if (FMD_API_VERSION_MAJOR != FM_LIB_VERSION_MAJOR) || \
34 : : (FMD_API_VERSION_MINOR != FM_LIB_VERSION_MINOR)
35 : : #warning FMD and FMLIB version mismatch
36 : : #endif
37 : :
38 : : t_handle
39 : 0 : fm_open(uint8_t id)
40 : : {
41 : : t_device *p_dev;
42 : : int fd;
43 : : char dev_name[20];
44 : : static bool called;
45 : : ioc_fm_api_version_t ver;
46 : :
47 : : _fml_dbg("Calling...");
48 : :
49 : 0 : p_dev = (t_device *)malloc(sizeof(t_device));
50 [ # # ]: 0 : if (p_dev == NULL)
51 : : return NULL;
52 : :
53 : : memset(dev_name, 0, 20);
54 : 0 : sprintf(dev_name, "%s%s%d", "/dev/", DEV_FM_NAME, id);
55 : : fd = open(dev_name, O_RDWR);
56 [ # # ]: 0 : if (fd < 0) {
57 : 0 : free(p_dev);
58 : 0 : return NULL;
59 : : }
60 : :
61 : 0 : p_dev->id = id;
62 : 0 : p_dev->fd = fd;
63 [ # # ]: 0 : if (!called) {
64 : 0 : called = true;
65 : 0 : fm_get_api_version((t_handle)p_dev, &ver);
66 : :
67 : 0 : if (ver.version.major != FMD_API_VERSION_MAJOR ||
68 [ # # ]: 0 : ver.version.minor != FMD_API_VERSION_MINOR ||
69 : : ver.version.respin != FMD_API_VERSION_RESPIN) {
70 : 0 : DPAA_PMD_WARN("Compiled against FMD API ver %u.%u.%u",
71 : : FMD_API_VERSION_MAJOR,
72 : : FMD_API_VERSION_MINOR, FMD_API_VERSION_RESPIN);
73 : 0 : DPAA_PMD_WARN("Running with FMD API ver %u.%u.%u",
74 : : ver.version.major, ver.version.minor,
75 : : ver.version.respin);
76 : : }
77 : : }
78 : : _fml_dbg("Finishing.");
79 : :
80 : : return (t_handle)p_dev;
81 : : }
82 : :
83 : 0 : void fm_close(t_handle h_fm)
84 : : {
85 : : t_device *p_dev = (t_device *)h_fm;
86 : :
87 : : _fml_dbg("Calling...");
88 : :
89 : 0 : close(p_dev->fd);
90 : 0 : free(p_dev);
91 : :
92 : : _fml_dbg("Finishing.");
93 : 0 : }
94 : :
95 : : uint32_t
96 : 0 : fm_get_api_version(t_handle h_fm, ioc_fm_api_version_t *p_version)
97 : : {
98 : : t_device *p_dev = (t_device *)h_fm;
99 : : int ret;
100 : :
101 : : _fml_dbg("Calling...");
102 : :
103 : 0 : ret = ioctl(p_dev->fd, FM_IOC_GET_API_VERSION, p_version);
104 [ # # ]: 0 : if (ret) {
105 : 0 : DPAA_PMD_ERR("cannot get API version, error %i (%s)",
106 : : errno, strerror(errno));
107 : 0 : RETURN_ERROR(MINOR, E_INVALID_OPERATION, NO_MSG);
108 : : }
109 : : _fml_dbg("Finishing.");
110 : :
111 : : return E_OK;
112 : : }
113 : :
114 : : t_handle
115 : 0 : fm_pcd_open(t_fm_pcd_params *p_fm_pcd_params)
116 : : {
117 : : t_device *p_dev;
118 : : int fd;
119 : : char dev_name[20];
120 : :
121 : : _fml_dbg("Calling...");
122 : :
123 : 0 : p_dev = (t_device *)malloc(sizeof(t_device));
124 [ # # ]: 0 : if (p_dev == NULL)
125 : : return NULL;
126 : :
127 : : memset(dev_name, 0, 20);
128 : 0 : sprintf(dev_name, "%s%s%u-pcd", "/dev/", DEV_FM_NAME,
129 : 0 : (uint32_t)((t_device *)p_fm_pcd_params->h_fm)->id);
130 : : fd = open(dev_name, O_RDWR);
131 [ # # ]: 0 : if (fd < 0) {
132 : 0 : free(p_dev);
133 : 0 : return NULL;
134 : : }
135 : :
136 : 0 : p_dev->id = ((t_device *)p_fm_pcd_params->h_fm)->id;
137 : 0 : p_dev->fd = fd;
138 : 0 : p_dev->owners = 0;
139 : :
140 : : _fml_dbg("Finishing.");
141 : :
142 : 0 : return (t_handle)p_dev;
143 : : }
144 : :
145 : : void
146 : 0 : fm_pcd_close(t_handle h_fm_pcd)
147 : : {
148 : : t_device *p_dev = (t_device *)h_fm_pcd;
149 : :
150 : : _fml_dbg("Calling...");
151 : :
152 : 0 : close(p_dev->fd);
153 : :
154 [ # # ]: 0 : if (p_dev->owners) {
155 : : printf("\nTry delete a prev created pcd handler(owners:%u)!",
156 : : p_dev->owners);
157 : 0 : return;
158 : : }
159 : :
160 : 0 : free(p_dev);
161 : :
162 : : _fml_dbg("Finishing.");
163 : : }
164 : :
165 : : uint32_t
166 : 0 : fm_pcd_enable(t_handle h_fm_pcd)
167 : : {
168 : : t_device *p_dev = (t_device *)h_fm_pcd;
169 : :
170 : : _fml_dbg("Calling...");
171 : :
172 [ # # ]: 0 : if (ioctl(p_dev->fd, FM_PCD_IOC_ENABLE))
173 : 0 : RETURN_ERROR(MINOR, E_INVALID_OPERATION, NO_MSG);
174 : :
175 : : _fml_dbg("Finishing.");
176 : :
177 : : return E_OK;
178 : : }
179 : :
180 : : uint32_t
181 : 0 : fm_pcd_disable(t_handle h_fm_pcd)
182 : : {
183 : : t_device *p_dev = (t_device *)h_fm_pcd;
184 : :
185 : : _fml_dbg("Calling...");
186 : :
187 [ # # ]: 0 : if (ioctl(p_dev->fd, FM_PCD_IOC_DISABLE))
188 : 0 : RETURN_ERROR(MINOR, E_INVALID_OPERATION, NO_MSG);
189 : :
190 : : _fml_dbg("Finishing.");
191 : :
192 : : return E_OK;
193 : : }
194 : :
195 : : t_handle
196 : 0 : fm_pcd_net_env_characteristics_set(t_handle h_fm_pcd,
197 : : ioc_fm_pcd_net_env_params_t *params)
198 : : {
199 : : t_device *p_pcd_dev = (t_device *)h_fm_pcd;
200 : : t_device *p_dev = NULL;
201 : :
202 : : _fml_dbg("Calling...");
203 : :
204 : 0 : params->id = NULL;
205 : :
206 [ # # ]: 0 : if (ioctl(p_pcd_dev->fd, FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET,
207 : : params))
208 : : return NULL;
209 : :
210 : 0 : p_dev = (t_device *)malloc(sizeof(t_device));
211 [ # # ]: 0 : if (p_dev == NULL)
212 : : return NULL;
213 : :
214 : : memset(p_dev, 0, sizeof(t_device));
215 : 0 : p_dev->h_user_priv = (t_handle)p_pcd_dev;
216 : 0 : p_pcd_dev->owners++;
217 : 0 : p_dev->id = PTR_TO_UINT(params->id);
218 : :
219 : : _fml_dbg("Finishing.");
220 : :
221 : 0 : return (t_handle)p_dev;
222 : : }
223 : :
224 : : uint32_t
225 : 0 : fm_pcd_net_env_characteristics_delete(t_handle h_net_env)
226 : : {
227 : : t_device *p_dev = (t_device *)h_net_env;
228 : : t_device *p_pcd_dev = NULL;
229 : : ioc_fm_obj_t id;
230 : :
231 : : _fml_dbg("Calling...");
232 : :
233 : 0 : p_pcd_dev = (t_device *)p_dev->h_user_priv;
234 : 0 : id.obj = UINT_TO_PTR(p_dev->id);
235 : :
236 [ # # ]: 0 : if (ioctl(p_pcd_dev->fd, FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE,
237 : : &id))
238 : : RETURN_ERROR(MINOR, E_INVALID_OPERATION, NO_MSG);
239 : :
240 : 0 : p_pcd_dev->owners--;
241 : 0 : free(p_dev);
242 : :
243 : : _fml_dbg("Finishing.");
244 : :
245 : 0 : return E_OK;
246 : : }
247 : :
248 : : t_handle
249 : 0 : fm_pcd_kg_scheme_set(t_handle h_fm_pcd,
250 : : ioc_fm_pcd_kg_scheme_params_t *params)
251 : : {
252 : : t_device *p_pcd_dev = (t_device *)h_fm_pcd;
253 : : t_device *p_dev = NULL;
254 : : int ret;
255 : :
256 : : _fml_dbg("Calling...");
257 : :
258 : 0 : params->id = NULL;
259 : :
260 [ # # ]: 0 : if (params->param.modify) {
261 [ # # ]: 0 : if (params->param.scm_id.scheme_id)
262 : 0 : DEV_TO_ID(params->param.scm_id.scheme_id);
263 : : else
264 : : return NULL;
265 : : }
266 : :
267 : : /* correct h_net_env param from scheme */
268 [ # # ]: 0 : if (params->param.net_env_params.net_env_id)
269 : 0 : DEV_TO_ID(params->param.net_env_params.net_env_id);
270 : :
271 : : /* correct next engine params handlers: cc*/
272 [ # # ]: 0 : if (params->param.next_engine == e_IOC_FM_PCD_CC &&
273 [ # # ]: 0 : params->param.kg_next_engine_params.cc.tree_id)
274 : 0 : DEV_TO_ID(params->param.kg_next_engine_params.cc.tree_id);
275 : :
276 : 0 : ret = ioctl(p_pcd_dev->fd, FM_PCD_IOC_KG_SCHEME_SET, params);
277 [ # # ]: 0 : if (ret) {
278 : 0 : DPAA_PMD_ERR(" cannot set kg scheme, error %i (%s)",
279 : : errno, strerror(errno));
280 : 0 : return NULL;
281 : : }
282 : :
283 : 0 : p_dev = (t_device *)malloc(sizeof(t_device));
284 [ # # ]: 0 : if (p_dev == NULL)
285 : : return NULL;
286 : :
287 : : memset(p_dev, 0, sizeof(t_device));
288 : 0 : p_dev->h_user_priv = (t_handle)p_pcd_dev;
289 : : /* increase owners only if a new scheme is created */
290 [ # # ]: 0 : if (!params->param.modify)
291 : 0 : p_pcd_dev->owners++;
292 : 0 : p_dev->id = PTR_TO_UINT(params->id);
293 : :
294 : : _fml_dbg("Finishing.");
295 : :
296 : 0 : return (t_handle)p_dev;
297 : : }
298 : :
299 : : uint32_t
300 : 0 : fm_pcd_kg_scheme_delete(t_handle h_scheme)
301 : : {
302 : : t_device *p_dev = (t_device *)h_scheme;
303 : : t_device *p_pcd_dev = NULL;
304 : : ioc_fm_obj_t id;
305 : :
306 : : _fml_dbg("Calling...");
307 : :
308 : 0 : p_pcd_dev = (t_device *)p_dev->h_user_priv;
309 : 0 : id.obj = UINT_TO_PTR(p_dev->id);
310 : :
311 [ # # ]: 0 : if (ioctl(p_pcd_dev->fd, FM_PCD_IOC_KG_SCHEME_DELETE, &id)) {
312 : 0 : DPAA_PMD_WARN("cannot delete kg scheme, error %i (%s)",
313 : : errno, strerror(errno));
314 : 0 : RETURN_ERROR(MINOR, E_INVALID_OPERATION, NO_MSG);
315 : : }
316 : :
317 : 0 : p_pcd_dev->owners--;
318 : 0 : free(p_dev);
319 : :
320 : : _fml_dbg("Finishing.");
321 : :
322 : 0 : return E_OK;
323 : : }
324 : :
325 : : typedef struct {
326 : : e_fm_port_type port_type; /**< Port type */
327 : : uint8_t port_id; /**< Port Id - relative to type */
328 : : } t_fm_port;
329 : :
330 : : t_handle
331 : 0 : fm_port_open(t_fm_port_params *p_fm_port_params)
332 : : {
333 : : t_device *p_dev;
334 : : int fd;
335 : : char dev_name[30];
336 : : t_fm_port *p_fm_port;
337 : :
338 : : _fml_dbg("Calling...");
339 : :
340 : 0 : p_dev = (t_device *)malloc(sizeof(t_device));
341 [ # # ]: 0 : if (p_dev == NULL)
342 : : return NULL;
343 : :
344 : : memset(p_dev, 0, sizeof(t_device));
345 : :
346 : 0 : p_fm_port = (t_fm_port *)malloc(sizeof(t_fm_port));
347 [ # # ]: 0 : if (!p_fm_port) {
348 : 0 : free(p_dev);
349 : 0 : return NULL;
350 : : }
351 : : memset(p_fm_port, 0, sizeof(t_fm_port));
352 : : memset(dev_name, 0, sizeof(dev_name));
353 [ # # # # : 0 : switch (p_fm_port_params->port_type) {
# # ]
354 : 0 : case e_FM_PORT_TYPE_OH_OFFLINE_PARSING:
355 : 0 : sprintf(dev_name, "%s%s%u-port-oh%d", "/dev/", DEV_FM_NAME,
356 : 0 : (uint32_t)((t_device *)p_fm_port_params->h_fm)->id,
357 : 0 : p_fm_port_params->port_id);
358 : : break;
359 : 0 : case e_FM_PORT_TYPE_RX:
360 : 0 : sprintf(dev_name, "%s%s%u-port-rx%d", "/dev/", DEV_FM_NAME,
361 : 0 : (uint32_t)((t_device *)p_fm_port_params->h_fm)->id,
362 : 0 : p_fm_port_params->port_id);
363 : : break;
364 : 0 : case e_FM_PORT_TYPE_RX_10G:
365 : 0 : sprintf(dev_name, "%s%s%u-port-rx%d", "/dev/", DEV_FM_NAME,
366 : 0 : (uint32_t)((t_device *)p_fm_port_params->h_fm)->id,
367 : 0 : FM_MAX_NUM_OF_1G_RX_PORTS + p_fm_port_params->port_id);
368 : : break;
369 : 0 : case e_FM_PORT_TYPE_TX:
370 : 0 : sprintf(dev_name, "%s%s%u-port-tx%d", "/dev/", DEV_FM_NAME,
371 : 0 : (uint32_t)((t_device *)p_fm_port_params->h_fm)->id,
372 : 0 : p_fm_port_params->port_id);
373 : : break;
374 : 0 : case e_FM_PORT_TYPE_TX_10G:
375 : 0 : sprintf(dev_name, "%s%s%u-port-tx%d", "/dev/", DEV_FM_NAME,
376 : 0 : (uint32_t)((t_device *)p_fm_port_params->h_fm)->id,
377 : 0 : FM_MAX_NUM_OF_1G_TX_PORTS + p_fm_port_params->port_id);
378 : : break;
379 : 0 : default:
380 : 0 : free(p_fm_port);
381 : 0 : free(p_dev);
382 : 0 : return NULL;
383 : : }
384 : :
385 : : fd = open(dev_name, O_RDWR);
386 [ # # ]: 0 : if (fd < 0) {
387 : 0 : free(p_fm_port);
388 : 0 : free(p_dev);
389 : 0 : return NULL;
390 : : }
391 : :
392 : 0 : p_fm_port->port_type = p_fm_port_params->port_type;
393 : 0 : p_fm_port->port_id = p_fm_port_params->port_id;
394 : 0 : p_dev->id = p_fm_port_params->port_id;
395 : 0 : p_dev->fd = fd;
396 : 0 : p_dev->h_user_priv = (t_handle)p_fm_port;
397 : :
398 : : _fml_dbg("Finishing.");
399 : :
400 : 0 : return (t_handle)p_dev;
401 : : }
402 : :
403 : : void
404 : 0 : fm_port_close(t_handle h_fm_port)
405 : : {
406 : : t_device *p_dev = (t_device *)h_fm_port;
407 : :
408 : : _fml_dbg("Calling...");
409 : :
410 : 0 : close(p_dev->fd);
411 : 0 : free(p_dev->h_user_priv);
412 : 0 : free(p_dev);
413 : :
414 : : _fml_dbg("Finishing.");
415 : 0 : }
416 : :
417 : : uint32_t
418 : 0 : fm_port_disable(t_handle h_fm_port)
419 : : {
420 : : t_device *p_dev = (t_device *)h_fm_port;
421 : :
422 : : _fml_dbg("Calling...");
423 : :
424 [ # # ]: 0 : if (ioctl(p_dev->fd, FM_PORT_IOC_DISABLE))
425 : 0 : RETURN_ERROR(MINOR, E_INVALID_OPERATION, NO_MSG);
426 : :
427 : : _fml_dbg("Finishing.");
428 : :
429 : : return E_OK;
430 : : }
431 : :
432 : : uint32_t
433 : 0 : fm_port_enable(t_handle h_fm_port)
434 : : {
435 : : t_device *p_dev = (t_device *)h_fm_port;
436 : :
437 : : _fml_dbg("Calling...");
438 : :
439 [ # # ]: 0 : if (ioctl(p_dev->fd, FM_PORT_IOC_ENABLE))
440 : 0 : RETURN_ERROR(MINOR, E_INVALID_OPERATION, NO_MSG);
441 : :
442 : : _fml_dbg("Finishing.");
443 : :
444 : : return E_OK;
445 : : }
446 : :
447 : : uint32_t
448 : 0 : fm_port_set_pcd(t_handle h_fm_port,
449 : : ioc_fm_port_pcd_params_t *p)
450 : : {
451 : : t_device *p_dev = (t_device *)h_fm_port;
452 : :
453 : : _fml_dbg("Calling...");
454 : :
455 : : /* correct h_net_env param from t_fm_portPcdParams */
456 : 0 : DEV_TO_ID(p->net_env_id);
457 : :
458 : : /* correct pcd structures according to what support was set */
459 : 0 : if (p->pcd_support == e_IOC_FM_PCD_PRS_KG_AND_CC ||
460 [ # # ]: 0 : p->pcd_support == e_IOC_FM_PCD_PRS_KG_AND_CC_AND_PLCR ||
461 : : p->pcd_support == e_IOC_FM_PCD_PRS_CC) {
462 [ # # # # ]: 0 : if (p->p_cc_params && p->p_cc_params->cc_tree_id)
463 : 0 : DEV_TO_ID(p->p_cc_params->cc_tree_id);
464 : : else
465 : 0 : DPAA_PMD_WARN("Coarse Classification not set !");
466 : : }
467 : :
468 : 0 : if (p->pcd_support == e_IOC_FM_PCD_PRS_KG ||
469 : : p->pcd_support == e_IOC_FM_PCD_PRS_KG_AND_CC ||
470 [ # # ]: 0 : p->pcd_support == e_IOC_FM_PCD_PRS_KG_AND_CC_AND_PLCR ||
471 : : p->pcd_support == e_IOC_FM_PCD_PRS_KG_AND_PLCR){
472 [ # # ]: 0 : if (p->p_kg_params) {
473 : : uint32_t i;
474 : : ioc_fm_port_pcd_kg_params_t *kg_params;
475 : :
476 : : kg_params = p->p_kg_params;
477 : :
478 [ # # ]: 0 : for (i = 0; i < kg_params->num_schemes; i++)
479 [ # # ]: 0 : if (kg_params->scheme_ids[i])
480 : 0 : DEV_TO_ID(kg_params->scheme_ids[i]);
481 : : else
482 : 0 : DPAA_PMD_WARN("Scheme:%u not set!!", i);
483 : :
484 [ # # ]: 0 : if (kg_params->direct_scheme)
485 : 0 : DEV_TO_ID(kg_params->direct_scheme_id);
486 : : } else {
487 : 0 : DPAA_PMD_WARN("KeyGen not set !");
488 : : }
489 : : }
490 : :
491 : 0 : if (p->pcd_support == e_IOC_FM_PCD_PLCR_ONLY ||
492 [ # # ]: 0 : p->pcd_support == e_IOC_FM_PCD_PRS_PLCR ||
493 [ # # ]: 0 : p->pcd_support == e_IOC_FM_PCD_PRS_KG_AND_CC_AND_PLCR ||
494 : : p->pcd_support == e_IOC_FM_PCD_PRS_KG_AND_PLCR) {
495 [ # # ]: 0 : if (p->p_plcr_params) {
496 [ # # ]: 0 : if (p->p_plcr_params->plcr_profile_id)
497 : 0 : DEV_TO_ID(p->p_plcr_params->plcr_profile_id);
498 : : else
499 : 0 : DPAA_PMD_WARN("Policer not set !");
500 : : }
501 : : }
502 : :
503 [ # # ]: 0 : if (p->p_ip_reassembly_manip)
504 : 0 : DEV_TO_ID(p->p_ip_reassembly_manip);
505 : :
506 [ # # ]: 0 : if (p->p_capwap_reassembly_manip)
507 : 0 : DEV_TO_ID(p->p_capwap_reassembly_manip);
508 : :
509 [ # # ]: 0 : if (ioctl(p_dev->fd, FM_PORT_IOC_SET_PCD, p))
510 : 0 : RETURN_ERROR(MINOR, E_INVALID_OPERATION, NO_MSG);
511 : :
512 : : _fml_dbg("Finishing.");
513 : :
514 : : return E_OK;
515 : : }
516 : :
517 : : uint32_t
518 : 0 : fm_port_delete_pcd(t_handle h_fm_port)
519 : : {
520 : : t_device *p_dev = (t_device *)h_fm_port;
521 : :
522 : : _fml_dbg("Calling...");
523 : :
524 [ # # ]: 0 : if (ioctl(p_dev->fd, FM_PORT_IOC_DELETE_PCD))
525 : 0 : RETURN_ERROR(MINOR, E_INVALID_OPERATION, NO_MSG);
526 : :
527 : : _fml_dbg("Finishing.");
528 : :
529 : : return E_OK;
530 : : }
531 : :
532 : : t_handle
533 : 0 : create_device(t_handle h_user_priv, t_handle h_dev_id)
534 : : {
535 : : t_device *p_user_priv_dev = (t_device *)h_user_priv;
536 : : t_device *p_dev = NULL;
537 : :
538 : : _fml_dbg("Calling...");
539 : :
540 : 0 : p_dev = (t_device *)malloc(sizeof(t_device));
541 [ # # ]: 0 : if (p_dev == NULL)
542 : : return NULL;
543 : :
544 : : memset(p_dev, 0, sizeof(t_device));
545 : 0 : p_dev->h_user_priv = h_user_priv;
546 : 0 : p_user_priv_dev->owners++;
547 : 0 : p_dev->id = PTR_TO_UINT(h_dev_id);
548 : :
549 : : _fml_dbg("Finishing.");
550 : :
551 : 0 : return (t_handle)p_dev;
552 : : }
553 : :
554 : : t_handle
555 : 0 : get_device_id(t_handle h_dev)
556 : : {
557 : : t_device *p_dev = (t_device *)h_dev;
558 : :
559 : 0 : return (t_handle)p_dev->id;
560 : : }
|