1 /* 2 * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #ifndef _HAL_BE_TX_H_ 21 #define _HAL_BE_TX_H_ 22 23 #include "hal_be_hw_headers.h" 24 #include "hal_tx.h" 25 26 /* Number of TX banks reserved i.e, will not be used by host driver. */ 27 /* MAX_TCL_BANK reserved for FW use */ 28 #define HAL_TX_NUM_RESERVED_BANKS 1 29 30 /* 31 * Number of Priority to TID mapping 32 */ 33 #define HAL_BE_TX_MAP0_PRI2TID_MAX 10 34 #define HAL_BE_TX_MAP1_PRI2TID_MAX 6 35 36 enum hal_be_tx_ret_buf_manager { 37 HAL_BE_WBM_SW0_BM_ID = 5, 38 HAL_BE_WBM_SW1_BM_ID = 6, 39 HAL_BE_WBM_SW2_BM_ID = 7, 40 HAL_BE_WBM_SW3_BM_ID = 8, 41 HAL_BE_WBM_SW4_BM_ID = 9, 42 HAL_BE_WBM_SW5_BM_ID = 10, 43 HAL_BE_WBM_SW6_BM_ID = 11, 44 }; 45 46 enum hal_tx_mcast_ctrl { 47 /* mcast traffic exceptioned to FW 48 * valid only for AP VAP default for AP 49 */ 50 HAL_TX_MCAST_CTRL_FW_EXCEPTION = 0, 51 /* mcast traffic dropped in TCL*/ 52 HAL_TX_MCAST_CTRL_DROP, 53 /* MEC notification are enabled 54 * valid only for client VAP 55 */ 56 HAL_TX_MCAST_CTRL_MEC_NOTIFY, 57 /* no special routing for mcast 58 * valid for client vap when index search is enabled 59 */ 60 HAL_TX_MCAST_CTRL_NO_SPECIAL, 61 }; 62 63 /** 64 * enum hal_tx_notify_frame_type - TX notify frame type 65 * @NO_TX_NOTIFY: Not a notify frame 66 * @TX_HARD_NOTIFY: Hard notify TX frame 67 * @TX_SOFT_NOTIFY_E: Soft Notify Tx frame 68 * @TX_SEMI_HARD_NOTIFY_E: Semi Hard notify TX frame 69 */ 70 enum hal_tx_notify_frame_type { 71 NO_TX_NOTIFY = 0, 72 TX_HARD_NOTIFY = 1, 73 TX_SOFT_NOTIFY_E = 2, 74 TX_SEMI_HARD_NOTIFY_E = 3 75 }; 76 77 /*--------------------------------------------------------------------------- 78 * Structures 79 * --------------------------------------------------------------------------- 80 */ 81 /** 82 * union hal_tx_bank_config - SW config bank params 83 * @epd: EPD indication flag 84 * @encap_type: encapsulation type 85 * @encrypt_type: encrypt type 86 * @src_buffer_swap: big-endia switch for packet buffer 87 * @link_meta_swap: big-endian switch for link metadata 88 * @index_lookup_enable: Enable index lookup 89 * @addrx_en: Address-X search 90 * @addry_en: Address-Y search 91 * @mesh_enable:mesh enable flag 92 * @vdev_id_check_en: vdev id check 93 * @pmac_id: mac id 94 * @mcast_pkt_ctrl: mulitcast packet control 95 * @dscp_tid_map_id: DSCP to TID map id 96 * @reserved: unused bits 97 * @val: value representing bank config 98 */ 99 union hal_tx_bank_config { 100 struct { 101 uint32_t epd:1, 102 encap_type:2, 103 encrypt_type:4, 104 src_buffer_swap:1, 105 link_meta_swap:1, 106 index_lookup_enable:1, 107 addrx_en:1, 108 addry_en:1, 109 mesh_enable:2, 110 vdev_id_check_en:1, 111 pmac_id:2, 112 mcast_pkt_ctrl:2, 113 dscp_tid_map_id:6, 114 reserved:7; 115 }; 116 uint32_t val; 117 }; 118 119 /** 120 * union hal_tx_cmn_config_ppe - SW config exception related parameters 121 * @drop_prec_err: Exception drop_prec errors. 122 * @fake_mac_hdr: Exception fake mac header. 123 * @cpu_code_inv: Exception cpu code invalid. 124 * @data_buff_err: Exception buffer length/offset erorors. 125 * @l3_l4_err: Exception m3_l4 checksum errors 126 * @data_offset_max: Maximum data offset allowed. 127 * @data_len_max: Maximum data length allowed. 128 * @val: aggregate 32-bit value 129 */ 130 union hal_tx_cmn_config_ppe { 131 struct { 132 uint32_t drop_prec_err:1, 133 fake_mac_hdr:1, 134 cpu_code_inv:1, 135 data_buff_err:1, 136 l3_l4_err:1, 137 data_offset_max:12, 138 data_len_max:14; 139 }; 140 uint32_t val; 141 }; 142 143 /** 144 * union hal_tx_ppe_vp_config - SW config PPE VP table 145 * @vp_num: Virtual port number 146 * @pmac_id: Lmac ID 147 * @bank_id: Bank ID corresponding to this I/F. 148 * @vdev_id: VDEV ID of the I/F. 149 * @search_idx_reg_num: Register number of this SI. 150 * @use_ppe_int_pri: Use the PPE INT_PRI to TID table 151 * @to_fw: Use FW 152 * @drop_prec_enable: Enable precedence drop. 153 * @val: aggregate 32-bit value 154 */ 155 union hal_tx_ppe_vp_config { 156 struct { 157 uint32_t vp_num:8, 158 pmac_id:2, 159 bank_id:6, 160 vdev_id:8, 161 search_idx_reg_num:3, 162 use_ppe_int_pri:1, 163 to_fw:1, 164 drop_prec_enable:1; 165 }; 166 uint32_t val; 167 }; 168 169 /** 170 * union hal_tx_ppe_idx_map_config - Use ppe index mapping table 171 * @search_idx: Search index 172 * @cache_set: Cache set number 173 * @val: aggregate 32-bit value 174 */ 175 union hal_tx_ppe_idx_map_config { 176 struct { 177 uint32_t search_idx:20, 178 cache_set:4; 179 }; 180 uint32_t val; 181 }; 182 183 /** 184 * union hal_tx_ppe_pri2tid_map0_config - Configure ppe INT_PRI to tid map 185 * @int_pri0: INT_PRI_0 186 * @int_pri1: INT_PRI_1 187 * @int_pri2: INT_PRI_2 188 * @int_pri3: INT_PRI_3 189 * @int_pri4: INT_PRI_4 190 * @int_pri5: INT_PRI_5 191 * @int_pri6: INT_PRI_6 192 * @int_pri7: INT_PRI_7 193 * @int_pri8: INT_PRI_8 194 * @int_pri9: INT_PRI_9 195 * @val: aggregate 32-bit value 196 */ 197 union hal_tx_ppe_pri2tid_map0_config { 198 struct { 199 uint32_t int_pri0:3, 200 int_pri1:3, 201 int_pri2:3, 202 int_pri3:3, 203 int_pri4:3, 204 int_pri5:3, 205 int_pri6:3, 206 int_pri7:3, 207 int_pri8:3, 208 int_pri9:3; 209 }; 210 uint32_t val; 211 }; 212 213 /** 214 * union hal_tx_ppe_pri2tid_map1_config - Configure ppe INT_PRI to tid map 215 * @int_pri10: INT_PRI_10 216 * @int_pri11: INT_PRI_11 217 * @int_pri12: INT_PRI_12 218 * @int_pri13: INT_PRI_13 219 * @int_pri14: INT_PRI_14 220 * @int_pri15: INT_PRI_15 221 * @val: aggregate 32-bit value 222 */ 223 union hal_tx_ppe_pri2tid_map1_config { 224 struct { 225 uint32_t int_pri10:3, 226 int_pri11:3, 227 int_pri12:3, 228 int_pri13:3, 229 int_pri14:3, 230 int_pri15:3; 231 }; 232 uint32_t val; 233 }; 234 235 /*--------------------------------------------------------------------------- 236 * Function declarations and documentation 237 * --------------------------------------------------------------------------- 238 */ 239 240 /*--------------------------------------------------------------------------- 241 * TCL Descriptor accessor APIs 242 *--------------------------------------------------------------------------- 243 */ 244 245 /** 246 * hal_tx_desc_set_tx_notify_frame() - Set TX notify_frame field in Tx desc 247 * @desc: Handle to Tx Descriptor 248 * @val: Value to be set 249 * 250 * Return: None 251 */ hal_tx_desc_set_tx_notify_frame(void * desc,uint8_t val)252 static inline void hal_tx_desc_set_tx_notify_frame(void *desc, 253 uint8_t val) 254 { 255 HAL_SET_FLD(desc, TCL_DATA_CMD, TX_NOTIFY_FRAME) |= 256 HAL_TX_SM(TCL_DATA_CMD, TX_NOTIFY_FRAME, val); 257 } 258 259 /** 260 * hal_tx_desc_set_flow_override_enable() - Set flow_override_enable field 261 * @desc: Handle to Tx Descriptor 262 * @val: Value to be set 263 * 264 * Return: None 265 */ hal_tx_desc_set_flow_override_enable(void * desc,uint8_t val)266 static inline void hal_tx_desc_set_flow_override_enable(void *desc, 267 uint8_t val) 268 { 269 HAL_SET_FLD(desc, TCL_DATA_CMD, FLOW_OVERRIDE_ENABLE) |= 270 HAL_TX_SM(TCL_DATA_CMD, FLOW_OVERRIDE_ENABLE, val); 271 } 272 273 /** 274 * hal_tx_desc_set_flow_override() - Set flow_override field in TX desc 275 * @desc: Handle to Tx Descriptor 276 * @val: Value to be set 277 * 278 * Return: None 279 */ hal_tx_desc_set_flow_override(void * desc,uint8_t val)280 static inline void hal_tx_desc_set_flow_override(void *desc, 281 uint8_t val) 282 { 283 HAL_SET_FLD(desc, TCL_DATA_CMD, FLOW_OVERRIDE) |= 284 HAL_TX_SM(TCL_DATA_CMD, FLOW_OVERRIDE, val); 285 } 286 287 /** 288 * hal_tx_desc_set_who_classify_info_sel() - Set who_classify_info_sel field 289 * @desc: Handle to Tx Descriptor 290 * @val: Value to be set 291 * 292 * Return: None 293 */ hal_tx_desc_set_who_classify_info_sel(void * desc,uint8_t val)294 static inline void hal_tx_desc_set_who_classify_info_sel(void *desc, 295 uint8_t val) 296 { 297 HAL_SET_FLD(desc, TCL_DATA_CMD, WHO_CLASSIFY_INFO_SEL) |= 298 HAL_TX_SM(TCL_DATA_CMD, WHO_CLASSIFY_INFO_SEL, val); 299 } 300 301 /** 302 * hal_tx_desc_set_buf_length() - Set Data length in bytes in Tx Descriptor 303 * @desc: Handle to Tx Descriptor 304 * @data_length: MSDU length in case of direct descriptor. 305 * Length of link extension descriptor in case of Link extension 306 * descriptor.Includes the length of Metadata 307 * Return: None 308 */ hal_tx_desc_set_buf_length(void * desc,uint16_t data_length)309 static inline void hal_tx_desc_set_buf_length(void *desc, 310 uint16_t data_length) 311 { 312 HAL_SET_FLD(desc, TCL_DATA_CMD, DATA_LENGTH) |= 313 HAL_TX_SM(TCL_DATA_CMD, DATA_LENGTH, data_length); 314 } 315 316 /** 317 * hal_tx_desc_set_buf_offset() - Sets Packet Offset field in Tx descriptor 318 * @desc: Handle to Tx Descriptor 319 * @offset: Packet offset from Metadata in case of direct buffer descriptor. 320 * 321 * Return: void 322 */ hal_tx_desc_set_buf_offset(void * desc,uint8_t offset)323 static inline void hal_tx_desc_set_buf_offset(void *desc, 324 uint8_t offset) 325 { 326 HAL_SET_FLD(desc, TCL_DATA_CMD, PACKET_OFFSET) |= 327 HAL_TX_SM(TCL_DATA_CMD, PACKET_OFFSET, offset); 328 } 329 330 /** 331 * hal_tx_desc_set_l4_checksum_en() - Set TCP/IP checksum enable flags 332 * Tx Descriptor for MSDU_buffer type 333 * @desc: Handle to Tx Descriptor 334 * @en: UDP/TCP over ipv4/ipv6 checksum enable flags (5 bits) 335 * 336 * Return: void 337 */ hal_tx_desc_set_l4_checksum_en(void * desc,uint8_t en)338 static inline void hal_tx_desc_set_l4_checksum_en(void *desc, 339 uint8_t en) 340 { 341 HAL_SET_FLD(desc, TCL_DATA_CMD, IPV4_CHECKSUM_EN) |= 342 (HAL_TX_SM(TCL_DATA_CMD, UDP_OVER_IPV4_CHECKSUM_EN, en) | 343 HAL_TX_SM(TCL_DATA_CMD, UDP_OVER_IPV6_CHECKSUM_EN, en) | 344 HAL_TX_SM(TCL_DATA_CMD, TCP_OVER_IPV4_CHECKSUM_EN, en) | 345 HAL_TX_SM(TCL_DATA_CMD, TCP_OVER_IPV6_CHECKSUM_EN, en)); 346 } 347 348 /** 349 * hal_tx_desc_set_l3_checksum_en() - Set IPv4 checksum enable flag in 350 * Tx Descriptor for MSDU_buffer type 351 * @desc: Handle to Tx Descriptor 352 * @en: ipv4 checksum enable flags 353 * 354 * Return: void 355 */ hal_tx_desc_set_l3_checksum_en(void * desc,uint8_t en)356 static inline void hal_tx_desc_set_l3_checksum_en(void *desc, 357 uint8_t en) 358 { 359 HAL_SET_FLD(desc, TCL_DATA_CMD, IPV4_CHECKSUM_EN) |= 360 HAL_TX_SM(TCL_DATA_CMD, IPV4_CHECKSUM_EN, en); 361 } 362 363 /** 364 * hal_tx_desc_set_fw_metadata() - Sets the metadata that is part of TCL descriptor 365 * @desc: Handle to Tx Descriptor 366 * @metadata: Metadata to be sent to Firmware 367 * 368 * Return: void 369 */ hal_tx_desc_set_fw_metadata(void * desc,uint16_t metadata)370 static inline void hal_tx_desc_set_fw_metadata(void *desc, 371 uint16_t metadata) 372 { 373 HAL_SET_FLD(desc, TCL_DATA_CMD, TCL_CMD_NUMBER) |= 374 HAL_TX_SM(TCL_DATA_CMD, TCL_CMD_NUMBER, metadata); 375 } 376 377 /** 378 * hal_tx_desc_set_to_fw() - Set To_FW bit in Tx Descriptor. 379 * @desc: Handle to Tx Descriptor 380 * @to_fw: if set, Forward packet to FW along with classification result 381 * 382 * Return: void 383 */ hal_tx_desc_set_to_fw(void * desc,uint8_t to_fw)384 static inline void hal_tx_desc_set_to_fw(void *desc, uint8_t to_fw) 385 { 386 HAL_SET_FLD(desc, TCL_DATA_CMD, TO_FW) |= 387 HAL_TX_SM(TCL_DATA_CMD, TO_FW, to_fw); 388 } 389 390 /** 391 * hal_tx_desc_set_hlos_tid() - Set the TID value (override DSCP/PCP fields in 392 * frame) to be used for Tx Frame 393 * @desc: Handle to Tx Descriptor 394 * @hlos_tid: HLOS TID 395 * 396 * Return: void 397 */ hal_tx_desc_set_hlos_tid(void * desc,uint8_t hlos_tid)398 static inline void hal_tx_desc_set_hlos_tid(void *desc, 399 uint8_t hlos_tid) 400 { 401 HAL_SET_FLD(desc, TCL_DATA_CMD, HLOS_TID) |= 402 HAL_TX_SM(TCL_DATA_CMD, HLOS_TID, hlos_tid); 403 404 HAL_SET_FLD(desc, TCL_DATA_CMD, HLOS_TID_OVERWRITE) |= 405 HAL_TX_SM(TCL_DATA_CMD, HLOS_TID_OVERWRITE, 1); 406 } 407 408 /** 409 * hal_tx_desc_sync() - Commit the descriptor to Hardware 410 * @hal_tx_desc_cached: Cached descriptor that software maintains 411 * @hw_desc: Hardware descriptor to be updated 412 * @num_bytes: descriptor size 413 */ hal_tx_desc_sync(void * hal_tx_desc_cached,void * hw_desc,uint8_t num_bytes)414 static inline void hal_tx_desc_sync(void *hal_tx_desc_cached, 415 void *hw_desc, uint8_t num_bytes) 416 { 417 qdf_mem_copy(hw_desc, hal_tx_desc_cached, num_bytes); 418 } 419 420 /** 421 * hal_tx_desc_set_vdev_id() - set vdev id to the descriptor to Hardware 422 * @desc: Cached descriptor that software maintains 423 * @vdev_id: vdev id 424 */ hal_tx_desc_set_vdev_id(void * desc,uint8_t vdev_id)425 static inline void hal_tx_desc_set_vdev_id(void *desc, uint8_t vdev_id) 426 { 427 HAL_SET_FLD(desc, TCL_DATA_CMD, VDEV_ID) |= 428 HAL_TX_SM(TCL_DATA_CMD, VDEV_ID, vdev_id); 429 } 430 431 /** 432 * hal_tx_desc_set_bank_id() - set bank id to the descriptor to Hardware 433 * @desc: Cached descriptor that software maintains 434 * @bank_id: bank id 435 */ hal_tx_desc_set_bank_id(void * desc,uint8_t bank_id)436 static inline void hal_tx_desc_set_bank_id(void *desc, uint8_t bank_id) 437 { 438 HAL_SET_FLD(desc, TCL_DATA_CMD, BANK_ID) |= 439 HAL_TX_SM(TCL_DATA_CMD, BANK_ID, bank_id); 440 } 441 442 /** 443 * hal_tx_desc_set_tcl_cmd_type() - set tcl command type to the descriptor 444 * to Hardware 445 * @desc: Cached descriptor that software maintains 446 * @tcl_cmd_type: tcl command type 447 */ 448 static inline void hal_tx_desc_set_tcl_cmd_type(void * desc,uint8_t tcl_cmd_type)449 hal_tx_desc_set_tcl_cmd_type(void *desc, uint8_t tcl_cmd_type) 450 { 451 HAL_SET_FLD(desc, TCL_DATA_CMD, TCL_CMD_TYPE) |= 452 HAL_TX_SM(TCL_DATA_CMD, TCL_CMD_TYPE, tcl_cmd_type); 453 } 454 455 /** 456 * hal_tx_desc_set_lmac_id_be() - set lmac id to the descriptor to Hardware 457 * @hal_soc_hdl: hal soc handle 458 * @desc: Cached descriptor that software maintains 459 * @lmac_id: lmac id 460 */ 461 static inline void hal_tx_desc_set_lmac_id_be(hal_soc_handle_t hal_soc_hdl,void * desc,uint8_t lmac_id)462 hal_tx_desc_set_lmac_id_be(hal_soc_handle_t hal_soc_hdl, void *desc, 463 uint8_t lmac_id) 464 { 465 HAL_SET_FLD(desc, TCL_DATA_CMD, PMAC_ID) |= 466 HAL_TX_SM(TCL_DATA_CMD, PMAC_ID, lmac_id); 467 } 468 469 /** 470 * hal_tx_desc_set_search_index_be() - set search index to the 471 * descriptor to Hardware 472 * @hal_soc_hdl: hal soc handle 473 * @desc: Cached descriptor that software maintains 474 * @search_index: search index 475 */ 476 static inline void hal_tx_desc_set_search_index_be(hal_soc_handle_t hal_soc_hdl,void * desc,uint32_t search_index)477 hal_tx_desc_set_search_index_be(hal_soc_handle_t hal_soc_hdl, void *desc, 478 uint32_t search_index) 479 { 480 HAL_SET_FLD(desc, TCL_DATA_CMD, SEARCH_INDEX) |= 481 HAL_TX_SM(TCL_DATA_CMD, SEARCH_INDEX, search_index); 482 } 483 484 /** 485 * hal_tx_desc_set_cache_set_num() - set cache set num to the 486 * descriptor to Hardware 487 * @hal_soc_hdl: hal soc handle 488 * @desc: Cached descriptor that software maintains 489 * @cache_num: cache number 490 */ 491 static inline void hal_tx_desc_set_cache_set_num(hal_soc_handle_t hal_soc_hdl,void * desc,uint8_t cache_num)492 hal_tx_desc_set_cache_set_num(hal_soc_handle_t hal_soc_hdl, void *desc, 493 uint8_t cache_num) 494 { 495 HAL_SET_FLD(desc, TCL_DATA_CMD, CACHE_SET_NUM) |= 496 HAL_TX_SM(TCL_DATA_CMD, CACHE_SET_NUM, cache_num); 497 } 498 499 /** 500 * hal_tx_desc_set_index_lookup_override() - set lookup override num to the 501 * descriptor to Hardware 502 * @hal_soc_hdl: hal soc handle 503 * @desc: Cached descriptor that software maintains 504 * @num: set number 505 */ 506 static inline void hal_tx_desc_set_index_lookup_override(hal_soc_handle_t hal_soc_hdl,void * desc,uint8_t num)507 hal_tx_desc_set_index_lookup_override(hal_soc_handle_t hal_soc_hdl, 508 void *desc, uint8_t num) 509 { 510 HAL_SET_FLD(desc, TCL_DATA_CMD, INDEX_LOOKUP_OVERRIDE) |= 511 HAL_TX_SM(TCL_DATA_CMD, INDEX_LOOKUP_OVERRIDE, num); 512 } 513 514 /*--------------------------------------------------------------------------- 515 * WBM Descriptor accessor APIs for Tx completions 516 * --------------------------------------------------------------------------- 517 */ 518 519 /** 520 * hal_tx_get_wbm_sw0_bm_id() - Get the BM ID for first tx completion ring 521 * 522 * Return: BM ID for first tx completion ring 523 */ hal_tx_get_wbm_sw0_bm_id(void)524 static inline uint32_t hal_tx_get_wbm_sw0_bm_id(void) 525 { 526 return HAL_BE_WBM_SW0_BM_ID; 527 } 528 529 /** 530 * hal_tx_comp_get_desc_id() - Get TX descriptor id within comp descriptor 531 * @hal_desc: completion ring descriptor pointer 532 * 533 * This function will tx descriptor id, cookie, within hardware completion 534 * descriptor. For cases when cookie conversion is disabled, the sw_cookie 535 * is present in the 2nd DWORD. 536 * 537 * Return: cookie 538 */ hal_tx_comp_get_desc_id(void * hal_desc)539 static inline uint32_t hal_tx_comp_get_desc_id(void *hal_desc) 540 { 541 uint32_t comp_desc = 542 *(uint32_t *)(((uint8_t *)hal_desc) + 543 BUFFER_ADDR_INFO_SW_BUFFER_COOKIE_OFFSET); 544 545 /* Cookie is placed on 2nd word */ 546 return (comp_desc & BUFFER_ADDR_INFO_SW_BUFFER_COOKIE_MASK) >> 547 BUFFER_ADDR_INFO_SW_BUFFER_COOKIE_LSB; 548 } 549 550 /** 551 * hal_tx_comp_get_paddr() - Get paddr within comp descriptor 552 * @hal_desc: completion ring descriptor pointer 553 * 554 * This function will get buffer physical address within hardware completion 555 * descriptor 556 * 557 * Return: Buffer physical address 558 */ hal_tx_comp_get_paddr(void * hal_desc)559 static inline qdf_dma_addr_t hal_tx_comp_get_paddr(void *hal_desc) 560 { 561 uint32_t paddr_lo; 562 uint32_t paddr_hi; 563 564 paddr_lo = *(uint32_t *)(((uint8_t *)hal_desc) + 565 BUFFER_ADDR_INFO_BUFFER_ADDR_31_0_OFFSET); 566 567 paddr_hi = *(uint32_t *)(((uint8_t *)hal_desc) + 568 BUFFER_ADDR_INFO_BUFFER_ADDR_39_32_OFFSET); 569 570 paddr_hi = (paddr_hi & BUFFER_ADDR_INFO_BUFFER_ADDR_39_32_MASK) >> 571 BUFFER_ADDR_INFO_BUFFER_ADDR_39_32_LSB; 572 573 return (qdf_dma_addr_t)(paddr_lo | (((uint64_t)paddr_hi) << 32)); 574 } 575 576 #ifdef DP_HW_COOKIE_CONVERT_EXCEPTION 577 /* HW set dowrd-2 bit30 to 1 if HW CC is done */ 578 #define HAL_WBM2SW_COMPLETION_RING_TX_CC_DONE_OFFSET 0x8 579 #define HAL_WBM2SW_COMPLETION_RING_TX_CC_DONE_MASK 0x40000000 580 #define HAL_WBM2SW_COMPLETION_RING_TX_CC_DONE_LSB 0x1E 581 /** 582 * hal_tx_comp_get_cookie_convert_done() - Get cookie conversion done flag 583 * @hal_desc: completion ring descriptor pointer 584 * 585 * This function will get the bit value that indicate HW cookie 586 * conversion done or not 587 * 588 * Return: 1 - HW cookie conversion done, 0 - not 589 */ hal_tx_comp_get_cookie_convert_done(void * hal_desc)590 static inline uint8_t hal_tx_comp_get_cookie_convert_done(void *hal_desc) 591 { 592 return HAL_TX_DESC_GET(hal_desc, HAL_WBM2SW_COMPLETION_RING_TX, 593 CC_DONE); 594 } 595 #endif 596 597 /** 598 * hal_tx_comp_set_desc_va_63_32() - Set bit 32~63 value for 64 bit VA 599 * @hal_desc: completion ring descriptor pointer 600 * @val: value to be set 601 * 602 * Return: None 603 */ hal_tx_comp_set_desc_va_63_32(void * hal_desc,uint32_t val)604 static inline void hal_tx_comp_set_desc_va_63_32(void *hal_desc, uint32_t val) 605 { 606 HAL_SET_FLD(hal_desc, 607 WBM2SW_COMPLETION_RING_TX, 608 BUFFER_VIRT_ADDR_63_32) = val; 609 } 610 611 /** 612 * hal_tx_comp_get_desc_va() - Get Desc virtual address within completion Desc 613 * @hal_desc: completion ring descriptor pointer 614 * 615 * This function will get the TX Desc virtual address 616 * 617 * Return: TX desc virtual address 618 */ hal_tx_comp_get_desc_va(void * hal_desc)619 static inline uint64_t hal_tx_comp_get_desc_va(void *hal_desc) 620 { 621 uint64_t va_from_desc; 622 623 va_from_desc = qdf_le64_to_cpu(HAL_TX_DESC_GET(hal_desc, 624 WBM2SW_COMPLETION_RING_TX, 625 BUFFER_VIRT_ADDR_31_0) | 626 (((uint64_t)HAL_TX_DESC_GET( 627 hal_desc, 628 WBM2SW_COMPLETION_RING_TX, 629 BUFFER_VIRT_ADDR_63_32)) << 32)); 630 631 return va_from_desc; 632 } 633 634 /*--------------------------------------------------------------------------- 635 * TX BANK register accessor APIs 636 * --------------------------------------------------------------------------- 637 */ 638 639 /** 640 * hal_tx_get_num_tcl_banks() - Get number of banks for target 641 * @hal_soc_hdl: HAL soc handle 642 * 643 * Return: None 644 */ 645 static inline uint8_t hal_tx_get_num_tcl_banks(hal_soc_handle_t hal_soc_hdl)646 hal_tx_get_num_tcl_banks(hal_soc_handle_t hal_soc_hdl) 647 { 648 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 649 int hal_banks = 0; 650 651 if (hal_soc->ops->hal_tx_get_num_tcl_banks) { 652 hal_banks = hal_soc->ops->hal_tx_get_num_tcl_banks(); 653 hal_banks -= HAL_TX_NUM_RESERVED_BANKS; 654 hal_banks = (hal_banks < 0) ? 0 : hal_banks; 655 } 656 657 return hal_banks; 658 } 659 660 /** 661 * hal_tx_populate_bank_register() - populate the bank register with 662 * the software configs. 663 * @hal_soc_hdl: HAL soc handle 664 * @config: bank config 665 * @bank_id: bank id to be configured 666 * 667 * Returns: None 668 */ 669 static inline void hal_tx_populate_bank_register(hal_soc_handle_t hal_soc_hdl,union hal_tx_bank_config * config,uint8_t bank_id)670 hal_tx_populate_bank_register(hal_soc_handle_t hal_soc_hdl, 671 union hal_tx_bank_config *config, 672 uint8_t bank_id) 673 { 674 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 675 676 hal_soc->ops->hal_tx_populate_bank_register(hal_soc_hdl, config, 677 bank_id); 678 } 679 680 #ifdef DP_TX_IMPLICIT_RBM_MAPPING 681 682 #define RBM_MAPPING_BMSK HWIO_TCL_R0_RBM_MAPPING0_SW2TCL1_RING_BMSK 683 #define RBM_MAPPING_SHFT HWIO_TCL_R0_RBM_MAPPING0_SW2TCL2_RING_SHFT 684 685 #define RBM_PPE2TCL_OFFSET \ 686 (HWIO_TCL_R0_RBM_MAPPING0_PPE2TCL1_RING_SHFT >> 2) 687 #define RBM_TCL_CMD_CREDIT_OFFSET \ 688 (HWIO_TCL_R0_RBM_MAPPING0_SW2TCL_CREDIT_RING_SHFT >> 2) 689 690 /** 691 * hal_tx_config_rbm_mapping_be() - Update return buffer manager ring id 692 * @hal_soc_hdl: HAL SoC context 693 * @hal_ring_hdl: Source ring pointer 694 * @rbm_id: return buffer manager ring id 695 * 696 * Return: void 697 */ 698 static inline void hal_tx_config_rbm_mapping_be(hal_soc_handle_t hal_soc_hdl,hal_ring_handle_t hal_ring_hdl,uint8_t rbm_id)699 hal_tx_config_rbm_mapping_be(hal_soc_handle_t hal_soc_hdl, 700 hal_ring_handle_t hal_ring_hdl, 701 uint8_t rbm_id) 702 { 703 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 704 705 hal_soc->ops->hal_tx_config_rbm_mapping_be(hal_soc_hdl, hal_ring_hdl, 706 rbm_id); 707 } 708 #else 709 static inline void hal_tx_config_rbm_mapping_be(hal_soc_handle_t hal_soc_hdl,hal_ring_handle_t hal_ring_hdl,uint8_t rbm_id)710 hal_tx_config_rbm_mapping_be(hal_soc_handle_t hal_soc_hdl, 711 hal_ring_handle_t hal_ring_hdl, 712 uint8_t rbm_id) 713 { 714 } 715 #endif 716 717 /** 718 * hal_tx_desc_set_buf_addr_be() - Fill Buffer Address information in Tx Desc 719 * @hal_soc_hdl: HAL SoC context 720 * @desc: Handle to Tx Descriptor 721 * @paddr: Physical Address 722 * @rbm_id: Return Buffer Manager ID 723 * @desc_id: Descriptor ID 724 * @type: 0 - Address points to a MSDU buffer 725 * 1 - Address points to MSDU extension descriptor 726 * 727 * Return: void 728 */ 729 #ifdef DP_TX_IMPLICIT_RBM_MAPPING 730 static inline void hal_tx_desc_set_buf_addr_be(hal_soc_handle_t hal_soc_hdl,void * desc,dma_addr_t paddr,uint8_t rbm_id,uint32_t desc_id,uint8_t type)731 hal_tx_desc_set_buf_addr_be(hal_soc_handle_t hal_soc_hdl, void *desc, 732 dma_addr_t paddr, uint8_t rbm_id, 733 uint32_t desc_id, uint8_t type) 734 { 735 /* Set buffer_addr_info.buffer_addr_31_0 */ 736 HAL_SET_FLD(desc, TCL_DATA_CMD, 737 BUF_ADDR_INFO_BUFFER_ADDR_31_0) = 738 HAL_TX_SM(TCL_DATA_CMD, BUF_ADDR_INFO_BUFFER_ADDR_31_0, paddr); 739 740 /* Set buffer_addr_info.buffer_addr_39_32 */ 741 HAL_SET_FLD(desc, TCL_DATA_CMD, 742 BUF_ADDR_INFO_BUFFER_ADDR_39_32) |= 743 HAL_TX_SM(TCL_DATA_CMD, BUF_ADDR_INFO_BUFFER_ADDR_39_32, 744 (((uint64_t)paddr) >> 32)); 745 746 /* Set buffer_addr_info.sw_buffer_cookie = desc_id */ 747 HAL_SET_FLD(desc, TCL_DATA_CMD, 748 BUF_ADDR_INFO_SW_BUFFER_COOKIE) |= 749 HAL_TX_SM(TCL_DATA_CMD, BUF_ADDR_INFO_SW_BUFFER_COOKIE, 750 desc_id); 751 752 /* Set Buffer or Ext Descriptor Type */ 753 HAL_SET_FLD(desc, TCL_DATA_CMD, 754 BUF_OR_EXT_DESC_TYPE) |= 755 HAL_TX_SM(TCL_DATA_CMD, BUF_OR_EXT_DESC_TYPE, type); 756 } 757 #else 758 static inline void hal_tx_desc_set_buf_addr_be(hal_soc_handle_t hal_soc_hdl,void * desc,dma_addr_t paddr,uint8_t rbm_id,uint32_t desc_id,uint8_t type)759 hal_tx_desc_set_buf_addr_be(hal_soc_handle_t hal_soc_hdl, void *desc, 760 dma_addr_t paddr, uint8_t rbm_id, 761 uint32_t desc_id, uint8_t type) 762 { 763 /* Set buffer_addr_info.buffer_addr_31_0 */ 764 HAL_SET_FLD(desc, TCL_DATA_CMD, 765 BUF_ADDR_INFO_BUFFER_ADDR_31_0) = 766 HAL_TX_SM(TCL_DATA_CMD, BUF_ADDR_INFO_BUFFER_ADDR_31_0, paddr); 767 768 /* Set buffer_addr_info.buffer_addr_39_32 */ 769 HAL_SET_FLD(desc, TCL_DATA_CMD, 770 BUF_ADDR_INFO_BUFFER_ADDR_39_32) |= 771 HAL_TX_SM(TCL_DATA_CMD, BUF_ADDR_INFO_BUFFER_ADDR_39_32, 772 (((uint64_t)paddr) >> 32)); 773 774 /* Set buffer_addr_info.return_buffer_manager = rbm id */ 775 HAL_SET_FLD(desc, TCL_DATA_CMD, 776 BUF_ADDR_INFO_RETURN_BUFFER_MANAGER) |= 777 HAL_TX_SM(TCL_DATA_CMD, 778 BUF_ADDR_INFO_RETURN_BUFFER_MANAGER, rbm_id); 779 780 /* Set buffer_addr_info.sw_buffer_cookie = desc_id */ 781 HAL_SET_FLD(desc, TCL_DATA_CMD, 782 BUF_ADDR_INFO_SW_BUFFER_COOKIE) |= 783 HAL_TX_SM(TCL_DATA_CMD, BUF_ADDR_INFO_SW_BUFFER_COOKIE, 784 desc_id); 785 786 /* Set Buffer or Ext Descriptor Type */ 787 HAL_SET_FLD(desc, TCL_DATA_CMD, 788 BUF_OR_EXT_DESC_TYPE) |= 789 HAL_TX_SM(TCL_DATA_CMD, BUF_OR_EXT_DESC_TYPE, type); 790 } 791 #endif 792 793 /** 794 * hal_tx_vdev_mismatch_routing_set() - set vdev mismatch exception routing 795 * @hal_soc_hdl: HAL SoC context 796 * @config: HAL_TX_VDEV_MISMATCH_TQM_NOTIFY - route via TQM 797 * HAL_TX_VDEV_MISMATCH_FW_NOTIFY - route via FW 798 * 799 * Return: void 800 */ 801 #ifdef HWIO_TCL_R0_CMN_CONFIG_VDEVID_MISMATCH_EXCEPTION_BMSK 802 static inline void hal_tx_vdev_mismatch_routing_set(hal_soc_handle_t hal_soc_hdl,enum hal_tx_vdev_mismatch_notify config)803 hal_tx_vdev_mismatch_routing_set(hal_soc_handle_t hal_soc_hdl, 804 enum hal_tx_vdev_mismatch_notify config) 805 { 806 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 807 808 hal_soc->ops->hal_tx_vdev_mismatch_routing_set(hal_soc_hdl, config); 809 } 810 #else 811 static inline void hal_tx_vdev_mismatch_routing_set(hal_soc_handle_t hal_soc_hdl,enum hal_tx_vdev_mismatch_notify config)812 hal_tx_vdev_mismatch_routing_set(hal_soc_handle_t hal_soc_hdl, 813 enum hal_tx_vdev_mismatch_notify config) 814 { 815 } 816 #endif 817 818 /** 819 * hal_tx_mcast_mlo_reinject_routing_set() - set MLO multicast reinject routing 820 * @hal_soc_hdl: HAL SoC context 821 * @config: HAL_TX_MCAST_MLO_REINJECT_FW_NOTIFY - route via FW 822 * HAL_TX_MCAST_MLO_REINJECT_TQM_NOTIFY - route via TQM 823 * 824 * Return: void 825 */ 826 #if defined(HWIO_TCL_R0_CMN_CONFIG_MCAST_CMN_PN_SN_MLO_REINJECT_ENABLE_BMSK) && \ 827 defined(WLAN_MCAST_MLO) && !defined(CONFIG_MLO_SINGLE_DEV) 828 static inline void hal_tx_mcast_mlo_reinject_routing_set(hal_soc_handle_t hal_soc_hdl,enum hal_tx_mcast_mlo_reinject_notify config)829 hal_tx_mcast_mlo_reinject_routing_set( 830 hal_soc_handle_t hal_soc_hdl, 831 enum hal_tx_mcast_mlo_reinject_notify config) 832 { 833 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 834 hal_soc->ops->hal_tx_mcast_mlo_reinject_routing_set(hal_soc_hdl, 835 config); 836 } 837 #else 838 static inline void hal_tx_mcast_mlo_reinject_routing_set(hal_soc_handle_t hal_soc_hdl,enum hal_tx_mcast_mlo_reinject_notify config)839 hal_tx_mcast_mlo_reinject_routing_set( 840 hal_soc_handle_t hal_soc_hdl, 841 enum hal_tx_mcast_mlo_reinject_notify config) 842 { 843 } 844 #endif 845 846 /** 847 * hal_reo_config_reo2ppe_dest_info() - Configure reo2ppe dest info 848 * @hal_soc_hdl: HAL SoC Context 849 * 850 * Return: None. 851 */ 852 static inline hal_reo_config_reo2ppe_dest_info(hal_soc_handle_t hal_soc_hdl)853 void hal_reo_config_reo2ppe_dest_info(hal_soc_handle_t hal_soc_hdl) 854 { 855 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 856 857 if (hal_soc->ops->hal_reo_config_reo2ppe_dest_info) 858 hal_soc->ops->hal_reo_config_reo2ppe_dest_info(hal_soc_hdl); 859 } 860 861 /** 862 * hal_tx_get_num_ppe_vp_tbl_entries() - Get the total number of VP table entries 863 * @hal_soc_hdl: HAL SoC Context 864 * 865 * Return: Total number of entries. 866 */ 867 static inline hal_tx_get_num_ppe_vp_tbl_entries(hal_soc_handle_t hal_soc_hdl)868 uint32_t hal_tx_get_num_ppe_vp_tbl_entries(hal_soc_handle_t hal_soc_hdl) 869 { 870 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 871 872 return hal_soc->ops->hal_tx_get_num_ppe_vp_tbl_entries(hal_soc_hdl); 873 } 874 875 /** 876 * hal_tx_get_num_ppe_vp_search_idx_tbl_entries() - Get the total number of 877 * search idx registers 878 * @hal_soc_hdl: HAL SoC Context 879 * 880 * Return: Total number of entries. 881 */ 882 static inline hal_tx_get_num_ppe_vp_search_idx_tbl_entries(hal_soc_handle_t hal_soc_hdl)883 uint32_t hal_tx_get_num_ppe_vp_search_idx_tbl_entries(hal_soc_handle_t hal_soc_hdl) 884 { 885 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 886 887 return hal_soc->ops->hal_tx_get_num_ppe_vp_search_idx_tbl_entries(hal_soc_hdl); 888 } 889 890 /** 891 * hal_tx_set_ppe_cmn_cfg()- Set the PPE common config 892 * @hal_soc_hdl: HAL SoC context 893 * @cmn_cfg: HAL PPE VP common config 894 * 895 * Return: void 896 */ 897 static inline void hal_tx_set_ppe_cmn_cfg(hal_soc_handle_t hal_soc_hdl,union hal_tx_cmn_config_ppe * cmn_cfg)898 hal_tx_set_ppe_cmn_cfg(hal_soc_handle_t hal_soc_hdl, 899 union hal_tx_cmn_config_ppe *cmn_cfg) 900 { 901 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 902 903 hal_soc->ops->hal_tx_set_ppe_cmn_cfg(hal_soc_hdl, cmn_cfg); 904 } 905 906 /** 907 * hal_tx_populate_ppe_vp_entry() - Populate ppe VP entry 908 * @hal_soc_hdl: HAL SoC context 909 * @vp_cfg: HAL PPE VP config 910 * @ppe_vp_idx: PPE VP index 911 * 912 * Return: void 913 */ 914 static inline void hal_tx_populate_ppe_vp_entry(hal_soc_handle_t hal_soc_hdl,union hal_tx_ppe_vp_config * vp_cfg,int ppe_vp_idx)915 hal_tx_populate_ppe_vp_entry(hal_soc_handle_t hal_soc_hdl, 916 union hal_tx_ppe_vp_config *vp_cfg, 917 int ppe_vp_idx) 918 { 919 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 920 921 hal_soc->ops->hal_tx_set_ppe_vp_entry(hal_soc_hdl, vp_cfg, ppe_vp_idx); 922 } 923 924 /** 925 * hal_ppeds_cfg_ast_override_map_reg() - Set ppe index mapping table value 926 * @hal_soc_hdl: HAL SoC context 927 * @reg_idx: index into the table 928 * @overide_map: HAL PPE INDEX MAPPING config 929 * 930 * Return: void 931 */ 932 static inline void hal_ppeds_cfg_ast_override_map_reg(hal_soc_handle_t hal_soc_hdl,uint8_t reg_idx,union hal_tx_ppe_idx_map_config * overide_map)933 hal_ppeds_cfg_ast_override_map_reg(hal_soc_handle_t hal_soc_hdl, 934 uint8_t reg_idx, union hal_tx_ppe_idx_map_config *overide_map) 935 { 936 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 937 938 if (hal_soc->ops->hal_ppeds_cfg_ast_override_map_reg) 939 hal_soc->ops->hal_ppeds_cfg_ast_override_map_reg(hal_soc_hdl, 940 reg_idx, 941 overide_map); 942 } 943 944 /** 945 * hal_tx_set_int_pri2tid() - Set the pri2tid table. 946 * @hal_soc_hdl: HAL SoC context 947 * @val: value to set 948 * @map_no: index in SW INT_PRI to TID table 949 * 950 * Return: void 951 */ 952 static inline void hal_tx_set_int_pri2tid(hal_soc_handle_t hal_soc_hdl,uint32_t val,uint8_t map_no)953 hal_tx_set_int_pri2tid(hal_soc_handle_t hal_soc_hdl, 954 uint32_t val, uint8_t map_no) 955 { 956 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 957 958 hal_soc->ops->hal_tx_set_ppe_pri2tid(hal_soc_hdl, val, map_no); 959 } 960 961 /** 962 * hal_tx_update_int_pri2tid() - Populate the pri2tid table. 963 * @hal_soc_hdl: HAL SoC context 964 * @pri: INT_PRI value 965 * @tid: Wi-Fi TID 966 * 967 * Return: void 968 */ 969 static inline void hal_tx_update_int_pri2tid(hal_soc_handle_t hal_soc_hdl,uint8_t pri,uint8_t tid)970 hal_tx_update_int_pri2tid(hal_soc_handle_t hal_soc_hdl, 971 uint8_t pri, uint8_t tid) 972 { 973 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 974 975 hal_soc->ops->hal_tx_update_ppe_pri2tid(hal_soc_hdl, pri, tid); 976 } 977 978 /** 979 * hal_tx_dump_ppe_vp_entry() - Dump the PPE VP entry 980 * @hal_soc_hdl: HAL SoC context 981 * 982 * Return: void 983 */ 984 static inline void hal_tx_dump_ppe_vp_entry(hal_soc_handle_t hal_soc_hdl)985 hal_tx_dump_ppe_vp_entry(hal_soc_handle_t hal_soc_hdl) 986 { 987 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 988 989 hal_soc->ops->hal_tx_dump_ppe_vp_entry(hal_soc_hdl); 990 } 991 992 /** 993 * hal_tx_enable_pri2tid_map() - Enable the priority to tid mapping 994 * @hal_soc_hdl: HAL SoC context 995 * @val: True/False value 996 * @ppe_vp_idx: map index 997 * 998 * Return: void 999 */ 1000 static inline void hal_tx_enable_pri2tid_map(hal_soc_handle_t hal_soc_hdl,bool val,uint8_t ppe_vp_idx)1001 hal_tx_enable_pri2tid_map(hal_soc_handle_t hal_soc_hdl, bool val, 1002 uint8_t ppe_vp_idx) 1003 { 1004 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 1005 1006 hal_soc->ops->hal_tx_enable_pri2tid_map(hal_soc_hdl, val, 1007 ppe_vp_idx); 1008 } 1009 1010 #ifdef HWIO_TCL_R0_VDEV_MCAST_PACKET_CTRL_MAP_n_VAL_SHFT 1011 static inline void hal_tx_vdev_mcast_ctrl_set(hal_soc_handle_t hal_soc_hdl,uint8_t vdev_id,uint8_t mcast_ctrl_val)1012 hal_tx_vdev_mcast_ctrl_set(hal_soc_handle_t hal_soc_hdl, 1013 uint8_t vdev_id, uint8_t mcast_ctrl_val) 1014 { 1015 struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; 1016 1017 hal_soc->ops->hal_tx_vdev_mcast_ctrl_set(hal_soc_hdl, vdev_id, 1018 mcast_ctrl_val); 1019 } 1020 #else 1021 static inline void hal_tx_vdev_mcast_ctrl_set(hal_soc_handle_t hal_soc_hdl,uint8_t vdev_id,uint8_t mcast_ctrl_val)1022 hal_tx_vdev_mcast_ctrl_set(hal_soc_handle_t hal_soc_hdl, 1023 uint8_t vdev_id, uint8_t mcast_ctrl_val) 1024 { 1025 } 1026 #endif 1027 #endif /* _HAL_BE_TX_H_ */ 1028