summaryrefslogtreecommitdiff
path: root/drivers/platform/surface/aggregator/ssh_packet_layer.h
blob: 64633522f9716ea60e4ca9f35fa2ae2485c23574 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * SSH packet transport layer.
 *
 * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
 */

#ifndef _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H
#define _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H

#include <linux/atomic.h>
#include <linux/kfifo.h>
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/serdev.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/workqueue.h>

#include <linux/surface_aggregator/serial_hub.h>
#include "ssh_parser.h"

/**
 * enum ssh_ptl_state_flags - State-flags for &struct ssh_ptl.
 *
 * @SSH_PTL_SF_SHUTDOWN_BIT:
 *	Indicates that the packet transport layer has been shut down or is
 *	being shut down and should not accept any new packets/data.
 */
enum ssh_ptl_state_flags {
	SSH_PTL_SF_SHUTDOWN_BIT,
};

/**
 * struct ssh_ptl_ops - Callback operations for packet transport layer.
 * @data_received: Function called when a data-packet has been received. Both,
 *                 the packet layer on which the packet has been received and
 *                 the packet's payload data are provided to this function.
 */
struct ssh_ptl_ops {
	void (*data_received)(struct ssh_ptl *p, const struct ssam_span *data);
};

/**
 * struct ssh_ptl - SSH packet transport layer.
 * @serdev:        Serial device providing the underlying data transport.
 * @state:         State(-flags) of the transport layer.
 * @queue:         Packet submission queue.
 * @queue.lock:    Lock for modifying the packet submission queue.
 * @queue.head:    List-head of the packet submission queue.
 * @pending:       Set/list of pending packets.
 * @pending.lock:  Lock for modifying the pending set.
 * @pending.head:  List-head of the pending set/list.
 * @pending.count: Number of currently pending packets.
 * @tx:            Transmitter subsystem.
 * @tx.running:    Flag indicating (desired) transmitter thread state.
 * @tx.thread:     Transmitter thread.
 * @tx.thread_cplt_tx:  Completion for transmitter thread waiting on transfer.
 * @tx.thread_cplt_pkt: Completion for transmitter thread waiting on packets.
 * @tx.packet_wq:  Waitqueue-head for packet transmit completion.
 * @rx:            Receiver subsystem.
 * @rx.thread:     Receiver thread.
 * @rx.wq:         Waitqueue-head for receiver thread.
 * @rx.fifo:       Buffer for receiving data/pushing data to receiver thread.
 * @rx.buf:        Buffer for evaluating data on receiver thread.
 * @rx.blocked:    List of recent/blocked sequence IDs to detect retransmission.
 * @rx.blocked.seqs:   Array of blocked sequence IDs.
 * @rx.blocked.offset: Offset indicating where a new ID should be inserted.
 * @rtx_timeout:   Retransmission timeout subsystem.
 * @rtx_timeout.lock:    Lock for modifying the retransmission timeout reaper.
 * @rtx_timeout.timeout: Timeout interval for retransmission.
 * @rtx_timeout.expires: Time specifying when the reaper work is next scheduled.
 * @rtx_timeout.reaper:  Work performing timeout checks and subsequent actions.
 * @ops:           Packet layer operations.
 */
struct ssh_ptl {
	struct serdev_device *serdev;
	unsigned long state;

	struct {
		spinlock_t lock;
		struct list_head head;
	} queue;

	struct {
		spinlock_t lock;
		struct list_head head;
		atomic_t count;
	} pending;

	struct {
		atomic_t running;
		struct task_struct *thread;
		struct completion thread_cplt_tx;
		struct completion thread_cplt_pkt;
		struct wait_queue_head packet_wq;
	} tx;

	struct {
		struct task_struct *thread;
		struct wait_queue_head wq;
		struct kfifo fifo;
		struct sshp_buf buf;

		struct {
			u16 seqs[8];
			u16 offset;
		} blocked;
	} rx;

	struct {
		spinlock_t lock;
		ktime_t timeout;
		ktime_t expires;
		struct delayed_work reaper;
	} rtx_timeout;

	struct ssh_ptl_ops ops;
};

#define __ssam_prcond(func, p, fmt, ...)		\
	do {						\
		typeof(p) __p = (p);			\
							\
		if (__p)				\
			func(__p, fmt, ##__VA_ARGS__);	\
	} while (0)

#define ptl_dbg(p, fmt, ...)  dev_dbg(&(p)->serdev->dev, fmt, ##__VA_ARGS__)
#define ptl_info(p, fmt, ...) dev_info(&(p)->serdev->dev, fmt, ##__VA_ARGS__)
#define ptl_warn(p, fmt, ...) dev_warn(&(p)->serdev->dev, fmt, ##__VA_ARGS__)
#define ptl_err(p, fmt, ...)  dev_err(&(p)->serdev->dev, fmt, ##__VA_ARGS__)
#define ptl_dbg_cond(p, fmt, ...) __ssam_prcond(ptl_dbg, p, fmt, ##__VA_ARGS__)

#define to_ssh_ptl(ptr, member) \
	container_of(ptr, struct ssh_ptl, member)

int ssh_ptl_init(struct ssh_ptl *ptl, struct serdev_device *serdev,
		 struct ssh_ptl_ops *ops);

void ssh_ptl_destroy(struct ssh_ptl *ptl);

/**
 * ssh_ptl_get_device() - Get device associated with packet transport layer.
 * @ptl: The packet transport layer.
 *
 * Return: Returns the device on which the given packet transport layer builds
 * upon.
 */
static inline struct device *ssh_ptl_get_device(struct ssh_ptl *ptl)
{
	return ptl->serdev ? &ptl->serdev->dev : NULL;
}

int ssh_ptl_tx_start(struct ssh_ptl *ptl);
int ssh_ptl_tx_stop(struct ssh_ptl *ptl);
int ssh_ptl_rx_start(struct ssh_ptl *ptl);
int ssh_ptl_rx_stop(struct ssh_ptl *ptl);
void ssh_ptl_shutdown(struct ssh_ptl *ptl);

int ssh_ptl_submit(struct ssh_ptl *ptl, struct ssh_packet *p);
void ssh_ptl_cancel(struct ssh_packet *p);

int ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n);

/**
 * ssh_ptl_tx_wakeup_transfer() - Wake up packet transmitter thread for
 * transfer.
 * @ptl: The packet transport layer.
 *
 * Wakes up the packet transmitter thread, notifying it that the underlying
 * transport has more space for data to be transmitted. If the packet
 * transport layer has been shut down, calls to this function will be ignored.
 */
static inline void ssh_ptl_tx_wakeup_transfer(struct ssh_ptl *ptl)
{
	if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state))
		return;

	complete(&ptl->tx.thread_cplt_tx);
}

void ssh_packet_init(struct ssh_packet *packet, unsigned long type,
		     u8 priority, const struct ssh_packet_ops *ops);

int ssh_ctrl_packet_cache_init(void);
void ssh_ctrl_packet_cache_destroy(void);

#endif /* _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H */