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
mm81x_yaps_hw_lock(struct mm81x_yaps * yaps)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
mm81x_yaps_hw_unlock(struct mm81x_yaps * yaps)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
mm81x_yaps_hw_fill_aux_data_from_hw_tbl(struct mm81x_yaps_hw_aux_data * a,struct mm81x_yaps_hw_table * t)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
mm81x_yaps_hw_crc(u32 word)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
mm81x_write_pkts_h_build_delim(struct mm81x_yaps * yaps,unsigned int size,u8 pool_id,bool irq)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
mm81x_yaps_hw_enable_irqs(struct mm81x * mors,bool enable)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
mm81x_yaps_hw_read_table(struct mm81x * mors,struct mm81x_yaps_hw_table * tbl_ptr)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
mm81x_write_pkts_h_pages_required(struct mm81x_yaps * yaps,unsigned int size_bytes)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 */
mm81x_write_pkts_h_will_fit(struct mm81x_yaps * yaps,struct mm81x_yaps_pkt * pkt,bool update)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
mm81x_write_pkts_h_err_check(struct mm81x_yaps * yaps,struct mm81x_yaps_pkt * pkt)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
mm81x_yaps_hw_write_pkts(struct mm81x_yaps * yaps,struct mm81x_yaps_pkt * pkts,int num_pkts,int * num_pkts_sent)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
mm81x_read_pkts_h_is_valid_delim(u32 delim)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
mm81x_read_pkts_h_bytes_remaining(struct mm81x_yaps * yaps)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
mm81x_yaps_hw_read_pkts(struct mm81x_yaps * yaps,struct mm81x_yaps_pkt * pkts,int num_pkts_max,int * num_pkts_received)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
mm81x_yaps_hw_update_status(struct mm81x_yaps * yaps)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
mm81x_yaps_hw_init(struct mm81x * mors)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
mm81x_yaps_hw_finish(struct mm81x * mors)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