| 1 | /* |
| 2 | * Copyright 2010-2017 Intel Corporation. |
| 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License, version 2, |
| 6 | * as published by the Free Software Foundation. |
| 7 | * |
| 8 | * This program is distributed in the hope that it will be useful, |
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 11 | * General Public License for more details. |
| 12 | * |
| 13 | * Disclaimer: The codes contained in these modules may be specific to |
| 14 | * the Intel Software Development Platform codenamed Knights Ferry, |
| 15 | * and the Intel product codenamed Knights Corner, and are not backward |
| 16 | * compatible with other Intel products. Additionally, Intel will NOT |
| 17 | * support the codes or instruction set in future products. |
| 18 | * |
| 19 | * Intel offers no warranty of any kind regarding the code. This code is |
| 20 | * licensed on an "AS IS" basis and Intel is not obligated to provide |
| 21 | * any support, assistance, installation, training, or other services |
| 22 | * of any kind. Intel is also not obligated to provide any updates, |
| 23 | * enhancements or extensions. Intel specifically disclaims any warranty |
| 24 | * of merchantability, non-infringement, fitness for any particular |
| 25 | * purpose, and any other warranty. |
| 26 | * |
| 27 | * Further, Intel disclaims all liability of any kind, including but |
| 28 | * not limited to liability for infringement of any proprietary rights, |
| 29 | * relating to the use of the code, even if Intel is notified of the |
| 30 | * possibility of such liability. Except as expressly stated in an Intel |
| 31 | * license agreement provided with this code and agreed upon with Intel, |
| 32 | * no license, express or implied, by estoppel or otherwise, to any |
| 33 | * intellectual property rights is granted herein. |
| 34 | */ |
| 35 | |
| 36 | /* |
| 37 | * RAS module common internal declarations |
| 38 | * |
| 39 | * Configuration flags, constants and function prototypes |
| 40 | * for the RAS sysfs, MT and MC module. |
| 41 | */ |
| 42 | |
| 43 | #ifndef _MICRAS_H_ |
| 44 | #define _MICRAS_H_ 1 |
| 45 | |
| 46 | |
| 47 | /* |
| 48 | * Public APIs first. |
| 49 | * Must be self-contained and independent of local tunables. |
| 50 | */ |
| 51 | |
| 52 | #include "micras_api.h" |
| 53 | #include "micmca_api.h" |
| 54 | #include "micpm_api.h" |
| 55 | |
| 56 | |
| 57 | /* |
| 58 | * Local configurables & tunables |
| 59 | */ |
| 60 | |
| 61 | #define USE_PM 1 /* Support power management */ |
| 62 | |
| 63 | #define RAS_HALT 1 /* Panic on uncorrectable MCAs */ |
| 64 | |
| 65 | #define I2C_SLOW 1 /* Default to lowest speed on I2C */ |
| 66 | |
| 67 | #define USE_FSC 1 /* Allow using FSC MGBR/MGBSR protocol */ |
| 68 | #define USE_SVID 0 /* Allow using SVID for VR info */ |
| 69 | #define USE_SMC 1 /* Prefer SMC over SBOX (telemetry) */ |
| 70 | |
| 71 | #define MT_TIMER 1 /* Enable periodic wakeup */ |
| 72 | #define MT_PERIOD 999 /* Period sleep (mS) */ |
| 73 | |
| 74 | #define MCU_NMI 1 /* Use NMI in SBOX redirection table */ |
| 75 | |
| 76 | #define EE_VERIFY 0 /* Verify all EEPROM writes */ |
| 77 | #define EE_PROC 1 /* Enable access to EEPROM from /proc/elog */ |
| 78 | #define EE_PROC_NEW 0 /* Only display events between head & tail */ |
| 79 | #define EE_INJECT 0 /* Enable writes to EEPROM via /proc/elog */ |
| 80 | |
| 81 | #define BEAM_TEST 0 /* Neuter MC handling for beam test */ |
| 82 | |
| 83 | #define MT_VERBOSE 0 /* Track MT activity in kernel log */ |
| 84 | #define MC_VERBOSE 0 /* Track MC activity in kernel log */ |
| 85 | #define PM_VERBOSE 0 /* Track PM activity in kernel log */ |
| 86 | |
| 87 | #define GBOX_WORKING 0 /* Set to one when GBOX writes are stable */ |
| 88 | |
| 89 | #define WA_4845465 0 /* Use HSD #4845465 workaround */ |
| 90 | |
| 91 | #define ADD_DIE_TEMP 1 /* Embed die temperature in event reports */ |
| 92 | |
| 93 | #define NOT_YET 0 /* 'Hide' code that's not currently in use */ |
| 94 | |
| 95 | |
| 96 | /* |
| 97 | * Useful macros |
| 98 | *TBD: Cast everything to 64 bit (ULL)? |
| 99 | * For now all is 32 bit (U) |
| 100 | */ |
| 101 | |
| 102 | #define GET_BITS(l,r,v) (((v) >> (r)) & ((1U << ((l) - (r) +1)) -1)) |
| 103 | #define PUT_BITS(l,r,v) (((v) & ((1U << ((l) - (r) +1)) -1)) << (r)) |
| 104 | |
| 105 | #define GET_BIT(n,v) GET_BITS((n), (n), (v)) |
| 106 | #define PUT_BIT(n,v) PUT_BITS((n), (n), (v)) |
| 107 | |
| 108 | |
| 109 | /* |
| 110 | * Init/Exit functions |
| 111 | */ |
| 112 | |
| 113 | extern void mr_mt_init(void); |
| 114 | extern void mr_mt_exit(void); |
| 115 | extern void mr_mt_card_init(void); |
| 116 | extern void mr_mt_card_exit(void); |
| 117 | |
| 118 | |
| 119 | /* |
| 120 | * Command line options (exported from generic MCE handler) |
| 121 | */ |
| 122 | |
| 123 | extern int mce_disabled; |
| 124 | |
| 125 | |
| 126 | /* |
| 127 | * MT opcode/function table. |
| 128 | * Resides in micras_main() and gates access though sysctls and SCIF. |
| 129 | */ |
| 130 | |
| 131 | struct fnc_tab { |
| 132 | uint16_t cmd; |
| 133 | uint8_t simple; |
| 134 | uint8_t privileged; |
| 135 | int (*fnc)(void *); |
| 136 | }; |
| 137 | |
| 138 | extern int micras_priv; |
| 139 | extern int micras_mt_call(uint16_t, void *); |
| 140 | |
| 141 | |
| 142 | /* |
| 143 | * MT get functions |
| 144 | * Spread over micras_{common,knf,knc}.c |
| 145 | */ |
| 146 | extern int mr_get_hwinf(void *); |
| 147 | extern int mr_get_vers(void *); |
| 148 | extern int mr_get_pver(void *); |
| 149 | extern int mr_get_freq(void *); |
| 150 | extern int mr_get_volt(void *); |
| 151 | extern int mr_get_power(void *); |
| 152 | extern int mr_get_plim(void *); |
| 153 | extern int mr_get_clst(void *); |
| 154 | extern int mr_get_gddr(void *); |
| 155 | extern int mr_get_gfreq(void *); |
| 156 | extern int mr_get_gvolt(void *); |
| 157 | extern int mr_get_temp(void *); |
| 158 | extern int mr_get_fan(void *); |
| 159 | extern int mr_get_ecc(void *); |
| 160 | extern int mr_get_trc(void *); |
| 161 | extern int mr_get_trbo(void *); |
| 162 | extern int mr_get_oclk(void *); |
| 163 | extern int mr_get_cutl(void *); |
| 164 | extern int mr_get_mem(void *); |
| 165 | extern int mr_get_os(void *); |
| 166 | extern int mr_get_proc(void *); |
| 167 | extern int mr_get_pmcfg(void *); |
| 168 | |
| 169 | /* |
| 170 | * MT set functions |
| 171 | * Spread over micras_{common,knf,knc}.c |
| 172 | */ |
| 173 | extern int mr_set_freq(void *); |
| 174 | extern int mr_set_volt(void *); |
| 175 | extern int mr_set_plim(void *); |
| 176 | extern int mr_set_gfreq(void *); |
| 177 | extern int mr_set_gvolt(void *); |
| 178 | extern int mr_set_fan(void *); |
| 179 | extern int mr_set_trc(void *); |
| 180 | extern int mr_set_trbo(void *); |
| 181 | extern int mr_set_oclk(void *); |
| 182 | |
| 183 | |
| 184 | /* |
| 185 | * MT cmd functions |
| 186 | */ |
| 187 | extern int mr_cmd_pkill(void *); |
| 188 | extern int mr_cmd_ukill(void *); |
| 189 | |
| 190 | |
| 191 | #if defined(CONFIG_ML1OM) && USE_FSC |
| 192 | /* |
| 193 | * MT FSC access functions |
| 194 | * KnF specific, located in micras_knf.c |
| 195 | */ |
| 196 | extern int mr_get_fsc(void *); |
| 197 | extern int mr_set_fsc(void *); |
| 198 | #endif |
| 199 | |
| 200 | #if defined(CONFIG_MK1OM) |
| 201 | /* |
| 202 | * MT SMC access functions |
| 203 | * KnC specific, located in micras_knc.c |
| 204 | */ |
| 205 | extern int mr_get_smc(void *); |
| 206 | extern int mr_get_led(void *); |
| 207 | extern int mr_get_prochot(void *); |
| 208 | extern int mr_get_pwralt(void *); |
| 209 | extern int mr_get_perst(void *); |
| 210 | extern int mr_get_ttl(void *); |
| 211 | |
| 212 | extern int mr_set_smc(void *); |
| 213 | extern int mr_set_led(void *); |
| 214 | extern int mr_set_prochot(void *); |
| 215 | extern int mr_set_pwralt(void *); |
| 216 | extern int mr_set_perst(void *); |
| 217 | #endif |
| 218 | |
| 219 | |
| 220 | #if defined(CONFIG_MK1OM) && USE_PM |
| 221 | /* |
| 222 | * PM get functions |
| 223 | */ |
| 224 | extern int pm_get_pl0(void *); |
| 225 | extern int pm_get_pl1(void *); |
| 226 | extern int pm_get_pavg(void *); |
| 227 | extern int pm_get_pttl(void *); |
| 228 | extern int pm_get_volt(void *); |
| 229 | extern int pm_get_temp(void *); |
| 230 | extern int pm_get_tach(void *); |
| 231 | extern int pm_get_tttl(void *); |
| 232 | extern int pm_get_fttl(void *); |
| 233 | |
| 234 | /* |
| 235 | * PM set functions |
| 236 | */ |
| 237 | extern int pm_set_pl0(void *); |
| 238 | extern int pm_set_pl1(void *); |
| 239 | extern int pm_set_fttl(void *); |
| 240 | #endif |
| 241 | |
| 242 | |
| 243 | /* |
| 244 | * MC & TTL event distribution functions |
| 245 | * Spread over micras_{main,elog,core}.c |
| 246 | */ |
| 247 | |
| 248 | #ifdef MR_MCE_PORT |
| 249 | extern int micras_mc_send(struct mce_info *, int); |
| 250 | extern void micras_mc_ipmi(struct mce_info *, int); |
| 251 | extern void micras_mc_log(struct mce_info *); |
| 252 | extern uint32_t micras_mc_filter(struct mce_info *, uint64_t, int); |
| 253 | #endif |
| 254 | #ifdef MR_TTL_PORT |
| 255 | extern void micras_ttl_send(struct ttl_info *); |
| 256 | #endif |
| 257 | |
| 258 | |
| 259 | /* |
| 260 | * BOX constants (card variations). |
| 261 | */ |
| 262 | |
| 263 | #ifdef CONFIG_ML1OM |
| 264 | #define DBOX_NUM 1 |
| 265 | #define GBOX_NUM 4 |
| 266 | #endif |
| 267 | |
| 268 | #ifdef CONFIG_MK1OM |
| 269 | #define DBOX_NUM 2 |
| 270 | #define GBOX_NUM 8 /* Max count, SKU dependent */ |
| 271 | #define TBOX_NUM 8 /* Max count, SKU dependent */ |
| 272 | #endif |
| 273 | |
| 274 | #ifndef COMMON_MMIO_BOX_SIZE |
| 275 | #define COMMON_MMIO_BOX_SIZE (1<<16) |
| 276 | #endif |
| 277 | |
| 278 | |
| 279 | /* |
| 280 | * BOX utility functions |
| 281 | * Most located in micras_main.c |
| 282 | */ |
| 283 | |
| 284 | extern char *mr_sku(void); |
| 285 | extern int mr_mch(void); |
| 286 | extern int mr_txs(void); |
| 287 | |
| 288 | extern uint8_t *micras_sbox; |
| 289 | extern uint8_t *micras_dbox[DBOX_NUM]; |
| 290 | extern uint8_t *micras_gbox[GBOX_NUM]; |
| 291 | #ifdef CONFIG_MK1OM |
| 292 | extern uint8_t *micras_tbox[TBOX_NUM]; |
| 293 | #endif |
| 294 | |
| 295 | extern uint8_t *mr_sbox_base(int); |
| 296 | extern uint32_t mr_sbox_rl(int, uint32_t); |
| 297 | extern void mr_sbox_wl(int, uint32_t, uint32_t); |
| 298 | extern uint64_t mr_sbox_rq(int, uint32_t); |
| 299 | extern void mr_sbox_wq(int, uint32_t, uint64_t); |
| 300 | |
| 301 | extern uint8_t *mr_dbox_base(int); |
| 302 | extern uint32_t mr_dbox_rl(int, uint32_t); |
| 303 | extern void mr_dbox_wl(int, uint32_t, uint32_t); |
| 304 | extern uint64_t mr_dbox_rq(int, uint32_t); |
| 305 | extern void mr_dbox_wq(int, uint32_t, uint64_t); |
| 306 | |
| 307 | extern uint8_t *mr_gbox_base(int); |
| 308 | extern uint32_t mr_gbox_rl(int, uint32_t); |
| 309 | extern void mr_gbox_wl(int, uint32_t, uint32_t); |
| 310 | extern uint64_t mr_gbox_rq(int, uint32_t); |
| 311 | extern void mr_gbox_wq(int, uint32_t, uint64_t); |
| 312 | |
| 313 | #ifdef CONFIG_MK1OM |
| 314 | extern uint8_t *mr_tbox_base(int); |
| 315 | extern uint32_t mr_tbox_rl(int, uint32_t); |
| 316 | extern void mr_tbox_wl(int, uint32_t, uint32_t); |
| 317 | extern uint64_t mr_tbox_rq(int, uint32_t); |
| 318 | extern void mr_tbox_wq(int, uint32_t, uint64_t); |
| 319 | #endif |
| 320 | |
| 321 | |
| 322 | /* |
| 323 | * Un-core MCA register offsets |
| 324 | * Some #defines stolen from FreeBSD uOS. |
| 325 | * |
| 326 | *TBD: check again when we get real register include files |
| 327 | */ |
| 328 | |
| 329 | #define SBOX_MCX_CTL_LO 0x00003090 |
| 330 | #define SBOX_MCX_STATUS_LO 0x00003098 |
| 331 | #define SBOX_MCX_STATUS_HI 0x0000309C |
| 332 | #define SBOX_MCX_ADDR_LO 0x000030A0 |
| 333 | #define SBOX_MCX_ADDR_HI 0x000030A4 |
| 334 | #define SBOX_MCX_MISC 0x000030A8 |
| 335 | #define SBOX_MCX_MISC2 0x000030AC |
| 336 | #define SBOX_MCA_INT_STAT 0x0000AB00 |
| 337 | #define SBOX_MCA_INT_EN 0x0000AB04 |
| 338 | #define SBOX_COMPONENT_ID 0x00004134 |
| 339 | |
| 340 | #define DBOX_MC2_CTL 0x00000340 |
| 341 | #define DBOX_MC2_STATUS 0x00000348 |
| 342 | #define DBOX_MC2_ADDR 0x00000350 |
| 343 | |
| 344 | #define GBOX_FBOX_MCA_CTL_LO 0x0000005C |
| 345 | #define GBOX_FBOX_MCA_CTL_HI 0x00000060 |
| 346 | #define GBOX_FBOX_MCA_STATUS_LO 0x00000064 |
| 347 | #define GBOX_FBOX_MCA_STATUS_HI 0x00000068 |
| 348 | #define GBOX_FBOX_MCA_ADDR_LO 0x0000006C |
| 349 | #define GBOX_FBOX_MCA_ADDR_HI 0x00000070 |
| 350 | #define GBOX_FBOX_MCA_MISC 0x00000074 |
| 351 | |
| 352 | #ifdef CONFIG_MK1OM |
| 353 | #define TXS_MCX_CONTROL 0x00003700 |
| 354 | #define TXS_MCX_STATUS 0x00003740 |
| 355 | #define TXS_MCX_ADDRESS 0x00003780 |
| 356 | #endif |
| 357 | |
| 358 | |
| 359 | /* |
| 360 | * Thermal register offsets |
| 361 | */ |
| 362 | |
| 363 | #if defined(CONFIG_MK1OM) && WA_4845465 |
| 364 | #ifndef SBOX_MICROCONTROLLER_FAN_STATUS |
| 365 | #define SBOX_MICROCONTROLLER_FAN_STATUS 0x1020 |
| 366 | #endif |
| 367 | #endif |
| 368 | #if defined(CONFIG_MK1OM) && (WA_4845465 || ADD_DIE_TEMP || USE_PM) |
| 369 | #ifndef SBOX_THERMAL_STATUS_2 |
| 370 | #define SBOX_THERMAL_STATUS_2 0x1080 |
| 371 | #endif |
| 372 | #endif |
| 373 | |
| 374 | |
| 375 | /* |
| 376 | * SMP utilities |
| 377 | * Located in micras_main.c |
| 378 | */ |
| 379 | |
| 380 | extern uint32_t rd_cr4_on_cpu(int); |
| 381 | extern void set_in_cr4_on_cpu(int, uint32_t); |
| 382 | extern void clear_in_cr4_on_cpu(int, uint32_t); |
| 383 | extern uint64_t rdtsc(void); |
| 384 | |
| 385 | |
| 386 | /* |
| 387 | * General EEPROM and POST card UART access |
| 388 | * Located in micras_elog.c |
| 389 | */ |
| 390 | |
| 391 | #define EE_BUF_COUNT 100 |
| 392 | #define EE_BUF_LINELEN 256 |
| 393 | extern char ee_buf[]; |
| 394 | extern atomic_t ee_msg; |
| 395 | extern atomic_t ee_seen; |
| 396 | |
| 397 | extern char * ee_fmt(char *, va_list); |
| 398 | extern int ee_printk(char *, ...); |
| 399 | extern int ee_print(char *, ...); |
| 400 | #ifdef CONFIG_MK1OM |
| 401 | extern void ee_list(void); |
| 402 | extern void ee_wipe(void); |
| 403 | #endif |
| 404 | extern int ee_init(void); |
| 405 | extern int ee_exit(void); |
| 406 | |
| 407 | extern void myDELAY(uint64_t); |
| 408 | |
| 409 | |
| 410 | /* |
| 411 | * SMC access API |
| 412 | * Provided by the kernel |
| 413 | */ |
| 414 | |
| 415 | extern int gmbus_i2c_read(uint8_t, uint8_t, uint8_t, uint8_t *, uint16_t); |
| 416 | extern int gmbus_i2c_write(uint8_t, uint8_t, uint8_t, uint8_t *, uint16_t); |
| 417 | |
| 418 | |
| 419 | /* |
| 420 | * RAS core MCA handling |
| 421 | * Located in micras_core.c |
| 422 | */ |
| 423 | |
| 424 | extern uint8_t xlat_cpu[NR_CPUS]; |
| 425 | extern void mcc_sync(void); |
| 426 | extern int mcc_init(void); |
| 427 | extern int mcc_exit(void); |
| 428 | extern void mcc_flt_parm(uint8_t *); |
| 429 | |
| 430 | |
| 431 | /* |
| 432 | * RAS un-core MCA handling |
| 433 | * Located in micras_uncore.c |
| 434 | */ |
| 435 | |
| 436 | extern void box_reset(int); |
| 437 | extern int mcu_init(void); |
| 438 | extern int mcu_exit(void); |
| 439 | |
| 440 | |
| 441 | #if defined(CONFIG_MK1OM) && USE_PM |
| 442 | /* |
| 443 | * RAS PM handling |
| 444 | * Located in micras_pm.c |
| 445 | * |
| 446 | * Power management registration exchange records: |
| 447 | * The RAS module populates a 'params' record and pass it to |
| 448 | * the PM module through the micpm_ras_register() function. |
| 449 | * In return the PM module populate the passed 'callbacks' record. |
| 450 | * The PM module is responsible for populating the lists of |
| 451 | * supported core frequencies and core voltages. In contrast to |
| 452 | * KnF, where the lists reflect the hardware capabilities, these |
| 453 | * reflect the actual frequencies and voltages that core-freq |
| 454 | * module can use to lower power consumption. |
| 455 | */ |
| 456 | |
| 457 | struct micpm_params { |
| 458 | uint32_t * freq_lst; /* Core frequency list */ |
| 459 | uint32_t * freq_len; /* Core freq count */ |
| 460 | uint32_t freq_siz; /* Space in core freq list */ |
| 461 | uint32_t * volt_lst; /* Core voltage list */ |
| 462 | uint32_t * volt_len; /* Core voltage count */ |
| 463 | uint32_t volt_siz; /* Space in core volt list */ |
| 464 | int (* mt_call)(uint16_t, void *); /* Access MT function */ |
| 465 | void (* mt_ttl)(int, int); /* Throttle notifier */ |
| 466 | }; |
| 467 | |
| 468 | struct micpm_callbacks { |
| 469 | int (*micpm_get_turbo)(void); /* Get PM turbo setting */ |
| 470 | void (*micpm_set_turbo)(int); /* Notify PM of new turbo setting */ |
| 471 | void (*micpm_vf_refresh)(void); /* Refresh core V/F lists */ |
| 472 | int (*micpm_get_pmcfg)(void); /* Get PM operating mode */ |
| 473 | }; |
| 474 | |
| 475 | extern struct micpm_params pm_reg; |
| 476 | extern struct micpm_callbacks pm_cb; |
| 477 | |
| 478 | |
| 479 | /* |
| 480 | * Args for mt_ttl() function |
| 481 | */ |
| 482 | |
| 483 | #define TTL_OFF 0 |
| 484 | #define TTL_ON 1 |
| 485 | |
| 486 | #define TTL_POWER 0 |
| 487 | #define TTL_THERMAL 1 |
| 488 | |
| 489 | |
| 490 | /* |
| 491 | * Bit locations for micpm_get_turbo() and micpm_set_turbo() |
| 492 | */ |
| 493 | |
| 494 | #define MR_PM_MODE (1 << 0) /* Turbo mode */ |
| 495 | #define MR_PM_STATE (1 << 1) /* Current turbo state */ |
| 496 | #define MR_PM_AVAIL (1 << 2) /* Turbo mode available */ |
| 497 | |
| 498 | |
| 499 | /* |
| 500 | * Bit positions for the different features turned on/off |
| 501 | * in the uOS PM configuration, for micpm_get_pmcfg(). |
| 502 | */ |
| 503 | |
| 504 | #define PMCFG_PSTATES_BIT 0 |
| 505 | #define PMCFG_COREC6_BIT 1 |
| 506 | #define PMCFG_PC3_BIT 2 |
| 507 | #define PMCFG_PC6_BIT 3 |
| 508 | |
| 509 | |
| 510 | /* |
| 511 | * Register/Unregister functions in micpm driver that RAS calls |
| 512 | * during module init/exit. Pointers to the exchanged data |
| 513 | * structures are passed during registration. |
| 514 | * The RAS module guarantee that the pointers are valid until |
| 515 | * the unregister function is called. That way the PM module can |
| 516 | * modify the core frequency/voltage lists if they gets changed. |
| 517 | * The callbacks must always either be a valid function pointer |
| 518 | * or a null pointer. |
| 519 | */ |
| 520 | |
| 521 | extern int micpm_ras_register(struct micpm_callbacks *, struct micpm_params *); |
| 522 | extern void micpm_ras_unregister(void); |
| 523 | |
| 524 | extern int mr_pm_ttl(struct mr_rsp_ttl *); |
| 525 | extern int pm_init(void); |
| 526 | extern void pm_exit(void); |
| 527 | #endif |
| 528 | |
| 529 | |
| 530 | /* |
| 531 | * Debug tools |
| 532 | */ |
| 533 | |
| 534 | extern void dmp_hex(void *, int, const char *, ...); |
| 535 | |
| 536 | #endif /* Recursion block */ |