1c167b9c7SMaximilian Luz // SPDX-License-Identifier: GPL-2.0+
2c167b9c7SMaximilian Luz /*
3c167b9c7SMaximilian Luz  * SSH packet transport layer.
4c167b9c7SMaximilian Luz  *
5221756e6SMaximilian Luz  * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
6c167b9c7SMaximilian Luz  */
7c167b9c7SMaximilian Luz 
8c167b9c7SMaximilian Luz #include <asm/unaligned.h>
9c167b9c7SMaximilian Luz #include <linux/atomic.h>
1002be44f6SMaximilian Luz #include <linux/error-injection.h>
11c167b9c7SMaximilian Luz #include <linux/jiffies.h>
12c167b9c7SMaximilian Luz #include <linux/kfifo.h>
13c167b9c7SMaximilian Luz #include <linux/kref.h>
14c167b9c7SMaximilian Luz #include <linux/kthread.h>
15c167b9c7SMaximilian Luz #include <linux/ktime.h>
16c167b9c7SMaximilian Luz #include <linux/limits.h>
17c167b9c7SMaximilian Luz #include <linux/list.h>
18c167b9c7SMaximilian Luz #include <linux/lockdep.h>
19c167b9c7SMaximilian Luz #include <linux/serdev.h>
20c167b9c7SMaximilian Luz #include <linux/slab.h>
21c167b9c7SMaximilian Luz #include <linux/spinlock.h>
22c167b9c7SMaximilian Luz #include <linux/workqueue.h>
23c167b9c7SMaximilian Luz 
24c167b9c7SMaximilian Luz #include <linux/surface_aggregator/serial_hub.h>
25c167b9c7SMaximilian Luz 
26c167b9c7SMaximilian Luz #include "ssh_msgb.h"
27c167b9c7SMaximilian Luz #include "ssh_packet_layer.h"
28c167b9c7SMaximilian Luz #include "ssh_parser.h"
29c167b9c7SMaximilian Luz 
300d21bb85SMaximilian Luz #include "trace.h"
310d21bb85SMaximilian Luz 
32c167b9c7SMaximilian Luz /*
33c167b9c7SMaximilian Luz  * To simplify reasoning about the code below, we define a few concepts. The
34c167b9c7SMaximilian Luz  * system below is similar to a state-machine for packets, however, there are
35c167b9c7SMaximilian Luz  * too many states to explicitly write them down. To (somewhat) manage the
36c167b9c7SMaximilian Luz  * states and packets we rely on flags, reference counting, and some simple
37c167b9c7SMaximilian Luz  * concepts. State transitions are triggered by actions.
38c167b9c7SMaximilian Luz  *
39c167b9c7SMaximilian Luz  * >> Actions <<
40c167b9c7SMaximilian Luz  *
41c167b9c7SMaximilian Luz  * - submit
42c167b9c7SMaximilian Luz  * - transmission start (process next item in queue)
43c167b9c7SMaximilian Luz  * - transmission finished (guaranteed to never be parallel to transmission
44c167b9c7SMaximilian Luz  *   start)
45c167b9c7SMaximilian Luz  * - ACK received
46c167b9c7SMaximilian Luz  * - NAK received (this is equivalent to issuing re-submit for all pending
47c167b9c7SMaximilian Luz  *   packets)
48c167b9c7SMaximilian Luz  * - timeout (this is equivalent to re-issuing a submit or canceling)
49c167b9c7SMaximilian Luz  * - cancel (non-pending and pending)
50c167b9c7SMaximilian Luz  *
51c167b9c7SMaximilian Luz  * >> Data Structures, Packet Ownership, General Overview <<
52c167b9c7SMaximilian Luz  *
53c167b9c7SMaximilian Luz  * The code below employs two main data structures: The packet queue,
54c167b9c7SMaximilian Luz  * containing all packets scheduled for transmission, and the set of pending
55c167b9c7SMaximilian Luz  * packets, containing all packets awaiting an ACK.
56c167b9c7SMaximilian Luz  *
57c167b9c7SMaximilian Luz  * Shared ownership of a packet is controlled via reference counting. Inside
58c167b9c7SMaximilian Luz  * the transport system are a total of five packet owners:
59c167b9c7SMaximilian Luz  *
60c167b9c7SMaximilian Luz  * - the packet queue,
61c167b9c7SMaximilian Luz  * - the pending set,
62c167b9c7SMaximilian Luz  * - the transmitter thread,
63c167b9c7SMaximilian Luz  * - the receiver thread (via ACKing), and
64c167b9c7SMaximilian Luz  * - the timeout work item.
65c167b9c7SMaximilian Luz  *
66c167b9c7SMaximilian Luz  * Normal operation is as follows: The initial reference of the packet is
67c167b9c7SMaximilian Luz  * obtained by submitting the packet and queuing it. The receiver thread takes
68c167b9c7SMaximilian Luz  * packets from the queue. By doing this, it does not increment the refcount
69c167b9c7SMaximilian Luz  * but takes over the reference (removing it from the queue). If the packet is
70c167b9c7SMaximilian Luz  * sequenced (i.e. needs to be ACKed by the client), the transmitter thread
71c167b9c7SMaximilian Luz  * sets-up the timeout and adds the packet to the pending set before starting
72c167b9c7SMaximilian Luz  * to transmit it. As the timeout is handled by a reaper task, no additional
73c167b9c7SMaximilian Luz  * reference for it is needed. After the transmit is done, the reference held
74c167b9c7SMaximilian Luz  * by the transmitter thread is dropped. If the packet is unsequenced (i.e.
75c167b9c7SMaximilian Luz  * does not need an ACK), the packet is completed by the transmitter thread
76c167b9c7SMaximilian Luz  * before dropping that reference.
77c167b9c7SMaximilian Luz  *
78c167b9c7SMaximilian Luz  * On receival of an ACK, the receiver thread removes and obtains the
79c167b9c7SMaximilian Luz  * reference to the packet from the pending set. The receiver thread will then
80c167b9c7SMaximilian Luz  * complete the packet and drop its reference.
81c167b9c7SMaximilian Luz  *
82c167b9c7SMaximilian Luz  * On receival of a NAK, the receiver thread re-submits all currently pending
83c167b9c7SMaximilian Luz  * packets.
84c167b9c7SMaximilian Luz  *
85c167b9c7SMaximilian Luz  * Packet timeouts are detected by the timeout reaper. This is a task,
86c167b9c7SMaximilian Luz  * scheduled depending on the earliest packet timeout expiration date,
87c167b9c7SMaximilian Luz  * checking all currently pending packets if their timeout has expired. If the
88c167b9c7SMaximilian Luz  * timeout of a packet has expired, it is re-submitted and the number of tries
89c167b9c7SMaximilian Luz  * of this packet is incremented. If this number reaches its limit, the packet
90c167b9c7SMaximilian Luz  * will be completed with a failure.
91c167b9c7SMaximilian Luz  *
92c167b9c7SMaximilian Luz  * On transmission failure (such as repeated packet timeouts), the completion
93c167b9c7SMaximilian Luz  * callback is immediately run by on thread on which the error was detected.
94c167b9c7SMaximilian Luz  *
95c167b9c7SMaximilian Luz  * To ensure that a packet eventually leaves the system it is marked as
96c167b9c7SMaximilian Luz  * "locked" directly before it is going to be completed or when it is
97c167b9c7SMaximilian Luz  * canceled. Marking a packet as "locked" has the effect that passing and
98c167b9c7SMaximilian Luz  * creating new references of the packet is disallowed. This means that the
99c167b9c7SMaximilian Luz  * packet cannot be added to the queue, the pending set, and the timeout, or
100c167b9c7SMaximilian Luz  * be picked up by the transmitter thread or receiver thread. To remove a
101c167b9c7SMaximilian Luz  * packet from the system it has to be marked as locked and subsequently all
102c167b9c7SMaximilian Luz  * references from the data structures (queue, pending) have to be removed.
103c167b9c7SMaximilian Luz  * References held by threads will eventually be dropped automatically as
104c167b9c7SMaximilian Luz  * their execution progresses.
105c167b9c7SMaximilian Luz  *
106c167b9c7SMaximilian Luz  * Note that the packet completion callback is, in case of success and for a
107c167b9c7SMaximilian Luz  * sequenced packet, guaranteed to run on the receiver thread, thus providing
108c167b9c7SMaximilian Luz  * a way to reliably identify responses to the packet. The packet completion
109c167b9c7SMaximilian Luz  * callback is only run once and it does not indicate that the packet has
110c167b9c7SMaximilian Luz  * fully left the system (for this, one should rely on the release method,
111c167b9c7SMaximilian Luz  * triggered when the reference count of the packet reaches zero). In case of
112c167b9c7SMaximilian Luz  * re-submission (and with somewhat unlikely timing), it may be possible that
113c167b9c7SMaximilian Luz  * the packet is being re-transmitted while the completion callback runs.
114c167b9c7SMaximilian Luz  * Completion will occur both on success and internal error, as well as when
115c167b9c7SMaximilian Luz  * the packet is canceled.
116c167b9c7SMaximilian Luz  *
117c167b9c7SMaximilian Luz  * >> Flags <<
118c167b9c7SMaximilian Luz  *
119c167b9c7SMaximilian Luz  * Flags are used to indicate the state and progression of a packet. Some flags
120c167b9c7SMaximilian Luz  * have stricter guarantees than other:
121c167b9c7SMaximilian Luz  *
122c167b9c7SMaximilian Luz  * - locked
123c167b9c7SMaximilian Luz  *   Indicates if the packet is locked. If the packet is locked, passing and/or
124c167b9c7SMaximilian Luz  *   creating additional references to the packet is forbidden. The packet thus
125c167b9c7SMaximilian Luz  *   may not be queued, dequeued, or removed or added to the pending set. Note
126c167b9c7SMaximilian Luz  *   that the packet state flags may still change (e.g. it may be marked as
127c167b9c7SMaximilian Luz  *   ACKed, transmitted, ...).
128c167b9c7SMaximilian Luz  *
129c167b9c7SMaximilian Luz  * - completed
130c167b9c7SMaximilian Luz  *   Indicates if the packet completion callback has been executed or is about
131c167b9c7SMaximilian Luz  *   to be executed. This flag is used to ensure that the packet completion
132c167b9c7SMaximilian Luz  *   callback is only run once.
133c167b9c7SMaximilian Luz  *
134c167b9c7SMaximilian Luz  * - queued
135c167b9c7SMaximilian Luz  *   Indicates if a packet is present in the submission queue or not. This flag
136c167b9c7SMaximilian Luz  *   must only be modified with the queue lock held, and must be coherent to the
137c167b9c7SMaximilian Luz  *   presence of the packet in the queue.
138c167b9c7SMaximilian Luz  *
139c167b9c7SMaximilian Luz  * - pending
140c167b9c7SMaximilian Luz  *   Indicates if a packet is present in the set of pending packets or not.
141c167b9c7SMaximilian Luz  *   This flag must only be modified with the pending lock held, and must be
142c167b9c7SMaximilian Luz  *   coherent to the presence of the packet in the pending set.
143c167b9c7SMaximilian Luz  *
144c167b9c7SMaximilian Luz  * - transmitting
145c167b9c7SMaximilian Luz  *   Indicates if the packet is currently transmitting. In case of
146c167b9c7SMaximilian Luz  *   re-transmissions, it is only safe to wait on the "transmitted" completion
147c167b9c7SMaximilian Luz  *   after this flag has been set. The completion will be set both in success
148c167b9c7SMaximilian Luz  *   and error case.
149c167b9c7SMaximilian Luz  *
150c167b9c7SMaximilian Luz  * - transmitted
151c167b9c7SMaximilian Luz  *   Indicates if the packet has been transmitted. This flag is not cleared by
152c167b9c7SMaximilian Luz  *   the system, thus it indicates the first transmission only.
153c167b9c7SMaximilian Luz  *
154c167b9c7SMaximilian Luz  * - acked
155c167b9c7SMaximilian Luz  *   Indicates if the packet has been acknowledged by the client. There are no
156c167b9c7SMaximilian Luz  *   other guarantees given. For example, the packet may still be canceled
157c167b9c7SMaximilian Luz  *   and/or the completion may be triggered an error even though this bit is
158c167b9c7SMaximilian Luz  *   set. Rely on the status provided to the completion callback instead.
159c167b9c7SMaximilian Luz  *
160c167b9c7SMaximilian Luz  * - canceled
161c167b9c7SMaximilian Luz  *   Indicates if the packet has been canceled from the outside. There are no
162c167b9c7SMaximilian Luz  *   other guarantees given. Specifically, the packet may be completed by
163c167b9c7SMaximilian Luz  *   another part of the system before the cancellation attempts to complete it.
164c167b9c7SMaximilian Luz  *
165c167b9c7SMaximilian Luz  * >> General Notes <<
166c167b9c7SMaximilian Luz  *
167c167b9c7SMaximilian Luz  * - To avoid deadlocks, if both queue and pending locks are required, the
168c167b9c7SMaximilian Luz  *   pending lock must be acquired before the queue lock.
169c167b9c7SMaximilian Luz  *
170c167b9c7SMaximilian Luz  * - The packet priority must be accessed only while holding the queue lock.
171c167b9c7SMaximilian Luz  *
172c167b9c7SMaximilian Luz  * - The packet timestamp must be accessed only while holding the pending
173c167b9c7SMaximilian Luz  *   lock.
174c167b9c7SMaximilian Luz  */
175c167b9c7SMaximilian Luz 
176c167b9c7SMaximilian Luz /*
177c167b9c7SMaximilian Luz  * SSH_PTL_MAX_PACKET_TRIES - Maximum transmission attempts for packet.
178c167b9c7SMaximilian Luz  *
179c167b9c7SMaximilian Luz  * Maximum number of transmission attempts per sequenced packet in case of
180c167b9c7SMaximilian Luz  * time-outs. Must be smaller than 16. If the packet times out after this
181c167b9c7SMaximilian Luz  * amount of tries, the packet will be completed with %-ETIMEDOUT as status
182c167b9c7SMaximilian Luz  * code.
183c167b9c7SMaximilian Luz  */
184c167b9c7SMaximilian Luz #define SSH_PTL_MAX_PACKET_TRIES		3
185c167b9c7SMaximilian Luz 
186c167b9c7SMaximilian Luz /*
187c167b9c7SMaximilian Luz  * SSH_PTL_TX_TIMEOUT - Packet transmission timeout.
188c167b9c7SMaximilian Luz  *
189c167b9c7SMaximilian Luz  * Timeout in jiffies for packet transmission via the underlying serial
190c167b9c7SMaximilian Luz  * device. If transmitting the packet takes longer than this timeout, the
191c167b9c7SMaximilian Luz  * packet will be completed with -ETIMEDOUT. It will not be re-submitted.
192c167b9c7SMaximilian Luz  */
193c167b9c7SMaximilian Luz #define SSH_PTL_TX_TIMEOUT			HZ
194c167b9c7SMaximilian Luz 
195c167b9c7SMaximilian Luz /*
196c167b9c7SMaximilian Luz  * SSH_PTL_PACKET_TIMEOUT - Packet response timeout.
197c167b9c7SMaximilian Luz  *
198c167b9c7SMaximilian Luz  * Timeout as ktime_t delta for ACKs. If we have not received an ACK in this
199c167b9c7SMaximilian Luz  * time-frame after starting transmission, the packet will be re-submitted.
200c167b9c7SMaximilian Luz  */
201c167b9c7SMaximilian Luz #define SSH_PTL_PACKET_TIMEOUT			ms_to_ktime(1000)
202c167b9c7SMaximilian Luz 
203c167b9c7SMaximilian Luz /*
204c167b9c7SMaximilian Luz  * SSH_PTL_PACKET_TIMEOUT_RESOLUTION - Packet timeout granularity.
205c167b9c7SMaximilian Luz  *
206c167b9c7SMaximilian Luz  * Time-resolution for timeouts. Should be larger than one jiffy to avoid
207c167b9c7SMaximilian Luz  * direct re-scheduling of reaper work_struct.
208c167b9c7SMaximilian Luz  */
209c167b9c7SMaximilian Luz #define SSH_PTL_PACKET_TIMEOUT_RESOLUTION	ms_to_ktime(max(2000 / HZ, 50))
210c167b9c7SMaximilian Luz 
211c167b9c7SMaximilian Luz /*
212c167b9c7SMaximilian Luz  * SSH_PTL_MAX_PENDING - Maximum number of pending packets.
213c167b9c7SMaximilian Luz  *
214c167b9c7SMaximilian Luz  * Maximum number of sequenced packets concurrently waiting for an ACK.
215c167b9c7SMaximilian Luz  * Packets marked as blocking will not be transmitted while this limit is
216c167b9c7SMaximilian Luz  * reached.
217c167b9c7SMaximilian Luz  */
218c167b9c7SMaximilian Luz #define SSH_PTL_MAX_PENDING			1
219c167b9c7SMaximilian Luz 
220c167b9c7SMaximilian Luz /*
221c167b9c7SMaximilian Luz  * SSH_PTL_RX_BUF_LEN - Evaluation-buffer size in bytes.
222c167b9c7SMaximilian Luz  */
223c167b9c7SMaximilian Luz #define SSH_PTL_RX_BUF_LEN			4096
224c167b9c7SMaximilian Luz 
225c167b9c7SMaximilian Luz /*
226c167b9c7SMaximilian Luz  * SSH_PTL_RX_FIFO_LEN - Fifo input-buffer size in bytes.
227c167b9c7SMaximilian Luz  */
228c167b9c7SMaximilian Luz #define SSH_PTL_RX_FIFO_LEN			4096
229c167b9c7SMaximilian Luz 
23002be44f6SMaximilian Luz #ifdef CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION
23102be44f6SMaximilian Luz 
23202be44f6SMaximilian Luz /**
23302be44f6SMaximilian Luz  * ssh_ptl_should_drop_ack_packet() - Error injection hook to drop ACK packets.
23402be44f6SMaximilian Luz  *
23502be44f6SMaximilian Luz  * Useful to test detection and handling of automated re-transmits by the EC.
23602be44f6SMaximilian Luz  * Specifically of packets that the EC considers not-ACKed but the driver
23702be44f6SMaximilian Luz  * already considers ACKed (due to dropped ACK). In this case, the EC
23802be44f6SMaximilian Luz  * re-transmits the packet-to-be-ACKed and the driver should detect it as
23902be44f6SMaximilian Luz  * duplicate/already handled. Note that the driver should still send an ACK
24002be44f6SMaximilian Luz  * for the re-transmitted packet.
24102be44f6SMaximilian Luz  */
ssh_ptl_should_drop_ack_packet(void)24202be44f6SMaximilian Luz static noinline bool ssh_ptl_should_drop_ack_packet(void)
24302be44f6SMaximilian Luz {
24402be44f6SMaximilian Luz 	return false;
24502be44f6SMaximilian Luz }
24602be44f6SMaximilian Luz ALLOW_ERROR_INJECTION(ssh_ptl_should_drop_ack_packet, TRUE);
24702be44f6SMaximilian Luz 
24802be44f6SMaximilian Luz /**
24902be44f6SMaximilian Luz  * ssh_ptl_should_drop_nak_packet() - Error injection hook to drop NAK packets.
25002be44f6SMaximilian Luz  *
25102be44f6SMaximilian Luz  * Useful to test/force automated (timeout-based) re-transmit by the EC.
25202be44f6SMaximilian Luz  * Specifically, packets that have not reached the driver completely/with valid
25302be44f6SMaximilian Luz  * checksums. Only useful in combination with receival of (injected) bad data.
25402be44f6SMaximilian Luz  */
ssh_ptl_should_drop_nak_packet(void)25502be44f6SMaximilian Luz static noinline bool ssh_ptl_should_drop_nak_packet(void)
25602be44f6SMaximilian Luz {
25702be44f6SMaximilian Luz 	return false;
25802be44f6SMaximilian Luz }
25902be44f6SMaximilian Luz ALLOW_ERROR_INJECTION(ssh_ptl_should_drop_nak_packet, TRUE);
26002be44f6SMaximilian Luz 
26102be44f6SMaximilian Luz /**
26202be44f6SMaximilian Luz  * ssh_ptl_should_drop_dsq_packet() - Error injection hook to drop sequenced
26302be44f6SMaximilian Luz  * data packet.
26402be44f6SMaximilian Luz  *
26502be44f6SMaximilian Luz  * Useful to test re-transmit timeout of the driver. If the data packet has not
26602be44f6SMaximilian Luz  * been ACKed after a certain time, the driver should re-transmit the packet up
26702be44f6SMaximilian Luz  * to limited number of times defined in SSH_PTL_MAX_PACKET_TRIES.
26802be44f6SMaximilian Luz  */
ssh_ptl_should_drop_dsq_packet(void)26902be44f6SMaximilian Luz static noinline bool ssh_ptl_should_drop_dsq_packet(void)
27002be44f6SMaximilian Luz {
27102be44f6SMaximilian Luz 	return false;
27202be44f6SMaximilian Luz }
27302be44f6SMaximilian Luz ALLOW_ERROR_INJECTION(ssh_ptl_should_drop_dsq_packet, TRUE);
27402be44f6SMaximilian Luz 
27502be44f6SMaximilian Luz /**
27602be44f6SMaximilian Luz  * ssh_ptl_should_fail_write() - Error injection hook to make
27702be44f6SMaximilian Luz  * serdev_device_write() fail.
27802be44f6SMaximilian Luz  *
27902be44f6SMaximilian Luz  * Hook to simulate errors in serdev_device_write when transmitting packets.
28002be44f6SMaximilian Luz  */
ssh_ptl_should_fail_write(void)28102be44f6SMaximilian Luz static noinline int ssh_ptl_should_fail_write(void)
28202be44f6SMaximilian Luz {
28302be44f6SMaximilian Luz 	return 0;
28402be44f6SMaximilian Luz }
28502be44f6SMaximilian Luz ALLOW_ERROR_INJECTION(ssh_ptl_should_fail_write, ERRNO);
28602be44f6SMaximilian Luz 
28702be44f6SMaximilian Luz /**
28802be44f6SMaximilian Luz  * ssh_ptl_should_corrupt_tx_data() - Error injection hook to simulate invalid
28902be44f6SMaximilian Luz  * data being sent to the EC.
29002be44f6SMaximilian Luz  *
29102be44f6SMaximilian Luz  * Hook to simulate corrupt/invalid data being sent from host (driver) to EC.
29202be44f6SMaximilian Luz  * Causes the packet data to be actively corrupted by overwriting it with
29302be44f6SMaximilian Luz  * pre-defined values, such that it becomes invalid, causing the EC to respond
29402be44f6SMaximilian Luz  * with a NAK packet. Useful to test handling of NAK packets received by the
29502be44f6SMaximilian Luz  * driver.
29602be44f6SMaximilian Luz  */
ssh_ptl_should_corrupt_tx_data(void)29702be44f6SMaximilian Luz static noinline bool ssh_ptl_should_corrupt_tx_data(void)
29802be44f6SMaximilian Luz {
29902be44f6SMaximilian Luz 	return false;
30002be44f6SMaximilian Luz }
30102be44f6SMaximilian Luz ALLOW_ERROR_INJECTION(ssh_ptl_should_corrupt_tx_data, TRUE);
30202be44f6SMaximilian Luz 
30302be44f6SMaximilian Luz /**
30402be44f6SMaximilian Luz  * ssh_ptl_should_corrupt_rx_syn() - Error injection hook to simulate invalid
30502be44f6SMaximilian Luz  * data being sent by the EC.
30602be44f6SMaximilian Luz  *
30702be44f6SMaximilian Luz  * Hook to simulate invalid SYN bytes, i.e. an invalid start of messages and
30802be44f6SMaximilian Luz  * test handling thereof in the driver.
30902be44f6SMaximilian Luz  */
ssh_ptl_should_corrupt_rx_syn(void)31002be44f6SMaximilian Luz static noinline bool ssh_ptl_should_corrupt_rx_syn(void)
31102be44f6SMaximilian Luz {
31202be44f6SMaximilian Luz 	return false;
31302be44f6SMaximilian Luz }
31402be44f6SMaximilian Luz ALLOW_ERROR_INJECTION(ssh_ptl_should_corrupt_rx_syn, TRUE);
31502be44f6SMaximilian Luz 
31602be44f6SMaximilian Luz /**
31702be44f6SMaximilian Luz  * ssh_ptl_should_corrupt_rx_data() - Error injection hook to simulate invalid
31802be44f6SMaximilian Luz  * data being sent by the EC.
31902be44f6SMaximilian Luz  *
32002be44f6SMaximilian Luz  * Hook to simulate invalid data/checksum of the message frame and test handling
32102be44f6SMaximilian Luz  * thereof in the driver.
32202be44f6SMaximilian Luz  */
ssh_ptl_should_corrupt_rx_data(void)32302be44f6SMaximilian Luz static noinline bool ssh_ptl_should_corrupt_rx_data(void)
32402be44f6SMaximilian Luz {
32502be44f6SMaximilian Luz 	return false;
32602be44f6SMaximilian Luz }
32702be44f6SMaximilian Luz ALLOW_ERROR_INJECTION(ssh_ptl_should_corrupt_rx_data, TRUE);
32802be44f6SMaximilian Luz 
__ssh_ptl_should_drop_ack_packet(struct ssh_packet * packet)32902be44f6SMaximilian Luz static bool __ssh_ptl_should_drop_ack_packet(struct ssh_packet *packet)
33002be44f6SMaximilian Luz {
33102be44f6SMaximilian Luz 	if (likely(!ssh_ptl_should_drop_ack_packet()))
33202be44f6SMaximilian Luz 		return false;
33302be44f6SMaximilian Luz 
33402be44f6SMaximilian Luz 	trace_ssam_ei_tx_drop_ack_packet(packet);
33502be44f6SMaximilian Luz 	ptl_info(packet->ptl, "packet error injection: dropping ACK packet %p\n",
33602be44f6SMaximilian Luz 		 packet);
33702be44f6SMaximilian Luz 
33802be44f6SMaximilian Luz 	return true;
33902be44f6SMaximilian Luz }
34002be44f6SMaximilian Luz 
__ssh_ptl_should_drop_nak_packet(struct ssh_packet * packet)34102be44f6SMaximilian Luz static bool __ssh_ptl_should_drop_nak_packet(struct ssh_packet *packet)
34202be44f6SMaximilian Luz {
34302be44f6SMaximilian Luz 	if (likely(!ssh_ptl_should_drop_nak_packet()))
34402be44f6SMaximilian Luz 		return false;
34502be44f6SMaximilian Luz 
34602be44f6SMaximilian Luz 	trace_ssam_ei_tx_drop_nak_packet(packet);
34702be44f6SMaximilian Luz 	ptl_info(packet->ptl, "packet error injection: dropping NAK packet %p\n",
34802be44f6SMaximilian Luz 		 packet);
34902be44f6SMaximilian Luz 
35002be44f6SMaximilian Luz 	return true;
35102be44f6SMaximilian Luz }
35202be44f6SMaximilian Luz 
__ssh_ptl_should_drop_dsq_packet(struct ssh_packet * packet)35302be44f6SMaximilian Luz static bool __ssh_ptl_should_drop_dsq_packet(struct ssh_packet *packet)
35402be44f6SMaximilian Luz {
35502be44f6SMaximilian Luz 	if (likely(!ssh_ptl_should_drop_dsq_packet()))
35602be44f6SMaximilian Luz 		return false;
35702be44f6SMaximilian Luz 
35802be44f6SMaximilian Luz 	trace_ssam_ei_tx_drop_dsq_packet(packet);
35902be44f6SMaximilian Luz 	ptl_info(packet->ptl,
36002be44f6SMaximilian Luz 		 "packet error injection: dropping sequenced data packet %p\n",
36102be44f6SMaximilian Luz 		 packet);
36202be44f6SMaximilian Luz 
36302be44f6SMaximilian Luz 	return true;
36402be44f6SMaximilian Luz }
36502be44f6SMaximilian Luz 
ssh_ptl_should_drop_packet(struct ssh_packet * packet)36602be44f6SMaximilian Luz static bool ssh_ptl_should_drop_packet(struct ssh_packet *packet)
36702be44f6SMaximilian Luz {
36802be44f6SMaximilian Luz 	/* Ignore packets that don't carry any data (i.e. flush). */
36902be44f6SMaximilian Luz 	if (!packet->data.ptr || !packet->data.len)
37002be44f6SMaximilian Luz 		return false;
37102be44f6SMaximilian Luz 
37202be44f6SMaximilian Luz 	switch (packet->data.ptr[SSH_MSGOFFSET_FRAME(type)]) {
37302be44f6SMaximilian Luz 	case SSH_FRAME_TYPE_ACK:
37402be44f6SMaximilian Luz 		return __ssh_ptl_should_drop_ack_packet(packet);
37502be44f6SMaximilian Luz 
37602be44f6SMaximilian Luz 	case SSH_FRAME_TYPE_NAK:
37702be44f6SMaximilian Luz 		return __ssh_ptl_should_drop_nak_packet(packet);
37802be44f6SMaximilian Luz 
37902be44f6SMaximilian Luz 	case SSH_FRAME_TYPE_DATA_SEQ:
38002be44f6SMaximilian Luz 		return __ssh_ptl_should_drop_dsq_packet(packet);
38102be44f6SMaximilian Luz 
38202be44f6SMaximilian Luz 	default:
38302be44f6SMaximilian Luz 		return false;
38402be44f6SMaximilian Luz 	}
38502be44f6SMaximilian Luz }
38602be44f6SMaximilian Luz 
ssh_ptl_write_buf(struct ssh_ptl * ptl,struct ssh_packet * packet,const unsigned char * buf,size_t count)38702be44f6SMaximilian Luz static int ssh_ptl_write_buf(struct ssh_ptl *ptl, struct ssh_packet *packet,
38802be44f6SMaximilian Luz 			     const unsigned char *buf, size_t count)
38902be44f6SMaximilian Luz {
39002be44f6SMaximilian Luz 	int status;
39102be44f6SMaximilian Luz 
39202be44f6SMaximilian Luz 	status = ssh_ptl_should_fail_write();
39302be44f6SMaximilian Luz 	if (unlikely(status)) {
39402be44f6SMaximilian Luz 		trace_ssam_ei_tx_fail_write(packet, status);
39502be44f6SMaximilian Luz 		ptl_info(packet->ptl,
39602be44f6SMaximilian Luz 			 "packet error injection: simulating transmit error %d, packet %p\n",
39702be44f6SMaximilian Luz 			 status, packet);
39802be44f6SMaximilian Luz 
39902be44f6SMaximilian Luz 		return status;
40002be44f6SMaximilian Luz 	}
40102be44f6SMaximilian Luz 
40202be44f6SMaximilian Luz 	return serdev_device_write_buf(ptl->serdev, buf, count);
40302be44f6SMaximilian Luz }
40402be44f6SMaximilian Luz 
ssh_ptl_tx_inject_invalid_data(struct ssh_packet * packet)40502be44f6SMaximilian Luz static void ssh_ptl_tx_inject_invalid_data(struct ssh_packet *packet)
40602be44f6SMaximilian Luz {
40702be44f6SMaximilian Luz 	/* Ignore packets that don't carry any data (i.e. flush). */
40802be44f6SMaximilian Luz 	if (!packet->data.ptr || !packet->data.len)
40902be44f6SMaximilian Luz 		return;
41002be44f6SMaximilian Luz 
41102be44f6SMaximilian Luz 	/* Only allow sequenced data packets to be modified. */
41202be44f6SMaximilian Luz 	if (packet->data.ptr[SSH_MSGOFFSET_FRAME(type)] != SSH_FRAME_TYPE_DATA_SEQ)
41302be44f6SMaximilian Luz 		return;
41402be44f6SMaximilian Luz 
41502be44f6SMaximilian Luz 	if (likely(!ssh_ptl_should_corrupt_tx_data()))
41602be44f6SMaximilian Luz 		return;
41702be44f6SMaximilian Luz 
41802be44f6SMaximilian Luz 	trace_ssam_ei_tx_corrupt_data(packet);
41902be44f6SMaximilian Luz 	ptl_info(packet->ptl,
42002be44f6SMaximilian Luz 		 "packet error injection: simulating invalid transmit data on packet %p\n",
42102be44f6SMaximilian Luz 		 packet);
42202be44f6SMaximilian Luz 
42302be44f6SMaximilian Luz 	/*
42402be44f6SMaximilian Luz 	 * NB: The value 0xb3 has been chosen more or less randomly so that it
42502be44f6SMaximilian Luz 	 * doesn't have any (major) overlap with the SYN bytes (aa 55) and is
42602be44f6SMaximilian Luz 	 * non-trivial (i.e. non-zero, non-0xff).
42702be44f6SMaximilian Luz 	 */
42802be44f6SMaximilian Luz 	memset(packet->data.ptr, 0xb3, packet->data.len);
42902be44f6SMaximilian Luz }
43002be44f6SMaximilian Luz 
ssh_ptl_rx_inject_invalid_syn(struct ssh_ptl * ptl,struct ssam_span * data)43102be44f6SMaximilian Luz static void ssh_ptl_rx_inject_invalid_syn(struct ssh_ptl *ptl,
43202be44f6SMaximilian Luz 					  struct ssam_span *data)
43302be44f6SMaximilian Luz {
43402be44f6SMaximilian Luz 	struct ssam_span frame;
43502be44f6SMaximilian Luz 
43602be44f6SMaximilian Luz 	/* Check if there actually is something to corrupt. */
43702be44f6SMaximilian Luz 	if (!sshp_find_syn(data, &frame))
43802be44f6SMaximilian Luz 		return;
43902be44f6SMaximilian Luz 
44002be44f6SMaximilian Luz 	if (likely(!ssh_ptl_should_corrupt_rx_syn()))
44102be44f6SMaximilian Luz 		return;
44202be44f6SMaximilian Luz 
44302be44f6SMaximilian Luz 	trace_ssam_ei_rx_corrupt_syn(data->len);
44402be44f6SMaximilian Luz 
44502be44f6SMaximilian Luz 	data->ptr[1] = 0xb3;	/* Set second byte of SYN to "random" value. */
44602be44f6SMaximilian Luz }
44702be44f6SMaximilian Luz 
ssh_ptl_rx_inject_invalid_data(struct ssh_ptl * ptl,struct ssam_span * frame)44802be44f6SMaximilian Luz static void ssh_ptl_rx_inject_invalid_data(struct ssh_ptl *ptl,
44902be44f6SMaximilian Luz 					   struct ssam_span *frame)
45002be44f6SMaximilian Luz {
45102be44f6SMaximilian Luz 	size_t payload_len, message_len;
45202be44f6SMaximilian Luz 	struct ssh_frame *sshf;
45302be44f6SMaximilian Luz 
45402be44f6SMaximilian Luz 	/* Ignore incomplete messages, will get handled once it's complete. */
45502be44f6SMaximilian Luz 	if (frame->len < SSH_MESSAGE_LENGTH(0))
45602be44f6SMaximilian Luz 		return;
45702be44f6SMaximilian Luz 
45802be44f6SMaximilian Luz 	/* Ignore incomplete messages, part 2. */
45902be44f6SMaximilian Luz 	payload_len = get_unaligned_le16(&frame->ptr[SSH_MSGOFFSET_FRAME(len)]);
46002be44f6SMaximilian Luz 	message_len = SSH_MESSAGE_LENGTH(payload_len);
46102be44f6SMaximilian Luz 	if (frame->len < message_len)
46202be44f6SMaximilian Luz 		return;
46302be44f6SMaximilian Luz 
46402be44f6SMaximilian Luz 	if (likely(!ssh_ptl_should_corrupt_rx_data()))
46502be44f6SMaximilian Luz 		return;
46602be44f6SMaximilian Luz 
46702be44f6SMaximilian Luz 	sshf = (struct ssh_frame *)&frame->ptr[SSH_MSGOFFSET_FRAME(type)];
46802be44f6SMaximilian Luz 	trace_ssam_ei_rx_corrupt_data(sshf);
46902be44f6SMaximilian Luz 
47002be44f6SMaximilian Luz 	/*
47102be44f6SMaximilian Luz 	 * Flip bits in first byte of payload checksum. This is basically
47202be44f6SMaximilian Luz 	 * equivalent to a payload/frame data error without us having to worry
47302be44f6SMaximilian Luz 	 * about (the, arguably pretty small, probability of) accidental
47402be44f6SMaximilian Luz 	 * checksum collisions.
47502be44f6SMaximilian Luz 	 */
47602be44f6SMaximilian Luz 	frame->ptr[frame->len - 2] = ~frame->ptr[frame->len - 2];
47702be44f6SMaximilian Luz }
47802be44f6SMaximilian Luz 
47902be44f6SMaximilian Luz #else /* CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION */
48002be44f6SMaximilian Luz 
ssh_ptl_should_drop_packet(struct ssh_packet * packet)48102be44f6SMaximilian Luz static inline bool ssh_ptl_should_drop_packet(struct ssh_packet *packet)
48202be44f6SMaximilian Luz {
48302be44f6SMaximilian Luz 	return false;
48402be44f6SMaximilian Luz }
48502be44f6SMaximilian Luz 
ssh_ptl_write_buf(struct ssh_ptl * ptl,struct ssh_packet * packet,const unsigned char * buf,size_t count)48602be44f6SMaximilian Luz static inline int ssh_ptl_write_buf(struct ssh_ptl *ptl,
48702be44f6SMaximilian Luz 				    struct ssh_packet *packet,
48802be44f6SMaximilian Luz 				    const unsigned char *buf,
48902be44f6SMaximilian Luz 				    size_t count)
49002be44f6SMaximilian Luz {
49102be44f6SMaximilian Luz 	return serdev_device_write_buf(ptl->serdev, buf, count);
49202be44f6SMaximilian Luz }
49302be44f6SMaximilian Luz 
ssh_ptl_tx_inject_invalid_data(struct ssh_packet * packet)49402be44f6SMaximilian Luz static inline void ssh_ptl_tx_inject_invalid_data(struct ssh_packet *packet)
49502be44f6SMaximilian Luz {
49602be44f6SMaximilian Luz }
49702be44f6SMaximilian Luz 
ssh_ptl_rx_inject_invalid_syn(struct ssh_ptl * ptl,struct ssam_span * data)49802be44f6SMaximilian Luz static inline void ssh_ptl_rx_inject_invalid_syn(struct ssh_ptl *ptl,
49902be44f6SMaximilian Luz 						 struct ssam_span *data)
50002be44f6SMaximilian Luz {
50102be44f6SMaximilian Luz }
50202be44f6SMaximilian Luz 
ssh_ptl_rx_inject_invalid_data(struct ssh_ptl * ptl,struct ssam_span * frame)50302be44f6SMaximilian Luz static inline void ssh_ptl_rx_inject_invalid_data(struct ssh_ptl *ptl,
50402be44f6SMaximilian Luz 						  struct ssam_span *frame)
50502be44f6SMaximilian Luz {
50602be44f6SMaximilian Luz }
50702be44f6SMaximilian Luz 
50802be44f6SMaximilian Luz #endif /* CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION */
50902be44f6SMaximilian Luz 
__ssh_ptl_packet_release(struct kref * kref)510c167b9c7SMaximilian Luz static void __ssh_ptl_packet_release(struct kref *kref)
511c167b9c7SMaximilian Luz {
512c167b9c7SMaximilian Luz 	struct ssh_packet *p = container_of(kref, struct ssh_packet, refcnt);
513c167b9c7SMaximilian Luz 
5140d21bb85SMaximilian Luz 	trace_ssam_packet_release(p);
5150d21bb85SMaximilian Luz 
516c167b9c7SMaximilian Luz 	ptl_dbg_cond(p->ptl, "ptl: releasing packet %p\n", p);
517c167b9c7SMaximilian Luz 	p->ops->release(p);
518c167b9c7SMaximilian Luz }
519c167b9c7SMaximilian Luz 
520c167b9c7SMaximilian Luz /**
521c167b9c7SMaximilian Luz  * ssh_packet_get() - Increment reference count of packet.
522c167b9c7SMaximilian Luz  * @packet: The packet to increment the reference count of.
523c167b9c7SMaximilian Luz  *
524c167b9c7SMaximilian Luz  * Increments the reference count of the given packet. See ssh_packet_put()
525c167b9c7SMaximilian Luz  * for the counter-part of this function.
526c167b9c7SMaximilian Luz  *
527c167b9c7SMaximilian Luz  * Return: Returns the packet provided as input.
528c167b9c7SMaximilian Luz  */
ssh_packet_get(struct ssh_packet * packet)529c167b9c7SMaximilian Luz struct ssh_packet *ssh_packet_get(struct ssh_packet *packet)
530c167b9c7SMaximilian Luz {
531c167b9c7SMaximilian Luz 	if (packet)
532c167b9c7SMaximilian Luz 		kref_get(&packet->refcnt);
533c167b9c7SMaximilian Luz 	return packet;
534c167b9c7SMaximilian Luz }
535c167b9c7SMaximilian Luz EXPORT_SYMBOL_GPL(ssh_packet_get);
536c167b9c7SMaximilian Luz 
537c167b9c7SMaximilian Luz /**
538c167b9c7SMaximilian Luz  * ssh_packet_put() - Decrement reference count of packet.
539c167b9c7SMaximilian Luz  * @packet: The packet to decrement the reference count of.
540c167b9c7SMaximilian Luz  *
541c167b9c7SMaximilian Luz  * If the reference count reaches zero, the ``release`` callback specified in
542c167b9c7SMaximilian Luz  * the packet's &struct ssh_packet_ops, i.e. ``packet->ops->release``, will be
543c167b9c7SMaximilian Luz  * called.
544c167b9c7SMaximilian Luz  *
545c167b9c7SMaximilian Luz  * See ssh_packet_get() for the counter-part of this function.
546c167b9c7SMaximilian Luz  */
ssh_packet_put(struct ssh_packet * packet)547c167b9c7SMaximilian Luz void ssh_packet_put(struct ssh_packet *packet)
548c167b9c7SMaximilian Luz {
549c167b9c7SMaximilian Luz 	if (packet)
550c167b9c7SMaximilian Luz 		kref_put(&packet->refcnt, __ssh_ptl_packet_release);
551c167b9c7SMaximilian Luz }
552c167b9c7SMaximilian Luz EXPORT_SYMBOL_GPL(ssh_packet_put);
553c167b9c7SMaximilian Luz 
ssh_packet_get_seq(struct ssh_packet * packet)554c167b9c7SMaximilian Luz static u8 ssh_packet_get_seq(struct ssh_packet *packet)
555c167b9c7SMaximilian Luz {
556c167b9c7SMaximilian Luz 	return packet->data.ptr[SSH_MSGOFFSET_FRAME(seq)];
557c167b9c7SMaximilian Luz }
558c167b9c7SMaximilian Luz 
559c167b9c7SMaximilian Luz /**
560c167b9c7SMaximilian Luz  * ssh_packet_init() - Initialize SSH packet.
561c167b9c7SMaximilian Luz  * @packet:   The packet to initialize.
562c167b9c7SMaximilian Luz  * @type:     Type-flags of the packet.
563c167b9c7SMaximilian Luz  * @priority: Priority of the packet. See SSH_PACKET_PRIORITY() for details.
564c167b9c7SMaximilian Luz  * @ops:      Packet operations.
565c167b9c7SMaximilian Luz  *
566c167b9c7SMaximilian Luz  * Initializes the given SSH packet. Sets the transmission buffer pointer to
567c167b9c7SMaximilian Luz  * %NULL and the transmission buffer length to zero. For data-type packets,
568c167b9c7SMaximilian Luz  * this buffer has to be set separately via ssh_packet_set_data() before
569c167b9c7SMaximilian Luz  * submission, and must contain a valid SSH message, i.e. frame with optional
570c167b9c7SMaximilian Luz  * payload of any type.
571c167b9c7SMaximilian Luz  */
ssh_packet_init(struct ssh_packet * packet,unsigned long type,u8 priority,const struct ssh_packet_ops * ops)572c167b9c7SMaximilian Luz void ssh_packet_init(struct ssh_packet *packet, unsigned long type,
573c167b9c7SMaximilian Luz 		     u8 priority, const struct ssh_packet_ops *ops)
574c167b9c7SMaximilian Luz {
575c167b9c7SMaximilian Luz 	kref_init(&packet->refcnt);
576c167b9c7SMaximilian Luz 
577c167b9c7SMaximilian Luz 	packet->ptl = NULL;
578c167b9c7SMaximilian Luz 	INIT_LIST_HEAD(&packet->queue_node);
579c167b9c7SMaximilian Luz 	INIT_LIST_HEAD(&packet->pending_node);
580c167b9c7SMaximilian Luz 
581c167b9c7SMaximilian Luz 	packet->state = type & SSH_PACKET_FLAGS_TY_MASK;
582c167b9c7SMaximilian Luz 	packet->priority = priority;
583c167b9c7SMaximilian Luz 	packet->timestamp = KTIME_MAX;
584c167b9c7SMaximilian Luz 
585c167b9c7SMaximilian Luz 	packet->data.ptr = NULL;
586c167b9c7SMaximilian Luz 	packet->data.len = 0;
587c167b9c7SMaximilian Luz 
588c167b9c7SMaximilian Luz 	packet->ops = ops;
589c167b9c7SMaximilian Luz }
590c167b9c7SMaximilian Luz 
59144b84ee7SMaximilian Luz static struct kmem_cache *ssh_ctrl_packet_cache;
59244b84ee7SMaximilian Luz 
593c167b9c7SMaximilian Luz /**
59444b84ee7SMaximilian Luz  * ssh_ctrl_packet_cache_init() - Initialize the control packet cache.
59544b84ee7SMaximilian Luz  */
ssh_ctrl_packet_cache_init(void)59644b84ee7SMaximilian Luz int ssh_ctrl_packet_cache_init(void)
59744b84ee7SMaximilian Luz {
59844b84ee7SMaximilian Luz 	const unsigned int size = sizeof(struct ssh_packet) + SSH_MSG_LEN_CTRL;
59944b84ee7SMaximilian Luz 	const unsigned int align = __alignof__(struct ssh_packet);
60044b84ee7SMaximilian Luz 	struct kmem_cache *cache;
60144b84ee7SMaximilian Luz 
60244b84ee7SMaximilian Luz 	cache = kmem_cache_create("ssam_ctrl_packet", size, align, 0, NULL);
60344b84ee7SMaximilian Luz 	if (!cache)
60444b84ee7SMaximilian Luz 		return -ENOMEM;
60544b84ee7SMaximilian Luz 
60644b84ee7SMaximilian Luz 	ssh_ctrl_packet_cache = cache;
60744b84ee7SMaximilian Luz 	return 0;
60844b84ee7SMaximilian Luz }
60944b84ee7SMaximilian Luz 
61044b84ee7SMaximilian Luz /**
61144b84ee7SMaximilian Luz  * ssh_ctrl_packet_cache_destroy() - Deinitialize the control packet cache.
61244b84ee7SMaximilian Luz  */
ssh_ctrl_packet_cache_destroy(void)61344b84ee7SMaximilian Luz void ssh_ctrl_packet_cache_destroy(void)
61444b84ee7SMaximilian Luz {
61544b84ee7SMaximilian Luz 	kmem_cache_destroy(ssh_ctrl_packet_cache);
61644b84ee7SMaximilian Luz 	ssh_ctrl_packet_cache = NULL;
61744b84ee7SMaximilian Luz }
61844b84ee7SMaximilian Luz 
61944b84ee7SMaximilian Luz /**
62044b84ee7SMaximilian Luz  * ssh_ctrl_packet_alloc() - Allocate packet from control packet cache.
621c167b9c7SMaximilian Luz  * @packet: Where the pointer to the newly allocated packet should be stored.
622c167b9c7SMaximilian Luz  * @buffer: The buffer corresponding to this packet.
623c167b9c7SMaximilian Luz  * @flags:  Flags used for allocation.
624c167b9c7SMaximilian Luz  *
62544b84ee7SMaximilian Luz  * Allocates a packet and corresponding transport buffer from the control
62644b84ee7SMaximilian Luz  * packet cache. Sets the packet's buffer reference to the allocated buffer.
62744b84ee7SMaximilian Luz  * The packet must be freed via ssh_ctrl_packet_free(), which will also free
62844b84ee7SMaximilian Luz  * the corresponding buffer. The corresponding buffer must not be freed
62944b84ee7SMaximilian Luz  * separately. Intended to be used with %ssh_ptl_ctrl_packet_ops as packet
63044b84ee7SMaximilian Luz  * operations.
631c167b9c7SMaximilian Luz  *
632c167b9c7SMaximilian Luz  * Return: Returns zero on success, %-ENOMEM if the allocation failed.
633c167b9c7SMaximilian Luz  */
ssh_ctrl_packet_alloc(struct ssh_packet ** packet,struct ssam_span * buffer,gfp_t flags)634c167b9c7SMaximilian Luz static int ssh_ctrl_packet_alloc(struct ssh_packet **packet,
635c167b9c7SMaximilian Luz 				 struct ssam_span *buffer, gfp_t flags)
636c167b9c7SMaximilian Luz {
63744b84ee7SMaximilian Luz 	*packet = kmem_cache_alloc(ssh_ctrl_packet_cache, flags);
638c167b9c7SMaximilian Luz 	if (!*packet)
639c167b9c7SMaximilian Luz 		return -ENOMEM;
640c167b9c7SMaximilian Luz 
641c167b9c7SMaximilian Luz 	buffer->ptr = (u8 *)(*packet + 1);
642c167b9c7SMaximilian Luz 	buffer->len = SSH_MSG_LEN_CTRL;
643c167b9c7SMaximilian Luz 
6440d21bb85SMaximilian Luz 	trace_ssam_ctrl_packet_alloc(*packet, buffer->len);
645c167b9c7SMaximilian Luz 	return 0;
646c167b9c7SMaximilian Luz }
647c167b9c7SMaximilian Luz 
648c167b9c7SMaximilian Luz /**
64944b84ee7SMaximilian Luz  * ssh_ctrl_packet_free() - Free packet allocated from control packet cache.
650c167b9c7SMaximilian Luz  * @p: The packet to free.
651c167b9c7SMaximilian Luz  */
ssh_ctrl_packet_free(struct ssh_packet * p)652c167b9c7SMaximilian Luz static void ssh_ctrl_packet_free(struct ssh_packet *p)
653c167b9c7SMaximilian Luz {
6540d21bb85SMaximilian Luz 	trace_ssam_ctrl_packet_free(p);
65544b84ee7SMaximilian Luz 	kmem_cache_free(ssh_ctrl_packet_cache, p);
656c167b9c7SMaximilian Luz }
657c167b9c7SMaximilian Luz 
658c167b9c7SMaximilian Luz static const struct ssh_packet_ops ssh_ptl_ctrl_packet_ops = {
659c167b9c7SMaximilian Luz 	.complete = NULL,
660c167b9c7SMaximilian Luz 	.release = ssh_ctrl_packet_free,
661c167b9c7SMaximilian Luz };
662c167b9c7SMaximilian Luz 
ssh_ptl_timeout_reaper_mod(struct ssh_ptl * ptl,ktime_t now,ktime_t expires)663c167b9c7SMaximilian Luz static void ssh_ptl_timeout_reaper_mod(struct ssh_ptl *ptl, ktime_t now,
664c167b9c7SMaximilian Luz 				       ktime_t expires)
665c167b9c7SMaximilian Luz {
666c167b9c7SMaximilian Luz 	unsigned long delta = msecs_to_jiffies(ktime_ms_delta(expires, now));
667c167b9c7SMaximilian Luz 	ktime_t aexp = ktime_add(expires, SSH_PTL_PACKET_TIMEOUT_RESOLUTION);
668c167b9c7SMaximilian Luz 
669c167b9c7SMaximilian Luz 	spin_lock(&ptl->rtx_timeout.lock);
670c167b9c7SMaximilian Luz 
671c167b9c7SMaximilian Luz 	/* Re-adjust / schedule reaper only if it is above resolution delta. */
672c167b9c7SMaximilian Luz 	if (ktime_before(aexp, ptl->rtx_timeout.expires)) {
673c167b9c7SMaximilian Luz 		ptl->rtx_timeout.expires = expires;
674c167b9c7SMaximilian Luz 		mod_delayed_work(system_wq, &ptl->rtx_timeout.reaper, delta);
675c167b9c7SMaximilian Luz 	}
676c167b9c7SMaximilian Luz 
677c167b9c7SMaximilian Luz 	spin_unlock(&ptl->rtx_timeout.lock);
678c167b9c7SMaximilian Luz }
679c167b9c7SMaximilian Luz 
680c167b9c7SMaximilian Luz /* Must be called with queue lock held. */
ssh_packet_next_try(struct ssh_packet * p)681c167b9c7SMaximilian Luz static void ssh_packet_next_try(struct ssh_packet *p)
682c167b9c7SMaximilian Luz {
683c167b9c7SMaximilian Luz 	u8 base = ssh_packet_priority_get_base(p->priority);
684c167b9c7SMaximilian Luz 	u8 try = ssh_packet_priority_get_try(p->priority);
685c167b9c7SMaximilian Luz 
686c167b9c7SMaximilian Luz 	lockdep_assert_held(&p->ptl->queue.lock);
687c167b9c7SMaximilian Luz 
6880d21bb85SMaximilian Luz 	/*
6890d21bb85SMaximilian Luz 	 * Ensure that we write the priority in one go via WRITE_ONCE() so we
6900d21bb85SMaximilian Luz 	 * can access it via READ_ONCE() for tracing. Note that other access
6910d21bb85SMaximilian Luz 	 * is guarded by the queue lock, so no need to use READ_ONCE() there.
6920d21bb85SMaximilian Luz 	 */
6930d21bb85SMaximilian Luz 	WRITE_ONCE(p->priority, __SSH_PACKET_PRIORITY(base, try + 1));
694c167b9c7SMaximilian Luz }
695c167b9c7SMaximilian Luz 
696c167b9c7SMaximilian Luz /* Must be called with queue lock held. */
__ssh_ptl_queue_find_entrypoint(struct ssh_packet * p)697c167b9c7SMaximilian Luz static struct list_head *__ssh_ptl_queue_find_entrypoint(struct ssh_packet *p)
698c167b9c7SMaximilian Luz {
699c167b9c7SMaximilian Luz 	struct list_head *head;
700c167b9c7SMaximilian Luz 	struct ssh_packet *q;
701c167b9c7SMaximilian Luz 
702c167b9c7SMaximilian Luz 	lockdep_assert_held(&p->ptl->queue.lock);
703c167b9c7SMaximilian Luz 
704c167b9c7SMaximilian Luz 	/*
705c167b9c7SMaximilian Luz 	 * We generally assume that there are less control (ACK/NAK) packets
706c167b9c7SMaximilian Luz 	 * and re-submitted data packets as there are normal data packets (at
707c167b9c7SMaximilian Luz 	 * least in situations in which many packets are queued; if there
708c167b9c7SMaximilian Luz 	 * aren't many packets queued the decision on how to iterate should be
709c167b9c7SMaximilian Luz 	 * basically irrelevant; the number of control/data packets is more or
710c167b9c7SMaximilian Luz 	 * less limited via the maximum number of pending packets). Thus, when
711c167b9c7SMaximilian Luz 	 * inserting a control or re-submitted data packet, (determined by
712c167b9c7SMaximilian Luz 	 * their priority), we search from front to back. Normal data packets
713c167b9c7SMaximilian Luz 	 * are, usually queued directly at the tail of the queue, so for those
714c167b9c7SMaximilian Luz 	 * search from back to front.
715c167b9c7SMaximilian Luz 	 */
716c167b9c7SMaximilian Luz 
717c167b9c7SMaximilian Luz 	if (p->priority > SSH_PACKET_PRIORITY(DATA, 0)) {
718c167b9c7SMaximilian Luz 		list_for_each(head, &p->ptl->queue.head) {
719c167b9c7SMaximilian Luz 			q = list_entry(head, struct ssh_packet, queue_node);
720c167b9c7SMaximilian Luz 
721c167b9c7SMaximilian Luz 			if (q->priority < p->priority)
722c167b9c7SMaximilian Luz 				break;
723c167b9c7SMaximilian Luz 		}
724c167b9c7SMaximilian Luz 	} else {
725c167b9c7SMaximilian Luz 		list_for_each_prev(head, &p->ptl->queue.head) {
726c167b9c7SMaximilian Luz 			q = list_entry(head, struct ssh_packet, queue_node);
727c167b9c7SMaximilian Luz 
728c167b9c7SMaximilian Luz 			if (q->priority >= p->priority) {
729c167b9c7SMaximilian Luz 				head = head->next;
730c167b9c7SMaximilian Luz 				break;
731c167b9c7SMaximilian Luz 			}
732c167b9c7SMaximilian Luz 		}
733c167b9c7SMaximilian Luz 	}
734c167b9c7SMaximilian Luz 
735c167b9c7SMaximilian Luz 	return head;
736c167b9c7SMaximilian Luz }
737c167b9c7SMaximilian Luz 
738c167b9c7SMaximilian Luz /* Must be called with queue lock held. */
__ssh_ptl_queue_push(struct ssh_packet * packet)739c167b9c7SMaximilian Luz static int __ssh_ptl_queue_push(struct ssh_packet *packet)
740c167b9c7SMaximilian Luz {
741c167b9c7SMaximilian Luz 	struct ssh_ptl *ptl = packet->ptl;
742c167b9c7SMaximilian Luz 	struct list_head *head;
743c167b9c7SMaximilian Luz 
744c167b9c7SMaximilian Luz 	lockdep_assert_held(&ptl->queue.lock);
745c167b9c7SMaximilian Luz 
746c167b9c7SMaximilian Luz 	if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state))
747c167b9c7SMaximilian Luz 		return -ESHUTDOWN;
748c167b9c7SMaximilian Luz 
749c167b9c7SMaximilian Luz 	/* Avoid further transitions when canceling/completing. */
750c167b9c7SMaximilian Luz 	if (test_bit(SSH_PACKET_SF_LOCKED_BIT, &packet->state))
751c167b9c7SMaximilian Luz 		return -EINVAL;
752c167b9c7SMaximilian Luz 
753c167b9c7SMaximilian Luz 	/* If this packet has already been queued, do not add it. */
754c167b9c7SMaximilian Luz 	if (test_and_set_bit(SSH_PACKET_SF_QUEUED_BIT, &packet->state))
755c167b9c7SMaximilian Luz 		return -EALREADY;
756c167b9c7SMaximilian Luz 
757c167b9c7SMaximilian Luz 	head = __ssh_ptl_queue_find_entrypoint(packet);
758c167b9c7SMaximilian Luz 
759c167b9c7SMaximilian Luz 	list_add_tail(&ssh_packet_get(packet)->queue_node, head);
760c167b9c7SMaximilian Luz 	return 0;
761c167b9c7SMaximilian Luz }
762c167b9c7SMaximilian Luz 
ssh_ptl_queue_push(struct ssh_packet * packet)763c167b9c7SMaximilian Luz static int ssh_ptl_queue_push(struct ssh_packet *packet)
764c167b9c7SMaximilian Luz {
765c167b9c7SMaximilian Luz 	int status;
766c167b9c7SMaximilian Luz 
767c167b9c7SMaximilian Luz 	spin_lock(&packet->ptl->queue.lock);
768c167b9c7SMaximilian Luz 	status = __ssh_ptl_queue_push(packet);
769c167b9c7SMaximilian Luz 	spin_unlock(&packet->ptl->queue.lock);
770c167b9c7SMaximilian Luz 
771c167b9c7SMaximilian Luz 	return status;
772c167b9c7SMaximilian Luz }
773c167b9c7SMaximilian Luz 
ssh_ptl_queue_remove(struct ssh_packet * packet)774c167b9c7SMaximilian Luz static void ssh_ptl_queue_remove(struct ssh_packet *packet)
775c167b9c7SMaximilian Luz {
776c167b9c7SMaximilian Luz 	struct ssh_ptl *ptl = packet->ptl;
777c167b9c7SMaximilian Luz 
778c167b9c7SMaximilian Luz 	spin_lock(&ptl->queue.lock);
779c167b9c7SMaximilian Luz 
780c167b9c7SMaximilian Luz 	if (!test_and_clear_bit(SSH_PACKET_SF_QUEUED_BIT, &packet->state)) {
781c167b9c7SMaximilian Luz 		spin_unlock(&ptl->queue.lock);
782c167b9c7SMaximilian Luz 		return;
783c167b9c7SMaximilian Luz 	}
784c167b9c7SMaximilian Luz 
785c167b9c7SMaximilian Luz 	list_del(&packet->queue_node);
786c167b9c7SMaximilian Luz 
787c167b9c7SMaximilian Luz 	spin_unlock(&ptl->queue.lock);
788c167b9c7SMaximilian Luz 	ssh_packet_put(packet);
789c167b9c7SMaximilian Luz }
790c167b9c7SMaximilian Luz 
ssh_ptl_pending_push(struct ssh_packet * p)791c167b9c7SMaximilian Luz static void ssh_ptl_pending_push(struct ssh_packet *p)
792c167b9c7SMaximilian Luz {
793c167b9c7SMaximilian Luz 	struct ssh_ptl *ptl = p->ptl;
794c167b9c7SMaximilian Luz 	const ktime_t timestamp = ktime_get_coarse_boottime();
795c167b9c7SMaximilian Luz 	const ktime_t timeout = ptl->rtx_timeout.timeout;
796c167b9c7SMaximilian Luz 
797c167b9c7SMaximilian Luz 	/*
798c167b9c7SMaximilian Luz 	 * Note: We can get the time for the timestamp before acquiring the
799c167b9c7SMaximilian Luz 	 * lock as this is the only place we're setting it and this function
800c167b9c7SMaximilian Luz 	 * is called only from the transmitter thread. Thus it is not possible
801c167b9c7SMaximilian Luz 	 * to overwrite the timestamp with an outdated value below.
802c167b9c7SMaximilian Luz 	 */
803c167b9c7SMaximilian Luz 
804c167b9c7SMaximilian Luz 	spin_lock(&ptl->pending.lock);
805c167b9c7SMaximilian Luz 
806c167b9c7SMaximilian Luz 	/* If we are canceling/completing this packet, do not add it. */
807c167b9c7SMaximilian Luz 	if (test_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state)) {
808c167b9c7SMaximilian Luz 		spin_unlock(&ptl->pending.lock);
809c167b9c7SMaximilian Luz 		return;
810c167b9c7SMaximilian Luz 	}
811c167b9c7SMaximilian Luz 
812c167b9c7SMaximilian Luz 	/*
813c167b9c7SMaximilian Luz 	 * On re-submission, the packet has already been added the pending
814c167b9c7SMaximilian Luz 	 * set. We still need to update the timestamp as the packet timeout is
815c167b9c7SMaximilian Luz 	 * reset for each (re-)submission.
816c167b9c7SMaximilian Luz 	 */
817c167b9c7SMaximilian Luz 	p->timestamp = timestamp;
818c167b9c7SMaximilian Luz 
819c167b9c7SMaximilian Luz 	/* In case it is already pending (e.g. re-submission), do not add it. */
820c167b9c7SMaximilian Luz 	if (!test_and_set_bit(SSH_PACKET_SF_PENDING_BIT, &p->state)) {
821c167b9c7SMaximilian Luz 		atomic_inc(&ptl->pending.count);
822c167b9c7SMaximilian Luz 		list_add_tail(&ssh_packet_get(p)->pending_node, &ptl->pending.head);
823c167b9c7SMaximilian Luz 	}
824c167b9c7SMaximilian Luz 
825c167b9c7SMaximilian Luz 	spin_unlock(&ptl->pending.lock);
826c167b9c7SMaximilian Luz 
827c167b9c7SMaximilian Luz 	/* Arm/update timeout reaper. */
828c167b9c7SMaximilian Luz 	ssh_ptl_timeout_reaper_mod(ptl, timestamp, timestamp + timeout);
829c167b9c7SMaximilian Luz }
830c167b9c7SMaximilian Luz 
ssh_ptl_pending_remove(struct ssh_packet * packet)831c167b9c7SMaximilian Luz static void ssh_ptl_pending_remove(struct ssh_packet *packet)
832c167b9c7SMaximilian Luz {
833c167b9c7SMaximilian Luz 	struct ssh_ptl *ptl = packet->ptl;
834c167b9c7SMaximilian Luz 
835c167b9c7SMaximilian Luz 	spin_lock(&ptl->pending.lock);
836c167b9c7SMaximilian Luz 
837c167b9c7SMaximilian Luz 	if (!test_and_clear_bit(SSH_PACKET_SF_PENDING_BIT, &packet->state)) {
838c167b9c7SMaximilian Luz 		spin_unlock(&ptl->pending.lock);
839c167b9c7SMaximilian Luz 		return;
840c167b9c7SMaximilian Luz 	}
841c167b9c7SMaximilian Luz 
842c167b9c7SMaximilian Luz 	list_del(&packet->pending_node);
843c167b9c7SMaximilian Luz 	atomic_dec(&ptl->pending.count);
844c167b9c7SMaximilian Luz 
845c167b9c7SMaximilian Luz 	spin_unlock(&ptl->pending.lock);
846c167b9c7SMaximilian Luz 
847c167b9c7SMaximilian Luz 	ssh_packet_put(packet);
848c167b9c7SMaximilian Luz }
849c167b9c7SMaximilian Luz 
850c167b9c7SMaximilian Luz /* Warning: Does not check/set "completed" bit. */
__ssh_ptl_complete(struct ssh_packet * p,int status)851c167b9c7SMaximilian Luz static void __ssh_ptl_complete(struct ssh_packet *p, int status)
852c167b9c7SMaximilian Luz {
853c167b9c7SMaximilian Luz 	struct ssh_ptl *ptl = READ_ONCE(p->ptl);
854c167b9c7SMaximilian Luz 
8550d21bb85SMaximilian Luz 	trace_ssam_packet_complete(p, status);
856c167b9c7SMaximilian Luz 	ptl_dbg_cond(ptl, "ptl: completing packet %p (status: %d)\n", p, status);
857c167b9c7SMaximilian Luz 
858c167b9c7SMaximilian Luz 	if (p->ops->complete)
859c167b9c7SMaximilian Luz 		p->ops->complete(p, status);
860c167b9c7SMaximilian Luz }
861c167b9c7SMaximilian Luz 
ssh_ptl_remove_and_complete(struct ssh_packet * p,int status)862c167b9c7SMaximilian Luz static void ssh_ptl_remove_and_complete(struct ssh_packet *p, int status)
863c167b9c7SMaximilian Luz {
864c167b9c7SMaximilian Luz 	/*
865c167b9c7SMaximilian Luz 	 * A call to this function should in general be preceded by
866c167b9c7SMaximilian Luz 	 * set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->flags) to avoid re-adding the
867c167b9c7SMaximilian Luz 	 * packet to the structures it's going to be removed from.
868c167b9c7SMaximilian Luz 	 *
869c167b9c7SMaximilian Luz 	 * The set_bit call does not need explicit memory barriers as the
870c167b9c7SMaximilian Luz 	 * implicit barrier of the test_and_set_bit() call below ensure that the
871c167b9c7SMaximilian Luz 	 * flag is visible before we actually attempt to remove the packet.
872c167b9c7SMaximilian Luz 	 */
873c167b9c7SMaximilian Luz 
874c167b9c7SMaximilian Luz 	if (test_and_set_bit(SSH_PACKET_SF_COMPLETED_BIT, &p->state))
875c167b9c7SMaximilian Luz 		return;
876c167b9c7SMaximilian Luz 
877c167b9c7SMaximilian Luz 	ssh_ptl_queue_remove(p);
878c167b9c7SMaximilian Luz 	ssh_ptl_pending_remove(p);
879c167b9c7SMaximilian Luz 
880c167b9c7SMaximilian Luz 	__ssh_ptl_complete(p, status);
881c167b9c7SMaximilian Luz }
882c167b9c7SMaximilian Luz 
ssh_ptl_tx_can_process(struct ssh_packet * packet)883c167b9c7SMaximilian Luz static bool ssh_ptl_tx_can_process(struct ssh_packet *packet)
884c167b9c7SMaximilian Luz {
885c167b9c7SMaximilian Luz 	struct ssh_ptl *ptl = packet->ptl;
886c167b9c7SMaximilian Luz 
887c167b9c7SMaximilian Luz 	if (test_bit(SSH_PACKET_TY_FLUSH_BIT, &packet->state))
888c167b9c7SMaximilian Luz 		return !atomic_read(&ptl->pending.count);
889c167b9c7SMaximilian Luz 
890c167b9c7SMaximilian Luz 	/* We can always process non-blocking packets. */
891c167b9c7SMaximilian Luz 	if (!test_bit(SSH_PACKET_TY_BLOCKING_BIT, &packet->state))
892c167b9c7SMaximilian Luz 		return true;
893c167b9c7SMaximilian Luz 
894c167b9c7SMaximilian Luz 	/* If we are already waiting for this packet, send it again. */
895c167b9c7SMaximilian Luz 	if (test_bit(SSH_PACKET_SF_PENDING_BIT, &packet->state))
896c167b9c7SMaximilian Luz 		return true;
897c167b9c7SMaximilian Luz 
898c167b9c7SMaximilian Luz 	/* Otherwise: Check if we have the capacity to send. */
899c167b9c7SMaximilian Luz 	return atomic_read(&ptl->pending.count) < SSH_PTL_MAX_PENDING;
900c167b9c7SMaximilian Luz }
901c167b9c7SMaximilian Luz 
ssh_ptl_tx_pop(struct ssh_ptl * ptl)902c167b9c7SMaximilian Luz static struct ssh_packet *ssh_ptl_tx_pop(struct ssh_ptl *ptl)
903c167b9c7SMaximilian Luz {
904c167b9c7SMaximilian Luz 	struct ssh_packet *packet = ERR_PTR(-ENOENT);
905c167b9c7SMaximilian Luz 	struct ssh_packet *p, *n;
906c167b9c7SMaximilian Luz 
907c167b9c7SMaximilian Luz 	spin_lock(&ptl->queue.lock);
908c167b9c7SMaximilian Luz 	list_for_each_entry_safe(p, n, &ptl->queue.head, queue_node) {
909c167b9c7SMaximilian Luz 		/*
910c167b9c7SMaximilian Luz 		 * If we are canceling or completing this packet, ignore it.
911c167b9c7SMaximilian Luz 		 * It's going to be removed from this queue shortly.
912c167b9c7SMaximilian Luz 		 */
913c167b9c7SMaximilian Luz 		if (test_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state))
914c167b9c7SMaximilian Luz 			continue;
915c167b9c7SMaximilian Luz 
916c167b9c7SMaximilian Luz 		/*
917c167b9c7SMaximilian Luz 		 * Packets should be ordered non-blocking/to-be-resent first.
918c167b9c7SMaximilian Luz 		 * If we cannot process this packet, assume that we can't
919c167b9c7SMaximilian Luz 		 * process any following packet either and abort.
920c167b9c7SMaximilian Luz 		 */
921c167b9c7SMaximilian Luz 		if (!ssh_ptl_tx_can_process(p)) {
922c167b9c7SMaximilian Luz 			packet = ERR_PTR(-EBUSY);
923c167b9c7SMaximilian Luz 			break;
924c167b9c7SMaximilian Luz 		}
925c167b9c7SMaximilian Luz 
926c167b9c7SMaximilian Luz 		/*
927c167b9c7SMaximilian Luz 		 * We are allowed to change the state now. Remove it from the
928c167b9c7SMaximilian Luz 		 * queue and mark it as being transmitted.
929c167b9c7SMaximilian Luz 		 */
930c167b9c7SMaximilian Luz 
931c167b9c7SMaximilian Luz 		list_del(&p->queue_node);
932c167b9c7SMaximilian Luz 
933c167b9c7SMaximilian Luz 		set_bit(SSH_PACKET_SF_TRANSMITTING_BIT, &p->state);
934c167b9c7SMaximilian Luz 		/* Ensure that state never gets zero. */
935c167b9c7SMaximilian Luz 		smp_mb__before_atomic();
936c167b9c7SMaximilian Luz 		clear_bit(SSH_PACKET_SF_QUEUED_BIT, &p->state);
937c167b9c7SMaximilian Luz 
938c167b9c7SMaximilian Luz 		/*
939c167b9c7SMaximilian Luz 		 * Update number of tries. This directly influences the
940c167b9c7SMaximilian Luz 		 * priority in case the packet is re-submitted (e.g. via
941c167b9c7SMaximilian Luz 		 * timeout/NAK). Note that all reads and writes to the
942c167b9c7SMaximilian Luz 		 * priority after the first submission are guarded by the
943c167b9c7SMaximilian Luz 		 * queue lock.
944c167b9c7SMaximilian Luz 		 */
945c167b9c7SMaximilian Luz 		ssh_packet_next_try(p);
946c167b9c7SMaximilian Luz 
947c167b9c7SMaximilian Luz 		packet = p;
948c167b9c7SMaximilian Luz 		break;
949c167b9c7SMaximilian Luz 	}
950c167b9c7SMaximilian Luz 	spin_unlock(&ptl->queue.lock);
951c167b9c7SMaximilian Luz 
952c167b9c7SMaximilian Luz 	return packet;
953c167b9c7SMaximilian Luz }
954c167b9c7SMaximilian Luz 
ssh_ptl_tx_next(struct ssh_ptl * ptl)955c167b9c7SMaximilian Luz static struct ssh_packet *ssh_ptl_tx_next(struct ssh_ptl *ptl)
956c167b9c7SMaximilian Luz {
957c167b9c7SMaximilian Luz 	struct ssh_packet *p;
958c167b9c7SMaximilian Luz 
959c167b9c7SMaximilian Luz 	p = ssh_ptl_tx_pop(ptl);
960c167b9c7SMaximilian Luz 	if (IS_ERR(p))
961c167b9c7SMaximilian Luz 		return p;
962c167b9c7SMaximilian Luz 
963c167b9c7SMaximilian Luz 	if (test_bit(SSH_PACKET_TY_SEQUENCED_BIT, &p->state)) {
964c167b9c7SMaximilian Luz 		ptl_dbg(ptl, "ptl: transmitting sequenced packet %p\n", p);
965c167b9c7SMaximilian Luz 		ssh_ptl_pending_push(p);
966c167b9c7SMaximilian Luz 	} else {
967c167b9c7SMaximilian Luz 		ptl_dbg(ptl, "ptl: transmitting non-sequenced packet %p\n", p);
968c167b9c7SMaximilian Luz 	}
969c167b9c7SMaximilian Luz 
970c167b9c7SMaximilian Luz 	return p;
971c167b9c7SMaximilian Luz }
972c167b9c7SMaximilian Luz 
ssh_ptl_tx_compl_success(struct ssh_packet * packet)973c167b9c7SMaximilian Luz static void ssh_ptl_tx_compl_success(struct ssh_packet *packet)
974c167b9c7SMaximilian Luz {
975c167b9c7SMaximilian Luz 	struct ssh_ptl *ptl = packet->ptl;
976c167b9c7SMaximilian Luz 
977c167b9c7SMaximilian Luz 	ptl_dbg(ptl, "ptl: successfully transmitted packet %p\n", packet);
978c167b9c7SMaximilian Luz 
979c167b9c7SMaximilian Luz 	/* Transition state to "transmitted". */
980c167b9c7SMaximilian Luz 	set_bit(SSH_PACKET_SF_TRANSMITTED_BIT, &packet->state);
981c167b9c7SMaximilian Luz 	/* Ensure that state never gets zero. */
982c167b9c7SMaximilian Luz 	smp_mb__before_atomic();
983c167b9c7SMaximilian Luz 	clear_bit(SSH_PACKET_SF_TRANSMITTING_BIT, &packet->state);
984c167b9c7SMaximilian Luz 
985c167b9c7SMaximilian Luz 	/* If the packet is unsequenced, we're done: Lock and complete. */
986c167b9c7SMaximilian Luz 	if (!test_bit(SSH_PACKET_TY_SEQUENCED_BIT, &packet->state)) {
987c167b9c7SMaximilian Luz 		set_bit(SSH_PACKET_SF_LOCKED_BIT, &packet->state);
988c167b9c7SMaximilian Luz 		ssh_ptl_remove_and_complete(packet, 0);
989c167b9c7SMaximilian Luz 	}
990c167b9c7SMaximilian Luz 
991c167b9c7SMaximilian Luz 	/*
992c167b9c7SMaximilian Luz 	 * Notify that a packet transmission has finished. In general we're only
993c167b9c7SMaximilian Luz 	 * waiting for one packet (if any), so wake_up_all should be fine.
994c167b9c7SMaximilian Luz 	 */
995c167b9c7SMaximilian Luz 	wake_up_all(&ptl->tx.packet_wq);
996c167b9c7SMaximilian Luz }
997c167b9c7SMaximilian Luz 
ssh_ptl_tx_compl_error(struct ssh_packet * packet,int status)998c167b9c7SMaximilian Luz static void ssh_ptl_tx_compl_error(struct ssh_packet *packet, int status)
999c167b9c7SMaximilian Luz {
1000c167b9c7SMaximilian Luz 	/* Transmission failure: Lock the packet and try to complete it. */
1001c167b9c7SMaximilian Luz 	set_bit(SSH_PACKET_SF_LOCKED_BIT, &packet->state);
1002c167b9c7SMaximilian Luz 	/* Ensure that state never gets zero. */
1003c167b9c7SMaximilian Luz 	smp_mb__before_atomic();
1004c167b9c7SMaximilian Luz 	clear_bit(SSH_PACKET_SF_TRANSMITTING_BIT, &packet->state);
1005c167b9c7SMaximilian Luz 
1006c167b9c7SMaximilian Luz 	ptl_err(packet->ptl, "ptl: transmission error: %d\n", status);
1007c167b9c7SMaximilian Luz 	ptl_dbg(packet->ptl, "ptl: failed to transmit packet: %p\n", packet);
1008c167b9c7SMaximilian Luz 
1009c167b9c7SMaximilian Luz 	ssh_ptl_remove_and_complete(packet, status);
1010c167b9c7SMaximilian Luz 
1011c167b9c7SMaximilian Luz 	/*
1012c167b9c7SMaximilian Luz 	 * Notify that a packet transmission has finished. In general we're only
1013c167b9c7SMaximilian Luz 	 * waiting for one packet (if any), so wake_up_all should be fine.
1014c167b9c7SMaximilian Luz 	 */
1015c167b9c7SMaximilian Luz 	wake_up_all(&packet->ptl->tx.packet_wq);
1016c167b9c7SMaximilian Luz }
1017c167b9c7SMaximilian Luz 
ssh_ptl_tx_wait_packet(struct ssh_ptl * ptl)1018c167b9c7SMaximilian Luz static long ssh_ptl_tx_wait_packet(struct ssh_ptl *ptl)
1019c167b9c7SMaximilian Luz {
1020c167b9c7SMaximilian Luz 	int status;
1021c167b9c7SMaximilian Luz 
1022c167b9c7SMaximilian Luz 	status = wait_for_completion_interruptible(&ptl->tx.thread_cplt_pkt);
1023c167b9c7SMaximilian Luz 	reinit_completion(&ptl->tx.thread_cplt_pkt);
1024c167b9c7SMaximilian Luz 
1025c167b9c7SMaximilian Luz 	/*
1026c167b9c7SMaximilian Luz 	 * Ensure completion is cleared before continuing to avoid lost update
1027c167b9c7SMaximilian Luz 	 * problems.
1028c167b9c7SMaximilian Luz 	 */
1029c167b9c7SMaximilian Luz 	smp_mb__after_atomic();
1030c167b9c7SMaximilian Luz 
1031c167b9c7SMaximilian Luz 	return status;
1032c167b9c7SMaximilian Luz }
1033c167b9c7SMaximilian Luz 
ssh_ptl_tx_wait_transfer(struct ssh_ptl * ptl,long timeout)1034c167b9c7SMaximilian Luz static long ssh_ptl_tx_wait_transfer(struct ssh_ptl *ptl, long timeout)
1035c167b9c7SMaximilian Luz {
1036c167b9c7SMaximilian Luz 	long status;
1037c167b9c7SMaximilian Luz 
1038c167b9c7SMaximilian Luz 	status = wait_for_completion_interruptible_timeout(&ptl->tx.thread_cplt_tx,
1039c167b9c7SMaximilian Luz 							   timeout);
1040c167b9c7SMaximilian Luz 	reinit_completion(&ptl->tx.thread_cplt_tx);
1041c167b9c7SMaximilian Luz 
1042c167b9c7SMaximilian Luz 	/*
1043c167b9c7SMaximilian Luz 	 * Ensure completion is cleared before continuing to avoid lost update
1044c167b9c7SMaximilian Luz 	 * problems.
1045c167b9c7SMaximilian Luz 	 */
1046c167b9c7SMaximilian Luz 	smp_mb__after_atomic();
1047c167b9c7SMaximilian Luz 
1048c167b9c7SMaximilian Luz 	return status;
1049c167b9c7SMaximilian Luz }
1050c167b9c7SMaximilian Luz 
ssh_ptl_tx_packet(struct ssh_ptl * ptl,struct ssh_packet * packet)1051c167b9c7SMaximilian Luz static int ssh_ptl_tx_packet(struct ssh_ptl *ptl, struct ssh_packet *packet)
1052c167b9c7SMaximilian Luz {
1053c167b9c7SMaximilian Luz 	long timeout = SSH_PTL_TX_TIMEOUT;
1054c167b9c7SMaximilian Luz 	size_t offset = 0;
1055c167b9c7SMaximilian Luz 
1056c167b9c7SMaximilian Luz 	/* Note: Flush-packets don't have any data. */
1057c167b9c7SMaximilian Luz 	if (unlikely(!packet->data.ptr))
1058c167b9c7SMaximilian Luz 		return 0;
1059c167b9c7SMaximilian Luz 
106002be44f6SMaximilian Luz 	/* Error injection: drop packet to simulate transmission problem. */
106102be44f6SMaximilian Luz 	if (ssh_ptl_should_drop_packet(packet))
106202be44f6SMaximilian Luz 		return 0;
106302be44f6SMaximilian Luz 
106402be44f6SMaximilian Luz 	/* Error injection: simulate invalid packet data. */
106502be44f6SMaximilian Luz 	ssh_ptl_tx_inject_invalid_data(packet);
106602be44f6SMaximilian Luz 
1067c167b9c7SMaximilian Luz 	ptl_dbg(ptl, "tx: sending data (length: %zu)\n", packet->data.len);
1068c167b9c7SMaximilian Luz 	print_hex_dump_debug("tx: ", DUMP_PREFIX_OFFSET, 16, 1,
1069c167b9c7SMaximilian Luz 			     packet->data.ptr, packet->data.len, false);
1070c167b9c7SMaximilian Luz 
1071c167b9c7SMaximilian Luz 	do {
1072c167b9c7SMaximilian Luz 		ssize_t status, len;
1073c167b9c7SMaximilian Luz 		u8 *buf;
1074c167b9c7SMaximilian Luz 
1075c167b9c7SMaximilian Luz 		buf = packet->data.ptr + offset;
1076c167b9c7SMaximilian Luz 		len = packet->data.len - offset;
1077c167b9c7SMaximilian Luz 
107802be44f6SMaximilian Luz 		status = ssh_ptl_write_buf(ptl, packet, buf, len);
1079c167b9c7SMaximilian Luz 		if (status < 0)
1080c167b9c7SMaximilian Luz 			return status;
1081c167b9c7SMaximilian Luz 
1082c167b9c7SMaximilian Luz 		if (status == len)
1083c167b9c7SMaximilian Luz 			return 0;
1084c167b9c7SMaximilian Luz 
1085c167b9c7SMaximilian Luz 		offset += status;
1086c167b9c7SMaximilian Luz 
1087c167b9c7SMaximilian Luz 		timeout = ssh_ptl_tx_wait_transfer(ptl, timeout);
1088c167b9c7SMaximilian Luz 		if (kthread_should_stop() || !atomic_read(&ptl->tx.running))
1089c167b9c7SMaximilian Luz 			return -ESHUTDOWN;
1090c167b9c7SMaximilian Luz 
1091c167b9c7SMaximilian Luz 		if (timeout < 0)
1092c167b9c7SMaximilian Luz 			return -EINTR;
1093c167b9c7SMaximilian Luz 
1094c167b9c7SMaximilian Luz 		if (timeout == 0)
1095c167b9c7SMaximilian Luz 			return -ETIMEDOUT;
1096c167b9c7SMaximilian Luz 	} while (true);
1097c167b9c7SMaximilian Luz }
1098c167b9c7SMaximilian Luz 
ssh_ptl_tx_threadfn(void * data)1099c167b9c7SMaximilian Luz static int ssh_ptl_tx_threadfn(void *data)
1100c167b9c7SMaximilian Luz {
1101c167b9c7SMaximilian Luz 	struct ssh_ptl *ptl = data;
1102c167b9c7SMaximilian Luz 
1103c167b9c7SMaximilian Luz 	while (!kthread_should_stop() && atomic_read(&ptl->tx.running)) {
1104c167b9c7SMaximilian Luz 		struct ssh_packet *packet;
1105c167b9c7SMaximilian Luz 		int status;
1106c167b9c7SMaximilian Luz 
1107c167b9c7SMaximilian Luz 		/* Try to get the next packet. */
1108c167b9c7SMaximilian Luz 		packet = ssh_ptl_tx_next(ptl);
1109c167b9c7SMaximilian Luz 
1110c167b9c7SMaximilian Luz 		/* If no packet can be processed, we are done. */
1111c167b9c7SMaximilian Luz 		if (IS_ERR(packet)) {
1112c167b9c7SMaximilian Luz 			ssh_ptl_tx_wait_packet(ptl);
1113c167b9c7SMaximilian Luz 			continue;
1114c167b9c7SMaximilian Luz 		}
1115c167b9c7SMaximilian Luz 
1116c167b9c7SMaximilian Luz 		/* Transfer and complete packet. */
1117c167b9c7SMaximilian Luz 		status = ssh_ptl_tx_packet(ptl, packet);
1118c167b9c7SMaximilian Luz 		if (status)
1119c167b9c7SMaximilian Luz 			ssh_ptl_tx_compl_error(packet, status);
1120c167b9c7SMaximilian Luz 		else
1121c167b9c7SMaximilian Luz 			ssh_ptl_tx_compl_success(packet);
1122c167b9c7SMaximilian Luz 
1123c167b9c7SMaximilian Luz 		ssh_packet_put(packet);
1124c167b9c7SMaximilian Luz 	}
1125c167b9c7SMaximilian Luz 
1126c167b9c7SMaximilian Luz 	return 0;
1127c167b9c7SMaximilian Luz }
1128c167b9c7SMaximilian Luz 
1129c167b9c7SMaximilian Luz /**
1130c167b9c7SMaximilian Luz  * ssh_ptl_tx_wakeup_packet() - Wake up packet transmitter thread for new
1131c167b9c7SMaximilian Luz  * packet.
1132c167b9c7SMaximilian Luz  * @ptl: The packet transport layer.
1133c167b9c7SMaximilian Luz  *
1134c167b9c7SMaximilian Luz  * Wakes up the packet transmitter thread, notifying it that a new packet has
1135c167b9c7SMaximilian Luz  * arrived and is ready for transfer. If the packet transport layer has been
1136c167b9c7SMaximilian Luz  * shut down, calls to this function will be ignored.
1137c167b9c7SMaximilian Luz  */
ssh_ptl_tx_wakeup_packet(struct ssh_ptl * ptl)1138c167b9c7SMaximilian Luz static void ssh_ptl_tx_wakeup_packet(struct ssh_ptl *ptl)
1139c167b9c7SMaximilian Luz {
1140c167b9c7SMaximilian Luz 	if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state))
1141c167b9c7SMaximilian Luz 		return;
1142c167b9c7SMaximilian Luz 
1143c167b9c7SMaximilian Luz 	complete(&ptl->tx.thread_cplt_pkt);
1144c167b9c7SMaximilian Luz }
1145c167b9c7SMaximilian Luz 
1146c167b9c7SMaximilian Luz /**
1147c167b9c7SMaximilian Luz  * ssh_ptl_tx_start() - Start packet transmitter thread.
1148c167b9c7SMaximilian Luz  * @ptl: The packet transport layer.
1149c167b9c7SMaximilian Luz  *
1150c167b9c7SMaximilian Luz  * Return: Returns zero on success, a negative error code on failure.
1151c167b9c7SMaximilian Luz  */
ssh_ptl_tx_start(struct ssh_ptl * ptl)1152c167b9c7SMaximilian Luz int ssh_ptl_tx_start(struct ssh_ptl *ptl)
1153c167b9c7SMaximilian Luz {
1154c167b9c7SMaximilian Luz 	atomic_set_release(&ptl->tx.running, 1);
1155c167b9c7SMaximilian Luz 
1156c167b9c7SMaximilian Luz 	ptl->tx.thread = kthread_run(ssh_ptl_tx_threadfn, ptl, "ssam_serial_hub-tx");
1157c167b9c7SMaximilian Luz 	if (IS_ERR(ptl->tx.thread))
1158c167b9c7SMaximilian Luz 		return PTR_ERR(ptl->tx.thread);
1159c167b9c7SMaximilian Luz 
1160c167b9c7SMaximilian Luz 	return 0;
1161c167b9c7SMaximilian Luz }
1162c167b9c7SMaximilian Luz 
1163c167b9c7SMaximilian Luz /**
1164c167b9c7SMaximilian Luz  * ssh_ptl_tx_stop() - Stop packet transmitter thread.
1165c167b9c7SMaximilian Luz  * @ptl: The packet transport layer.
1166c167b9c7SMaximilian Luz  *
1167c167b9c7SMaximilian Luz  * Return: Returns zero on success, a negative error code on failure.
1168c167b9c7SMaximilian Luz  */
ssh_ptl_tx_stop(struct ssh_ptl * ptl)1169c167b9c7SMaximilian Luz int ssh_ptl_tx_stop(struct ssh_ptl *ptl)
1170c167b9c7SMaximilian Luz {
1171c167b9c7SMaximilian Luz 	int status = 0;
1172c167b9c7SMaximilian Luz 
1173c167b9c7SMaximilian Luz 	if (!IS_ERR_OR_NULL(ptl->tx.thread)) {
1174c167b9c7SMaximilian Luz 		/* Tell thread to stop. */
1175c167b9c7SMaximilian Luz 		atomic_set_release(&ptl->tx.running, 0);
1176c167b9c7SMaximilian Luz 
1177c167b9c7SMaximilian Luz 		/*
1178c167b9c7SMaximilian Luz 		 * Wake up thread in case it is paused. Do not use wakeup
1179c167b9c7SMaximilian Luz 		 * helpers as this may be called when the shutdown bit has
1180c167b9c7SMaximilian Luz 		 * already been set.
1181c167b9c7SMaximilian Luz 		 */
1182c167b9c7SMaximilian Luz 		complete(&ptl->tx.thread_cplt_pkt);
1183c167b9c7SMaximilian Luz 		complete(&ptl->tx.thread_cplt_tx);
1184c167b9c7SMaximilian Luz 
1185c167b9c7SMaximilian Luz 		/* Finally, wait for thread to stop. */
1186c167b9c7SMaximilian Luz 		status = kthread_stop(ptl->tx.thread);
1187c167b9c7SMaximilian Luz 		ptl->tx.thread = NULL;
1188c167b9c7SMaximilian Luz 	}
1189c167b9c7SMaximilian Luz 
1190c167b9c7SMaximilian Luz 	return status;
1191c167b9c7SMaximilian Luz }
1192c167b9c7SMaximilian Luz 
ssh_ptl_ack_pop(struct ssh_ptl * ptl,u8 seq_id)1193c167b9c7SMaximilian Luz static struct ssh_packet *ssh_ptl_ack_pop(struct ssh_ptl *ptl, u8 seq_id)
1194c167b9c7SMaximilian Luz {
1195c167b9c7SMaximilian Luz 	struct ssh_packet *packet = ERR_PTR(-ENOENT);
1196c167b9c7SMaximilian Luz 	struct ssh_packet *p, *n;
1197c167b9c7SMaximilian Luz 
1198c167b9c7SMaximilian Luz 	spin_lock(&ptl->pending.lock);
1199c167b9c7SMaximilian Luz 	list_for_each_entry_safe(p, n, &ptl->pending.head, pending_node) {
1200c167b9c7SMaximilian Luz 		/*
1201c167b9c7SMaximilian Luz 		 * We generally expect packets to be in order, so first packet
1202c167b9c7SMaximilian Luz 		 * to be added to pending is first to be sent, is first to be
1203c167b9c7SMaximilian Luz 		 * ACKed.
1204c167b9c7SMaximilian Luz 		 */
1205c167b9c7SMaximilian Luz 		if (unlikely(ssh_packet_get_seq(p) != seq_id))
1206c167b9c7SMaximilian Luz 			continue;
1207c167b9c7SMaximilian Luz 
1208c167b9c7SMaximilian Luz 		/*
1209c167b9c7SMaximilian Luz 		 * In case we receive an ACK while handling a transmission
1210c167b9c7SMaximilian Luz 		 * error completion. The packet will be removed shortly.
1211c167b9c7SMaximilian Luz 		 */
1212c167b9c7SMaximilian Luz 		if (unlikely(test_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state))) {
1213c167b9c7SMaximilian Luz 			packet = ERR_PTR(-EPERM);
1214c167b9c7SMaximilian Luz 			break;
1215c167b9c7SMaximilian Luz 		}
1216c167b9c7SMaximilian Luz 
1217c167b9c7SMaximilian Luz 		/*
1218c167b9c7SMaximilian Luz 		 * Mark the packet as ACKed and remove it from pending by
1219c167b9c7SMaximilian Luz 		 * removing its node and decrementing the pending counter.
1220c167b9c7SMaximilian Luz 		 */
1221c167b9c7SMaximilian Luz 		set_bit(SSH_PACKET_SF_ACKED_BIT, &p->state);
1222c167b9c7SMaximilian Luz 		/* Ensure that state never gets zero. */
1223c167b9c7SMaximilian Luz 		smp_mb__before_atomic();
1224c167b9c7SMaximilian Luz 		clear_bit(SSH_PACKET_SF_PENDING_BIT, &p->state);
1225c167b9c7SMaximilian Luz 
1226c167b9c7SMaximilian Luz 		atomic_dec(&ptl->pending.count);
1227c167b9c7SMaximilian Luz 		list_del(&p->pending_node);
1228c167b9c7SMaximilian Luz 		packet = p;
1229c167b9c7SMaximilian Luz 
1230c167b9c7SMaximilian Luz 		break;
1231c167b9c7SMaximilian Luz 	}
1232c167b9c7SMaximilian Luz 	spin_unlock(&ptl->pending.lock);
1233c167b9c7SMaximilian Luz 
1234c167b9c7SMaximilian Luz 	return packet;
1235c167b9c7SMaximilian Luz }
1236c167b9c7SMaximilian Luz 
ssh_ptl_wait_until_transmitted(struct ssh_packet * packet)1237c167b9c7SMaximilian Luz static void ssh_ptl_wait_until_transmitted(struct ssh_packet *packet)
1238c167b9c7SMaximilian Luz {
1239c167b9c7SMaximilian Luz 	wait_event(packet->ptl->tx.packet_wq,
1240c167b9c7SMaximilian Luz 		   test_bit(SSH_PACKET_SF_TRANSMITTED_BIT, &packet->state) ||
1241c167b9c7SMaximilian Luz 		   test_bit(SSH_PACKET_SF_LOCKED_BIT, &packet->state));
1242c167b9c7SMaximilian Luz }
1243c167b9c7SMaximilian Luz 
ssh_ptl_acknowledge(struct ssh_ptl * ptl,u8 seq)1244c167b9c7SMaximilian Luz static void ssh_ptl_acknowledge(struct ssh_ptl *ptl, u8 seq)
1245c167b9c7SMaximilian Luz {
1246c167b9c7SMaximilian Luz 	struct ssh_packet *p;
1247c167b9c7SMaximilian Luz 
1248c167b9c7SMaximilian Luz 	p = ssh_ptl_ack_pop(ptl, seq);
1249c167b9c7SMaximilian Luz 	if (IS_ERR(p)) {
1250c167b9c7SMaximilian Luz 		if (PTR_ERR(p) == -ENOENT) {
1251c167b9c7SMaximilian Luz 			/*
1252c167b9c7SMaximilian Luz 			 * The packet has not been found in the set of pending
1253c167b9c7SMaximilian Luz 			 * packets.
1254c167b9c7SMaximilian Luz 			 */
1255c167b9c7SMaximilian Luz 			ptl_warn(ptl, "ptl: received ACK for non-pending packet\n");
1256c167b9c7SMaximilian Luz 		} else {
1257c167b9c7SMaximilian Luz 			/*
1258c167b9c7SMaximilian Luz 			 * The packet is pending, but we are not allowed to take
1259c167b9c7SMaximilian Luz 			 * it because it has been locked.
1260c167b9c7SMaximilian Luz 			 */
1261c167b9c7SMaximilian Luz 			WARN_ON(PTR_ERR(p) != -EPERM);
1262c167b9c7SMaximilian Luz 		}
1263c167b9c7SMaximilian Luz 		return;
1264c167b9c7SMaximilian Luz 	}
1265c167b9c7SMaximilian Luz 
1266c167b9c7SMaximilian Luz 	ptl_dbg(ptl, "ptl: received ACK for packet %p\n", p);
1267c167b9c7SMaximilian Luz 
1268c167b9c7SMaximilian Luz 	/*
1269c167b9c7SMaximilian Luz 	 * It is possible that the packet has been transmitted, but the state
1270c167b9c7SMaximilian Luz 	 * has not been updated from "transmitting" to "transmitted" yet.
1271c167b9c7SMaximilian Luz 	 * In that case, we need to wait for this transition to occur in order
1272c167b9c7SMaximilian Luz 	 * to determine between success or failure.
1273c167b9c7SMaximilian Luz 	 *
1274c167b9c7SMaximilian Luz 	 * On transmission failure, the packet will be locked after this call.
1275c167b9c7SMaximilian Luz 	 * On success, the transmitted bit will be set.
1276c167b9c7SMaximilian Luz 	 */
1277c167b9c7SMaximilian Luz 	ssh_ptl_wait_until_transmitted(p);
1278c167b9c7SMaximilian Luz 
1279c167b9c7SMaximilian Luz 	/*
1280c167b9c7SMaximilian Luz 	 * The packet will already be locked in case of a transmission error or
1281c167b9c7SMaximilian Luz 	 * cancellation. Let the transmitter or cancellation issuer complete the
1282c167b9c7SMaximilian Luz 	 * packet.
1283c167b9c7SMaximilian Luz 	 */
1284c167b9c7SMaximilian Luz 	if (unlikely(test_and_set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state))) {
1285c167b9c7SMaximilian Luz 		if (unlikely(!test_bit(SSH_PACKET_SF_TRANSMITTED_BIT, &p->state)))
1286c167b9c7SMaximilian Luz 			ptl_err(ptl, "ptl: received ACK before packet had been fully transmitted\n");
1287c167b9c7SMaximilian Luz 
1288c167b9c7SMaximilian Luz 		ssh_packet_put(p);
1289c167b9c7SMaximilian Luz 		return;
1290c167b9c7SMaximilian Luz 	}
1291c167b9c7SMaximilian Luz 
1292c167b9c7SMaximilian Luz 	ssh_ptl_remove_and_complete(p, 0);
1293c167b9c7SMaximilian Luz 	ssh_packet_put(p);
1294c167b9c7SMaximilian Luz 
1295c167b9c7SMaximilian Luz 	if (atomic_read(&ptl->pending.count) < SSH_PTL_MAX_PENDING)
1296c167b9c7SMaximilian Luz 		ssh_ptl_tx_wakeup_packet(ptl);
1297c167b9c7SMaximilian Luz }
1298c167b9c7SMaximilian Luz 
1299c167b9c7SMaximilian Luz /**
1300c167b9c7SMaximilian Luz  * ssh_ptl_submit() - Submit a packet to the transport layer.
1301c167b9c7SMaximilian Luz  * @ptl: The packet transport layer to submit the packet to.
1302c167b9c7SMaximilian Luz  * @p:   The packet to submit.
1303c167b9c7SMaximilian Luz  *
1304c167b9c7SMaximilian Luz  * Submits a new packet to the transport layer, queuing it to be sent. This
1305c167b9c7SMaximilian Luz  * function should not be used for re-submission.
1306c167b9c7SMaximilian Luz  *
1307c167b9c7SMaximilian Luz  * Return: Returns zero on success, %-EINVAL if a packet field is invalid or
1308c167b9c7SMaximilian Luz  * the packet has been canceled prior to submission, %-EALREADY if the packet
1309c167b9c7SMaximilian Luz  * has already been submitted, or %-ESHUTDOWN if the packet transport layer
1310c167b9c7SMaximilian Luz  * has been shut down.
1311c167b9c7SMaximilian Luz  */
ssh_ptl_submit(struct ssh_ptl * ptl,struct ssh_packet * p)1312c167b9c7SMaximilian Luz int ssh_ptl_submit(struct ssh_ptl *ptl, struct ssh_packet *p)
1313c167b9c7SMaximilian Luz {
1314c167b9c7SMaximilian Luz 	struct ssh_ptl *ptl_old;
1315c167b9c7SMaximilian Luz 	int status;
1316c167b9c7SMaximilian Luz 
13170d21bb85SMaximilian Luz 	trace_ssam_packet_submit(p);
13180d21bb85SMaximilian Luz 
1319c167b9c7SMaximilian Luz 	/* Validate packet fields. */
1320c167b9c7SMaximilian Luz 	if (test_bit(SSH_PACKET_TY_FLUSH_BIT, &p->state)) {
1321c167b9c7SMaximilian Luz 		if (p->data.ptr || test_bit(SSH_PACKET_TY_SEQUENCED_BIT, &p->state))
1322c167b9c7SMaximilian Luz 			return -EINVAL;
1323c167b9c7SMaximilian Luz 	} else if (!p->data.ptr) {
1324c167b9c7SMaximilian Luz 		return -EINVAL;
1325c167b9c7SMaximilian Luz 	}
1326c167b9c7SMaximilian Luz 
1327c167b9c7SMaximilian Luz 	/*
1328c167b9c7SMaximilian Luz 	 * The ptl reference only gets set on or before the first submission.
1329c167b9c7SMaximilian Luz 	 * After the first submission, it has to be read-only.
1330c167b9c7SMaximilian Luz 	 *
1331c167b9c7SMaximilian Luz 	 * Note that ptl may already be set from upper-layer request
1332c167b9c7SMaximilian Luz 	 * submission, thus we cannot expect it to be NULL.
1333c167b9c7SMaximilian Luz 	 */
1334c167b9c7SMaximilian Luz 	ptl_old = READ_ONCE(p->ptl);
1335c167b9c7SMaximilian Luz 	if (!ptl_old)
1336c167b9c7SMaximilian Luz 		WRITE_ONCE(p->ptl, ptl);
1337c167b9c7SMaximilian Luz 	else if (WARN_ON(ptl_old != ptl))
1338c167b9c7SMaximilian Luz 		return -EALREADY;	/* Submitted on different PTL. */
1339c167b9c7SMaximilian Luz 
1340c167b9c7SMaximilian Luz 	status = ssh_ptl_queue_push(p);
1341c167b9c7SMaximilian Luz 	if (status)
1342c167b9c7SMaximilian Luz 		return status;
1343c167b9c7SMaximilian Luz 
1344c167b9c7SMaximilian Luz 	if (!test_bit(SSH_PACKET_TY_BLOCKING_BIT, &p->state) ||
1345c167b9c7SMaximilian Luz 	    (atomic_read(&ptl->pending.count) < SSH_PTL_MAX_PENDING))
1346c167b9c7SMaximilian Luz 		ssh_ptl_tx_wakeup_packet(ptl);
1347c167b9c7SMaximilian Luz 
1348c167b9c7SMaximilian Luz 	return 0;
1349c167b9c7SMaximilian Luz }
1350c167b9c7SMaximilian Luz 
1351c167b9c7SMaximilian Luz /*
1352c167b9c7SMaximilian Luz  * __ssh_ptl_resubmit() - Re-submit a packet to the transport layer.
1353c167b9c7SMaximilian Luz  * @packet: The packet to re-submit.
1354c167b9c7SMaximilian Luz  *
1355c167b9c7SMaximilian Luz  * Re-submits the given packet: Checks if it can be re-submitted and queues it
1356c167b9c7SMaximilian Luz  * if it can, resetting the packet timestamp in the process. Must be called
1357c167b9c7SMaximilian Luz  * with the pending lock held.
1358c167b9c7SMaximilian Luz  *
1359c167b9c7SMaximilian Luz  * Return: Returns %-ECANCELED if the packet has exceeded its number of tries,
1360c167b9c7SMaximilian Luz  * %-EINVAL if the packet has been locked, %-EALREADY if the packet is already
1361c167b9c7SMaximilian Luz  * on the queue, and %-ESHUTDOWN if the transmission layer has been shut down.
1362c167b9c7SMaximilian Luz  */
__ssh_ptl_resubmit(struct ssh_packet * packet)1363c167b9c7SMaximilian Luz static int __ssh_ptl_resubmit(struct ssh_packet *packet)
1364c167b9c7SMaximilian Luz {
1365c167b9c7SMaximilian Luz 	int status;
1366c167b9c7SMaximilian Luz 	u8 try;
1367c167b9c7SMaximilian Luz 
1368c167b9c7SMaximilian Luz 	lockdep_assert_held(&packet->ptl->pending.lock);
1369c167b9c7SMaximilian Luz 
13700d21bb85SMaximilian Luz 	trace_ssam_packet_resubmit(packet);
13710d21bb85SMaximilian Luz 
1372c167b9c7SMaximilian Luz 	spin_lock(&packet->ptl->queue.lock);
1373c167b9c7SMaximilian Luz 
1374c167b9c7SMaximilian Luz 	/* Check if the packet is out of tries. */
1375c167b9c7SMaximilian Luz 	try = ssh_packet_priority_get_try(packet->priority);
1376c167b9c7SMaximilian Luz 	if (try >= SSH_PTL_MAX_PACKET_TRIES) {
1377c167b9c7SMaximilian Luz 		spin_unlock(&packet->ptl->queue.lock);
1378c167b9c7SMaximilian Luz 		return -ECANCELED;
1379c167b9c7SMaximilian Luz 	}
1380c167b9c7SMaximilian Luz 
1381c167b9c7SMaximilian Luz 	status = __ssh_ptl_queue_push(packet);
1382c167b9c7SMaximilian Luz 	if (status) {
1383c167b9c7SMaximilian Luz 		/*
1384c167b9c7SMaximilian Luz 		 * An error here indicates that the packet has either already
1385c167b9c7SMaximilian Luz 		 * been queued, been locked, or the transport layer is being
1386c167b9c7SMaximilian Luz 		 * shut down. In all cases: Ignore the error.
1387c167b9c7SMaximilian Luz 		 */
1388c167b9c7SMaximilian Luz 		spin_unlock(&packet->ptl->queue.lock);
1389c167b9c7SMaximilian Luz 		return status;
1390c167b9c7SMaximilian Luz 	}
1391c167b9c7SMaximilian Luz 
1392c167b9c7SMaximilian Luz 	packet->timestamp = KTIME_MAX;
1393c167b9c7SMaximilian Luz 
1394c167b9c7SMaximilian Luz 	spin_unlock(&packet->ptl->queue.lock);
1395c167b9c7SMaximilian Luz 	return 0;
1396c167b9c7SMaximilian Luz }
1397c167b9c7SMaximilian Luz 
ssh_ptl_resubmit_pending(struct ssh_ptl * ptl)1398c167b9c7SMaximilian Luz static void ssh_ptl_resubmit_pending(struct ssh_ptl *ptl)
1399c167b9c7SMaximilian Luz {
1400c167b9c7SMaximilian Luz 	struct ssh_packet *p;
1401c167b9c7SMaximilian Luz 	bool resub = false;
1402c167b9c7SMaximilian Luz 
1403c167b9c7SMaximilian Luz 	/*
1404c167b9c7SMaximilian Luz 	 * Note: We deliberately do not remove/attempt to cancel and complete
1405c167b9c7SMaximilian Luz 	 * packets that are out of tires in this function. The packet will be
1406c167b9c7SMaximilian Luz 	 * eventually canceled and completed by the timeout. Removing the packet
1407c167b9c7SMaximilian Luz 	 * here could lead to overly eager cancellation if the packet has not
1408c167b9c7SMaximilian Luz 	 * been re-transmitted yet but the tries-counter already updated (i.e
1409c167b9c7SMaximilian Luz 	 * ssh_ptl_tx_next() removed the packet from the queue and updated the
1410c167b9c7SMaximilian Luz 	 * counter, but re-transmission for the last try has not actually
1411c167b9c7SMaximilian Luz 	 * started yet).
1412c167b9c7SMaximilian Luz 	 */
1413c167b9c7SMaximilian Luz 
1414c167b9c7SMaximilian Luz 	spin_lock(&ptl->pending.lock);
1415c167b9c7SMaximilian Luz 
1416c167b9c7SMaximilian Luz 	/* Re-queue all pending packets. */
1417c167b9c7SMaximilian Luz 	list_for_each_entry(p, &ptl->pending.head, pending_node) {
1418c167b9c7SMaximilian Luz 		/*
1419c167b9c7SMaximilian Luz 		 * Re-submission fails if the packet is out of tries, has been
1420c167b9c7SMaximilian Luz 		 * locked, is already queued, or the layer is being shut down.
1421c167b9c7SMaximilian Luz 		 * No need to re-schedule tx-thread in those cases.
1422c167b9c7SMaximilian Luz 		 */
1423c167b9c7SMaximilian Luz 		if (!__ssh_ptl_resubmit(p))
1424c167b9c7SMaximilian Luz 			resub = true;
1425c167b9c7SMaximilian Luz 	}
1426c167b9c7SMaximilian Luz 
1427c167b9c7SMaximilian Luz 	spin_unlock(&ptl->pending.lock);
1428c167b9c7SMaximilian Luz 
1429c167b9c7SMaximilian Luz 	if (resub)
1430c167b9c7SMaximilian Luz 		ssh_ptl_tx_wakeup_packet(ptl);
1431c167b9c7SMaximilian Luz }
1432c167b9c7SMaximilian Luz 
1433c167b9c7SMaximilian Luz /**
1434c167b9c7SMaximilian Luz  * ssh_ptl_cancel() - Cancel a packet.
1435c167b9c7SMaximilian Luz  * @p: The packet to cancel.
1436c167b9c7SMaximilian Luz  *
1437c167b9c7SMaximilian Luz  * Cancels a packet. There are no guarantees on when completion and release
1438c167b9c7SMaximilian Luz  * callbacks will be called. This may occur during execution of this function
1439c167b9c7SMaximilian Luz  * or may occur at any point later.
1440c167b9c7SMaximilian Luz  *
1441c167b9c7SMaximilian Luz  * Note that it is not guaranteed that the packet will actually be canceled if
1442c167b9c7SMaximilian Luz  * the packet is concurrently completed by another process. The only guarantee
1443c167b9c7SMaximilian Luz  * of this function is that the packet will be completed (with success,
1444c167b9c7SMaximilian Luz  * failure, or cancellation) and released from the transport layer in a
1445c167b9c7SMaximilian Luz  * reasonable time-frame.
1446c167b9c7SMaximilian Luz  *
1447c167b9c7SMaximilian Luz  * May be called before the packet has been submitted, in which case any later
1448c167b9c7SMaximilian Luz  * packet submission fails.
1449c167b9c7SMaximilian Luz  */
ssh_ptl_cancel(struct ssh_packet * p)1450c167b9c7SMaximilian Luz void ssh_ptl_cancel(struct ssh_packet *p)
1451c167b9c7SMaximilian Luz {
1452c167b9c7SMaximilian Luz 	if (test_and_set_bit(SSH_PACKET_SF_CANCELED_BIT, &p->state))
1453c167b9c7SMaximilian Luz 		return;
1454c167b9c7SMaximilian Luz 
14550d21bb85SMaximilian Luz 	trace_ssam_packet_cancel(p);
14560d21bb85SMaximilian Luz 
1457c167b9c7SMaximilian Luz 	/*
1458c167b9c7SMaximilian Luz 	 * Lock packet and commit with memory barrier. If this packet has
1459c167b9c7SMaximilian Luz 	 * already been locked, it's going to be removed and completed by
1460c167b9c7SMaximilian Luz 	 * another party, which should have precedence.
1461c167b9c7SMaximilian Luz 	 */
1462c167b9c7SMaximilian Luz 	if (test_and_set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state))
1463c167b9c7SMaximilian Luz 		return;
1464c167b9c7SMaximilian Luz 
1465c167b9c7SMaximilian Luz 	/*
1466c167b9c7SMaximilian Luz 	 * By marking the packet as locked and employing the implicit memory
1467c167b9c7SMaximilian Luz 	 * barrier of test_and_set_bit, we have guaranteed that, at this point,
1468c167b9c7SMaximilian Luz 	 * the packet cannot be added to the queue any more.
1469c167b9c7SMaximilian Luz 	 *
1470c167b9c7SMaximilian Luz 	 * In case the packet has never been submitted, packet->ptl is NULL. If
1471c167b9c7SMaximilian Luz 	 * the packet is currently being submitted, packet->ptl may be NULL or
1472c167b9c7SMaximilian Luz 	 * non-NULL. Due marking the packet as locked above and committing with
1473c167b9c7SMaximilian Luz 	 * the memory barrier, we have guaranteed that, if packet->ptl is NULL,
1474c167b9c7SMaximilian Luz 	 * the packet will never be added to the queue. If packet->ptl is
1475c167b9c7SMaximilian Luz 	 * non-NULL, we don't have any guarantees.
1476c167b9c7SMaximilian Luz 	 */
1477c167b9c7SMaximilian Luz 
1478c167b9c7SMaximilian Luz 	if (READ_ONCE(p->ptl)) {
1479c167b9c7SMaximilian Luz 		ssh_ptl_remove_and_complete(p, -ECANCELED);
1480c167b9c7SMaximilian Luz 
1481c167b9c7SMaximilian Luz 		if (atomic_read(&p->ptl->pending.count) < SSH_PTL_MAX_PENDING)
1482c167b9c7SMaximilian Luz 			ssh_ptl_tx_wakeup_packet(p->ptl);
1483c167b9c7SMaximilian Luz 
1484c167b9c7SMaximilian Luz 	} else if (!test_and_set_bit(SSH_PACKET_SF_COMPLETED_BIT, &p->state)) {
1485c167b9c7SMaximilian Luz 		__ssh_ptl_complete(p, -ECANCELED);
1486c167b9c7SMaximilian Luz 	}
1487c167b9c7SMaximilian Luz }
1488c167b9c7SMaximilian Luz 
1489c167b9c7SMaximilian Luz /* Must be called with pending lock held */
ssh_packet_get_expiration(struct ssh_packet * p,ktime_t timeout)1490c167b9c7SMaximilian Luz static ktime_t ssh_packet_get_expiration(struct ssh_packet *p, ktime_t timeout)
1491c167b9c7SMaximilian Luz {
1492c167b9c7SMaximilian Luz 	lockdep_assert_held(&p->ptl->pending.lock);
1493c167b9c7SMaximilian Luz 
1494c167b9c7SMaximilian Luz 	if (p->timestamp != KTIME_MAX)
1495c167b9c7SMaximilian Luz 		return ktime_add(p->timestamp, timeout);
1496c167b9c7SMaximilian Luz 	else
1497c167b9c7SMaximilian Luz 		return KTIME_MAX;
1498c167b9c7SMaximilian Luz }
1499c167b9c7SMaximilian Luz 
ssh_ptl_timeout_reap(struct work_struct * work)1500c167b9c7SMaximilian Luz static void ssh_ptl_timeout_reap(struct work_struct *work)
1501c167b9c7SMaximilian Luz {
1502c167b9c7SMaximilian Luz 	struct ssh_ptl *ptl = to_ssh_ptl(work, rtx_timeout.reaper.work);
1503c167b9c7SMaximilian Luz 	struct ssh_packet *p, *n;
1504c167b9c7SMaximilian Luz 	LIST_HEAD(claimed);
1505c167b9c7SMaximilian Luz 	ktime_t now = ktime_get_coarse_boottime();
1506c167b9c7SMaximilian Luz 	ktime_t timeout = ptl->rtx_timeout.timeout;
1507c167b9c7SMaximilian Luz 	ktime_t next = KTIME_MAX;
1508c167b9c7SMaximilian Luz 	bool resub = false;
1509c167b9c7SMaximilian Luz 	int status;
1510c167b9c7SMaximilian Luz 
15110d21bb85SMaximilian Luz 	trace_ssam_ptl_timeout_reap(atomic_read(&ptl->pending.count));
15120d21bb85SMaximilian Luz 
1513c167b9c7SMaximilian Luz 	/*
1514c167b9c7SMaximilian Luz 	 * Mark reaper as "not pending". This is done before checking any
1515c167b9c7SMaximilian Luz 	 * packets to avoid lost-update type problems.
1516c167b9c7SMaximilian Luz 	 */
1517c167b9c7SMaximilian Luz 	spin_lock(&ptl->rtx_timeout.lock);
1518c167b9c7SMaximilian Luz 	ptl->rtx_timeout.expires = KTIME_MAX;
1519c167b9c7SMaximilian Luz 	spin_unlock(&ptl->rtx_timeout.lock);
1520c167b9c7SMaximilian Luz 
1521c167b9c7SMaximilian Luz 	spin_lock(&ptl->pending.lock);
1522c167b9c7SMaximilian Luz 
1523c167b9c7SMaximilian Luz 	list_for_each_entry_safe(p, n, &ptl->pending.head, pending_node) {
1524c167b9c7SMaximilian Luz 		ktime_t expires = ssh_packet_get_expiration(p, timeout);
1525c167b9c7SMaximilian Luz 
1526c167b9c7SMaximilian Luz 		/*
1527c167b9c7SMaximilian Luz 		 * Check if the timeout hasn't expired yet. Find out next
1528c167b9c7SMaximilian Luz 		 * expiration date to be handled after this run.
1529c167b9c7SMaximilian Luz 		 */
1530c167b9c7SMaximilian Luz 		if (ktime_after(expires, now)) {
1531c167b9c7SMaximilian Luz 			next = ktime_before(expires, next) ? expires : next;
1532c167b9c7SMaximilian Luz 			continue;
1533c167b9c7SMaximilian Luz 		}
1534c167b9c7SMaximilian Luz 
15350d21bb85SMaximilian Luz 		trace_ssam_packet_timeout(p);
15360d21bb85SMaximilian Luz 
1537c167b9c7SMaximilian Luz 		status = __ssh_ptl_resubmit(p);
1538c167b9c7SMaximilian Luz 
1539c167b9c7SMaximilian Luz 		/*
1540c167b9c7SMaximilian Luz 		 * Re-submission fails if the packet is out of tries, has been
1541c167b9c7SMaximilian Luz 		 * locked, is already queued, or the layer is being shut down.
1542c167b9c7SMaximilian Luz 		 * No need to re-schedule tx-thread in those cases.
1543c167b9c7SMaximilian Luz 		 */
1544c167b9c7SMaximilian Luz 		if (!status)
1545c167b9c7SMaximilian Luz 			resub = true;
1546c167b9c7SMaximilian Luz 
1547c167b9c7SMaximilian Luz 		/* Go to next packet if this packet is not out of tries. */
1548c167b9c7SMaximilian Luz 		if (status != -ECANCELED)
1549c167b9c7SMaximilian Luz 			continue;
1550c167b9c7SMaximilian Luz 
1551c167b9c7SMaximilian Luz 		/* No more tries left: Cancel the packet. */
1552c167b9c7SMaximilian Luz 
1553c167b9c7SMaximilian Luz 		/*
1554c167b9c7SMaximilian Luz 		 * If someone else has locked the packet already, don't use it
1555c167b9c7SMaximilian Luz 		 * and let the other party complete it.
1556c167b9c7SMaximilian Luz 		 */
1557c167b9c7SMaximilian Luz 		if (test_and_set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state))
1558c167b9c7SMaximilian Luz 			continue;
1559c167b9c7SMaximilian Luz 
1560c167b9c7SMaximilian Luz 		/*
1561c167b9c7SMaximilian Luz 		 * We have now marked the packet as locked. Thus it cannot be
1562c167b9c7SMaximilian Luz 		 * added to the pending list again after we've removed it here.
1563c167b9c7SMaximilian Luz 		 * We can therefore re-use the pending_node of this packet
1564c167b9c7SMaximilian Luz 		 * temporarily.
1565c167b9c7SMaximilian Luz 		 */
1566c167b9c7SMaximilian Luz 
1567c167b9c7SMaximilian Luz 		clear_bit(SSH_PACKET_SF_PENDING_BIT, &p->state);
1568c167b9c7SMaximilian Luz 
1569c167b9c7SMaximilian Luz 		atomic_dec(&ptl->pending.count);
1570be9c4fa2SBaokun Li 		list_move_tail(&p->pending_node, &claimed);
1571c167b9c7SMaximilian Luz 	}
1572c167b9c7SMaximilian Luz 
1573c167b9c7SMaximilian Luz 	spin_unlock(&ptl->pending.lock);
1574c167b9c7SMaximilian Luz 
1575c167b9c7SMaximilian Luz 	/* Cancel and complete the packet. */
1576c167b9c7SMaximilian Luz 	list_for_each_entry_safe(p, n, &claimed, pending_node) {
1577c167b9c7SMaximilian Luz 		if (!test_and_set_bit(SSH_PACKET_SF_COMPLETED_BIT, &p->state)) {
1578c167b9c7SMaximilian Luz 			ssh_ptl_queue_remove(p);
1579c167b9c7SMaximilian Luz 			__ssh_ptl_complete(p, -ETIMEDOUT);
1580c167b9c7SMaximilian Luz 		}
1581c167b9c7SMaximilian Luz 
1582c167b9c7SMaximilian Luz 		/*
1583c167b9c7SMaximilian Luz 		 * Drop the reference we've obtained by removing it from
1584c167b9c7SMaximilian Luz 		 * the pending set.
1585c167b9c7SMaximilian Luz 		 */
1586c167b9c7SMaximilian Luz 		list_del(&p->pending_node);
1587c167b9c7SMaximilian Luz 		ssh_packet_put(p);
1588c167b9c7SMaximilian Luz 	}
1589c167b9c7SMaximilian Luz 
1590c167b9c7SMaximilian Luz 	/* Ensure that reaper doesn't run again immediately. */
1591c167b9c7SMaximilian Luz 	next = max(next, ktime_add(now, SSH_PTL_PACKET_TIMEOUT_RESOLUTION));
1592c167b9c7SMaximilian Luz 	if (next != KTIME_MAX)
1593c167b9c7SMaximilian Luz 		ssh_ptl_timeout_reaper_mod(ptl, now, next);
1594c167b9c7SMaximilian Luz 
1595c167b9c7SMaximilian Luz 	if (resub)
1596c167b9c7SMaximilian Luz 		ssh_ptl_tx_wakeup_packet(ptl);
1597c167b9c7SMaximilian Luz }
1598c167b9c7SMaximilian Luz 
ssh_ptl_rx_retransmit_check(struct ssh_ptl * ptl,const struct ssh_frame * frame)1599*d9a477f6SMaximilian Luz static bool ssh_ptl_rx_retransmit_check(struct ssh_ptl *ptl, const struct ssh_frame *frame)
1600c167b9c7SMaximilian Luz {
1601c167b9c7SMaximilian Luz 	int i;
1602c167b9c7SMaximilian Luz 
1603c167b9c7SMaximilian Luz 	/*
1604*d9a477f6SMaximilian Luz 	 * Ignore unsequenced packets. On some devices (notably Surface Pro 9),
1605*d9a477f6SMaximilian Luz 	 * unsequenced events will always be sent with SEQ=0x00. Attempting to
1606*d9a477f6SMaximilian Luz 	 * detect retransmission would thus just block all events.
1607*d9a477f6SMaximilian Luz 	 *
1608*d9a477f6SMaximilian Luz 	 * While sequence numbers would also allow detection of retransmitted
1609*d9a477f6SMaximilian Luz 	 * packets in unsequenced communication, they have only ever been used
1610*d9a477f6SMaximilian Luz 	 * to cover edge-cases in sequenced transmission. In particular, the
1611*d9a477f6SMaximilian Luz 	 * only instance of packets being retransmitted (that we are aware of)
1612*d9a477f6SMaximilian Luz 	 * is due to an ACK timeout. As this does not happen in unsequenced
1613*d9a477f6SMaximilian Luz 	 * communication, skip the retransmission check for those packets
1614*d9a477f6SMaximilian Luz 	 * entirely.
1615*d9a477f6SMaximilian Luz 	 */
1616*d9a477f6SMaximilian Luz 	if (frame->type == SSH_FRAME_TYPE_DATA_NSQ)
1617*d9a477f6SMaximilian Luz 		return false;
1618*d9a477f6SMaximilian Luz 
1619*d9a477f6SMaximilian Luz 	/*
1620c167b9c7SMaximilian Luz 	 * Check if SEQ has been seen recently (i.e. packet was
1621c167b9c7SMaximilian Luz 	 * re-transmitted and we should ignore it).
1622c167b9c7SMaximilian Luz 	 */
1623c167b9c7SMaximilian Luz 	for (i = 0; i < ARRAY_SIZE(ptl->rx.blocked.seqs); i++) {
1624*d9a477f6SMaximilian Luz 		if (likely(ptl->rx.blocked.seqs[i] != frame->seq))
1625c167b9c7SMaximilian Luz 			continue;
1626c167b9c7SMaximilian Luz 
1627c167b9c7SMaximilian Luz 		ptl_dbg(ptl, "ptl: ignoring repeated data packet\n");
1628c167b9c7SMaximilian Luz 		return true;
1629c167b9c7SMaximilian Luz 	}
1630c167b9c7SMaximilian Luz 
1631c167b9c7SMaximilian Luz 	/* Update list of blocked sequence IDs. */
1632*d9a477f6SMaximilian Luz 	ptl->rx.blocked.seqs[ptl->rx.blocked.offset] = frame->seq;
1633c167b9c7SMaximilian Luz 	ptl->rx.blocked.offset = (ptl->rx.blocked.offset + 1)
1634c167b9c7SMaximilian Luz 				  % ARRAY_SIZE(ptl->rx.blocked.seqs);
1635c167b9c7SMaximilian Luz 
1636c167b9c7SMaximilian Luz 	return false;
1637c167b9c7SMaximilian Luz }
1638c167b9c7SMaximilian Luz 
ssh_ptl_rx_dataframe(struct ssh_ptl * ptl,const struct ssh_frame * frame,const struct ssam_span * payload)1639c167b9c7SMaximilian Luz static void ssh_ptl_rx_dataframe(struct ssh_ptl *ptl,
1640c167b9c7SMaximilian Luz 				 const struct ssh_frame *frame,
1641c167b9c7SMaximilian Luz 				 const struct ssam_span *payload)
1642c167b9c7SMaximilian Luz {
1643*d9a477f6SMaximilian Luz 	if (ssh_ptl_rx_retransmit_check(ptl, frame))
1644c167b9c7SMaximilian Luz 		return;
1645c167b9c7SMaximilian Luz 
1646c167b9c7SMaximilian Luz 	ptl->ops.data_received(ptl, payload);
1647c167b9c7SMaximilian Luz }
1648c167b9c7SMaximilian Luz 
ssh_ptl_send_ack(struct ssh_ptl * ptl,u8 seq)1649c167b9c7SMaximilian Luz static void ssh_ptl_send_ack(struct ssh_ptl *ptl, u8 seq)
1650c167b9c7SMaximilian Luz {
1651c167b9c7SMaximilian Luz 	struct ssh_packet *packet;
1652c167b9c7SMaximilian Luz 	struct ssam_span buf;
1653c167b9c7SMaximilian Luz 	struct msgbuf msgb;
1654c167b9c7SMaximilian Luz 	int status;
1655c167b9c7SMaximilian Luz 
1656c167b9c7SMaximilian Luz 	status = ssh_ctrl_packet_alloc(&packet, &buf, GFP_KERNEL);
1657c167b9c7SMaximilian Luz 	if (status) {
1658c167b9c7SMaximilian Luz 		ptl_err(ptl, "ptl: failed to allocate ACK packet\n");
1659c167b9c7SMaximilian Luz 		return;
1660c167b9c7SMaximilian Luz 	}
1661c167b9c7SMaximilian Luz 
1662c167b9c7SMaximilian Luz 	ssh_packet_init(packet, 0, SSH_PACKET_PRIORITY(ACK, 0),
1663c167b9c7SMaximilian Luz 			&ssh_ptl_ctrl_packet_ops);
1664c167b9c7SMaximilian Luz 
1665c167b9c7SMaximilian Luz 	msgb_init(&msgb, buf.ptr, buf.len);
1666c167b9c7SMaximilian Luz 	msgb_push_ack(&msgb, seq);
1667c167b9c7SMaximilian Luz 	ssh_packet_set_data(packet, msgb.begin, msgb_bytes_used(&msgb));
1668c167b9c7SMaximilian Luz 
1669c167b9c7SMaximilian Luz 	ssh_ptl_submit(ptl, packet);
1670c167b9c7SMaximilian Luz 	ssh_packet_put(packet);
1671c167b9c7SMaximilian Luz }
1672c167b9c7SMaximilian Luz 
ssh_ptl_send_nak(struct ssh_ptl * ptl)1673c167b9c7SMaximilian Luz static void ssh_ptl_send_nak(struct ssh_ptl *ptl)
1674c167b9c7SMaximilian Luz {
1675c167b9c7SMaximilian Luz 	struct ssh_packet *packet;
1676c167b9c7SMaximilian Luz 	struct ssam_span buf;
1677c167b9c7SMaximilian Luz 	struct msgbuf msgb;
1678c167b9c7SMaximilian Luz 	int status;
1679c167b9c7SMaximilian Luz 
1680c167b9c7SMaximilian Luz 	status = ssh_ctrl_packet_alloc(&packet, &buf, GFP_KERNEL);
1681c167b9c7SMaximilian Luz 	if (status) {
1682c167b9c7SMaximilian Luz 		ptl_err(ptl, "ptl: failed to allocate NAK packet\n");
1683c167b9c7SMaximilian Luz 		return;
1684c167b9c7SMaximilian Luz 	}
1685c167b9c7SMaximilian Luz 
1686c167b9c7SMaximilian Luz 	ssh_packet_init(packet, 0, SSH_PACKET_PRIORITY(NAK, 0),
1687c167b9c7SMaximilian Luz 			&ssh_ptl_ctrl_packet_ops);
1688c167b9c7SMaximilian Luz 
1689c167b9c7SMaximilian Luz 	msgb_init(&msgb, buf.ptr, buf.len);
1690c167b9c7SMaximilian Luz 	msgb_push_nak(&msgb);
1691c167b9c7SMaximilian Luz 	ssh_packet_set_data(packet, msgb.begin, msgb_bytes_used(&msgb));
1692c167b9c7SMaximilian Luz 
1693c167b9c7SMaximilian Luz 	ssh_ptl_submit(ptl, packet);
1694c167b9c7SMaximilian Luz 	ssh_packet_put(packet);
1695c167b9c7SMaximilian Luz }
1696c167b9c7SMaximilian Luz 
ssh_ptl_rx_eval(struct ssh_ptl * ptl,struct ssam_span * source)1697c167b9c7SMaximilian Luz static size_t ssh_ptl_rx_eval(struct ssh_ptl *ptl, struct ssam_span *source)
1698c167b9c7SMaximilian Luz {
1699c167b9c7SMaximilian Luz 	struct ssh_frame *frame;
1700c167b9c7SMaximilian Luz 	struct ssam_span payload;
1701c167b9c7SMaximilian Luz 	struct ssam_span aligned;
1702c167b9c7SMaximilian Luz 	bool syn_found;
1703c167b9c7SMaximilian Luz 	int status;
1704c167b9c7SMaximilian Luz 
170502be44f6SMaximilian Luz 	/* Error injection: Modify data to simulate corrupt SYN bytes. */
170602be44f6SMaximilian Luz 	ssh_ptl_rx_inject_invalid_syn(ptl, source);
170702be44f6SMaximilian Luz 
1708c167b9c7SMaximilian Luz 	/* Find SYN. */
1709c167b9c7SMaximilian Luz 	syn_found = sshp_find_syn(source, &aligned);
1710c167b9c7SMaximilian Luz 
17112691d0aeSMaximilian Luz 	if (unlikely(aligned.ptr != source->ptr)) {
17122691d0aeSMaximilian Luz 		/*
17132691d0aeSMaximilian Luz 		 * We expect aligned.ptr == source->ptr. If this is not the
17142691d0aeSMaximilian Luz 		 * case, then aligned.ptr > source->ptr and we've encountered
17152691d0aeSMaximilian Luz 		 * some unexpected data where we'd expect the start of a new
17162691d0aeSMaximilian Luz 		 * message (i.e. the SYN sequence).
17172691d0aeSMaximilian Luz 		 *
17182691d0aeSMaximilian Luz 		 * This can happen when a CRC check for the previous message
17192691d0aeSMaximilian Luz 		 * failed and we start actively searching for the next one
17202691d0aeSMaximilian Luz 		 * (via the call to sshp_find_syn() above), or the first bytes
17212691d0aeSMaximilian Luz 		 * of a message got dropped or corrupted.
17222691d0aeSMaximilian Luz 		 *
17232691d0aeSMaximilian Luz 		 * In any case, we issue a warning, send a NAK to the EC to
17242691d0aeSMaximilian Luz 		 * request re-transmission of any data we haven't acknowledged
17252691d0aeSMaximilian Luz 		 * yet, and finally, skip everything up to the next SYN
17262691d0aeSMaximilian Luz 		 * sequence.
17272691d0aeSMaximilian Luz 		 */
17282691d0aeSMaximilian Luz 
1729c167b9c7SMaximilian Luz 		ptl_warn(ptl, "rx: parser: invalid start of frame, skipping\n");
1730c167b9c7SMaximilian Luz 
1731c167b9c7SMaximilian Luz 		/*
1732c167b9c7SMaximilian Luz 		 * Notes:
1733c167b9c7SMaximilian Luz 		 * - This might send multiple NAKs in case the communication
1734c167b9c7SMaximilian Luz 		 *   starts with an invalid SYN and is broken down into multiple
1735c167b9c7SMaximilian Luz 		 *   pieces. This should generally be handled fine, we just
1736c167b9c7SMaximilian Luz 		 *   might receive duplicate data in this case, which is
1737c167b9c7SMaximilian Luz 		 *   detected when handling data frames.
1738c167b9c7SMaximilian Luz 		 * - This path will also be executed on invalid CRCs: When an
1739c167b9c7SMaximilian Luz 		 *   invalid CRC is encountered, the code below will skip data
1740c167b9c7SMaximilian Luz 		 *   until directly after the SYN. This causes the search for
1741c167b9c7SMaximilian Luz 		 *   the next SYN, which is generally not placed directly after
1742c167b9c7SMaximilian Luz 		 *   the last one.
1743c167b9c7SMaximilian Luz 		 *
1744c167b9c7SMaximilian Luz 		 *   Open question: Should we send this in case of invalid
1745c167b9c7SMaximilian Luz 		 *   payload CRCs if the frame-type is non-sequential (current
1746c167b9c7SMaximilian Luz 		 *   implementation) or should we drop that frame without
1747c167b9c7SMaximilian Luz 		 *   telling the EC?
1748c167b9c7SMaximilian Luz 		 */
1749c167b9c7SMaximilian Luz 		ssh_ptl_send_nak(ptl);
1750c167b9c7SMaximilian Luz 	}
1751c167b9c7SMaximilian Luz 
1752c167b9c7SMaximilian Luz 	if (unlikely(!syn_found))
1753c167b9c7SMaximilian Luz 		return aligned.ptr - source->ptr;
1754c167b9c7SMaximilian Luz 
175502be44f6SMaximilian Luz 	/* Error injection: Modify data to simulate corruption. */
175602be44f6SMaximilian Luz 	ssh_ptl_rx_inject_invalid_data(ptl, &aligned);
175702be44f6SMaximilian Luz 
1758c167b9c7SMaximilian Luz 	/* Parse and validate frame. */
1759c167b9c7SMaximilian Luz 	status = sshp_parse_frame(&ptl->serdev->dev, &aligned, &frame, &payload,
1760c167b9c7SMaximilian Luz 				  SSH_PTL_RX_BUF_LEN);
1761c167b9c7SMaximilian Luz 	if (status)	/* Invalid frame: skip to next SYN. */
1762c167b9c7SMaximilian Luz 		return aligned.ptr - source->ptr + sizeof(u16);
1763c167b9c7SMaximilian Luz 	if (!frame)	/* Not enough data. */
1764c167b9c7SMaximilian Luz 		return aligned.ptr - source->ptr;
1765c167b9c7SMaximilian Luz 
17660d21bb85SMaximilian Luz 	trace_ssam_rx_frame_received(frame);
17670d21bb85SMaximilian Luz 
1768c167b9c7SMaximilian Luz 	switch (frame->type) {
1769c167b9c7SMaximilian Luz 	case SSH_FRAME_TYPE_ACK:
1770c167b9c7SMaximilian Luz 		ssh_ptl_acknowledge(ptl, frame->seq);
1771c167b9c7SMaximilian Luz 		break;
1772c167b9c7SMaximilian Luz 
1773c167b9c7SMaximilian Luz 	case SSH_FRAME_TYPE_NAK:
1774c167b9c7SMaximilian Luz 		ssh_ptl_resubmit_pending(ptl);
1775c167b9c7SMaximilian Luz 		break;
1776c167b9c7SMaximilian Luz 
1777c167b9c7SMaximilian Luz 	case SSH_FRAME_TYPE_DATA_SEQ:
1778c167b9c7SMaximilian Luz 		ssh_ptl_send_ack(ptl, frame->seq);
1779c167b9c7SMaximilian Luz 		fallthrough;
1780c167b9c7SMaximilian Luz 
1781c167b9c7SMaximilian Luz 	case SSH_FRAME_TYPE_DATA_NSQ:
1782c167b9c7SMaximilian Luz 		ssh_ptl_rx_dataframe(ptl, frame, &payload);
1783c167b9c7SMaximilian Luz 		break;
1784c167b9c7SMaximilian Luz 
1785c167b9c7SMaximilian Luz 	default:
1786c167b9c7SMaximilian Luz 		ptl_warn(ptl, "ptl: received frame with unknown type %#04x\n",
1787c167b9c7SMaximilian Luz 			 frame->type);
1788c167b9c7SMaximilian Luz 		break;
1789c167b9c7SMaximilian Luz 	}
1790c167b9c7SMaximilian Luz 
179186eb98cbSMaximilian Luz 	return aligned.ptr - source->ptr + SSH_MESSAGE_LENGTH(payload.len);
1792c167b9c7SMaximilian Luz }
1793c167b9c7SMaximilian Luz 
ssh_ptl_rx_threadfn(void * data)1794c167b9c7SMaximilian Luz static int ssh_ptl_rx_threadfn(void *data)
1795c167b9c7SMaximilian Luz {
1796c167b9c7SMaximilian Luz 	struct ssh_ptl *ptl = data;
1797c167b9c7SMaximilian Luz 
1798c167b9c7SMaximilian Luz 	while (true) {
1799c167b9c7SMaximilian Luz 		struct ssam_span span;
1800c167b9c7SMaximilian Luz 		size_t offs = 0;
1801c167b9c7SMaximilian Luz 		size_t n;
1802c167b9c7SMaximilian Luz 
1803c167b9c7SMaximilian Luz 		wait_event_interruptible(ptl->rx.wq,
1804c167b9c7SMaximilian Luz 					 !kfifo_is_empty(&ptl->rx.fifo) ||
1805c167b9c7SMaximilian Luz 					 kthread_should_stop());
1806c167b9c7SMaximilian Luz 		if (kthread_should_stop())
1807c167b9c7SMaximilian Luz 			break;
1808c167b9c7SMaximilian Luz 
1809c167b9c7SMaximilian Luz 		/* Copy from fifo to evaluation buffer. */
1810c167b9c7SMaximilian Luz 		n = sshp_buf_read_from_fifo(&ptl->rx.buf, &ptl->rx.fifo);
1811c167b9c7SMaximilian Luz 
1812c167b9c7SMaximilian Luz 		ptl_dbg(ptl, "rx: received data (size: %zu)\n", n);
1813c167b9c7SMaximilian Luz 		print_hex_dump_debug("rx: ", DUMP_PREFIX_OFFSET, 16, 1,
1814c167b9c7SMaximilian Luz 				     ptl->rx.buf.ptr + ptl->rx.buf.len - n,
1815c167b9c7SMaximilian Luz 				     n, false);
1816c167b9c7SMaximilian Luz 
1817c167b9c7SMaximilian Luz 		/* Parse until we need more bytes or buffer is empty. */
1818c167b9c7SMaximilian Luz 		while (offs < ptl->rx.buf.len) {
1819c167b9c7SMaximilian Luz 			sshp_buf_span_from(&ptl->rx.buf, offs, &span);
1820c167b9c7SMaximilian Luz 			n = ssh_ptl_rx_eval(ptl, &span);
1821c167b9c7SMaximilian Luz 			if (n == 0)
1822c167b9c7SMaximilian Luz 				break;	/* Need more bytes. */
1823c167b9c7SMaximilian Luz 
1824c167b9c7SMaximilian Luz 			offs += n;
1825c167b9c7SMaximilian Luz 		}
1826c167b9c7SMaximilian Luz 
1827c167b9c7SMaximilian Luz 		/* Throw away the evaluated parts. */
1828c167b9c7SMaximilian Luz 		sshp_buf_drop(&ptl->rx.buf, offs);
1829c167b9c7SMaximilian Luz 	}
1830c167b9c7SMaximilian Luz 
1831c167b9c7SMaximilian Luz 	return 0;
1832c167b9c7SMaximilian Luz }
1833c167b9c7SMaximilian Luz 
ssh_ptl_rx_wakeup(struct ssh_ptl * ptl)1834c167b9c7SMaximilian Luz static void ssh_ptl_rx_wakeup(struct ssh_ptl *ptl)
1835c167b9c7SMaximilian Luz {
1836c167b9c7SMaximilian Luz 	wake_up(&ptl->rx.wq);
1837c167b9c7SMaximilian Luz }
1838c167b9c7SMaximilian Luz 
1839c167b9c7SMaximilian Luz /**
1840c167b9c7SMaximilian Luz  * ssh_ptl_rx_start() - Start packet transport layer receiver thread.
1841c167b9c7SMaximilian Luz  * @ptl: The packet transport layer.
1842c167b9c7SMaximilian Luz  *
1843c167b9c7SMaximilian Luz  * Return: Returns zero on success, a negative error code on failure.
1844c167b9c7SMaximilian Luz  */
ssh_ptl_rx_start(struct ssh_ptl * ptl)1845c167b9c7SMaximilian Luz int ssh_ptl_rx_start(struct ssh_ptl *ptl)
1846c167b9c7SMaximilian Luz {
1847c167b9c7SMaximilian Luz 	if (ptl->rx.thread)
1848c167b9c7SMaximilian Luz 		return 0;
1849c167b9c7SMaximilian Luz 
1850c167b9c7SMaximilian Luz 	ptl->rx.thread = kthread_run(ssh_ptl_rx_threadfn, ptl,
1851c167b9c7SMaximilian Luz 				     "ssam_serial_hub-rx");
1852c167b9c7SMaximilian Luz 	if (IS_ERR(ptl->rx.thread))
1853c167b9c7SMaximilian Luz 		return PTR_ERR(ptl->rx.thread);
1854c167b9c7SMaximilian Luz 
1855c167b9c7SMaximilian Luz 	return 0;
1856c167b9c7SMaximilian Luz }
1857c167b9c7SMaximilian Luz 
1858c167b9c7SMaximilian Luz /**
1859c167b9c7SMaximilian Luz  * ssh_ptl_rx_stop() - Stop packet transport layer receiver thread.
1860c167b9c7SMaximilian Luz  * @ptl: The packet transport layer.
1861c167b9c7SMaximilian Luz  *
1862c167b9c7SMaximilian Luz  * Return: Returns zero on success, a negative error code on failure.
1863c167b9c7SMaximilian Luz  */
ssh_ptl_rx_stop(struct ssh_ptl * ptl)1864c167b9c7SMaximilian Luz int ssh_ptl_rx_stop(struct ssh_ptl *ptl)
1865c167b9c7SMaximilian Luz {
1866c167b9c7SMaximilian Luz 	int status = 0;
1867c167b9c7SMaximilian Luz 
1868c167b9c7SMaximilian Luz 	if (ptl->rx.thread) {
1869c167b9c7SMaximilian Luz 		status = kthread_stop(ptl->rx.thread);
1870c167b9c7SMaximilian Luz 		ptl->rx.thread = NULL;
1871c167b9c7SMaximilian Luz 	}
1872c167b9c7SMaximilian Luz 
1873c167b9c7SMaximilian Luz 	return status;
1874c167b9c7SMaximilian Luz }
1875c167b9c7SMaximilian Luz 
1876c167b9c7SMaximilian Luz /**
1877c167b9c7SMaximilian Luz  * ssh_ptl_rx_rcvbuf() - Push data from lower-layer transport to the packet
1878c167b9c7SMaximilian Luz  * layer.
1879c167b9c7SMaximilian Luz  * @ptl: The packet transport layer.
1880c167b9c7SMaximilian Luz  * @buf: Pointer to the data to push to the layer.
1881c167b9c7SMaximilian Luz  * @n:   Size of the data to push to the layer, in bytes.
1882c167b9c7SMaximilian Luz  *
1883c167b9c7SMaximilian Luz  * Pushes data from a lower-layer transport to the receiver fifo buffer of the
1884c167b9c7SMaximilian Luz  * packet layer and notifies the receiver thread. Calls to this function are
1885c167b9c7SMaximilian Luz  * ignored once the packet layer has been shut down.
1886c167b9c7SMaximilian Luz  *
1887c167b9c7SMaximilian Luz  * Return: Returns the number of bytes transferred (positive or zero) on
1888c167b9c7SMaximilian Luz  * success. Returns %-ESHUTDOWN if the packet layer has been shut down.
1889c167b9c7SMaximilian Luz  */
ssh_ptl_rx_rcvbuf(struct ssh_ptl * ptl,const u8 * buf,size_t n)1890c167b9c7SMaximilian Luz int ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n)
1891c167b9c7SMaximilian Luz {
1892c167b9c7SMaximilian Luz 	int used;
1893c167b9c7SMaximilian Luz 
1894c167b9c7SMaximilian Luz 	if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state))
1895c167b9c7SMaximilian Luz 		return -ESHUTDOWN;
1896c167b9c7SMaximilian Luz 
1897c167b9c7SMaximilian Luz 	used = kfifo_in(&ptl->rx.fifo, buf, n);
1898c167b9c7SMaximilian Luz 	if (used)
1899c167b9c7SMaximilian Luz 		ssh_ptl_rx_wakeup(ptl);
1900c167b9c7SMaximilian Luz 
1901c167b9c7SMaximilian Luz 	return used;
1902c167b9c7SMaximilian Luz }
1903c167b9c7SMaximilian Luz 
1904c167b9c7SMaximilian Luz /**
1905c167b9c7SMaximilian Luz  * ssh_ptl_shutdown() - Shut down the packet transport layer.
1906c167b9c7SMaximilian Luz  * @ptl: The packet transport layer.
1907c167b9c7SMaximilian Luz  *
1908c167b9c7SMaximilian Luz  * Shuts down the packet transport layer, removing and canceling all queued
1909c167b9c7SMaximilian Luz  * and pending packets. Packets canceled by this operation will be completed
1910c167b9c7SMaximilian Luz  * with %-ESHUTDOWN as status. Receiver and transmitter threads will be
1911c167b9c7SMaximilian Luz  * stopped.
1912c167b9c7SMaximilian Luz  *
1913c167b9c7SMaximilian Luz  * As a result of this function, the transport layer will be marked as shut
1914c167b9c7SMaximilian Luz  * down. Submission of packets after the transport layer has been shut down
1915c167b9c7SMaximilian Luz  * will fail with %-ESHUTDOWN.
1916c167b9c7SMaximilian Luz  */
ssh_ptl_shutdown(struct ssh_ptl * ptl)1917c167b9c7SMaximilian Luz void ssh_ptl_shutdown(struct ssh_ptl *ptl)
1918c167b9c7SMaximilian Luz {
1919c167b9c7SMaximilian Luz 	LIST_HEAD(complete_q);
1920c167b9c7SMaximilian Luz 	LIST_HEAD(complete_p);
1921c167b9c7SMaximilian Luz 	struct ssh_packet *p, *n;
1922c167b9c7SMaximilian Luz 	int status;
1923c167b9c7SMaximilian Luz 
1924c167b9c7SMaximilian Luz 	/* Ensure that no new packets (including ACK/NAK) can be submitted. */
1925c167b9c7SMaximilian Luz 	set_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state);
1926c167b9c7SMaximilian Luz 	/*
1927c167b9c7SMaximilian Luz 	 * Ensure that the layer gets marked as shut-down before actually
1928c167b9c7SMaximilian Luz 	 * stopping it. In combination with the check in ssh_ptl_queue_push(),
1929c167b9c7SMaximilian Luz 	 * this guarantees that no new packets can be added and all already
1930c167b9c7SMaximilian Luz 	 * queued packets are properly canceled. In combination with the check
1931c167b9c7SMaximilian Luz 	 * in ssh_ptl_rx_rcvbuf(), this guarantees that received data is
1932c167b9c7SMaximilian Luz 	 * properly cut off.
1933c167b9c7SMaximilian Luz 	 */
1934c167b9c7SMaximilian Luz 	smp_mb__after_atomic();
1935c167b9c7SMaximilian Luz 
1936c167b9c7SMaximilian Luz 	status = ssh_ptl_rx_stop(ptl);
1937c167b9c7SMaximilian Luz 	if (status)
1938c167b9c7SMaximilian Luz 		ptl_err(ptl, "ptl: failed to stop receiver thread\n");
1939c167b9c7SMaximilian Luz 
1940c167b9c7SMaximilian Luz 	status = ssh_ptl_tx_stop(ptl);
1941c167b9c7SMaximilian Luz 	if (status)
1942c167b9c7SMaximilian Luz 		ptl_err(ptl, "ptl: failed to stop transmitter thread\n");
1943c167b9c7SMaximilian Luz 
1944c167b9c7SMaximilian Luz 	cancel_delayed_work_sync(&ptl->rtx_timeout.reaper);
1945c167b9c7SMaximilian Luz 
1946c167b9c7SMaximilian Luz 	/*
1947c167b9c7SMaximilian Luz 	 * At this point, all threads have been stopped. This means that the
1948c167b9c7SMaximilian Luz 	 * only references to packets from inside the system are in the queue
1949c167b9c7SMaximilian Luz 	 * and pending set.
1950c167b9c7SMaximilian Luz 	 *
1951c167b9c7SMaximilian Luz 	 * Note: We still need locks here because someone could still be
1952c167b9c7SMaximilian Luz 	 * canceling packets.
1953c167b9c7SMaximilian Luz 	 *
1954c167b9c7SMaximilian Luz 	 * Note 2: We can re-use queue_node (or pending_node) if we mark the
1955c167b9c7SMaximilian Luz 	 * packet as locked an then remove it from the queue (or pending set
1956c167b9c7SMaximilian Luz 	 * respectively). Marking the packet as locked avoids re-queuing
1957c167b9c7SMaximilian Luz 	 * (which should already be prevented by having stopped the treads...)
1958c167b9c7SMaximilian Luz 	 * and not setting QUEUED_BIT (or PENDING_BIT) prevents removal from a
1959c167b9c7SMaximilian Luz 	 * new list via other threads (e.g. cancellation).
1960c167b9c7SMaximilian Luz 	 *
1961c167b9c7SMaximilian Luz 	 * Note 3: There may be overlap between complete_p and complete_q.
1962c167b9c7SMaximilian Luz 	 * This is handled via test_and_set_bit() on the "completed" flag
1963c167b9c7SMaximilian Luz 	 * (also handles cancellation).
1964c167b9c7SMaximilian Luz 	 */
1965c167b9c7SMaximilian Luz 
1966c167b9c7SMaximilian Luz 	/* Mark queued packets as locked and move them to complete_q. */
1967c167b9c7SMaximilian Luz 	spin_lock(&ptl->queue.lock);
1968c167b9c7SMaximilian Luz 	list_for_each_entry_safe(p, n, &ptl->queue.head, queue_node) {
1969c167b9c7SMaximilian Luz 		set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state);
1970c167b9c7SMaximilian Luz 		/* Ensure that state does not get zero. */
1971c167b9c7SMaximilian Luz 		smp_mb__before_atomic();
1972c167b9c7SMaximilian Luz 		clear_bit(SSH_PACKET_SF_QUEUED_BIT, &p->state);
1973c167b9c7SMaximilian Luz 
1974be9c4fa2SBaokun Li 		list_move_tail(&p->queue_node, &complete_q);
1975c167b9c7SMaximilian Luz 	}
1976c167b9c7SMaximilian Luz 	spin_unlock(&ptl->queue.lock);
1977c167b9c7SMaximilian Luz 
1978c167b9c7SMaximilian Luz 	/* Mark pending packets as locked and move them to complete_p. */
1979c167b9c7SMaximilian Luz 	spin_lock(&ptl->pending.lock);
1980c167b9c7SMaximilian Luz 	list_for_each_entry_safe(p, n, &ptl->pending.head, pending_node) {
1981c167b9c7SMaximilian Luz 		set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state);
1982c167b9c7SMaximilian Luz 		/* Ensure that state does not get zero. */
1983c167b9c7SMaximilian Luz 		smp_mb__before_atomic();
1984c167b9c7SMaximilian Luz 		clear_bit(SSH_PACKET_SF_PENDING_BIT, &p->state);
1985c167b9c7SMaximilian Luz 
1986be9c4fa2SBaokun Li 		list_move_tail(&p->pending_node, &complete_q);
1987c167b9c7SMaximilian Luz 	}
1988c167b9c7SMaximilian Luz 	atomic_set(&ptl->pending.count, 0);
1989c167b9c7SMaximilian Luz 	spin_unlock(&ptl->pending.lock);
1990c167b9c7SMaximilian Luz 
1991c167b9c7SMaximilian Luz 	/* Complete and drop packets on complete_q. */
1992c167b9c7SMaximilian Luz 	list_for_each_entry(p, &complete_q, queue_node) {
1993c167b9c7SMaximilian Luz 		if (!test_and_set_bit(SSH_PACKET_SF_COMPLETED_BIT, &p->state))
1994c167b9c7SMaximilian Luz 			__ssh_ptl_complete(p, -ESHUTDOWN);
1995c167b9c7SMaximilian Luz 
1996c167b9c7SMaximilian Luz 		ssh_packet_put(p);
1997c167b9c7SMaximilian Luz 	}
1998c167b9c7SMaximilian Luz 
1999c167b9c7SMaximilian Luz 	/* Complete and drop packets on complete_p. */
2000c167b9c7SMaximilian Luz 	list_for_each_entry(p, &complete_p, pending_node) {
2001c167b9c7SMaximilian Luz 		if (!test_and_set_bit(SSH_PACKET_SF_COMPLETED_BIT, &p->state))
2002c167b9c7SMaximilian Luz 			__ssh_ptl_complete(p, -ESHUTDOWN);
2003c167b9c7SMaximilian Luz 
2004c167b9c7SMaximilian Luz 		ssh_packet_put(p);
2005c167b9c7SMaximilian Luz 	}
2006c167b9c7SMaximilian Luz 
2007c167b9c7SMaximilian Luz 	/*
2008c167b9c7SMaximilian Luz 	 * At this point we have guaranteed that the system doesn't reference
2009c167b9c7SMaximilian Luz 	 * any packets any more.
2010c167b9c7SMaximilian Luz 	 */
2011c167b9c7SMaximilian Luz }
2012c167b9c7SMaximilian Luz 
2013c167b9c7SMaximilian Luz /**
2014c167b9c7SMaximilian Luz  * ssh_ptl_init() - Initialize packet transport layer.
2015c167b9c7SMaximilian Luz  * @ptl:    The packet transport layer to initialize.
2016c167b9c7SMaximilian Luz  * @serdev: The underlying serial device, i.e. the lower-level transport.
2017c167b9c7SMaximilian Luz  * @ops:    Packet layer operations.
2018c167b9c7SMaximilian Luz  *
2019c167b9c7SMaximilian Luz  * Initializes the given packet transport layer. Transmitter and receiver
2020c167b9c7SMaximilian Luz  * threads must be started separately via ssh_ptl_tx_start() and
2021c167b9c7SMaximilian Luz  * ssh_ptl_rx_start(), after the packet-layer has been initialized and the
2022c167b9c7SMaximilian Luz  * lower-level transport layer has been set up.
2023c167b9c7SMaximilian Luz  *
2024c167b9c7SMaximilian Luz  * Return: Returns zero on success and a nonzero error code on failure.
2025c167b9c7SMaximilian Luz  */
ssh_ptl_init(struct ssh_ptl * ptl,struct serdev_device * serdev,struct ssh_ptl_ops * ops)2026c167b9c7SMaximilian Luz int ssh_ptl_init(struct ssh_ptl *ptl, struct serdev_device *serdev,
2027c167b9c7SMaximilian Luz 		 struct ssh_ptl_ops *ops)
2028c167b9c7SMaximilian Luz {
2029c167b9c7SMaximilian Luz 	int i, status;
2030c167b9c7SMaximilian Luz 
2031c167b9c7SMaximilian Luz 	ptl->serdev = serdev;
2032c167b9c7SMaximilian Luz 	ptl->state = 0;
2033c167b9c7SMaximilian Luz 
2034c167b9c7SMaximilian Luz 	spin_lock_init(&ptl->queue.lock);
2035c167b9c7SMaximilian Luz 	INIT_LIST_HEAD(&ptl->queue.head);
2036c167b9c7SMaximilian Luz 
2037c167b9c7SMaximilian Luz 	spin_lock_init(&ptl->pending.lock);
2038c167b9c7SMaximilian Luz 	INIT_LIST_HEAD(&ptl->pending.head);
2039c167b9c7SMaximilian Luz 	atomic_set_release(&ptl->pending.count, 0);
2040c167b9c7SMaximilian Luz 
2041c167b9c7SMaximilian Luz 	ptl->tx.thread = NULL;
2042c167b9c7SMaximilian Luz 	atomic_set(&ptl->tx.running, 0);
2043c167b9c7SMaximilian Luz 	init_completion(&ptl->tx.thread_cplt_pkt);
2044c167b9c7SMaximilian Luz 	init_completion(&ptl->tx.thread_cplt_tx);
2045c167b9c7SMaximilian Luz 	init_waitqueue_head(&ptl->tx.packet_wq);
2046c167b9c7SMaximilian Luz 
2047c167b9c7SMaximilian Luz 	ptl->rx.thread = NULL;
2048c167b9c7SMaximilian Luz 	init_waitqueue_head(&ptl->rx.wq);
2049c167b9c7SMaximilian Luz 
2050c167b9c7SMaximilian Luz 	spin_lock_init(&ptl->rtx_timeout.lock);
2051c167b9c7SMaximilian Luz 	ptl->rtx_timeout.timeout = SSH_PTL_PACKET_TIMEOUT;
2052c167b9c7SMaximilian Luz 	ptl->rtx_timeout.expires = KTIME_MAX;
2053c167b9c7SMaximilian Luz 	INIT_DELAYED_WORK(&ptl->rtx_timeout.reaper, ssh_ptl_timeout_reap);
2054c167b9c7SMaximilian Luz 
2055c167b9c7SMaximilian Luz 	ptl->ops = *ops;
2056c167b9c7SMaximilian Luz 
2057c167b9c7SMaximilian Luz 	/* Initialize list of recent/blocked SEQs with invalid sequence IDs. */
2058c167b9c7SMaximilian Luz 	for (i = 0; i < ARRAY_SIZE(ptl->rx.blocked.seqs); i++)
2059c167b9c7SMaximilian Luz 		ptl->rx.blocked.seqs[i] = U16_MAX;
2060c167b9c7SMaximilian Luz 	ptl->rx.blocked.offset = 0;
2061c167b9c7SMaximilian Luz 
2062c167b9c7SMaximilian Luz 	status = kfifo_alloc(&ptl->rx.fifo, SSH_PTL_RX_FIFO_LEN, GFP_KERNEL);
2063c167b9c7SMaximilian Luz 	if (status)
2064c167b9c7SMaximilian Luz 		return status;
2065c167b9c7SMaximilian Luz 
2066c167b9c7SMaximilian Luz 	status = sshp_buf_alloc(&ptl->rx.buf, SSH_PTL_RX_BUF_LEN, GFP_KERNEL);
2067c167b9c7SMaximilian Luz 	if (status)
2068c167b9c7SMaximilian Luz 		kfifo_free(&ptl->rx.fifo);
2069c167b9c7SMaximilian Luz 
2070c167b9c7SMaximilian Luz 	return status;
2071c167b9c7SMaximilian Luz }
2072c167b9c7SMaximilian Luz 
2073c167b9c7SMaximilian Luz /**
2074c167b9c7SMaximilian Luz  * ssh_ptl_destroy() - Deinitialize packet transport layer.
2075c167b9c7SMaximilian Luz  * @ptl: The packet transport layer to deinitialize.
2076c167b9c7SMaximilian Luz  *
2077c167b9c7SMaximilian Luz  * Deinitializes the given packet transport layer and frees resources
2078c167b9c7SMaximilian Luz  * associated with it. If receiver and/or transmitter threads have been
2079c167b9c7SMaximilian Luz  * started, the layer must first be shut down via ssh_ptl_shutdown() before
2080c167b9c7SMaximilian Luz  * this function can be called.
2081c167b9c7SMaximilian Luz  */
ssh_ptl_destroy(struct ssh_ptl * ptl)2082c167b9c7SMaximilian Luz void ssh_ptl_destroy(struct ssh_ptl *ptl)
2083c167b9c7SMaximilian Luz {
2084c167b9c7SMaximilian Luz 	kfifo_free(&ptl->rx.fifo);
2085c167b9c7SMaximilian Luz 	sshp_buf_free(&ptl->rx.buf);
2086c167b9c7SMaximilian Luz }
2087