1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <npi_ipp.h> 29 30 uint64_t ipp_fzc_offset[] = { 31 IPP_CONFIG_REG, 32 IPP_DISCARD_PKT_CNT_REG, 33 IPP_TCP_CKSUM_ERR_CNT_REG, 34 IPP_ECC_ERR_COUNTER_REG, 35 IPP_INT_STATUS_REG, 36 IPP_INT_MASK_REG, 37 IPP_PFIFO_RD_DATA0_REG, 38 IPP_PFIFO_RD_DATA1_REG, 39 IPP_PFIFO_RD_DATA2_REG, 40 IPP_PFIFO_RD_DATA3_REG, 41 IPP_PFIFO_RD_DATA4_REG, 42 IPP_PFIFO_WR_DATA0_REG, 43 IPP_PFIFO_WR_DATA1_REG, 44 IPP_PFIFO_WR_DATA2_REG, 45 IPP_PFIFO_WR_DATA3_REG, 46 IPP_PFIFO_WR_DATA4_REG, 47 IPP_PFIFO_RD_PTR_REG, 48 IPP_PFIFO_WR_PTR_REG, 49 IPP_DFIFO_RD_DATA0_REG, 50 IPP_DFIFO_RD_DATA1_REG, 51 IPP_DFIFO_RD_DATA2_REG, 52 IPP_DFIFO_RD_DATA3_REG, 53 IPP_DFIFO_RD_DATA4_REG, 54 IPP_DFIFO_WR_DATA0_REG, 55 IPP_DFIFO_WR_DATA1_REG, 56 IPP_DFIFO_WR_DATA2_REG, 57 IPP_DFIFO_WR_DATA3_REG, 58 IPP_DFIFO_WR_DATA4_REG, 59 IPP_DFIFO_RD_PTR_REG, 60 IPP_DFIFO_WR_PTR_REG, 61 IPP_STATE_MACHINE_REG, 62 IPP_CKSUM_STATUS_REG, 63 IPP_FFLP_CKSUM_INFO_REG, 64 IPP_DEBUG_SELECT_REG, 65 IPP_DFIFO_ECC_SYNDROME_REG, 66 IPP_DFIFO_EOPM_RD_PTR_REG, 67 IPP_ECC_CTRL_REG 68 }; 69 70 const char *ipp_fzc_name[] = { 71 "IPP_CONFIG_REG", 72 "IPP_DISCARD_PKT_CNT_REG", 73 "IPP_TCP_CKSUM_ERR_CNT_REG", 74 "IPP_ECC_ERR_COUNTER_REG", 75 "IPP_INT_STATUS_REG", 76 "IPP_INT_MASK_REG", 77 "IPP_PFIFO_RD_DATA0_REG", 78 "IPP_PFIFO_RD_DATA1_REG", 79 "IPP_PFIFO_RD_DATA2_REG", 80 "IPP_PFIFO_RD_DATA3_REG", 81 "IPP_PFIFO_RD_DATA4_REG", 82 "IPP_PFIFO_WR_DATA0_REG", 83 "IPP_PFIFO_WR_DATA1_REG", 84 "IPP_PFIFO_WR_DATA2_REG", 85 "IPP_PFIFO_WR_DATA3_REG", 86 "IPP_PFIFO_WR_DATA4_REG", 87 "IPP_PFIFO_RD_PTR_REG", 88 "IPP_PFIFO_WR_PTR_REG", 89 "IPP_DFIFO_RD_DATA0_REG", 90 "IPP_DFIFO_RD_DATA1_REG", 91 "IPP_DFIFO_RD_DATA2_REG", 92 "IPP_DFIFO_RD_DATA3_REG", 93 "IPP_DFIFO_RD_DATA4_REG", 94 "IPP_DFIFO_WR_DATA0_REG", 95 "IPP_DFIFO_WR_DATA1_REG", 96 "IPP_DFIFO_WR_DATA2_REG", 97 "IPP_DFIFO_WR_DATA3_REG", 98 "IPP_DFIFO_WR_DATA4_REG", 99 "IPP_DFIFO_RD_PTR_REG", 100 "IPP_DFIFO_WR_PTR_REG", 101 "IPP_STATE_MACHINE_REG", 102 "IPP_CKSUM_STATUS_REG", 103 "IPP_FFLP_CKSUM_INFO_REG", 104 "IPP_DEBUG_SELECT_REG", 105 "IPP_DFIFO_ECC_SYNDROME_REG", 106 "IPP_DFIFO_EOPM_RD_PTR_REG", 107 "IPP_ECC_CTRL_REG", 108 }; 109 110 npi_status_t 111 npi_ipp_dump_regs(npi_handle_t handle, uint8_t port) 112 { 113 uint64_t value, offset; 114 int num_regs, i; 115 116 ASSERT(IS_PORT_NUM_VALID(port)); 117 118 NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, 119 "\nIPP PORT Register Dump for port %d\n", port)); 120 121 num_regs = sizeof (ipp_fzc_offset) / sizeof (uint64_t); 122 for (i = 0; i < num_regs; i++) { 123 offset = IPP_REG_ADDR(port, ipp_fzc_offset[i]); 124 NXGE_REG_RD64(handle, offset, &value); 125 NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, "0x%08llx " 126 "%s\t 0x%08llx \n", 127 offset, ipp_fzc_name[i], value)); 128 } 129 130 NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, 131 "\n IPP FZC Register Dump for port %d done\n", port)); 132 133 return (NPI_SUCCESS); 134 } 135 136 void 137 npi_ipp_read_regs(npi_handle_t handle, uint8_t port) 138 { 139 uint64_t value, offset; 140 int num_regs, i; 141 142 ASSERT(IS_PORT_NUM_VALID(port)); 143 144 NPI_DEBUG_MSG((handle.function, NPI_IPP_CTL, 145 "\nIPP PORT Register read (to clear) for port %d\n", port)); 146 147 num_regs = sizeof (ipp_fzc_offset) / sizeof (uint64_t); 148 for (i = 0; i < num_regs; i++) { 149 offset = IPP_REG_ADDR(port, ipp_fzc_offset[i]); 150 NXGE_REG_RD64(handle, offset, &value); 151 } 152 153 } 154 155 /* 156 * IPP Reset Routine 157 */ 158 npi_status_t 159 npi_ipp_reset(npi_handle_t handle, uint8_t portn) 160 { 161 uint64_t val = 0; 162 uint32_t cnt = MAX_PIO_RETRIES; 163 164 ASSERT(IS_PORT_NUM_VALID(portn)); 165 166 IPP_REG_RD(handle, portn, IPP_CONFIG_REG, &val); 167 val |= IPP_SOFT_RESET; 168 IPP_REG_WR(handle, portn, IPP_CONFIG_REG, val); 169 170 do { 171 NXGE_DELAY(IPP_RESET_WAIT); 172 IPP_REG_RD(handle, portn, IPP_CONFIG_REG, &val); 173 cnt--; 174 } while (((val & IPP_SOFT_RESET) != 0) && (cnt > 0)); 175 176 if (cnt == 0) { 177 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 178 " npi_ipp_reset" 179 " HW Error: IPP_RESET <0x%x>", val)); 180 return (NPI_FAILURE | NPI_IPP_RESET_FAILED(portn)); 181 } 182 183 return (NPI_SUCCESS); 184 } 185 186 187 /* 188 * IPP Configuration Routine 189 */ 190 npi_status_t 191 npi_ipp_config(npi_handle_t handle, config_op_t op, uint8_t portn, 192 ipp_config_t config) 193 { 194 uint64_t val = 0; 195 196 ASSERT(IS_PORT_NUM_VALID(portn)); 197 198 switch (op) { 199 200 case ENABLE: 201 case DISABLE: 202 if ((config == 0) || ((config & ~CFG_IPP_ALL) != 0)) { 203 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 204 " npi_ipp_config", 205 " Invalid Input config <0x%x>", 206 config)); 207 return (NPI_FAILURE | NPI_IPP_CONFIG_INVALID(portn)); 208 } 209 210 IPP_REG_RD(handle, portn, IPP_CONFIG_REG, &val); 211 212 if (op == ENABLE) 213 val |= config; 214 else 215 val &= ~config; 216 break; 217 218 case INIT: 219 if ((config & ~CFG_IPP_ALL) != 0) { 220 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 221 " npi_ipp_config" 222 " Invalid Input config <0x%x>", 223 config)); 224 return (NPI_FAILURE | NPI_IPP_CONFIG_INVALID(portn)); 225 } 226 IPP_REG_RD(handle, portn, IPP_CONFIG_REG, &val); 227 228 229 val &= (IPP_IP_MAX_PKT_BYTES_MASK); 230 val |= config; 231 break; 232 233 default: 234 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 235 " npi_ipp_config" 236 " Invalid Input op <0x%x>", op)); 237 return (NPI_FAILURE | NPI_IPP_OPCODE_INVALID(portn)); 238 } 239 240 IPP_REG_WR(handle, portn, IPP_CONFIG_REG, val); 241 return (NPI_SUCCESS); 242 } 243 244 npi_status_t 245 npi_ipp_set_max_pktsize(npi_handle_t handle, uint8_t portn, uint32_t bytes) 246 { 247 uint64_t val = 0; 248 249 ASSERT(IS_PORT_NUM_VALID(portn)); 250 251 if (bytes > IPP_IP_MAX_PKT_BYTES_MASK) { 252 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 253 " npi_ipp_set_max_pktsize" 254 " Invalid Input Max bytes <0x%x>", 255 bytes)); 256 return (NPI_FAILURE | NPI_IPP_MAX_PKT_BYTES_INVALID(portn)); 257 } 258 259 IPP_REG_RD(handle, portn, IPP_CONFIG_REG, &val); 260 val &= ~(IPP_IP_MAX_PKT_BYTES_MASK << IPP_IP_MAX_PKT_BYTES_SHIFT); 261 262 val |= (bytes << IPP_IP_MAX_PKT_BYTES_SHIFT); 263 IPP_REG_WR(handle, portn, IPP_CONFIG_REG, val); 264 265 return (NPI_SUCCESS); 266 } 267 268 /* 269 * IPP Interrupt Configuration Routine 270 */ 271 npi_status_t 272 npi_ipp_iconfig(npi_handle_t handle, config_op_t op, uint8_t portn, 273 ipp_iconfig_t iconfig) 274 { 275 uint64_t val = 0; 276 277 ASSERT(IS_PORT_NUM_VALID(portn)); 278 279 switch (op) { 280 case ENABLE: 281 case DISABLE: 282 283 if ((iconfig == 0) || ((iconfig & ~ICFG_IPP_ALL) != 0)) { 284 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 285 " npi_ipp_iconfig" 286 " Invalid Input iconfig <0x%x>", 287 iconfig)); 288 return (NPI_FAILURE | NPI_IPP_CONFIG_INVALID(portn)); 289 } 290 291 IPP_REG_RD(handle, portn, IPP_INT_MASK_REG, &val); 292 if (op == ENABLE) 293 val &= ~iconfig; 294 else 295 val |= iconfig; 296 IPP_REG_WR(handle, portn, IPP_INT_MASK_REG, val); 297 298 break; 299 case INIT: 300 301 if ((iconfig & ~ICFG_IPP_ALL) != 0) { 302 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 303 " npi_ipp_iconfig" 304 " Invalid Input iconfig <0x%x>", 305 iconfig)); 306 return (NPI_FAILURE | NPI_IPP_CONFIG_INVALID(portn)); 307 } 308 IPP_REG_WR(handle, portn, IPP_INT_MASK_REG, ~iconfig); 309 310 break; 311 default: 312 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 313 " npi_ipp_iconfig" 314 " Invalid Input iconfig <0x%x>", 315 iconfig)); 316 return (NPI_FAILURE | NPI_IPP_OPCODE_INVALID(portn)); 317 } 318 319 return (NPI_SUCCESS); 320 } 321 322 npi_status_t 323 npi_ipp_get_status(npi_handle_t handle, uint8_t portn, ipp_status_t *status) 324 { 325 uint64_t val; 326 327 ASSERT(IS_PORT_NUM_VALID(portn)); 328 329 IPP_REG_RD(handle, portn, IPP_INT_STATUS_REG, &val); 330 331 status->value = val; 332 return (NPI_SUCCESS); 333 } 334 335 npi_status_t 336 npi_ipp_get_pfifo_rd_ptr(npi_handle_t handle, uint8_t portn, uint16_t *rd_ptr) 337 { 338 uint64_t value; 339 340 ASSERT(IS_PORT_NUM_VALID(portn)); 341 342 IPP_REG_RD(handle, portn, IPP_PFIFO_RD_PTR_REG, &value); 343 *rd_ptr = value & 0xfff; 344 return (NPI_SUCCESS); 345 } 346 347 npi_status_t 348 npi_ipp_get_pfifo_wr_ptr(npi_handle_t handle, uint8_t portn, uint16_t *wr_ptr) 349 { 350 uint64_t value; 351 352 ASSERT(IS_PORT_NUM_VALID(portn)); 353 354 IPP_REG_RD(handle, portn, IPP_PFIFO_WR_PTR_REG, &value); 355 *wr_ptr = value & 0xfff; 356 return (NPI_SUCCESS); 357 } 358 359 npi_status_t 360 npi_ipp_get_dfifo_rd_ptr(npi_handle_t handle, uint8_t portn, uint16_t *rd_ptr) 361 { 362 uint64_t value; 363 364 ASSERT(IS_PORT_NUM_VALID(portn)); 365 366 IPP_REG_RD(handle, portn, IPP_DFIFO_RD_PTR_REG, &value); 367 *rd_ptr = (uint16_t)(value & ((portn < 2) ? IPP_XMAC_DFIFO_PTR_MASK : 368 IPP_BMAC_DFIFO_PTR_MASK)); 369 return (NPI_SUCCESS); 370 } 371 372 npi_status_t 373 npi_ipp_get_dfifo_wr_ptr(npi_handle_t handle, uint8_t portn, uint16_t *wr_ptr) 374 { 375 uint64_t value; 376 377 ASSERT(IS_PORT_NUM_VALID(portn)); 378 379 IPP_REG_RD(handle, portn, IPP_DFIFO_WR_PTR_REG, &value); 380 *wr_ptr = (uint16_t)(value & ((portn < 2) ? IPP_XMAC_DFIFO_PTR_MASK : 381 IPP_BMAC_DFIFO_PTR_MASK)); 382 return (NPI_SUCCESS); 383 } 384 385 npi_status_t 386 npi_ipp_write_pfifo(npi_handle_t handle, uint8_t portn, uint8_t addr, 387 uint32_t d0, uint32_t d1, uint32_t d2, uint32_t d3, uint32_t d4) 388 { 389 uint64_t val; 390 391 ASSERT(IS_PORT_NUM_VALID(portn)); 392 393 if (addr >= 64) { 394 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 395 " npi_ipp_write_pfifo" 396 " Invalid PFIFO address <0x%x>", addr)); 397 return (NPI_FAILURE | NPI_IPP_FIFO_ADDR_INVALID(portn)); 398 } 399 400 IPP_REG_RD(handle, portn, IPP_CONFIG_REG, &val); 401 val |= IPP_PRE_FIFO_PIO_WR_EN; 402 IPP_REG_WR(handle, portn, IPP_CONFIG_REG, val); 403 404 IPP_REG_WR(handle, portn, IPP_PFIFO_WR_PTR_REG, addr); 405 IPP_REG_WR(handle, portn, IPP_PFIFO_WR_DATA0_REG, d0); 406 IPP_REG_WR(handle, portn, IPP_PFIFO_WR_DATA1_REG, d1); 407 IPP_REG_WR(handle, portn, IPP_PFIFO_WR_DATA2_REG, d2); 408 IPP_REG_WR(handle, portn, IPP_PFIFO_WR_DATA3_REG, d3); 409 IPP_REG_WR(handle, portn, IPP_PFIFO_WR_DATA4_REG, d4); 410 411 val &= ~IPP_PRE_FIFO_PIO_WR_EN; 412 IPP_REG_WR(handle, portn, IPP_CONFIG_REG, val); 413 414 return (NPI_SUCCESS); 415 } 416 417 npi_status_t 418 npi_ipp_read_pfifo(npi_handle_t handle, uint8_t portn, uint8_t addr, 419 uint32_t *d0, uint32_t *d1, uint32_t *d2, uint32_t *d3, 420 uint32_t *d4) 421 { 422 ASSERT(IS_PORT_NUM_VALID(portn)); 423 424 if (addr >= 64) { 425 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 426 " npi_ipp_read_pfifo" 427 " Invalid PFIFO address <0x%x>", addr)); 428 return (NPI_FAILURE | NPI_IPP_FIFO_ADDR_INVALID(portn)); 429 } 430 431 IPP_REG_WR(handle, portn, IPP_PFIFO_RD_PTR_REG, addr); 432 IPP_REG_RD(handle, portn, IPP_PFIFO_RD_DATA0_REG, d0); 433 IPP_REG_RD(handle, portn, IPP_PFIFO_RD_DATA1_REG, d1); 434 IPP_REG_RD(handle, portn, IPP_PFIFO_RD_DATA2_REG, d2); 435 IPP_REG_RD(handle, portn, IPP_PFIFO_RD_DATA3_REG, d3); 436 IPP_REG_RD(handle, portn, IPP_PFIFO_RD_DATA4_REG, d4); 437 438 return (NPI_SUCCESS); 439 } 440 441 npi_status_t 442 npi_ipp_write_dfifo(npi_handle_t handle, uint8_t portn, uint16_t addr, 443 uint32_t d0, uint32_t d1, uint32_t d2, uint32_t d3, uint32_t d4) 444 { 445 uint64_t val; 446 447 ASSERT(IS_PORT_NUM_VALID(portn)); 448 449 if (addr >= 2048) { 450 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 451 " npi_ipp_write_dfifo" 452 " Invalid DFIFO address <0x%x>", addr)); 453 return (NPI_FAILURE | NPI_IPP_FIFO_ADDR_INVALID(portn)); 454 } 455 456 IPP_REG_RD(handle, portn, IPP_CONFIG_REG, &val); 457 val |= IPP_DFIFO_PIO_WR_EN; 458 IPP_REG_WR(handle, portn, IPP_CONFIG_REG, val); 459 460 IPP_REG_WR(handle, portn, IPP_DFIFO_WR_PTR_REG, addr); 461 IPP_REG_WR(handle, portn, IPP_DFIFO_WR_DATA0_REG, d0); 462 IPP_REG_WR(handle, portn, IPP_DFIFO_WR_DATA1_REG, d1); 463 IPP_REG_WR(handle, portn, IPP_DFIFO_WR_DATA2_REG, d2); 464 IPP_REG_WR(handle, portn, IPP_DFIFO_WR_DATA3_REG, d3); 465 IPP_REG_WR(handle, portn, IPP_DFIFO_WR_DATA4_REG, d4); 466 467 val &= ~IPP_DFIFO_PIO_WR_EN; 468 IPP_REG_WR(handle, portn, IPP_CONFIG_REG, val); 469 470 return (NPI_SUCCESS); 471 } 472 473 npi_status_t 474 npi_ipp_read_dfifo(npi_handle_t handle, uint8_t portn, uint16_t addr, 475 uint32_t *d0, uint32_t *d1, uint32_t *d2, uint32_t *d3, 476 uint32_t *d4) 477 { 478 ASSERT(IS_PORT_NUM_VALID(portn)); 479 480 if (addr >= 2048) { 481 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 482 " npi_ipp_read_dfifo" 483 " Invalid DFIFO address <0x%x>", addr)); 484 return (NPI_FAILURE | NPI_IPP_FIFO_ADDR_INVALID(portn)); 485 } 486 487 IPP_REG_WR(handle, portn, IPP_DFIFO_RD_PTR_REG, addr); 488 IPP_REG_RD(handle, portn, IPP_DFIFO_RD_DATA0_REG, d0); 489 IPP_REG_RD(handle, portn, IPP_DFIFO_RD_DATA1_REG, d1); 490 IPP_REG_RD(handle, portn, IPP_DFIFO_RD_DATA2_REG, d2); 491 IPP_REG_RD(handle, portn, IPP_DFIFO_RD_DATA3_REG, d3); 492 IPP_REG_RD(handle, portn, IPP_DFIFO_RD_DATA4_REG, d4); 493 494 return (NPI_SUCCESS); 495 } 496 497 npi_status_t 498 npi_ipp_get_ecc_syndrome(npi_handle_t handle, uint8_t portn, uint16_t *syndrome) 499 { 500 uint64_t val; 501 502 ASSERT(IS_PORT_NUM_VALID(portn)); 503 504 IPP_REG_RD(handle, portn, IPP_DFIFO_ECC_SYNDROME_REG, &val); 505 506 *syndrome = (uint16_t)val; 507 return (NPI_SUCCESS); 508 } 509 510 npi_status_t 511 npi_ipp_get_dfifo_eopm_rdptr(npi_handle_t handle, uint8_t portn, 512 uint16_t *rdptr) 513 { 514 uint64_t val; 515 516 ASSERT(IS_PORT_NUM_VALID(portn)); 517 518 IPP_REG_RD(handle, portn, IPP_DFIFO_EOPM_RD_PTR_REG, &val); 519 520 *rdptr = (uint16_t)val; 521 return (NPI_SUCCESS); 522 } 523 524 npi_status_t 525 npi_ipp_get_state_mach(npi_handle_t handle, uint8_t portn, uint32_t *sm) 526 { 527 uint64_t val; 528 529 ASSERT(IS_PORT_NUM_VALID(portn)); 530 531 IPP_REG_RD(handle, portn, IPP_STATE_MACHINE_REG, &val); 532 533 *sm = (uint32_t)val; 534 return (NPI_SUCCESS); 535 } 536 537 npi_status_t 538 npi_ipp_get_ecc_err_count(npi_handle_t handle, uint8_t portn, uint8_t *err_cnt) 539 { 540 ASSERT(IS_PORT_NUM_VALID(portn)); 541 542 IPP_REG_RD(handle, portn, IPP_ECC_ERR_COUNTER_REG, err_cnt); 543 544 return (NPI_SUCCESS); 545 } 546 547 npi_status_t 548 npi_ipp_get_pkt_dis_count(npi_handle_t handle, uint8_t portn, uint16_t *dis_cnt) 549 { 550 ASSERT(IS_PORT_NUM_VALID(portn)); 551 552 IPP_REG_RD(handle, portn, IPP_DISCARD_PKT_CNT_REG, dis_cnt); 553 554 return (NPI_SUCCESS); 555 } 556 557 npi_status_t 558 npi_ipp_get_cs_err_count(npi_handle_t handle, uint8_t portn, uint16_t *err_cnt) 559 { 560 ASSERT(IS_PORT_NUM_VALID(portn)); 561 562 IPP_REG_RD(handle, portn, IPP_ECC_ERR_COUNTER_REG, err_cnt); 563 564 return (NPI_SUCCESS); 565 } 566