1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2017-2026 Morse Micro 4 */ 5 #include "yaps_hw.h" 6 #include "bus.h" 7 #include "hif.h" 8 #include "yaps.h" 9 10 #define YAPS_HW_WINDOW_SIZE_BYTES 32768 11 #define YAPS_MAX_PKT_SIZE_BYTES 16128 12 #define YAPS_METADATA_PAGE_COUNT 1 13 14 #define YAPS_PHANDLE_CORRUPTION_WAR_EXTRA_PAGE 1 15 16 #define YAPS_PAGE_SIZE 256 17 18 /* Calculate padding required for yaps transaction */ 19 #define YAPS_CALC_PADDING(_bytes) ((_bytes) & 0x3 ? (4 - ((_bytes) & 0x3)) : 0) 20 21 #define YAPS_RESERVED_PAGE_SIZE 256 22 23 /* 24 * Yaps data stream delimiter is a 32 bit word with the following fields: 25 * 26 * pkt_size (14 bits) - Packet size not including delimiter or padding 27 * pool_id (3 bits) - Pool that pages should be allocated from. 28 * padding (2 bits) - Padding required to bring packet to word (4 byte) 29 * irq (1 bit ) - Raise a PKT_IRQ on the YDS this is sent to 30 * reserved (5 bits) - Reserved, must write as 0 31 * crc (7 bits) - YAPS CRC 32 */ 33 34 /* Packet size not including delimiter or padding */ 35 #define YAPS_DELIM_GET_PKT_SIZE(_delim) \ 36 (((_delim) & 0x3FFF) - YAPS_RESERVED_PAGE_SIZE) 37 #define YAPS_DELIM_SET_PKT_SIZE(_pkt_size) \ 38 (((_pkt_size) & 0x3FFF) + YAPS_RESERVED_PAGE_SIZE) 39 #define YAPS_DELIM_GET_PHANDLE_SIZE(_delim) (((_delim) & 0x3FFF)) 40 41 /* Pool that pages should be allocated from. */ 42 #define YAPS_DELIM_SET_POOL_ID(_pool_id) (((_pool_id) & 0x7) << 14) 43 44 /* Padding required to bring packet to word (4 byte) boundary */ 45 #define YAPS_DELIM_GET_PADDING(_delim) (((_delim) >> 17) & 0x3) 46 #define YAPS_DELIM_SET_PADDING(_padding) (((_padding) & 0x3) << 17) 47 48 /* Raise a PKT_IRQ on the YDS this is sent to */ 49 #define YAPS_DELIM_SET_IRQ(_irq) (((_irq) & 0x1) << 19) 50 51 /* YAPS CRC */ 52 #define YAPS_DELIM_GET_CRC(_delim) (((_delim) >> 25) & 0x7F) 53 #define YAPS_DELIM_SET_CRC(_crc) (((_crc) & 0x7F) << 25) 54 55 struct mm81x_yaps_status_regs { 56 /* Allocation pools */ 57 u32 tc_tx_pool_num_pages; 58 u32 tc_cmd_pool_num_pages; 59 u32 tc_beacon_pool_num_pages; 60 u32 tc_mgmt_pool_num_pages; 61 u32 fc_rx_pool_num_pages; 62 u32 fc_resp_pool_num_pages; 63 u32 fc_tx_sts_pool_num_pages; 64 u32 fc_aux_pool_num_pages; 65 u32 tc_tx_num_pkts; 66 u32 tc_cmd_num_pkts; 67 u32 tc_beacon_num_pkts; 68 u32 tc_mgmt_num_pkts; 69 u32 fc_num_pkts; 70 u32 fc_done_num_pkts; 71 u32 fc_rx_bytes_in_queue; 72 u32 tc_delim_crc_fail_detected; 73 u32 fc_host_ysl_status; 74 u32 lock; 75 } __packed __aligned(8); 76 77 struct mm81x_yaps_hw_status_regs { 78 __le32 tc_tx_pool_num_pages; 79 __le32 tc_cmd_pool_num_pages; 80 __le32 tc_beacon_pool_num_pages; 81 __le32 tc_mgmt_pool_num_pages; 82 __le32 fc_rx_pool_num_pages; 83 __le32 fc_resp_pool_num_pages; 84 __le32 fc_tx_sts_pool_num_pages; 85 __le32 fc_aux_pool_num_pages; 86 __le32 tc_tx_num_pkts; 87 __le32 tc_cmd_num_pkts; 88 __le32 tc_beacon_num_pkts; 89 __le32 tc_mgmt_num_pkts; 90 __le32 fc_num_pkts; 91 __le32 fc_done_num_pkts; 92 __le32 fc_rx_bytes_in_queue; 93 __le32 tc_delim_crc_fail_detected; 94 __le32 fc_host_ysl_status; 95 __le32 lock; 96 } __packed __aligned(8); 97 98 struct mm81x_yaps_hw_aux_data { 99 unsigned long access_lock; 100 101 u32 yds_addr; 102 u32 ysl_addr; 103 u32 status_regs_addr; 104 105 /* Alloc pool sizes */ 106 u16 tc_tx_pool_size; 107 u16 tc_cmd_pool_size; 108 u8 tc_beacon_pool_size; 109 u8 tc_mgmt_pool_size; 110 u8 fc_rx_pool_size; 111 u8 fc_resp_pool_size; 112 u8 fc_tx_sts_pool_size; 113 u8 fc_aux_pool_size; 114 115 /* To chip/from chip queue sizes */ 116 u8 tc_tx_q_size; 117 u8 tc_cmd_q_size; 118 u8 tc_beacon_q_size; 119 u8 tc_mgmt_q_size; 120 u8 fc_q_size; 121 u8 fc_done_q_size; 122 123 u16 reserved_yaps_page_size; 124 125 /* Buffers to/from chip to support large contiguous reads/writes */ 126 char *to_chip_buffer; 127 char *from_chip_buffer; 128 129 /* status registers in host endian */ 130 struct mm81x_yaps_status_regs status_regs; 131 132 /* DMA target buffer in firmware endian */ 133 struct mm81x_yaps_hw_status_regs hw_status_regs; 134 }; 135 136 static int mm81x_yaps_hw_lock(struct mm81x_yaps *yaps) 137 { 138 if (test_and_set_bit_lock(0, &yaps->aux_data->access_lock)) 139 return -1; 140 return 0; 141 } 142 143 static void mm81x_yaps_hw_unlock(struct mm81x_yaps *yaps) 144 { 145 clear_bit_unlock(0, &yaps->aux_data->access_lock); 146 } 147 148 static void 149 mm81x_yaps_hw_fill_aux_data_from_hw_tbl(struct mm81x_yaps_hw_aux_data *a, 150 struct mm81x_yaps_hw_table *t) 151 { 152 a->ysl_addr = __le32_to_cpu(t->ysl_addr); 153 a->yds_addr = __le32_to_cpu(t->yds_addr); 154 a->status_regs_addr = __le32_to_cpu(t->status_regs_addr); 155 a->tc_tx_pool_size = __le16_to_cpu(t->tc_tx_pool_size); 156 a->fc_rx_pool_size = __le16_to_cpu(t->fc_rx_pool_size); 157 a->tc_cmd_pool_size = t->tc_cmd_pool_size; 158 a->tc_beacon_pool_size = t->tc_beacon_pool_size; 159 a->tc_mgmt_pool_size = t->tc_mgmt_pool_size; 160 a->fc_resp_pool_size = t->fc_resp_pool_size; 161 a->fc_tx_sts_pool_size = t->fc_tx_sts_pool_size; 162 a->fc_aux_pool_size = t->fc_aux_pool_size; 163 a->tc_tx_q_size = t->tc_tx_q_size; 164 a->tc_cmd_q_size = t->tc_cmd_q_size; 165 a->tc_beacon_q_size = t->tc_beacon_q_size; 166 a->tc_mgmt_q_size = t->tc_mgmt_q_size; 167 a->fc_q_size = t->fc_q_size; 168 a->fc_done_q_size = t->fc_done_q_size; 169 a->reserved_yaps_page_size = le16_to_cpu(t->yaps_reserved_page_size); 170 } 171 172 static u8 mm81x_yaps_hw_crc(u32 word) 173 { 174 u8 crc = 0; 175 u8 byte; 176 int i; 177 178 /* Mask to look at only non-CRC bits */ 179 word &= 0x1ffffff; 180 181 for (i = 0; i < 4; i++) { 182 byte = (word >> 24) & 0xff; 183 crc = crc7_be(crc, &byte, 1); 184 word <<= 8; 185 } 186 187 return crc >> 1; 188 } 189 190 static u32 mm81x_write_pkts_h_build_delim(struct mm81x_yaps *yaps, 191 unsigned int size, u8 pool_id, 192 bool irq) 193 { 194 u32 delim = 0; 195 196 delim |= YAPS_DELIM_SET_PKT_SIZE(size); 197 delim |= YAPS_DELIM_SET_PADDING(YAPS_CALC_PADDING(size)); 198 delim |= YAPS_DELIM_SET_POOL_ID(pool_id); 199 delim |= YAPS_DELIM_SET_IRQ(irq); 200 delim |= YAPS_DELIM_SET_CRC(mm81x_yaps_hw_crc(delim)); 201 return delim; 202 } 203 204 void mm81x_yaps_hw_enable_irqs(struct mm81x *mors, bool enable) 205 { 206 mm81x_hw_irq_enable(mors, MM81X_INT_YAPS_FC_PKT_WAITING_IRQN, enable); 207 mm81x_hw_irq_enable(mors, MM81X_INT_YAPS_FC_PACKET_FREED_UP_IRQN, 208 enable); 209 } 210 211 void mm81x_yaps_hw_read_table(struct mm81x *mors, 212 struct mm81x_yaps_hw_table *tbl_ptr) 213 { 214 mm81x_yaps_hw_fill_aux_data_from_hw_tbl(mors->hif.u.yaps.aux_data, 215 tbl_ptr); 216 mm81x_yaps_hw_enable_irqs(mors, true); 217 } 218 219 static unsigned int mm81x_write_pkts_h_pages_required(struct mm81x_yaps *yaps, 220 unsigned int size_bytes) 221 { 222 /* Always account for the first metadata page */ 223 return DIV_ROUND_UP(size_bytes + 224 yaps->aux_data->reserved_yaps_page_size, 225 YAPS_PAGE_SIZE) + 226 YAPS_METADATA_PAGE_COUNT + 227 YAPS_PHANDLE_CORRUPTION_WAR_EXTRA_PAGE; 228 } 229 230 /* 231 * Checks if a single pkt will fit in the chip using the pool/alloc holding 232 * information from the last status register read. 233 */ 234 static bool mm81x_write_pkts_h_will_fit(struct mm81x_yaps *yaps, 235 struct mm81x_yaps_pkt *pkt, bool update) 236 { 237 bool will_fit = true; 238 const int pages_required = 239 mm81x_write_pkts_h_pages_required(yaps, pkt->skb->len); 240 int *pool_pages_avail = NULL; 241 int *pkts_in_queue = NULL; 242 int queue_pkts_avail = 0; 243 244 switch (pkt->tc_queue) { 245 case MM81X_YAPS_TX_Q: 246 pool_pages_avail = 247 &yaps->aux_data->status_regs.tc_tx_pool_num_pages; 248 pkts_in_queue = &yaps->aux_data->status_regs.tc_tx_num_pkts; 249 queue_pkts_avail = 250 yaps->aux_data->tc_tx_q_size - *pkts_in_queue; 251 break; 252 case MM81X_YAPS_CMD_Q: 253 pool_pages_avail = 254 &yaps->aux_data->status_regs.tc_cmd_pool_num_pages; 255 pkts_in_queue = &yaps->aux_data->status_regs.tc_cmd_num_pkts; 256 queue_pkts_avail = 257 yaps->aux_data->tc_cmd_q_size - *pkts_in_queue; 258 break; 259 case MM81X_YAPS_BEACON_Q: 260 pool_pages_avail = 261 &yaps->aux_data->status_regs.tc_beacon_pool_num_pages; 262 pkts_in_queue = &yaps->aux_data->status_regs.tc_beacon_num_pkts; 263 queue_pkts_avail = 264 yaps->aux_data->tc_beacon_q_size - *pkts_in_queue; 265 break; 266 case MM81X_YAPS_MGMT_Q: 267 pool_pages_avail = 268 &yaps->aux_data->status_regs.tc_mgmt_pool_num_pages; 269 pkts_in_queue = &yaps->aux_data->status_regs.tc_mgmt_num_pkts; 270 queue_pkts_avail = 271 yaps->aux_data->tc_mgmt_q_size - *pkts_in_queue; 272 break; 273 default: 274 dev_err(yaps->mors->dev, "yaps invalid tc queue"); 275 return false; 276 } 277 278 WARN_ON(queue_pkts_avail < 0); 279 280 if (pages_required > *pool_pages_avail) 281 will_fit = false; 282 283 if (queue_pkts_avail == 0) 284 will_fit = false; 285 286 if (will_fit && update) { 287 *pool_pages_avail -= pages_required; 288 *pkts_in_queue += 1; 289 } 290 291 return will_fit; 292 } 293 294 static int mm81x_write_pkts_h_err_check(struct mm81x_yaps *yaps, 295 struct mm81x_yaps_pkt *pkt) 296 { 297 if (pkt->skb->len + yaps->aux_data->reserved_yaps_page_size > 298 YAPS_MAX_PKT_SIZE_BYTES) 299 return -EMSGSIZE; 300 if (pkt->tc_queue >= MM81X_YAPS_NUM_TC_Q) 301 return -EINVAL; 302 if (!mm81x_write_pkts_h_will_fit(yaps, pkt, true)) 303 return -EAGAIN; 304 305 return 0; 306 } 307 308 static int mm81x_yaps_hw_write_pkts(struct mm81x_yaps *yaps, 309 struct mm81x_yaps_pkt *pkts, int num_pkts, 310 int *num_pkts_sent) 311 { 312 int ret = 0; 313 int i; 314 u32 delim = 0; 315 int tx_len; 316 int batch_txn_len = 0; 317 int pkts_pending = 0; 318 bool delim_irq = false; 319 char *to_chip_buffer_aligned = 320 PTR_ALIGN(yaps->aux_data->to_chip_buffer, 321 mm81x_bus_get_alignment(yaps->mors)); 322 char *write_buf = to_chip_buffer_aligned; 323 324 ret = mm81x_yaps_hw_lock(yaps); 325 if (ret) { 326 dev_dbg(yaps->mors->dev, "yaps lock failed %d", ret); 327 return ret; 328 } 329 330 *num_pkts_sent = 0; 331 332 /* Check packet conditions */ 333 ret = mm81x_write_pkts_h_err_check(yaps, &pkts[0]); 334 if (ret) 335 goto exit; 336 337 /* Batch packets into larger transactions */ 338 for (i = 0; i < num_pkts; ++i) { 339 u32 pkt_size = 340 pkts[i].skb->len + YAPS_CALC_PADDING(pkts[i].skb->len); 341 tx_len = pkt_size + sizeof(delim); 342 343 /* 344 * Send when we have reached window size, don't split pkt over 345 * boundary 346 */ 347 if ((batch_txn_len + tx_len) > YAPS_HW_WINDOW_SIZE_BYTES) { 348 ret = mm81x_dm_write(yaps->mors, 349 yaps->aux_data->yds_addr, 350 to_chip_buffer_aligned, 351 batch_txn_len); 352 353 batch_txn_len = 0; 354 if (ret) 355 goto exit; 356 write_buf = to_chip_buffer_aligned; 357 *num_pkts_sent += pkts_pending; 358 pkts_pending = 0; 359 } 360 361 if ((i + 1) == num_pkts) { 362 /* The last packet in the queue has IRQ set */ 363 delim_irq = true; 364 } else { 365 /* 366 * Since this is not the last packet, we can check for 367 * the next one. In case of errors in the next packet 368 * set the IRQ 369 */ 370 ret = mm81x_write_pkts_h_err_check(yaps, &pkts[i + 1]); 371 if (ret) 372 delim_irq = true; 373 } 374 375 /* Build stream header*/ 376 delim = mm81x_write_pkts_h_build_delim( 377 yaps, pkt_size, pkts[i].tc_queue, delim_irq); 378 *((__le32 *)write_buf) = cpu_to_le32(delim); 379 memcpy(write_buf + sizeof(delim), pkts[i].skb->data, 380 pkts[i].skb->len); 381 382 write_buf += tx_len; 383 batch_txn_len += tx_len; 384 pkts_pending++; 385 386 if (ret) 387 goto exit; 388 } 389 390 exit: 391 if (batch_txn_len > 0) { 392 ret = mm81x_dm_write(yaps->mors, yaps->aux_data->yds_addr, 393 to_chip_buffer_aligned, batch_txn_len); 394 *num_pkts_sent += pkts_pending; 395 } 396 397 mm81x_yaps_hw_unlock(yaps); 398 return ret; 399 } 400 401 static bool mm81x_read_pkts_h_is_valid_delim(u32 delim) 402 { 403 u8 calc_crc = mm81x_yaps_hw_crc(delim); 404 int pkt_size = YAPS_DELIM_GET_PHANDLE_SIZE(delim); 405 int padding = YAPS_DELIM_GET_PADDING(delim); 406 407 if (calc_crc != YAPS_DELIM_GET_CRC(delim)) 408 return false; 409 410 if (pkt_size == 0) 411 return false; 412 413 if ((pkt_size + padding) > YAPS_MAX_PKT_SIZE_BYTES) 414 return false; 415 416 /* Pkt length + padding should not require more padding */ 417 if (YAPS_CALC_PADDING(pkt_size) != padding) 418 return false; 419 420 return true; 421 } 422 423 static int mm81x_read_pkts_h_bytes_remaining(struct mm81x_yaps *yaps) 424 { 425 u32 bytes_in_queue = yaps->aux_data->status_regs.fc_rx_bytes_in_queue; 426 u32 delim_overhead = 427 yaps->aux_data->status_regs.fc_num_pkts * sizeof(u32); 428 u32 reserved_bytes = yaps->aux_data->status_regs.fc_num_pkts * 429 yaps->aux_data->reserved_yaps_page_size; 430 431 if (WARN_ON(bytes_in_queue > INT_MAX) || 432 WARN_ON(delim_overhead > INT_MAX) || 433 WARN_ON(reserved_bytes > INT_MAX)) 434 return -EIO; 435 436 return (int)bytes_in_queue; 437 } 438 439 static int mm81x_yaps_hw_read_pkts(struct mm81x_yaps *yaps, 440 struct mm81x_yaps_pkt *pkts, 441 int num_pkts_max, int *num_pkts_received) 442 { 443 int ret; 444 int i = 0; 445 char *from_chip_buffer_aligned = 446 PTR_ALIGN(yaps->aux_data->from_chip_buffer, 447 mm81x_bus_get_alignment(yaps->mors)); 448 char *read_ptr = from_chip_buffer_aligned; 449 int bytes_remaining = mm81x_read_pkts_h_bytes_remaining(yaps); 450 bool again = false; 451 452 *num_pkts_received = 0; 453 454 if (num_pkts_max == 0 || bytes_remaining == 0) 455 return 0; 456 if (bytes_remaining < 0) 457 return bytes_remaining; 458 459 if (bytes_remaining > YAPS_HW_WINDOW_SIZE_BYTES) { 460 bytes_remaining = YAPS_HW_WINDOW_SIZE_BYTES; 461 again = true; 462 } 463 464 /* 465 * This is more coarse-grained than it needs to be - once the data 466 * is read into a local buffer the lock can be released, however 467 * access to from_chip_buffer will need to be protected with its 468 * own lock 469 */ 470 ret = mm81x_yaps_hw_lock(yaps); 471 if (ret) { 472 dev_dbg(yaps->mors->dev, "yaps lock failed %d", ret); 473 return ret; 474 } 475 476 /* Read all available packets to the buffer */ 477 ret = mm81x_dm_read(yaps->mors, yaps->aux_data->ysl_addr, 478 from_chip_buffer_aligned, bytes_remaining); 479 480 if (ret) 481 goto exit; 482 483 /* Split serialised packets from buffer */ 484 while (i < num_pkts_max && bytes_remaining > 0) { 485 u32 delim; 486 int total_len; 487 int pkt_size; 488 489 delim = le32_to_cpu(*((__le32 *)read_ptr)); 490 read_ptr += sizeof(delim); 491 bytes_remaining -= sizeof(delim); 492 493 /* End of stream */ 494 if (!delim) 495 break; 496 497 if (!mm81x_read_pkts_h_is_valid_delim(delim)) { 498 /* 499 * This will start a hunt for a valid delimiter. Given 500 * the CRC is only 7 bit it's possible to find an 501 * invalid block with a valid delimiter, leading to 502 * desynchronisation. 503 */ 504 dev_warn(yaps->mors->dev, "yaps invalid delim"); 505 break; 506 } 507 508 /* Total length in chip */ 509 pkt_size = YAPS_DELIM_GET_PKT_SIZE(delim); 510 total_len = pkt_size + YAPS_DELIM_GET_PADDING(delim); 511 512 if (pkts[i].skb) 513 dev_err(yaps->mors->dev, "yaps packet leak"); 514 515 /* SKB doesn't want padding */ 516 pkts[i].skb = dev_alloc_skb(pkt_size); 517 if (!pkts[i].skb) { 518 ret = -ENOMEM; 519 dev_err(yaps->mors->dev, "yaps no mem for skb"); 520 goto exit; 521 } 522 skb_put(pkts[i].skb, pkt_size); 523 524 if (total_len <= bytes_remaining) { 525 memcpy(pkts[i].skb->data, read_ptr, pkt_size); 526 read_ptr += total_len; 527 bytes_remaining -= total_len; 528 } else { 529 const int read_overhang_len = 530 total_len - bytes_remaining; 531 const int pkt_overhang_len = pkt_size - bytes_remaining; 532 533 memcpy(pkts[i].skb->data, read_ptr, bytes_remaining); 534 read_ptr = from_chip_buffer_aligned; 535 536 ret = mm81x_dm_read( 537 yaps->mors, 538 /* Offset by 4 to avoid retry logic */ 539 yaps->aux_data->ysl_addr + 4, read_ptr, 540 read_overhang_len); 541 542 if (ret) 543 goto exit; 544 545 memcpy(pkts[i].skb->data + bytes_remaining, read_ptr, 546 pkt_overhang_len); 547 read_ptr += read_overhang_len; 548 bytes_remaining = 0; 549 } 550 551 *num_pkts_received += 1; 552 i++; 553 } 554 555 if (again) 556 ret = -EAGAIN; 557 558 exit: 559 mm81x_yaps_hw_unlock(yaps); 560 return ret; 561 } 562 563 static int mm81x_yaps_hw_update_status(struct mm81x_yaps *yaps) 564 { 565 int ret; 566 int tc_total_pkt_count; 567 unsigned long reg_read_timeout; 568 struct mm81x_yaps_status_regs *r = &yaps->aux_data->status_regs; 569 struct mm81x_yaps_hw_status_regs *hw_r = &yaps->aux_data->hw_status_regs; 570 571 ret = mm81x_yaps_hw_lock(yaps); 572 if (ret) { 573 dev_dbg(yaps->mors->dev, "yaps lock failed %d", ret); 574 return ret; 575 } 576 577 reg_read_timeout = jiffies + msecs_to_jiffies(100); 578 do { 579 if (time_after(jiffies, reg_read_timeout)) { 580 dev_err(yaps->mors->dev, 581 "timed out reading status registers: %d", ret); 582 ret = -ETIMEDOUT; 583 break; 584 } 585 586 ret = mm81x_dm_read(yaps->mors, 587 yaps->aux_data->status_regs_addr, 588 (u8 *)hw_r, sizeof(*hw_r)); 589 } while (!ret && le32_to_cpu(hw_r->lock)); 590 591 if (ret) { 592 if (ret != -ENODEV) { 593 dev_err(yaps->mors->dev, 594 "error reading yaps status registers: %d", ret); 595 } 596 goto exit_unlock; 597 } 598 599 r->tc_tx_pool_num_pages = le32_to_cpu(hw_r->tc_tx_pool_num_pages); 600 r->tc_cmd_pool_num_pages = le32_to_cpu(hw_r->tc_cmd_pool_num_pages); 601 r->tc_beacon_pool_num_pages = le32_to_cpu(hw_r->tc_beacon_pool_num_pages); 602 r->tc_mgmt_pool_num_pages = le32_to_cpu(hw_r->tc_mgmt_pool_num_pages); 603 r->fc_rx_pool_num_pages = le32_to_cpu(hw_r->fc_rx_pool_num_pages); 604 r->fc_resp_pool_num_pages = le32_to_cpu(hw_r->fc_resp_pool_num_pages); 605 r->fc_tx_sts_pool_num_pages = le32_to_cpu(hw_r->fc_tx_sts_pool_num_pages); 606 r->fc_aux_pool_num_pages = le32_to_cpu(hw_r->fc_aux_pool_num_pages); 607 r->tc_tx_num_pkts = le32_to_cpu(hw_r->tc_tx_num_pkts); 608 r->tc_cmd_num_pkts = le32_to_cpu(hw_r->tc_cmd_num_pkts); 609 r->tc_beacon_num_pkts = le32_to_cpu(hw_r->tc_beacon_num_pkts); 610 r->tc_mgmt_num_pkts = le32_to_cpu(hw_r->tc_mgmt_num_pkts); 611 r->fc_num_pkts = le32_to_cpu(hw_r->fc_num_pkts); 612 r->fc_done_num_pkts = le32_to_cpu(hw_r->fc_done_num_pkts); 613 r->fc_rx_bytes_in_queue = le32_to_cpu(hw_r->fc_rx_bytes_in_queue); 614 r->tc_delim_crc_fail_detected = le32_to_cpu(hw_r->tc_delim_crc_fail_detected); 615 r->lock = le32_to_cpu(hw_r->lock); 616 r->fc_host_ysl_status = le32_to_cpu(hw_r->fc_host_ysl_status); 617 618 tc_total_pkt_count = r->tc_tx_num_pkts + r->tc_cmd_num_pkts + 619 r->tc_beacon_num_pkts + r->tc_mgmt_num_pkts; 620 621 if (r->tc_delim_crc_fail_detected) { 622 /* 623 * Host and chip have become desynchronised. This can happen if 624 * the chip crashes during a YAPS transaction. We cannot 625 * recover from this. 626 */ 627 dev_err(yaps->mors->dev, 628 "to-chip yaps delimiter CRC fail, pkt_count=%d", 629 tc_total_pkt_count); 630 ret = -EIO; 631 } 632 633 if (mm81x_read_pkts_h_bytes_remaining(yaps)) 634 set_bit(MM81X_HIF_EVT_RX_PEND, &yaps->mors->hif.event_flags); 635 636 exit_unlock: 637 mm81x_yaps_hw_unlock(yaps); 638 return ret; 639 } 640 641 static const struct mm81x_yaps_ops mm81x_yaps_hw_ops = { 642 .write_pkts = mm81x_yaps_hw_write_pkts, 643 .read_pkts = mm81x_yaps_hw_read_pkts, 644 .update_status = mm81x_yaps_hw_update_status, 645 }; 646 647 int mm81x_yaps_hw_init(struct mm81x *mors) 648 { 649 int ret = 0; 650 struct mm81x_yaps *yaps = NULL; 651 int aux_data_len = sizeof(struct mm81x_yaps_hw_aux_data); 652 int alignment = mm81x_bus_get_alignment(mors); 653 654 yaps = &mors->hif.u.yaps; 655 yaps->aux_data = kzalloc(aux_data_len, GFP_KERNEL); 656 if (!yaps->aux_data) { 657 ret = -ENOMEM; 658 goto err_exit; 659 } 660 661 yaps->aux_data->to_chip_buffer = 662 kzalloc(YAPS_HW_WINDOW_SIZE_BYTES + alignment - 1, GFP_KERNEL); 663 if (!yaps->aux_data->to_chip_buffer) { 664 ret = -ENOMEM; 665 goto err_exit; 666 } 667 668 yaps->aux_data->from_chip_buffer = 669 kzalloc(YAPS_HW_WINDOW_SIZE_BYTES + alignment - 1, GFP_KERNEL); 670 if (!yaps->aux_data->from_chip_buffer) { 671 ret = -ENOMEM; 672 goto err_exit; 673 } 674 675 if (!IS_ALIGNED((uintptr_t)&yaps->aux_data->status_regs, alignment)) { 676 dev_warn(mors->dev, 677 "Status registers are not aligned to %d bytes", 678 alignment); 679 } 680 681 yaps->ops = &mm81x_yaps_hw_ops; 682 return ret; 683 684 err_exit: 685 mm81x_yaps_hw_finish(mors); 686 return ret; 687 } 688 689 void mm81x_yaps_hw_finish(struct mm81x *mors) 690 { 691 struct mm81x_yaps *yaps; 692 693 yaps = &mors->hif.u.yaps; 694 if (yaps->aux_data) { 695 kfree(yaps->aux_data->from_chip_buffer); 696 yaps->aux_data->from_chip_buffer = NULL; 697 kfree(yaps->aux_data->to_chip_buffer); 698 yaps->aux_data->to_chip_buffer = NULL; 699 kfree(yaps->aux_data); 700 yaps->aux_data = NULL; 701 } 702 } 703