xref: /linux/drivers/net/wireless/morsemicro/mm81x/yaps_hw.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
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