xref: /linux/drivers/thunderbolt/stream.c (revision 3d5e48944e824bddc20d7b874e784f7b279636fe)
1*6db21d81SMika Westerberg // SPDX-License-Identifier: GPL-2.0
2*6db21d81SMika Westerberg /*
3*6db21d81SMika Westerberg  * Stream data over Thunderbolt/USB4 cable
4*6db21d81SMika Westerberg  *
5*6db21d81SMika Westerberg  * Copyright (C) 2026, Intel Corporation
6*6db21d81SMika Westerberg  * Authors: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
7*6db21d81SMika Westerberg  *	    Mika Westerberg <mika.westerberg@linux.intel.com>
8*6db21d81SMika Westerberg  */
9*6db21d81SMika Westerberg 
10*6db21d81SMika Westerberg #define pr_fmt(fmt) "tbstream: " fmt
11*6db21d81SMika Westerberg 
12*6db21d81SMika Westerberg #include <linux/configfs.h>
13*6db21d81SMika Westerberg #include <linux/file.h>
14*6db21d81SMika Westerberg #include <linux/fs.h>
15*6db21d81SMika Westerberg #include <linux/idr.h>
16*6db21d81SMika Westerberg #include <linux/miscdevice.h>
17*6db21d81SMika Westerberg #include <linux/module.h>
18*6db21d81SMika Westerberg #include <linux/mutex.h>
19*6db21d81SMika Westerberg #include <linux/poll.h>
20*6db21d81SMika Westerberg #include <linux/sizes.h>
21*6db21d81SMika Westerberg #include <linux/thunderbolt.h>
22*6db21d81SMika Westerberg #include <linux/uaccess.h>
23*6db21d81SMika Westerberg #include <linux/uio.h>
24*6db21d81SMika Westerberg #include <linux/uuid.h>
25*6db21d81SMika Westerberg #include <linux/wait.h>
26*6db21d81SMika Westerberg 
27*6db21d81SMika Westerberg /*
28*6db21d81SMika Westerberg  * USB4STREAM - Stream data directly over Thunderbolt/USB4 cable
29*6db21d81SMika Westerberg  *
30*6db21d81SMika Westerberg  * HopIDs are configured by the user. In Linux this is done through
31*6db21d81SMika Westerberg  * ConfigFS. Once that is done paths are be established the first time
32*6db21d81SMika Westerberg  * the stream is opened. Typically the read side is opened first to make
33*6db21d81SMika Westerberg  * sure all the data will be received.
34*6db21d81SMika Westerberg  *
35*6db21d81SMika Westerberg  * End-to-end flow control is mandatory on both sides.
36*6db21d81SMika Westerberg  *
37*6db21d81SMika Westerberg  * Data is sent to the other side as tunneled DATA packets. All the data
38*6db21d81SMika Westerberg  * is owned by the user and passed as-is from the writer to the reader.
39*6db21d81SMika Westerberg  *
40*6db21d81SMika Westerberg  * Once the stream device is closed, a CLOSE packet is sent to the peer
41*6db21d81SMika Westerberg  * so it can take the necessary action. On Linux this typically results
42*6db21d81SMika Westerberg  * in EOF being returned to the reader.
43*6db21d81SMika Westerberg  *
44*6db21d81SMika Westerberg  * Tunneled packet types:
45*6db21d81SMika Westerberg  *
46*6db21d81SMika Westerberg  * +-------+---------+------------------+
47*6db21d81SMika Westerberg  * |  PDF  |  Type   | Payload size     |
48*6db21d81SMika Westerberg  * +-------+---------+------------------+
49*6db21d81SMika Westerberg  * |   2   | DATA    | up to 4 KiB      |
50*6db21d81SMika Westerberg  * |   3   | CLOSE   | up to 256 bytes  |
51*6db21d81SMika Westerberg  * +-------+---------+------------------+
52*6db21d81SMika Westerberg  *
53*6db21d81SMika Westerberg  * Each stream can optionally publish configuration values under its own
54*6db21d81SMika Westerberg  * XDomain property directory. The name of the directory is the name of
55*6db21d81SMika Westerberg  * the stream in question and the UUID is up to the stream. For example
56*6db21d81SMika Westerberg  * if the stream exposes video output then the directory name could be
57*6db21d81SMika Westerberg  * "video".
58*6db21d81SMika Westerberg  *
59*6db21d81SMika Westerberg  * Below values are reserved and can be used by the stream:
60*6db21d81SMika Westerberg  *
61*6db21d81SMika Westerberg  * +----------+-----------+-------------------------+
62*6db21d81SMika Westerberg  * |   Key    |   Type    | Contents                |
63*6db21d81SMika Westerberg  * +----------+-----------+-------------------------+
64*6db21d81SMika Westerberg  * | inhopid  | IMMEDIATE | Configured input HopID  |
65*6db21d81SMika Westerberg  * | outhopid | IMMEDIATE | Configured output HopID |
66*6db21d81SMika Westerberg  * +----------+-----------+-------------------------+
67*6db21d81SMika Westerberg  *
68*6db21d81SMika Westerberg  * It is allowed to add more stream specific properties as well if the
69*6db21d81SMika Westerberg  * above are not enough.
70*6db21d81SMika Westerberg  */
71*6db21d81SMika Westerberg 
72*6db21d81SMika Westerberg #define TBSTREAM_DEV_RING_SIZE		256
73*6db21d81SMika Westerberg #define TBSTREAM_DEV_MIN_RING_SIZE	32
74*6db21d81SMika Westerberg #define TBSTREAM_DEV_MAX_RING_SIZE	4096
75*6db21d81SMika Westerberg #define TBSTREAM_DEV_THROTTLING		8192
76*6db21d81SMika Westerberg #define TBSTREAM_DEV_MAX_THROTTLING	16776960
77*6db21d81SMika Westerberg 
78*6db21d81SMika Westerberg /**
79*6db21d81SMika Westerberg  * enum tbstream_frame_pdf - PDF numbers for tunneled frames
80*6db21d81SMika Westerberg  * @TBSTREAM_FRAME_START: PDF of the start of the frame
81*6db21d81SMika Westerberg  * @TBSTREAM_DATA: PDF of the DATA frame
82*6db21d81SMika Westerberg  * @TBSTREAM_CLOSE: PDF of the CLOSE frame
83*6db21d81SMika Westerberg  */
84*6db21d81SMika Westerberg enum tbstream_frame_pdf {
85*6db21d81SMika Westerberg 	TBSTREAM_FRAME_START = 1,
86*6db21d81SMika Westerberg 	TBSTREAM_DATA,
87*6db21d81SMika Westerberg 	TBSTREAM_CLOSE,
88*6db21d81SMika Westerberg };
89*6db21d81SMika Westerberg 
90*6db21d81SMika Westerberg /**
91*6db21d81SMika Westerberg  * struct tbstream_frame - Frame submitted to/from the rings
92*6db21d81SMika Westerberg  * @sdev: Pointer to the stream device
93*6db21d81SMika Westerberg  * @page: Page holding the packet
94*6db21d81SMika Westerberg  * @offset: Offset inside @page if partial read is done
95*6db21d81SMika Westerberg  * @completed: %true if the RX frame is completed
96*6db21d81SMika Westerberg  * @frame: Underlying frame structure
97*6db21d81SMika Westerberg  */
98*6db21d81SMika Westerberg struct tbstream_frame {
99*6db21d81SMika Westerberg 	struct tbstream_dev *sdev;
100*6db21d81SMika Westerberg 	struct page *page;
101*6db21d81SMika Westerberg 	unsigned int offset;
102*6db21d81SMika Westerberg 	bool completed;
103*6db21d81SMika Westerberg 	struct ring_frame frame;
104*6db21d81SMika Westerberg };
105*6db21d81SMika Westerberg 
106*6db21d81SMika Westerberg /**
107*6db21d81SMika Westerberg  * struct tbstream_ring - Stream RX/TX ring structure
108*6db21d81SMika Westerberg  * @ring: Pointer to the API ring
109*6db21d81SMika Westerberg  * @prod: Current value of producer
110*6db21d81SMika Westerberg  * @cons: Current value of consumer
111*6db21d81SMika Westerberg  * @frames: Holds the ring frames
112*6db21d81SMika Westerberg  */
113*6db21d81SMika Westerberg struct tbstream_ring {
114*6db21d81SMika Westerberg 	struct tb_ring *ring;
115*6db21d81SMika Westerberg 	unsigned long prod;
116*6db21d81SMika Westerberg 	unsigned long cons;
117*6db21d81SMika Westerberg 	struct tbstream_frame *frames;
118*6db21d81SMika Westerberg };
119*6db21d81SMika Westerberg 
120*6db21d81SMika Westerberg /**
121*6db21d81SMika Westerberg  * struct tbstream_dev - Stream character device
122*6db21d81SMika Westerberg  * @group: ConfigFS group for this device
123*6db21d81SMika Westerberg  * @stream: Pointer to the stream if it is attached (%NULL otherwise)
124*6db21d81SMika Westerberg  * @misc: Character device used for tunneling
125*6db21d81SMika Westerberg  * @kref: Reference count
126*6db21d81SMika Westerberg  * @index: Unique identifier for the character device
127*6db21d81SMika Westerberg  * @in_hopid: In HopID
128*6db21d81SMika Westerberg  * @out_hopid: Out HopID
129*6db21d81SMika Westerberg  * @ring_size: Size of the rings
130*6db21d81SMika Westerberg  * @throttling: Interrupt throttling rate in ns
131*6db21d81SMika Westerberg  * @users: Number of times @cdev has been opened
132*6db21d81SMika Westerberg  * @closed: CLOSE packet was received
133*6db21d81SMika Westerberg  * @removed: Userspace removed the ConfigFS group underneath.
134*6db21d81SMika Westerberg  * @wait: Waitqueue for open, read and write
135*6db21d81SMika Westerberg  * @lock: Lock protecting this structure
136*6db21d81SMika Westerberg  * @tx_ring: Transmit ring
137*6db21d81SMika Westerberg  * @rx_ring: Receive ring
138*6db21d81SMika Westerberg  * @list: Stream devices are linked through this
139*6db21d81SMika Westerberg  */
140*6db21d81SMika Westerberg struct tbstream_dev {
141*6db21d81SMika Westerberg 	struct config_group group;
142*6db21d81SMika Westerberg 	struct tbstream *stream;
143*6db21d81SMika Westerberg 	struct miscdevice misc;
144*6db21d81SMika Westerberg 	struct kref kref;
145*6db21d81SMika Westerberg 	int index;
146*6db21d81SMika Westerberg 	int in_hopid;
147*6db21d81SMika Westerberg 	int out_hopid;
148*6db21d81SMika Westerberg 	unsigned int ring_size;
149*6db21d81SMika Westerberg 	unsigned int throttling;
150*6db21d81SMika Westerberg 	int users;
151*6db21d81SMika Westerberg 	bool closed;
152*6db21d81SMika Westerberg 	bool removed;
153*6db21d81SMika Westerberg 	wait_queue_head_t wait;
154*6db21d81SMika Westerberg 	struct mutex lock;
155*6db21d81SMika Westerberg 	struct tbstream_ring tx_ring;
156*6db21d81SMika Westerberg 	struct tbstream_ring rx_ring;
157*6db21d81SMika Westerberg 	struct list_head list;
158*6db21d81SMika Westerberg };
159*6db21d81SMika Westerberg 
160*6db21d81SMika Westerberg /**
161*6db21d81SMika Westerberg  * struct tbstream_group - Config group for stream
162*6db21d81SMika Westerberg  * @group: ConfigFS group for @stream
163*6db21d81SMika Westerberg  * @stream: Stream the ConfigFS group is attached to. %NULL if there is
164*6db21d81SMika Westerberg  *	    no stream attached.
165*6db21d81SMika Westerberg  * @lock: Lock protecting this structure
166*6db21d81SMika Westerberg  * @dev_list: List of stream devices
167*6db21d81SMika Westerberg  *
168*6db21d81SMika Westerberg  * This is the ConfigFS directory for one connection to another host.
169*6db21d81SMika Westerberg  * There can be several &struct stream_dev linked through @dev_list of
170*6db21d81SMika Westerberg  * this structure. Reference count managed through @group.
171*6db21d81SMika Westerberg  */
172*6db21d81SMika Westerberg struct tbstream_group {
173*6db21d81SMika Westerberg 	struct config_group group;
174*6db21d81SMika Westerberg 	struct tbstream *stream;
175*6db21d81SMika Westerberg 	struct mutex lock;
176*6db21d81SMika Westerberg 	struct list_head dev_list;
177*6db21d81SMika Westerberg };
178*6db21d81SMika Westerberg 
179*6db21d81SMika Westerberg /**
180*6db21d81SMika Westerberg  * struct tbstream - Stream service private data
181*6db21d81SMika Westerberg  * @kref: Reference count
182*6db21d81SMika Westerberg  * @svc: Pointer to the service device
183*6db21d81SMika Westerberg  * @list: Streams are linked through this in @stream_list
184*6db21d81SMika Westerberg  *
185*6db21d81SMika Westerberg  * This represents the actual physical connection between two hosts.
186*6db21d81SMika Westerberg  */
187*6db21d81SMika Westerberg struct tbstream {
188*6db21d81SMika Westerberg 	struct kref kref;
189*6db21d81SMika Westerberg 	struct tb_service *svc;
190*6db21d81SMika Westerberg 	struct list_head list;
191*6db21d81SMika Westerberg };
192*6db21d81SMika Westerberg 
193*6db21d81SMika Westerberg static DEFINE_IDA(tbstream_indices);
194*6db21d81SMika Westerberg 
195*6db21d81SMika Westerberg /* Protects tbstream_list */
196*6db21d81SMika Westerberg static DEFINE_MUTEX(tbstream_lock);
197*6db21d81SMika Westerberg static LIST_HEAD(tbstream_list);
198*6db21d81SMika Westerberg 
199*6db21d81SMika Westerberg /* Serializes tbstream_get()/put() */
200*6db21d81SMika Westerberg static DEFINE_MUTEX(tbstream_kref_lock);
201*6db21d81SMika Westerberg 
202*6db21d81SMika Westerberg /* Serializes tbstream_dev_get()/put() */
203*6db21d81SMika Westerberg static DEFINE_MUTEX(tbstream_dev_kref_lock);
204*6db21d81SMika Westerberg 
205*6db21d81SMika Westerberg /* Stream property directory UUID: 3a1cb984-c4d9-4469-a277-ce2fdfd11f0d */
206*6db21d81SMika Westerberg static const uuid_t tbstream_dir_uuid =
207*6db21d81SMika Westerberg 	UUID_INIT(0x3a1cb984, 0xc4d9, 0x4469,
208*6db21d81SMika Westerberg 		  0xa2, 0x77, 0xce, 0x2f, 0xdf, 0xd1, 0x1f, 0x0d);
209*6db21d81SMika Westerberg 
210*6db21d81SMika Westerberg static struct tb_property_dir *tbstream_dir;
211*6db21d81SMika Westerberg 
212*6db21d81SMika Westerberg static void tbstream_release(struct kref *kref)
213*6db21d81SMika Westerberg {
214*6db21d81SMika Westerberg 	struct tbstream *stream = container_of(kref, typeof(*stream), kref);
215*6db21d81SMika Westerberg 
216*6db21d81SMika Westerberg 	tb_service_put(stream->svc);
217*6db21d81SMika Westerberg 	kfree(stream);
218*6db21d81SMika Westerberg }
219*6db21d81SMika Westerberg 
220*6db21d81SMika Westerberg static void tbstream_put(struct tbstream *stream)
221*6db21d81SMika Westerberg {
222*6db21d81SMika Westerberg 	if (stream) {
223*6db21d81SMika Westerberg 		guard(mutex)(&tbstream_kref_lock);
224*6db21d81SMika Westerberg 		kref_put(&stream->kref, tbstream_release);
225*6db21d81SMika Westerberg 	}
226*6db21d81SMika Westerberg }
227*6db21d81SMika Westerberg 
228*6db21d81SMika Westerberg static struct tbstream *tbstream_get(struct tbstream *stream)
229*6db21d81SMika Westerberg {
230*6db21d81SMika Westerberg 	if (stream) {
231*6db21d81SMika Westerberg 		guard(mutex)(&tbstream_kref_lock);
232*6db21d81SMika Westerberg 		kref_get(&stream->kref);
233*6db21d81SMika Westerberg 	}
234*6db21d81SMika Westerberg 	return stream;
235*6db21d81SMika Westerberg }
236*6db21d81SMika Westerberg 
237*6db21d81SMika Westerberg static inline bool tbstream_valid(const struct tbstream *stream)
238*6db21d81SMika Westerberg {
239*6db21d81SMika Westerberg 	if (stream)
240*6db21d81SMika Westerberg 		return !tb_service_parent(stream->svc)->is_unplugged;
241*6db21d81SMika Westerberg 	return false;
242*6db21d81SMika Westerberg }
243*6db21d81SMika Westerberg 
244*6db21d81SMika Westerberg static void tbstream_ring_free(struct tbstream_ring *ring)
245*6db21d81SMika Westerberg {
246*6db21d81SMika Westerberg 	struct device *dma_dev = tb_ring_dma_device(ring->ring);
247*6db21d81SMika Westerberg 	enum dma_data_direction dir;
248*6db21d81SMika Westerberg 	int i;
249*6db21d81SMika Westerberg 
250*6db21d81SMika Westerberg 	if (ring->ring->is_tx)
251*6db21d81SMika Westerberg 		dir = DMA_TO_DEVICE;
252*6db21d81SMika Westerberg 	else
253*6db21d81SMika Westerberg 		dir = DMA_FROM_DEVICE;
254*6db21d81SMika Westerberg 
255*6db21d81SMika Westerberg 	for (i = 0; i < tb_ring_size(ring->ring); i++) {
256*6db21d81SMika Westerberg 		struct tbstream_frame *sf = &ring->frames[i];
257*6db21d81SMika Westerberg 
258*6db21d81SMika Westerberg 		if (sf->frame.buffer_phy)
259*6db21d81SMika Westerberg 			dma_unmap_page(dma_dev, sf->frame.buffer_phy,
260*6db21d81SMika Westerberg 				       tb_ring_frame_size(&sf->frame), dir);
261*6db21d81SMika Westerberg 		sf->frame.buffer_phy = 0;
262*6db21d81SMika Westerberg 		if (sf->page)
263*6db21d81SMika Westerberg 			__free_page(sf->page);
264*6db21d81SMika Westerberg 		sf->page = NULL;
265*6db21d81SMika Westerberg 	}
266*6db21d81SMika Westerberg 
267*6db21d81SMika Westerberg 	ring->prod = 0;
268*6db21d81SMika Westerberg 	ring->cons = 0;
269*6db21d81SMika Westerberg 	kfree(ring->frames);
270*6db21d81SMika Westerberg }
271*6db21d81SMika Westerberg 
272*6db21d81SMika Westerberg static inline bool tbstream_ring_available(const struct tbstream_ring *ring)
273*6db21d81SMika Westerberg {
274*6db21d81SMika Westerberg 	return ring->prod > ring->cons;
275*6db21d81SMika Westerberg }
276*6db21d81SMika Westerberg 
277*6db21d81SMika Westerberg static inline struct tb_xdomain *tbstream_dev_xdomain(struct tbstream_dev *sdev)
278*6db21d81SMika Westerberg {
279*6db21d81SMika Westerberg 	if (sdev->stream)
280*6db21d81SMika Westerberg 		return tb_service_parent(sdev->stream->svc);
281*6db21d81SMika Westerberg 	return NULL;
282*6db21d81SMika Westerberg }
283*6db21d81SMika Westerberg 
284*6db21d81SMika Westerberg static void tbstream_dev_release(struct kref *kref)
285*6db21d81SMika Westerberg {
286*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = container_of(kref, struct tbstream_dev, kref);
287*6db21d81SMika Westerberg 
288*6db21d81SMika Westerberg 	if (sdev->stream) {
289*6db21d81SMika Westerberg 		struct tb_xdomain *xd = tbstream_dev_xdomain(sdev);
290*6db21d81SMika Westerberg 
291*6db21d81SMika Westerberg 		if (sdev->out_hopid > 0)
292*6db21d81SMika Westerberg 			tb_xdomain_release_out_hopid(xd, sdev->out_hopid);
293*6db21d81SMika Westerberg 		if (sdev->in_hopid > 0)
294*6db21d81SMika Westerberg 			tb_xdomain_release_in_hopid(xd, sdev->in_hopid);
295*6db21d81SMika Westerberg 
296*6db21d81SMika Westerberg 		tbstream_put(sdev->stream);
297*6db21d81SMika Westerberg 	}
298*6db21d81SMika Westerberg 	ida_free(&tbstream_indices, sdev->index);
299*6db21d81SMika Westerberg 	kfree(sdev->misc.name);
300*6db21d81SMika Westerberg 	kfree(sdev);
301*6db21d81SMika Westerberg }
302*6db21d81SMika Westerberg 
303*6db21d81SMika Westerberg static inline void tbstream_dev_put(struct tbstream_dev *sdev)
304*6db21d81SMika Westerberg {
305*6db21d81SMika Westerberg 	guard(mutex)(&tbstream_dev_kref_lock);
306*6db21d81SMika Westerberg 	kref_put(&sdev->kref, tbstream_dev_release);
307*6db21d81SMika Westerberg }
308*6db21d81SMika Westerberg 
309*6db21d81SMika Westerberg static inline struct tbstream_dev *tbstream_dev_get(struct tbstream_dev *sdev)
310*6db21d81SMika Westerberg {
311*6db21d81SMika Westerberg 	guard(mutex)(&tbstream_dev_kref_lock);
312*6db21d81SMika Westerberg 	kref_get(&sdev->kref);
313*6db21d81SMika Westerberg 	return sdev;
314*6db21d81SMika Westerberg }
315*6db21d81SMika Westerberg 
316*6db21d81SMika Westerberg static inline struct tbstream_dev *to_tbstream_dev(struct miscdevice *misc)
317*6db21d81SMika Westerberg {
318*6db21d81SMika Westerberg 	return container_of(misc, struct tbstream_dev, misc);
319*6db21d81SMika Westerberg }
320*6db21d81SMika Westerberg 
321*6db21d81SMika Westerberg static inline int tbstream_dev_valid(const struct tbstream_dev *sdev)
322*6db21d81SMika Westerberg {
323*6db21d81SMika Westerberg 	const struct tbstream *stream = sdev->stream;
324*6db21d81SMika Westerberg 
325*6db21d81SMika Westerberg 	if (!tbstream_valid(stream))
326*6db21d81SMika Westerberg 		return -ENXIO;
327*6db21d81SMika Westerberg 	if (sdev->in_hopid <= 0 || sdev->out_hopid <= 0)
328*6db21d81SMika Westerberg 		return -EINVAL;
329*6db21d81SMika Westerberg 	return 0;
330*6db21d81SMika Westerberg }
331*6db21d81SMika Westerberg 
332*6db21d81SMika Westerberg static inline bool tbstream_dev_removed(const struct tbstream_dev *sdev)
333*6db21d81SMika Westerberg {
334*6db21d81SMika Westerberg 	return sdev->removed;
335*6db21d81SMika Westerberg }
336*6db21d81SMika Westerberg 
337*6db21d81SMika Westerberg static inline bool tbstream_dev_closed(const struct tbstream_dev *sdev)
338*6db21d81SMika Westerberg {
339*6db21d81SMika Westerberg 	return sdev->closed;
340*6db21d81SMika Westerberg }
341*6db21d81SMika Westerberg 
342*6db21d81SMika Westerberg static void
343*6db21d81SMika Westerberg tbstream_dev_rx_callback(struct tb_ring *ring, struct ring_frame *frame,
344*6db21d81SMika Westerberg 			 bool canceled)
345*6db21d81SMika Westerberg {
346*6db21d81SMika Westerberg 	struct tbstream_frame *sf = container_of(frame, typeof(*sf), frame);
347*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = sf->sdev;
348*6db21d81SMika Westerberg 
349*6db21d81SMika Westerberg 	if (canceled)
350*6db21d81SMika Westerberg 		return;
351*6db21d81SMika Westerberg 
352*6db21d81SMika Westerberg 	sf->completed = true;
353*6db21d81SMika Westerberg 	sdev->rx_ring.prod++;
354*6db21d81SMika Westerberg 
355*6db21d81SMika Westerberg 	if (sf->frame.flags & RING_DESC_CRC_ERROR)
356*6db21d81SMika Westerberg 		pr_warn("RX CRC error\n");
357*6db21d81SMika Westerberg 	else if (sf->frame.flags & RING_DESC_BUFFER_OVERRUN)
358*6db21d81SMika Westerberg 		pr_warn("RX buffer overrun\n");
359*6db21d81SMika Westerberg 	else
360*6db21d81SMika Westerberg 		wake_up_interruptible_poll(&sdev->wait, EPOLLIN | EPOLLRDNORM);
361*6db21d81SMika Westerberg }
362*6db21d81SMika Westerberg 
363*6db21d81SMika Westerberg static struct tbstream_frame *
364*6db21d81SMika Westerberg tbstream_dev_completed_rx(struct tbstream_dev *sdev)
365*6db21d81SMika Westerberg {
366*6db21d81SMika Westerberg 	struct device *dma_dev = tb_ring_dma_device(sdev->rx_ring.ring);
367*6db21d81SMika Westerberg 	struct tbstream_frame *sf;
368*6db21d81SMika Westerberg 	int index;
369*6db21d81SMika Westerberg 
370*6db21d81SMika Westerberg 	index = sdev->rx_ring.cons % tb_ring_size(sdev->rx_ring.ring);
371*6db21d81SMika Westerberg 	sf = &sdev->rx_ring.frames[index];
372*6db21d81SMika Westerberg 	if (!sf->completed)
373*6db21d81SMika Westerberg 		return NULL;
374*6db21d81SMika Westerberg 
375*6db21d81SMika Westerberg 	dma_sync_single_for_cpu(dma_dev, sf->frame.buffer_phy,
376*6db21d81SMika Westerberg 				tb_ring_frame_size(&sf->frame),
377*6db21d81SMika Westerberg 				DMA_FROM_DEVICE);
378*6db21d81SMika Westerberg 	return sf;
379*6db21d81SMika Westerberg }
380*6db21d81SMika Westerberg 
381*6db21d81SMika Westerberg static int tbstream_dev_consume_rx(struct tbstream_dev *sdev)
382*6db21d81SMika Westerberg {
383*6db21d81SMika Westerberg 	struct device *dma_dev = tb_ring_dma_device(sdev->rx_ring.ring);
384*6db21d81SMika Westerberg 	struct tbstream_frame *sf;
385*6db21d81SMika Westerberg 	int index;
386*6db21d81SMika Westerberg 
387*6db21d81SMika Westerberg 	index = sdev->rx_ring.cons % tb_ring_size(sdev->rx_ring.ring);
388*6db21d81SMika Westerberg 	sdev->rx_ring.cons++;
389*6db21d81SMika Westerberg 
390*6db21d81SMika Westerberg 	sf = &sdev->rx_ring.frames[index];
391*6db21d81SMika Westerberg 	sf->completed = false;
392*6db21d81SMika Westerberg 	sf->offset = 0;
393*6db21d81SMika Westerberg 	sf->frame.size = 0;
394*6db21d81SMika Westerberg 
395*6db21d81SMika Westerberg 	dma_sync_single_for_device(dma_dev, sf->frame.buffer_phy,
396*6db21d81SMika Westerberg 				   tb_ring_frame_size(&sf->frame),
397*6db21d81SMika Westerberg 				   DMA_FROM_DEVICE);
398*6db21d81SMika Westerberg 
399*6db21d81SMika Westerberg 	return tb_ring_rx(sdev->rx_ring.ring, &sf->frame);
400*6db21d81SMika Westerberg }
401*6db21d81SMika Westerberg 
402*6db21d81SMika Westerberg static int tbstream_dev_alloc_rx_buffers(struct tbstream_dev *sdev)
403*6db21d81SMika Westerberg {
404*6db21d81SMika Westerberg 	size_t ring_size = tb_ring_size(sdev->rx_ring.ring);
405*6db21d81SMika Westerberg 	int i;
406*6db21d81SMika Westerberg 
407*6db21d81SMika Westerberg 	sdev->rx_ring.frames = kcalloc(ring_size, sizeof(struct tbstream_frame),
408*6db21d81SMika Westerberg 				       GFP_KERNEL);
409*6db21d81SMika Westerberg 	if (!sdev->rx_ring.frames)
410*6db21d81SMika Westerberg 		return -ENOMEM;
411*6db21d81SMika Westerberg 
412*6db21d81SMika Westerberg 	for (i = 0; i < ring_size; i++) {
413*6db21d81SMika Westerberg 		struct device *dma_dev = tb_ring_dma_device(sdev->rx_ring.ring);
414*6db21d81SMika Westerberg 		struct tbstream_frame *sf = &sdev->rx_ring.frames[i];
415*6db21d81SMika Westerberg 		dma_addr_t dma_addr;
416*6db21d81SMika Westerberg 
417*6db21d81SMika Westerberg 		sf->page = alloc_page(GFP_KERNEL);
418*6db21d81SMika Westerberg 		if (!sf->page)
419*6db21d81SMika Westerberg 			return -ENOMEM;
420*6db21d81SMika Westerberg 
421*6db21d81SMika Westerberg 		dma_addr = dma_map_page(dma_dev, sf->page, 0, TB_MAX_FRAME_SIZE,
422*6db21d81SMika Westerberg 					DMA_FROM_DEVICE);
423*6db21d81SMika Westerberg 		if (dma_mapping_error(dma_dev, dma_addr)) {
424*6db21d81SMika Westerberg 			__free_page(sf->page);
425*6db21d81SMika Westerberg 			sf->page = NULL;
426*6db21d81SMika Westerberg 			return -ENOMEM;
427*6db21d81SMika Westerberg 		}
428*6db21d81SMika Westerberg 
429*6db21d81SMika Westerberg 		sf->sdev = sdev;
430*6db21d81SMika Westerberg 		sf->frame.callback = tbstream_dev_rx_callback;
431*6db21d81SMika Westerberg 		sf->frame.buffer_phy = dma_addr;
432*6db21d81SMika Westerberg 
433*6db21d81SMika Westerberg 		tb_ring_rx(sdev->rx_ring.ring, &sf->frame);
434*6db21d81SMika Westerberg 	}
435*6db21d81SMika Westerberg 
436*6db21d81SMika Westerberg 	sdev->rx_ring.cons = 0;
437*6db21d81SMika Westerberg 	sdev->rx_ring.prod = 0;
438*6db21d81SMika Westerberg 	return 0;
439*6db21d81SMika Westerberg }
440*6db21d81SMika Westerberg 
441*6db21d81SMika Westerberg static void
442*6db21d81SMika Westerberg tbstream_dev_tx_callback(struct tb_ring *ring, struct ring_frame *frame,
443*6db21d81SMika Westerberg 			 bool canceled)
444*6db21d81SMika Westerberg {
445*6db21d81SMika Westerberg 	struct tbstream_frame *sf = container_of(frame, typeof(*sf), frame);
446*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = sf->sdev;
447*6db21d81SMika Westerberg 
448*6db21d81SMika Westerberg 	if (canceled)
449*6db21d81SMika Westerberg 		return;
450*6db21d81SMika Westerberg 
451*6db21d81SMika Westerberg 	sdev->tx_ring.prod++;
452*6db21d81SMika Westerberg 	if (sf->frame.eof == TBSTREAM_DATA)
453*6db21d81SMika Westerberg 		wake_up_interruptible_poll(&sdev->wait, EPOLLOUT | EPOLLWRNORM);
454*6db21d81SMika Westerberg }
455*6db21d81SMika Westerberg 
456*6db21d81SMika Westerberg static int tbstream_dev_alloc_tx_buffers(struct tbstream_dev *sdev)
457*6db21d81SMika Westerberg {
458*6db21d81SMika Westerberg 	struct device *dma_dev = tb_ring_dma_device(sdev->tx_ring.ring);
459*6db21d81SMika Westerberg 	size_t ring_size = tb_ring_size(sdev->tx_ring.ring);
460*6db21d81SMika Westerberg 	int i;
461*6db21d81SMika Westerberg 
462*6db21d81SMika Westerberg 	sdev->tx_ring.frames = kcalloc(ring_size, sizeof(struct tbstream_frame),
463*6db21d81SMika Westerberg 				       GFP_KERNEL);
464*6db21d81SMika Westerberg 	if (!sdev->tx_ring.frames)
465*6db21d81SMika Westerberg 		return -ENOMEM;
466*6db21d81SMika Westerberg 
467*6db21d81SMika Westerberg 	for (i = 0; i < ring_size; i++) {
468*6db21d81SMika Westerberg 		struct tbstream_frame *sf = &sdev->tx_ring.frames[i];
469*6db21d81SMika Westerberg 		dma_addr_t dma_addr;
470*6db21d81SMika Westerberg 
471*6db21d81SMika Westerberg 		sf->page = alloc_page(GFP_KERNEL);
472*6db21d81SMika Westerberg 		if (!sf->page)
473*6db21d81SMika Westerberg 			return -ENOMEM;
474*6db21d81SMika Westerberg 
475*6db21d81SMika Westerberg 		dma_addr = dma_map_page(dma_dev, sf->page, 0, TB_MAX_FRAME_SIZE,
476*6db21d81SMika Westerberg 					DMA_TO_DEVICE);
477*6db21d81SMika Westerberg 		if (dma_mapping_error(dma_dev, dma_addr)) {
478*6db21d81SMika Westerberg 			__free_page(sf->page);
479*6db21d81SMika Westerberg 			sf->page = NULL;
480*6db21d81SMika Westerberg 			return -ENOMEM;
481*6db21d81SMika Westerberg 		}
482*6db21d81SMika Westerberg 
483*6db21d81SMika Westerberg 		sf->sdev = sdev;
484*6db21d81SMika Westerberg 		sf->frame.callback = tbstream_dev_tx_callback;
485*6db21d81SMika Westerberg 		sf->frame.buffer_phy = dma_addr;
486*6db21d81SMika Westerberg 		sf->frame.sof = TBSTREAM_FRAME_START;
487*6db21d81SMika Westerberg 	}
488*6db21d81SMika Westerberg 
489*6db21d81SMika Westerberg 	sdev->tx_ring.cons = 0;
490*6db21d81SMika Westerberg 	sdev->tx_ring.prod = ring_size - 1;
491*6db21d81SMika Westerberg 	return 0;
492*6db21d81SMika Westerberg }
493*6db21d81SMika Westerberg 
494*6db21d81SMika Westerberg static struct tbstream_frame *
495*6db21d81SMika Westerberg tbstream_dev_alloc_tx(struct tbstream_dev *sdev, enum tbstream_frame_pdf pdf,
496*6db21d81SMika Westerberg 		      struct iov_iter *from, size_t size)
497*6db21d81SMika Westerberg {
498*6db21d81SMika Westerberg 	struct device *dma_dev = tb_ring_dma_device(sdev->tx_ring.ring);
499*6db21d81SMika Westerberg 	struct tbstream_frame *sf;
500*6db21d81SMika Westerberg 	int index;
501*6db21d81SMika Westerberg 
502*6db21d81SMika Westerberg 	if (!tbstream_ring_available(&sdev->tx_ring))
503*6db21d81SMika Westerberg 		return ERR_PTR(-ENOBUFS);
504*6db21d81SMika Westerberg 
505*6db21d81SMika Westerberg 	index = sdev->tx_ring.cons % tb_ring_size(sdev->tx_ring.ring);
506*6db21d81SMika Westerberg 	sdev->tx_ring.cons++;
507*6db21d81SMika Westerberg 
508*6db21d81SMika Westerberg 	sf = &sdev->tx_ring.frames[index];
509*6db21d81SMika Westerberg 	sf->frame.size = size < TB_MAX_FRAME_SIZE ? size : 0;
510*6db21d81SMika Westerberg 	sf->frame.eof = pdf;
511*6db21d81SMika Westerberg 
512*6db21d81SMika Westerberg 	dma_sync_single_for_cpu(dma_dev, sf->frame.buffer_phy, size,
513*6db21d81SMika Westerberg 				DMA_TO_DEVICE);
514*6db21d81SMika Westerberg 	if (pdf == TBSTREAM_DATA) {
515*6db21d81SMika Westerberg 		if (copy_page_from_iter(sf->page, 0, size, from) != size)
516*6db21d81SMika Westerberg 			return ERR_PTR(-EFAULT);
517*6db21d81SMika Westerberg 	} else {
518*6db21d81SMika Westerberg 		memset(page_address(sf->page), 0, size);
519*6db21d81SMika Westerberg 	}
520*6db21d81SMika Westerberg 	dma_sync_single_for_device(dma_dev, sf->frame.buffer_phy, size,
521*6db21d81SMika Westerberg 				   DMA_TO_DEVICE);
522*6db21d81SMika Westerberg 	return sf;
523*6db21d81SMika Westerberg }
524*6db21d81SMika Westerberg 
525*6db21d81SMika Westerberg static int
526*6db21d81SMika Westerberg tbstream_dev_send_data(struct tbstream_dev *sdev, struct iov_iter *from,
527*6db21d81SMika Westerberg 		       size_t size)
528*6db21d81SMika Westerberg {
529*6db21d81SMika Westerberg 	struct tbstream_frame *sf;
530*6db21d81SMika Westerberg 
531*6db21d81SMika Westerberg 	sf = tbstream_dev_alloc_tx(sdev, TBSTREAM_DATA, from, size);
532*6db21d81SMika Westerberg 	if (IS_ERR(sf))
533*6db21d81SMika Westerberg 		return PTR_ERR(sf);
534*6db21d81SMika Westerberg 	return tb_ring_tx(sdev->tx_ring.ring, &sf->frame);
535*6db21d81SMika Westerberg }
536*6db21d81SMika Westerberg 
537*6db21d81SMika Westerberg static int tbstream_dev_send_close(struct tbstream_dev *sdev)
538*6db21d81SMika Westerberg {
539*6db21d81SMika Westerberg 	struct tbstream_frame *sf;
540*6db21d81SMika Westerberg 
541*6db21d81SMika Westerberg 	sf = tbstream_dev_alloc_tx(sdev, TBSTREAM_CLOSE, NULL, SZ_256);
542*6db21d81SMika Westerberg 	if (IS_ERR(sf))
543*6db21d81SMika Westerberg 		return PTR_ERR(sf);
544*6db21d81SMika Westerberg 	return tb_ring_tx(sdev->tx_ring.ring, &sf->frame);
545*6db21d81SMika Westerberg }
546*6db21d81SMika Westerberg 
547*6db21d81SMika Westerberg static int tbstream_dev_start(struct tbstream_dev *sdev)
548*6db21d81SMika Westerberg {
549*6db21d81SMika Westerberg 	struct tb_xdomain *xd = tbstream_dev_xdomain(sdev);
550*6db21d81SMika Westerberg 	u16 sof_mask, eof_mask;
551*6db21d81SMika Westerberg 	struct tb_ring *ring;
552*6db21d81SMika Westerberg 	int ret, e2e_tx_hop;
553*6db21d81SMika Westerberg 
554*6db21d81SMika Westerberg 	ring = tb_ring_alloc_tx(xd->tb->nhi, -1, sdev->ring_size,
555*6db21d81SMika Westerberg 				RING_FLAG_FRAME | RING_FLAG_E2E);
556*6db21d81SMika Westerberg 	if (!ring)
557*6db21d81SMika Westerberg 		return -ENOMEM;
558*6db21d81SMika Westerberg 	sdev->tx_ring.ring = ring;
559*6db21d81SMika Westerberg 
560*6db21d81SMika Westerberg 	ret = tbstream_dev_alloc_tx_buffers(sdev);
561*6db21d81SMika Westerberg 	if (ret)
562*6db21d81SMika Westerberg 		goto err_free_tx;
563*6db21d81SMika Westerberg 
564*6db21d81SMika Westerberg 	e2e_tx_hop = ring->hop;
565*6db21d81SMika Westerberg 	sof_mask = BIT(TBSTREAM_FRAME_START);
566*6db21d81SMika Westerberg 	eof_mask = BIT(TBSTREAM_DATA) | BIT(TBSTREAM_CLOSE);
567*6db21d81SMika Westerberg 
568*6db21d81SMika Westerberg 	ring = tb_ring_alloc_rx(xd->tb->nhi, -1, sdev->ring_size,
569*6db21d81SMika Westerberg 				RING_FLAG_FRAME | RING_FLAG_E2E, e2e_tx_hop,
570*6db21d81SMika Westerberg 				sof_mask, eof_mask, NULL, NULL);
571*6db21d81SMika Westerberg 	if (!ring) {
572*6db21d81SMika Westerberg 		ret = -ENOMEM;
573*6db21d81SMika Westerberg 		goto err_free_tx_buffers;
574*6db21d81SMika Westerberg 	}
575*6db21d81SMika Westerberg 	sdev->rx_ring.ring = ring;
576*6db21d81SMika Westerberg 
577*6db21d81SMika Westerberg 	ret = tb_xdomain_enable_paths(xd, sdev->out_hopid,
578*6db21d81SMika Westerberg 				     sdev->tx_ring.ring->hop,
579*6db21d81SMika Westerberg 				     sdev->in_hopid,
580*6db21d81SMika Westerberg 				     sdev->rx_ring.ring->hop);
581*6db21d81SMika Westerberg 	if (ret)
582*6db21d81SMika Westerberg 		goto err_free_rx;
583*6db21d81SMika Westerberg 
584*6db21d81SMika Westerberg 	tb_ring_throttling(sdev->tx_ring.ring, sdev->throttling);
585*6db21d81SMika Westerberg 	tb_ring_throttling(sdev->rx_ring.ring, sdev->throttling);
586*6db21d81SMika Westerberg 
587*6db21d81SMika Westerberg 	tb_ring_start(sdev->tx_ring.ring);
588*6db21d81SMika Westerberg 	tb_ring_start(sdev->rx_ring.ring);
589*6db21d81SMika Westerberg 
590*6db21d81SMika Westerberg 	ret = tbstream_dev_alloc_rx_buffers(sdev);
591*6db21d81SMika Westerberg 	if (ret)
592*6db21d81SMika Westerberg 		goto err_stop;
593*6db21d81SMika Westerberg 	return 0;
594*6db21d81SMika Westerberg 
595*6db21d81SMika Westerberg err_stop:
596*6db21d81SMika Westerberg 	tb_ring_stop(sdev->rx_ring.ring);
597*6db21d81SMika Westerberg 	tb_ring_stop(sdev->tx_ring.ring);
598*6db21d81SMika Westerberg err_free_rx:
599*6db21d81SMika Westerberg 	tb_ring_free(sdev->rx_ring.ring);
600*6db21d81SMika Westerberg err_free_tx_buffers:
601*6db21d81SMika Westerberg 	tbstream_ring_free(&sdev->tx_ring);
602*6db21d81SMika Westerberg err_free_tx:
603*6db21d81SMika Westerberg 	tb_ring_free(sdev->tx_ring.ring);
604*6db21d81SMika Westerberg 
605*6db21d81SMika Westerberg 	return ret;
606*6db21d81SMika Westerberg }
607*6db21d81SMika Westerberg 
608*6db21d81SMika Westerberg static void tbstream_dev_stop(struct tbstream_dev *sdev)
609*6db21d81SMika Westerberg {
610*6db21d81SMika Westerberg 	struct tb_xdomain *xd;
611*6db21d81SMika Westerberg 
612*6db21d81SMika Westerberg 	/* Wait for the ring to complete any outstanding frames */
613*6db21d81SMika Westerberg 	tb_ring_flush(sdev->tx_ring.ring, 500);
614*6db21d81SMika Westerberg 	tb_ring_stop(sdev->tx_ring.ring);
615*6db21d81SMika Westerberg 	tb_ring_flush(sdev->rx_ring.ring, 500);
616*6db21d81SMika Westerberg 	tb_ring_stop(sdev->rx_ring.ring);
617*6db21d81SMika Westerberg 
618*6db21d81SMika Westerberg 	xd = tbstream_dev_xdomain(sdev);
619*6db21d81SMika Westerberg 	if (xd) {
620*6db21d81SMika Westerberg 		tb_xdomain_disable_paths(xd, sdev->out_hopid,
621*6db21d81SMika Westerberg 					 sdev->tx_ring.ring->hop,
622*6db21d81SMika Westerberg 					 sdev->in_hopid,
623*6db21d81SMika Westerberg 					 sdev->rx_ring.ring->hop);
624*6db21d81SMika Westerberg 	}
625*6db21d81SMika Westerberg 
626*6db21d81SMika Westerberg 	tbstream_ring_free(&sdev->rx_ring);
627*6db21d81SMika Westerberg 	tb_ring_free(sdev->rx_ring.ring);
628*6db21d81SMika Westerberg 	sdev->rx_ring.ring = NULL;
629*6db21d81SMika Westerberg 	tbstream_ring_free(&sdev->tx_ring);
630*6db21d81SMika Westerberg 	tb_ring_free(sdev->tx_ring.ring);
631*6db21d81SMika Westerberg 	sdev->tx_ring.ring = NULL;
632*6db21d81SMika Westerberg }
633*6db21d81SMika Westerberg 
634*6db21d81SMika Westerberg static ssize_t
635*6db21d81SMika Westerberg tbstream_dev_fops_read_iter(struct kiocb *kiocb, struct iov_iter *to)
636*6db21d81SMika Westerberg {
637*6db21d81SMika Westerberg 	struct file *file = kiocb->ki_filp;
638*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = to_tbstream_dev(file->private_data);
639*6db21d81SMika Westerberg 	size_t nbytes;
640*6db21d81SMika Westerberg 	int ret;
641*6db21d81SMika Westerberg 
642*6db21d81SMika Westerberg 	ret = tbstream_dev_valid(sdev);
643*6db21d81SMika Westerberg 	if (ret)
644*6db21d81SMika Westerberg 		return ret;
645*6db21d81SMika Westerberg 
646*6db21d81SMika Westerberg 	if (mutex_lock_interruptible(&sdev->lock))
647*6db21d81SMika Westerberg 		return -ERESTARTSYS;
648*6db21d81SMika Westerberg 
649*6db21d81SMika Westerberg 	while (!tbstream_ring_available(&sdev->rx_ring)) {
650*6db21d81SMika Westerberg 		mutex_unlock(&sdev->lock);
651*6db21d81SMika Westerberg 
652*6db21d81SMika Westerberg 		if (file->f_flags & O_NONBLOCK)
653*6db21d81SMika Westerberg 			return -EAGAIN;
654*6db21d81SMika Westerberg 		ret = wait_event_interruptible(sdev->wait,
655*6db21d81SMika Westerberg 				tbstream_ring_available(&sdev->rx_ring) ||
656*6db21d81SMika Westerberg 				tbstream_dev_valid(sdev) != 0 ||
657*6db21d81SMika Westerberg 				tbstream_dev_closed(sdev) ||
658*6db21d81SMika Westerberg 				tbstream_dev_removed(sdev));
659*6db21d81SMika Westerberg 		if (ret)
660*6db21d81SMika Westerberg 			return ret;
661*6db21d81SMika Westerberg 
662*6db21d81SMika Westerberg 		ret = tbstream_dev_valid(sdev);
663*6db21d81SMika Westerberg 		if (ret)
664*6db21d81SMika Westerberg 			return ret;
665*6db21d81SMika Westerberg 
666*6db21d81SMika Westerberg 		if (tbstream_dev_closed(sdev) || tbstream_dev_removed(sdev))
667*6db21d81SMika Westerberg 			return 0;
668*6db21d81SMika Westerberg 
669*6db21d81SMika Westerberg 		if (mutex_lock_interruptible(&sdev->lock))
670*6db21d81SMika Westerberg 			return -ERESTARTSYS;
671*6db21d81SMika Westerberg 	}
672*6db21d81SMika Westerberg 
673*6db21d81SMika Westerberg 	nbytes = 0;
674*6db21d81SMika Westerberg 	while (nbytes < iov_iter_count(to)) {
675*6db21d81SMika Westerberg 		struct tbstream_frame *sf;
676*6db21d81SMika Westerberg 		size_t size, sf_size;
677*6db21d81SMika Westerberg 
678*6db21d81SMika Westerberg 		sf = tbstream_dev_completed_rx(sdev);
679*6db21d81SMika Westerberg 		if (!sf)
680*6db21d81SMika Westerberg 			break;
681*6db21d81SMika Westerberg 		/*
682*6db21d81SMika Westerberg 		 * CLOSE tunneled packet. If userspace already read
683*6db21d81SMika Westerberg 		 * something then we stop processing now and return
684*6db21d81SMika Westerberg 		 * those bytes. Next time the first frame will be CLOSE
685*6db21d81SMika Westerberg 		 * in which case we return EOF to the user.
686*6db21d81SMika Westerberg 		 */
687*6db21d81SMika Westerberg 		if (sf->frame.eof == TBSTREAM_CLOSE) {
688*6db21d81SMika Westerberg 			if (!nbytes) {
689*6db21d81SMika Westerberg 				tbstream_dev_consume_rx(sdev);
690*6db21d81SMika Westerberg 				sdev->closed = true;
691*6db21d81SMika Westerberg 			}
692*6db21d81SMika Westerberg 			break;
693*6db21d81SMika Westerberg 		}
694*6db21d81SMika Westerberg 
695*6db21d81SMika Westerberg 		sf_size = tb_ring_frame_size(&sf->frame);
696*6db21d81SMika Westerberg 		size = min(iov_iter_count(to) - nbytes, sf_size);
697*6db21d81SMika Westerberg 
698*6db21d81SMika Westerberg 		if (copy_page_to_iter(sf->page, sf->offset, size, to) != size) {
699*6db21d81SMika Westerberg 			ret = -EFAULT;
700*6db21d81SMika Westerberg 			break;
701*6db21d81SMika Westerberg 		}
702*6db21d81SMika Westerberg 
703*6db21d81SMika Westerberg 		/*
704*6db21d81SMika Westerberg 		 * If not all data from the frame is read so leave it in
705*6db21d81SMika Westerberg 		 * place and update the offset accordingly so next read
706*6db21d81SMika Westerberg 		 * gets the rest.
707*6db21d81SMika Westerberg 		 */
708*6db21d81SMika Westerberg 		if (size < sf_size) {
709*6db21d81SMika Westerberg 			sf->offset += size;
710*6db21d81SMika Westerberg 			sf->frame.size = sf_size - size;
711*6db21d81SMika Westerberg 		} else {
712*6db21d81SMika Westerberg 			ret = tbstream_dev_consume_rx(sdev);
713*6db21d81SMika Westerberg 			if (ret)
714*6db21d81SMika Westerberg 				break;
715*6db21d81SMika Westerberg 		}
716*6db21d81SMika Westerberg 
717*6db21d81SMika Westerberg 		nbytes += size;
718*6db21d81SMika Westerberg 	}
719*6db21d81SMika Westerberg 
720*6db21d81SMika Westerberg 	mutex_unlock(&sdev->lock);
721*6db21d81SMika Westerberg 	if (ret)
722*6db21d81SMika Westerberg 		return ret;
723*6db21d81SMika Westerberg 	return nbytes;
724*6db21d81SMika Westerberg }
725*6db21d81SMika Westerberg 
726*6db21d81SMika Westerberg static ssize_t
727*6db21d81SMika Westerberg tbstream_dev_fops_write_iter(struct kiocb *kiocb, struct iov_iter *from)
728*6db21d81SMika Westerberg {
729*6db21d81SMika Westerberg 	struct file *file = kiocb->ki_filp;
730*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = to_tbstream_dev(file->private_data);
731*6db21d81SMika Westerberg 	size_t nbytes;
732*6db21d81SMika Westerberg 	int ret;
733*6db21d81SMika Westerberg 
734*6db21d81SMika Westerberg 	ret = tbstream_dev_valid(sdev);
735*6db21d81SMika Westerberg 	if (ret)
736*6db21d81SMika Westerberg 		return ret;
737*6db21d81SMika Westerberg 
738*6db21d81SMika Westerberg 	if (mutex_lock_interruptible(&sdev->lock))
739*6db21d81SMika Westerberg 		return -ERESTARTSYS;
740*6db21d81SMika Westerberg 
741*6db21d81SMika Westerberg 	while (!tbstream_ring_available(&sdev->tx_ring)) {
742*6db21d81SMika Westerberg 		mutex_unlock(&sdev->lock);
743*6db21d81SMika Westerberg 
744*6db21d81SMika Westerberg 		if (file->f_flags & O_NONBLOCK)
745*6db21d81SMika Westerberg 			return -EAGAIN;
746*6db21d81SMika Westerberg 		ret = wait_event_interruptible(sdev->wait,
747*6db21d81SMika Westerberg 				tbstream_ring_available(&sdev->tx_ring) ||
748*6db21d81SMika Westerberg 				tbstream_dev_valid(sdev) != 0 ||
749*6db21d81SMika Westerberg 				tbstream_dev_closed(sdev) ||
750*6db21d81SMika Westerberg 				tbstream_dev_removed(sdev));
751*6db21d81SMika Westerberg 		if (ret)
752*6db21d81SMika Westerberg 			return ret;
753*6db21d81SMika Westerberg 
754*6db21d81SMika Westerberg 		ret = tbstream_dev_valid(sdev);
755*6db21d81SMika Westerberg 		if (ret)
756*6db21d81SMika Westerberg 			return ret;
757*6db21d81SMika Westerberg 
758*6db21d81SMika Westerberg 		if (tbstream_dev_closed(sdev) || tbstream_dev_removed(sdev))
759*6db21d81SMika Westerberg 			return -ENXIO;
760*6db21d81SMika Westerberg 
761*6db21d81SMika Westerberg 		if (mutex_lock_interruptible(&sdev->lock))
762*6db21d81SMika Westerberg 			return -ERESTARTSYS;
763*6db21d81SMika Westerberg 	}
764*6db21d81SMika Westerberg 
765*6db21d81SMika Westerberg 	nbytes = 0;
766*6db21d81SMika Westerberg 	while (nbytes < iov_iter_count(from)) {
767*6db21d81SMika Westerberg 		size_t size;
768*6db21d81SMika Westerberg 
769*6db21d81SMika Westerberg 		size = min(iov_iter_count(from) - nbytes, TB_MAX_FRAME_SIZE);
770*6db21d81SMika Westerberg 		ret = tbstream_dev_send_data(sdev, from, size);
771*6db21d81SMika Westerberg 		if (ret) {
772*6db21d81SMika Westerberg 			/*
773*6db21d81SMika Westerberg 			 * If there are no more buffers we are done for
774*6db21d81SMika Westerberg 			 * this write.
775*6db21d81SMika Westerberg 			 */
776*6db21d81SMika Westerberg 			if (ret == -ENOBUFS)
777*6db21d81SMika Westerberg 				ret = 0;
778*6db21d81SMika Westerberg 			break;
779*6db21d81SMika Westerberg 		}
780*6db21d81SMika Westerberg 
781*6db21d81SMika Westerberg 		nbytes += size;
782*6db21d81SMika Westerberg 	}
783*6db21d81SMika Westerberg 
784*6db21d81SMika Westerberg 	mutex_unlock(&sdev->lock);
785*6db21d81SMika Westerberg 	if (ret)
786*6db21d81SMika Westerberg 		return ret;
787*6db21d81SMika Westerberg 	return nbytes;
788*6db21d81SMika Westerberg }
789*6db21d81SMika Westerberg 
790*6db21d81SMika Westerberg static __poll_t
791*6db21d81SMika Westerberg tbstream_dev_fops_poll(struct file *file, struct poll_table_struct *wait)
792*6db21d81SMika Westerberg {
793*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = to_tbstream_dev(file->private_data);
794*6db21d81SMika Westerberg 	__poll_t mask = 0;
795*6db21d81SMika Westerberg 
796*6db21d81SMika Westerberg 	poll_wait(file, &sdev->wait, wait);
797*6db21d81SMika Westerberg 	guard(mutex)(&sdev->lock);
798*6db21d81SMika Westerberg 	if (tbstream_dev_valid(sdev) != 0) {
799*6db21d81SMika Westerberg 		mask |= EPOLLHUP | EPOLLERR;
800*6db21d81SMika Westerberg 	} else {
801*6db21d81SMika Westerberg 		if (tbstream_ring_available(&sdev->tx_ring))
802*6db21d81SMika Westerberg 			mask |= EPOLLOUT | EPOLLWRNORM;
803*6db21d81SMika Westerberg 		if (tbstream_ring_available(&sdev->rx_ring))
804*6db21d81SMika Westerberg 			mask |= EPOLLIN | EPOLLRDNORM;
805*6db21d81SMika Westerberg 	}
806*6db21d81SMika Westerberg 	return mask;
807*6db21d81SMika Westerberg }
808*6db21d81SMika Westerberg 
809*6db21d81SMika Westerberg static int tbstream_dev_fops_open(struct inode *inode, struct file *file)
810*6db21d81SMika Westerberg {
811*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = to_tbstream_dev(file->private_data);
812*6db21d81SMika Westerberg 	int ret;
813*6db21d81SMika Westerberg 
814*6db21d81SMika Westerberg 	tbstream_dev_get(sdev);
815*6db21d81SMika Westerberg 
816*6db21d81SMika Westerberg 	if (mutex_lock_interruptible(&sdev->lock)) {
817*6db21d81SMika Westerberg 		tbstream_dev_put(sdev);
818*6db21d81SMika Westerberg 		return -ERESTARTSYS;
819*6db21d81SMika Westerberg 	}
820*6db21d81SMika Westerberg 
821*6db21d81SMika Westerberg 	/*
822*6db21d81SMika Westerberg 	 * If there is no stream attached yet, block until it appears
823*6db21d81SMika Westerberg 	 * unless this is opened in non-blocking mode.
824*6db21d81SMika Westerberg 	 */
825*6db21d81SMika Westerberg 	while ((ret = tbstream_dev_valid(sdev))) {
826*6db21d81SMika Westerberg 		mutex_unlock(&sdev->lock);
827*6db21d81SMika Westerberg 
828*6db21d81SMika Westerberg 		if (ret != -ENXIO || (file->f_flags & O_NONBLOCK))
829*6db21d81SMika Westerberg 			goto err_put;
830*6db21d81SMika Westerberg 
831*6db21d81SMika Westerberg 		ret = wait_event_interruptible(sdev->wait,
832*6db21d81SMika Westerberg 				tbstream_dev_valid(sdev) == 0 ||
833*6db21d81SMika Westerberg 				tbstream_dev_removed(sdev));
834*6db21d81SMika Westerberg 		if (ret)
835*6db21d81SMika Westerberg 			goto err_put;
836*6db21d81SMika Westerberg 
837*6db21d81SMika Westerberg 		if (tbstream_dev_removed(sdev)) {
838*6db21d81SMika Westerberg 			ret = -ENXIO;
839*6db21d81SMika Westerberg 			goto err_put;
840*6db21d81SMika Westerberg 		}
841*6db21d81SMika Westerberg 
842*6db21d81SMika Westerberg 		if (mutex_lock_interruptible(&sdev->lock)) {
843*6db21d81SMika Westerberg 			ret = -ERESTARTSYS;
844*6db21d81SMika Westerberg 			goto err_put;
845*6db21d81SMika Westerberg 		}
846*6db21d81SMika Westerberg 	}
847*6db21d81SMika Westerberg 
848*6db21d81SMika Westerberg 	/* Only on first open we allocate rings and enable paths */
849*6db21d81SMika Westerberg 	if (!sdev->users++) {
850*6db21d81SMika Westerberg 		ret = tbstream_dev_start(sdev);
851*6db21d81SMika Westerberg 		if (ret) {
852*6db21d81SMika Westerberg 			sdev->users--;
853*6db21d81SMika Westerberg 			goto err_unlock;
854*6db21d81SMika Westerberg 		}
855*6db21d81SMika Westerberg 		sdev->closed = false;
856*6db21d81SMika Westerberg 	}
857*6db21d81SMika Westerberg 
858*6db21d81SMika Westerberg 	mutex_unlock(&sdev->lock);
859*6db21d81SMika Westerberg 	return 0;
860*6db21d81SMika Westerberg 
861*6db21d81SMika Westerberg err_unlock:
862*6db21d81SMika Westerberg 	mutex_unlock(&sdev->lock);
863*6db21d81SMika Westerberg err_put:
864*6db21d81SMika Westerberg 	tbstream_dev_put(sdev);
865*6db21d81SMika Westerberg 
866*6db21d81SMika Westerberg 	return ret;
867*6db21d81SMika Westerberg }
868*6db21d81SMika Westerberg 
869*6db21d81SMika Westerberg static int tbstream_dev_fops_release(struct inode *inode, struct file *file)
870*6db21d81SMika Westerberg {
871*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = to_tbstream_dev(file->private_data);
872*6db21d81SMika Westerberg 
873*6db21d81SMika Westerberg 	mutex_lock(&sdev->lock);
874*6db21d81SMika Westerberg 	if (--sdev->users == 0) {
875*6db21d81SMika Westerberg 		/*
876*6db21d81SMika Westerberg 		 * Send CLOSE tunneled packet to notify the other end
877*6db21d81SMika Westerberg 		 * that we are closing the file. We do this twice if the
878*6db21d81SMika Westerberg 		 * first one fails.
879*6db21d81SMika Westerberg 		 */
880*6db21d81SMika Westerberg 		tbstream_dev_send_close(sdev);
881*6db21d81SMika Westerberg 		tbstream_dev_stop(sdev);
882*6db21d81SMika Westerberg 	}
883*6db21d81SMika Westerberg 	mutex_unlock(&sdev->lock);
884*6db21d81SMika Westerberg 
885*6db21d81SMika Westerberg 	tbstream_dev_put(sdev);
886*6db21d81SMika Westerberg 	return 0;
887*6db21d81SMika Westerberg }
888*6db21d81SMika Westerberg 
889*6db21d81SMika Westerberg static const struct file_operations tbstream_dev_fops = {
890*6db21d81SMika Westerberg 	.owner = THIS_MODULE,
891*6db21d81SMika Westerberg 	.llseek = noop_llseek,
892*6db21d81SMika Westerberg 	.read_iter = tbstream_dev_fops_read_iter,
893*6db21d81SMika Westerberg 	.write_iter = tbstream_dev_fops_write_iter,
894*6db21d81SMika Westerberg 	.poll = tbstream_dev_fops_poll,
895*6db21d81SMika Westerberg 	.open = tbstream_dev_fops_open,
896*6db21d81SMika Westerberg 	.release = tbstream_dev_fops_release,
897*6db21d81SMika Westerberg };
898*6db21d81SMika Westerberg 
899*6db21d81SMika Westerberg static inline struct tbstream_dev *
900*6db21d81SMika Westerberg tbstream_dev_from_group(struct config_group *group)
901*6db21d81SMika Westerberg {
902*6db21d81SMika Westerberg 	return container_of(group, struct tbstream_dev, group);
903*6db21d81SMika Westerberg }
904*6db21d81SMika Westerberg 
905*6db21d81SMika Westerberg static ssize_t tbstream_dev_index_show(struct config_item *item, char *buf)
906*6db21d81SMika Westerberg {
907*6db21d81SMika Westerberg 	struct config_group *group = to_config_group(item);
908*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = tbstream_dev_from_group(group);
909*6db21d81SMika Westerberg 
910*6db21d81SMika Westerberg 	return sysfs_emit(buf, "%d\n", sdev->index);
911*6db21d81SMika Westerberg }
912*6db21d81SMika Westerberg CONFIGFS_ATTR_RO(tbstream_dev_, index);
913*6db21d81SMika Westerberg 
914*6db21d81SMika Westerberg static ssize_t tbstream_dev_in_hopid_show(struct config_item *item, char *buf)
915*6db21d81SMika Westerberg {
916*6db21d81SMika Westerberg 	struct config_group *group = to_config_group(item);
917*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = tbstream_dev_from_group(group);
918*6db21d81SMika Westerberg 
919*6db21d81SMika Westerberg 	return sysfs_emit(buf, "%d\n", sdev->in_hopid);
920*6db21d81SMika Westerberg }
921*6db21d81SMika Westerberg 
922*6db21d81SMika Westerberg /* svc->lock must be held */
923*6db21d81SMika Westerberg static void service_remove_properties(struct tb_service *svc, const char *name)
924*6db21d81SMika Westerberg {
925*6db21d81SMika Westerberg 	struct tb_property *p;
926*6db21d81SMika Westerberg 
927*6db21d81SMika Westerberg 	if (!svc->local_properties)
928*6db21d81SMika Westerberg 		return;
929*6db21d81SMika Westerberg 
930*6db21d81SMika Westerberg 	p = tb_property_find(svc->local_properties, name,
931*6db21d81SMika Westerberg 			     TB_PROPERTY_TYPE_DIRECTORY);
932*6db21d81SMika Westerberg 	if (p) {
933*6db21d81SMika Westerberg 		tb_property_free_dir(p->value.dir);
934*6db21d81SMika Westerberg 		tb_property_remove(p);
935*6db21d81SMika Westerberg 
936*6db21d81SMika Westerberg 		dev_dbg(&svc->dev, "removed local directory %s\n", name);
937*6db21d81SMika Westerberg 
938*6db21d81SMika Westerberg 		/*
939*6db21d81SMika Westerberg 		 * Is the service directory empty already? If it is then
940*6db21d81SMika Westerberg 		 * we can release it as well.
941*6db21d81SMika Westerberg 		 */
942*6db21d81SMika Westerberg 		tb_property_for_each(svc->local_properties, p) {
943*6db21d81SMika Westerberg 			if (p->type == TB_PROPERTY_TYPE_DIRECTORY)
944*6db21d81SMika Westerberg 				return;
945*6db21d81SMika Westerberg 		}
946*6db21d81SMika Westerberg 
947*6db21d81SMika Westerberg 		tb_property_free_dir(svc->local_properties);
948*6db21d81SMika Westerberg 		svc->local_properties = NULL;
949*6db21d81SMika Westerberg 	}
950*6db21d81SMika Westerberg }
951*6db21d81SMika Westerberg 
952*6db21d81SMika Westerberg static int service_update_properties(struct tb_service *svc, const char *name,
953*6db21d81SMika Westerberg 				     int in_hopid, int out_hopid)
954*6db21d81SMika Westerberg {
955*6db21d81SMika Westerberg 	struct tb_property_dir *dir;
956*6db21d81SMika Westerberg 	struct tb_property *p;
957*6db21d81SMika Westerberg 
958*6db21d81SMika Westerberg 	guard(mutex)(&svc->lock);
959*6db21d81SMika Westerberg 
960*6db21d81SMika Westerberg 	if (in_hopid < 8 || out_hopid < 8) {
961*6db21d81SMika Westerberg 		service_remove_properties(svc, name);
962*6db21d81SMika Westerberg 		return 0;
963*6db21d81SMika Westerberg 	}
964*6db21d81SMika Westerberg 
965*6db21d81SMika Westerberg 	if (!svc->local_properties) {
966*6db21d81SMika Westerberg 		/*
967*6db21d81SMika Westerberg 		 * Add the service directory first time we
968*6db21d81SMika Westerberg 		 * populate the entries.
969*6db21d81SMika Westerberg 		 */
970*6db21d81SMika Westerberg 		svc->local_properties = tb_property_copy_dir(tbstream_dir);
971*6db21d81SMika Westerberg 		if (!svc->local_properties)
972*6db21d81SMika Westerberg 			return -ENOMEM;
973*6db21d81SMika Westerberg 	}
974*6db21d81SMika Westerberg 
975*6db21d81SMika Westerberg 	p = tb_property_find(svc->local_properties, name,
976*6db21d81SMika Westerberg 			     TB_PROPERTY_TYPE_DIRECTORY);
977*6db21d81SMika Westerberg 	if (p) {
978*6db21d81SMika Westerberg 		dir = p->value.dir;
979*6db21d81SMika Westerberg 
980*6db21d81SMika Westerberg 		p = tb_property_find(dir, "inhopid", TB_PROPERTY_TYPE_VALUE);
981*6db21d81SMika Westerberg 		if (p && p->value.immediate != in_hopid)
982*6db21d81SMika Westerberg 			p->value.immediate = in_hopid;
983*6db21d81SMika Westerberg 		p = tb_property_find(dir, "outhopid", TB_PROPERTY_TYPE_VALUE);
984*6db21d81SMika Westerberg 		if (p && p->value.immediate != out_hopid)
985*6db21d81SMika Westerberg 			p->value.immediate = out_hopid;
986*6db21d81SMika Westerberg 
987*6db21d81SMika Westerberg 		dev_dbg(&svc->dev,
988*6db21d81SMika Westerberg 			"updated local directory %s: in HopID %d, out HopID %d\n",
989*6db21d81SMika Westerberg 			name, in_hopid, out_hopid);
990*6db21d81SMika Westerberg 	} else {
991*6db21d81SMika Westerberg 		uuid_t uuid;
992*6db21d81SMika Westerberg 		int ret;
993*6db21d81SMika Westerberg 
994*6db21d81SMika Westerberg 		uuid_gen(&uuid);
995*6db21d81SMika Westerberg 		dir = tb_property_create_dir(&uuid);
996*6db21d81SMika Westerberg 		if (!dir)
997*6db21d81SMika Westerberg 			return -ENOMEM;
998*6db21d81SMika Westerberg 
999*6db21d81SMika Westerberg 		tb_property_add_immediate(dir, "inhopid", in_hopid);
1000*6db21d81SMika Westerberg 		tb_property_add_immediate(dir, "outhopid", out_hopid);
1001*6db21d81SMika Westerberg 
1002*6db21d81SMika Westerberg 		ret = tb_property_add_dir(svc->local_properties, name, dir);
1003*6db21d81SMika Westerberg 		if (ret) {
1004*6db21d81SMika Westerberg 			tb_property_free_dir(dir);
1005*6db21d81SMika Westerberg 			return ret;
1006*6db21d81SMika Westerberg 		}
1007*6db21d81SMika Westerberg 
1008*6db21d81SMika Westerberg 		dev_dbg(&svc->dev,
1009*6db21d81SMika Westerberg 			"added local directory %s: in HopID %d, out HopID %d\n",
1010*6db21d81SMika Westerberg 			name, in_hopid, out_hopid);
1011*6db21d81SMika Westerberg 	}
1012*6db21d81SMika Westerberg 
1013*6db21d81SMika Westerberg 	return 0;
1014*6db21d81SMika Westerberg }
1015*6db21d81SMika Westerberg 
1016*6db21d81SMika Westerberg static int tbstream_dev_update_properties(struct tbstream_dev *sdev)
1017*6db21d81SMika Westerberg {
1018*6db21d81SMika Westerberg 	struct tbstream *stream;
1019*6db21d81SMika Westerberg 	int ret;
1020*6db21d81SMika Westerberg 
1021*6db21d81SMika Westerberg 	stream = tbstream_get(sdev->stream);
1022*6db21d81SMika Westerberg 	if (!stream)
1023*6db21d81SMika Westerberg 		return 0;
1024*6db21d81SMika Westerberg 
1025*6db21d81SMika Westerberg 	ret = service_update_properties(stream->svc,
1026*6db21d81SMika Westerberg 					config_item_name(&sdev->group.cg_item),
1027*6db21d81SMika Westerberg 					sdev->in_hopid, sdev->out_hopid);
1028*6db21d81SMika Westerberg 	if (!ret)
1029*6db21d81SMika Westerberg 		tb_service_properties_changed(stream->svc);
1030*6db21d81SMika Westerberg 
1031*6db21d81SMika Westerberg 	tbstream_put(stream);
1032*6db21d81SMika Westerberg 	return ret;
1033*6db21d81SMika Westerberg }
1034*6db21d81SMika Westerberg 
1035*6db21d81SMika Westerberg static int tbstream_dev_alloc_in_hopid(struct tbstream_dev *sdev, int hopid)
1036*6db21d81SMika Westerberg {
1037*6db21d81SMika Westerberg 	struct tb_xdomain *xd = tbstream_dev_xdomain(sdev);
1038*6db21d81SMika Westerberg 	int ret;
1039*6db21d81SMika Westerberg 
1040*6db21d81SMika Westerberg 	if (sdev->in_hopid > 0 && sdev->in_hopid != hopid)
1041*6db21d81SMika Westerberg 		tb_xdomain_release_in_hopid(xd, sdev->in_hopid);
1042*6db21d81SMika Westerberg 	if (!hopid) {
1043*6db21d81SMika Westerberg 		sdev->in_hopid = hopid;
1044*6db21d81SMika Westerberg 		return 0;
1045*6db21d81SMika Westerberg 	}
1046*6db21d81SMika Westerberg 	ret = tb_xdomain_alloc_in_hopid(xd, hopid);
1047*6db21d81SMika Westerberg 	if (ret < 0)
1048*6db21d81SMika Westerberg 		return ret;
1049*6db21d81SMika Westerberg 	/*
1050*6db21d81SMika Westerberg 	 * If specific HopID was asked by the user and we did not get
1051*6db21d81SMika Westerberg 	 * that one then release and return error instead.
1052*6db21d81SMika Westerberg 	 */
1053*6db21d81SMika Westerberg 	if (hopid > 0 && hopid != ret) {
1054*6db21d81SMika Westerberg 		tb_xdomain_release_in_hopid(xd, ret);
1055*6db21d81SMika Westerberg 		return -EBUSY;
1056*6db21d81SMika Westerberg 	}
1057*6db21d81SMika Westerberg 	sdev->in_hopid = ret;
1058*6db21d81SMika Westerberg 	return 0;
1059*6db21d81SMika Westerberg }
1060*6db21d81SMika Westerberg 
1061*6db21d81SMika Westerberg static int tbstream_dev_alloc_out_hopid(struct tbstream_dev *sdev, int hopid)
1062*6db21d81SMika Westerberg {
1063*6db21d81SMika Westerberg 	struct tb_xdomain *xd = tbstream_dev_xdomain(sdev);
1064*6db21d81SMika Westerberg 	int ret;
1065*6db21d81SMika Westerberg 
1066*6db21d81SMika Westerberg 	if (sdev->out_hopid > 0 && sdev->out_hopid != hopid)
1067*6db21d81SMika Westerberg 		tb_xdomain_release_out_hopid(xd, sdev->out_hopid);
1068*6db21d81SMika Westerberg 	if (!hopid) {
1069*6db21d81SMika Westerberg 		sdev->out_hopid = hopid;
1070*6db21d81SMika Westerberg 		return 0;
1071*6db21d81SMika Westerberg 	}
1072*6db21d81SMika Westerberg 	ret = tb_xdomain_alloc_out_hopid(xd, hopid);
1073*6db21d81SMika Westerberg 	if (ret < 0)
1074*6db21d81SMika Westerberg 		return ret;
1075*6db21d81SMika Westerberg 	if (hopid > 0 && hopid != ret) {
1076*6db21d81SMika Westerberg 		tb_xdomain_release_out_hopid(xd, ret);
1077*6db21d81SMika Westerberg 		return -EBUSY;
1078*6db21d81SMika Westerberg 	}
1079*6db21d81SMika Westerberg 	sdev->out_hopid = ret;
1080*6db21d81SMika Westerberg 	return 0;
1081*6db21d81SMika Westerberg }
1082*6db21d81SMika Westerberg 
1083*6db21d81SMika Westerberg static ssize_t
1084*6db21d81SMika Westerberg tbstream_dev_in_hopid_store(struct config_item *item, const char *buf,
1085*6db21d81SMika Westerberg 			    size_t count)
1086*6db21d81SMika Westerberg {
1087*6db21d81SMika Westerberg 	struct config_group *group = to_config_group(item);
1088*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = tbstream_dev_from_group(group);
1089*6db21d81SMika Westerberg 	int ret, in_hopid;
1090*6db21d81SMika Westerberg 
1091*6db21d81SMika Westerberg 	ret = kstrtoint(buf, 0, &in_hopid);
1092*6db21d81SMika Westerberg 	if (ret)
1093*6db21d81SMika Westerberg 		return ret;
1094*6db21d81SMika Westerberg 
1095*6db21d81SMika Westerberg 	guard(mutex)(&sdev->lock);
1096*6db21d81SMika Westerberg 	if (sdev->users)
1097*6db21d81SMika Westerberg 		return -EBUSY;
1098*6db21d81SMika Westerberg 	if (sdev->stream) {
1099*6db21d81SMika Westerberg 		ret = tbstream_dev_alloc_in_hopid(sdev, in_hopid);
1100*6db21d81SMika Westerberg 		if (ret)
1101*6db21d81SMika Westerberg 			return ret;
1102*6db21d81SMika Westerberg 		ret = tbstream_dev_update_properties(sdev);
1103*6db21d81SMika Westerberg 	} else {
1104*6db21d81SMika Westerberg 		sdev->in_hopid = in_hopid;
1105*6db21d81SMika Westerberg 	}
1106*6db21d81SMika Westerberg 	return ret ? ret : count;
1107*6db21d81SMika Westerberg }
1108*6db21d81SMika Westerberg CONFIGFS_ATTR(tbstream_dev_, in_hopid);
1109*6db21d81SMika Westerberg 
1110*6db21d81SMika Westerberg static ssize_t tbstream_dev_out_hopid_show(struct config_item *item, char *buf)
1111*6db21d81SMika Westerberg {
1112*6db21d81SMika Westerberg 	struct config_group *group = to_config_group(item);
1113*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = tbstream_dev_from_group(group);
1114*6db21d81SMika Westerberg 
1115*6db21d81SMika Westerberg 	return sysfs_emit(buf, "%d\n", sdev->out_hopid);
1116*6db21d81SMika Westerberg }
1117*6db21d81SMika Westerberg 
1118*6db21d81SMika Westerberg static ssize_t
1119*6db21d81SMika Westerberg tbstream_dev_out_hopid_store(struct config_item *item, const char *buf,
1120*6db21d81SMika Westerberg 			     size_t count)
1121*6db21d81SMika Westerberg {
1122*6db21d81SMika Westerberg 	struct config_group *group = to_config_group(item);
1123*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = tbstream_dev_from_group(group);
1124*6db21d81SMika Westerberg 	int ret, out_hopid;
1125*6db21d81SMika Westerberg 
1126*6db21d81SMika Westerberg 	ret = kstrtoint(buf, 0, &out_hopid);
1127*6db21d81SMika Westerberg 	if (ret)
1128*6db21d81SMika Westerberg 		return ret;
1129*6db21d81SMika Westerberg 
1130*6db21d81SMika Westerberg 	guard(mutex)(&sdev->lock);
1131*6db21d81SMika Westerberg 	if (sdev->users)
1132*6db21d81SMika Westerberg 		return -EBUSY;
1133*6db21d81SMika Westerberg 	if (sdev->stream) {
1134*6db21d81SMika Westerberg 		ret = tbstream_dev_alloc_out_hopid(sdev, out_hopid);
1135*6db21d81SMika Westerberg 		if (ret)
1136*6db21d81SMika Westerberg 			return ret;
1137*6db21d81SMika Westerberg 		ret = tbstream_dev_update_properties(sdev);
1138*6db21d81SMika Westerberg 	} else {
1139*6db21d81SMika Westerberg 		sdev->out_hopid = out_hopid;
1140*6db21d81SMika Westerberg 	}
1141*6db21d81SMika Westerberg 	return ret ? ret : count;
1142*6db21d81SMika Westerberg }
1143*6db21d81SMika Westerberg CONFIGFS_ATTR(tbstream_dev_, out_hopid);
1144*6db21d81SMika Westerberg 
1145*6db21d81SMika Westerberg static ssize_t tbstream_dev_ring_size_show(struct config_item *item, char *buf)
1146*6db21d81SMika Westerberg {
1147*6db21d81SMika Westerberg 	struct config_group *group = to_config_group(item);
1148*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = tbstream_dev_from_group(group);
1149*6db21d81SMika Westerberg 
1150*6db21d81SMika Westerberg 	return sysfs_emit(buf, "%u\n", sdev->ring_size);
1151*6db21d81SMika Westerberg }
1152*6db21d81SMika Westerberg 
1153*6db21d81SMika Westerberg static ssize_t
1154*6db21d81SMika Westerberg tbstream_dev_ring_size_store(struct config_item *item, const char *buf,
1155*6db21d81SMika Westerberg 			     size_t count)
1156*6db21d81SMika Westerberg {
1157*6db21d81SMika Westerberg 	struct config_group *group = to_config_group(item);
1158*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = tbstream_dev_from_group(group);
1159*6db21d81SMika Westerberg 	unsigned int ring_size;
1160*6db21d81SMika Westerberg 	int ret;
1161*6db21d81SMika Westerberg 
1162*6db21d81SMika Westerberg 	ret = kstrtouint(buf, 0, &ring_size);
1163*6db21d81SMika Westerberg 	if (ret)
1164*6db21d81SMika Westerberg 		return ret;
1165*6db21d81SMika Westerberg 
1166*6db21d81SMika Westerberg 	if (ring_size < TBSTREAM_DEV_MIN_RING_SIZE ||
1167*6db21d81SMika Westerberg 	    ring_size > TBSTREAM_DEV_MAX_RING_SIZE)
1168*6db21d81SMika Westerberg 		return -EINVAL;
1169*6db21d81SMika Westerberg 
1170*6db21d81SMika Westerberg 	guard(mutex)(&sdev->lock);
1171*6db21d81SMika Westerberg 	if (sdev->users)
1172*6db21d81SMika Westerberg 		return -EBUSY;
1173*6db21d81SMika Westerberg 	sdev->ring_size = ring_size;
1174*6db21d81SMika Westerberg 	return count;
1175*6db21d81SMika Westerberg }
1176*6db21d81SMika Westerberg CONFIGFS_ATTR(tbstream_dev_, ring_size);
1177*6db21d81SMika Westerberg 
1178*6db21d81SMika Westerberg static ssize_t tbstream_dev_throttling_show(struct config_item *item, char *buf)
1179*6db21d81SMika Westerberg {
1180*6db21d81SMika Westerberg 	struct config_group *group = to_config_group(item);
1181*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = tbstream_dev_from_group(group);
1182*6db21d81SMika Westerberg 
1183*6db21d81SMika Westerberg 	return sysfs_emit(buf, "%u\n", sdev->throttling);
1184*6db21d81SMika Westerberg }
1185*6db21d81SMika Westerberg 
1186*6db21d81SMika Westerberg static ssize_t
1187*6db21d81SMika Westerberg tbstream_dev_throttling_store(struct config_item *item, const char *buf,
1188*6db21d81SMika Westerberg 			      size_t count)
1189*6db21d81SMika Westerberg {
1190*6db21d81SMika Westerberg 	struct config_group *group = to_config_group(item);
1191*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = tbstream_dev_from_group(group);
1192*6db21d81SMika Westerberg 	unsigned int throttling;
1193*6db21d81SMika Westerberg 	int ret;
1194*6db21d81SMika Westerberg 
1195*6db21d81SMika Westerberg 	ret = kstrtouint(buf, 0, &throttling);
1196*6db21d81SMika Westerberg 	if (ret)
1197*6db21d81SMika Westerberg 		return ret;
1198*6db21d81SMika Westerberg 
1199*6db21d81SMika Westerberg 	if (throttling > TBSTREAM_DEV_MAX_THROTTLING)
1200*6db21d81SMika Westerberg 		return -EINVAL;
1201*6db21d81SMika Westerberg 
1202*6db21d81SMika Westerberg 	guard(mutex)(&sdev->lock);
1203*6db21d81SMika Westerberg 	if (sdev->users)
1204*6db21d81SMika Westerberg 		return -EBUSY;
1205*6db21d81SMika Westerberg 	sdev->throttling = throttling;
1206*6db21d81SMika Westerberg 	return count;
1207*6db21d81SMika Westerberg }
1208*6db21d81SMika Westerberg CONFIGFS_ATTR(tbstream_dev_, throttling);
1209*6db21d81SMika Westerberg 
1210*6db21d81SMika Westerberg static struct configfs_attribute *tbstream_dev_attrs[] = {
1211*6db21d81SMika Westerberg 	&tbstream_dev_attr_index,
1212*6db21d81SMika Westerberg 	&tbstream_dev_attr_in_hopid,
1213*6db21d81SMika Westerberg 	&tbstream_dev_attr_out_hopid,
1214*6db21d81SMika Westerberg 	&tbstream_dev_attr_ring_size,
1215*6db21d81SMika Westerberg 	&tbstream_dev_attr_throttling,
1216*6db21d81SMika Westerberg 	NULL,
1217*6db21d81SMika Westerberg };
1218*6db21d81SMika Westerberg 
1219*6db21d81SMika Westerberg static void tbstream_dev_item_release(struct config_item *item)
1220*6db21d81SMika Westerberg {
1221*6db21d81SMika Westerberg 	struct config_group *group = to_config_group(item);
1222*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = tbstream_dev_from_group(group);
1223*6db21d81SMika Westerberg 
1224*6db21d81SMika Westerberg 	misc_deregister(&sdev->misc);
1225*6db21d81SMika Westerberg 	tbstream_dev_put(sdev);
1226*6db21d81SMika Westerberg }
1227*6db21d81SMika Westerberg 
1228*6db21d81SMika Westerberg static struct configfs_item_operations tbstream_dev_item_ops = {
1229*6db21d81SMika Westerberg 	.release = tbstream_dev_item_release,
1230*6db21d81SMika Westerberg };
1231*6db21d81SMika Westerberg 
1232*6db21d81SMika Westerberg static const struct config_item_type tbstream_dev_type = {
1233*6db21d81SMika Westerberg 	.ct_owner = THIS_MODULE,
1234*6db21d81SMika Westerberg 	.ct_item_ops = &tbstream_dev_item_ops,
1235*6db21d81SMika Westerberg 	.ct_attrs = tbstream_dev_attrs,
1236*6db21d81SMika Westerberg };
1237*6db21d81SMika Westerberg 
1238*6db21d81SMika Westerberg static void service_get_hopids(struct tb_service *svc, const char *name,
1239*6db21d81SMika Westerberg 			       int *in_hopid, int *out_hopid)
1240*6db21d81SMika Westerberg {
1241*6db21d81SMika Westerberg 	struct tb_property_dir *dir;
1242*6db21d81SMika Westerberg 	struct tb_property *p;
1243*6db21d81SMika Westerberg 
1244*6db21d81SMika Westerberg 	guard(mutex)(&svc->lock);
1245*6db21d81SMika Westerberg 
1246*6db21d81SMika Westerberg 	/* See if we have directory entry with the matching name */
1247*6db21d81SMika Westerberg 	p = tb_property_find(svc->remote_properties, name,
1248*6db21d81SMika Westerberg 			     TB_PROPERTY_TYPE_DIRECTORY);
1249*6db21d81SMika Westerberg 	if (!p)
1250*6db21d81SMika Westerberg 		return;
1251*6db21d81SMika Westerberg 
1252*6db21d81SMika Westerberg 	dir = p->value.dir;
1253*6db21d81SMika Westerberg 
1254*6db21d81SMika Westerberg 	/*
1255*6db21d81SMika Westerberg 	 * We need to reverse the HopIDs on our end so that in becomes
1256*6db21d81SMika Westerberg 	 * out and vice versa.
1257*6db21d81SMika Westerberg 	 */
1258*6db21d81SMika Westerberg 	p = tb_property_find(dir, "inhopid", TB_PROPERTY_TYPE_VALUE);
1259*6db21d81SMika Westerberg 	if (p && p->value.immediate >= 8)
1260*6db21d81SMika Westerberg 		*out_hopid = p->value.immediate;
1261*6db21d81SMika Westerberg 	p = tb_property_find(dir, "outhopid", TB_PROPERTY_TYPE_VALUE);
1262*6db21d81SMika Westerberg 	if (p && p->value.immediate >= 8)
1263*6db21d81SMika Westerberg 		*in_hopid = p->value.immediate;
1264*6db21d81SMika Westerberg }
1265*6db21d81SMika Westerberg 
1266*6db21d81SMika Westerberg static void
1267*6db21d81SMika Westerberg tbstream_dev_attach_stream(struct tbstream_dev *sdev, struct tbstream_group *sg)
1268*6db21d81SMika Westerberg {
1269*6db21d81SMika Westerberg 	const char *name = config_item_name(&sdev->group.cg_item);
1270*6db21d81SMika Westerberg 	struct tbstream *stream;
1271*6db21d81SMika Westerberg 
1272*6db21d81SMika Westerberg 	stream = tbstream_get(sg->stream);
1273*6db21d81SMika Westerberg 	if (!stream)
1274*6db21d81SMika Westerberg 		return;
1275*6db21d81SMika Westerberg 
1276*6db21d81SMika Westerberg 	scoped_guard(mutex, &sdev->lock) {
1277*6db21d81SMika Westerberg 		sdev->stream = stream;
1278*6db21d81SMika Westerberg 		/*
1279*6db21d81SMika Westerberg 		 * If there is no existing configuration (or automatic
1280*6db21d81SMika Westerberg 		 * configuration is being used) check if the other side
1281*6db21d81SMika Westerberg 		 * has configuration for this and use it.
1282*6db21d81SMika Westerberg 		 */
1283*6db21d81SMika Westerberg 		if (sdev->in_hopid <= 0 && sdev->out_hopid <= 0)
1284*6db21d81SMika Westerberg 			service_get_hopids(stream->svc, name, &sdev->in_hopid,
1285*6db21d81SMika Westerberg 					   &sdev->out_hopid);
1286*6db21d81SMika Westerberg 		if (sdev->in_hopid)
1287*6db21d81SMika Westerberg 			tbstream_dev_alloc_in_hopid(sdev, sdev->in_hopid);
1288*6db21d81SMika Westerberg 		if (sdev->out_hopid)
1289*6db21d81SMika Westerberg 			tbstream_dev_alloc_out_hopid(sdev, sdev->out_hopid);
1290*6db21d81SMika Westerberg 	}
1291*6db21d81SMika Westerberg 
1292*6db21d81SMika Westerberg 	service_update_properties(stream->svc, name, sdev->in_hopid,
1293*6db21d81SMika Westerberg 				  sdev->out_hopid);
1294*6db21d81SMika Westerberg 	tb_service_properties_changed(stream->svc);
1295*6db21d81SMika Westerberg 
1296*6db21d81SMika Westerberg 	/* Notify any openerers that the stream is now attached */
1297*6db21d81SMika Westerberg 	wake_up_interruptible(&sdev->wait);
1298*6db21d81SMika Westerberg }
1299*6db21d81SMika Westerberg 
1300*6db21d81SMika Westerberg static void tbstream_dev_detach_stream(struct tbstream_dev *sdev)
1301*6db21d81SMika Westerberg {
1302*6db21d81SMika Westerberg 	const char *name = config_item_name(&sdev->group.cg_item);
1303*6db21d81SMika Westerberg 	struct tbstream *stream;
1304*6db21d81SMika Westerberg 	struct tb_xdomain *xd;
1305*6db21d81SMika Westerberg 
1306*6db21d81SMika Westerberg 	scoped_guard(mutex, &sdev->lock) {
1307*6db21d81SMika Westerberg 		stream = sdev->stream;
1308*6db21d81SMika Westerberg 		if (!stream)
1309*6db21d81SMika Westerberg 			return;
1310*6db21d81SMika Westerberg 		sdev->stream = NULL;
1311*6db21d81SMika Westerberg 		xd = tb_service_parent(stream->svc);
1312*6db21d81SMika Westerberg 		if (sdev->out_hopid > 0)
1313*6db21d81SMika Westerberg 			tb_xdomain_release_out_hopid(xd, sdev->out_hopid);
1314*6db21d81SMika Westerberg 		if (sdev->in_hopid > 0)
1315*6db21d81SMika Westerberg 			tb_xdomain_release_in_hopid(xd, sdev->in_hopid);
1316*6db21d81SMika Westerberg 	}
1317*6db21d81SMika Westerberg 
1318*6db21d81SMika Westerberg 	service_update_properties(stream->svc, name, 0, 0);
1319*6db21d81SMika Westerberg 	tb_service_properties_changed(stream->svc);
1320*6db21d81SMika Westerberg 
1321*6db21d81SMika Westerberg 	tbstream_put(stream);
1322*6db21d81SMika Westerberg 
1323*6db21d81SMika Westerberg 	/* Notify any task that the stream is not valid anymore */
1324*6db21d81SMika Westerberg 	wake_up_interruptible_poll(&sdev->wait, EPOLLHUP | EPOLLERR);
1325*6db21d81SMika Westerberg }
1326*6db21d81SMika Westerberg 
1327*6db21d81SMika Westerberg static inline struct tbstream_group *
1328*6db21d81SMika Westerberg to_tbstream_group(struct config_group *group)
1329*6db21d81SMika Westerberg {
1330*6db21d81SMika Westerberg 	return container_of(group, struct tbstream_group, group);
1331*6db21d81SMika Westerberg }
1332*6db21d81SMika Westerberg 
1333*6db21d81SMika Westerberg static struct config_group *
1334*6db21d81SMika Westerberg tbstream_dev_make_group(struct config_group *group, const char *name)
1335*6db21d81SMika Westerberg {
1336*6db21d81SMika Westerberg 	struct tbstream_group *sg = to_tbstream_group(group);
1337*6db21d81SMika Westerberg 	struct tbstream_dev *sdev;
1338*6db21d81SMika Westerberg 	int ret, index;
1339*6db21d81SMika Westerberg 
1340*6db21d81SMika Westerberg 	/*
1341*6db21d81SMika Westerberg 	 * We want the names to be suitable for passing as property
1342*6db21d81SMika Westerberg 	 * directory names.
1343*6db21d81SMika Westerberg 	 */
1344*6db21d81SMika Westerberg 	if (strlen(name) > TB_PROPERTY_KEY_SIZE)
1345*6db21d81SMika Westerberg 		return ERR_PTR(-ENAMETOOLONG);
1346*6db21d81SMika Westerberg 
1347*6db21d81SMika Westerberg 	sdev = kzalloc_obj(*sdev, GFP_KERNEL);
1348*6db21d81SMika Westerberg 	if (!sdev)
1349*6db21d81SMika Westerberg 		return ERR_PTR(-ENOMEM);
1350*6db21d81SMika Westerberg 
1351*6db21d81SMika Westerberg 	index = ida_alloc(&tbstream_indices, GFP_KERNEL);
1352*6db21d81SMika Westerberg 	if (index < 0) {
1353*6db21d81SMika Westerberg 		kfree(sdev);
1354*6db21d81SMika Westerberg 		return ERR_PTR(index);
1355*6db21d81SMika Westerberg 	}
1356*6db21d81SMika Westerberg 
1357*6db21d81SMika Westerberg 	sdev->index = index;
1358*6db21d81SMika Westerberg 	sdev->ring_size = TBSTREAM_DEV_RING_SIZE;
1359*6db21d81SMika Westerberg 	sdev->throttling = TBSTREAM_DEV_THROTTLING;
1360*6db21d81SMika Westerberg 	mutex_init(&sdev->lock);
1361*6db21d81SMika Westerberg 	init_waitqueue_head(&sdev->wait);
1362*6db21d81SMika Westerberg 	INIT_LIST_HEAD(&sdev->list);
1363*6db21d81SMika Westerberg 	/* This point forward tbstream_dev_put() must be used to release sdev */
1364*6db21d81SMika Westerberg 	kref_init(&sdev->kref);
1365*6db21d81SMika Westerberg 
1366*6db21d81SMika Westerberg 	config_group_init_type_name(&sdev->group, name, &tbstream_dev_type);
1367*6db21d81SMika Westerberg 
1368*6db21d81SMika Westerberg 	scoped_guard(mutex, &sg->lock)
1369*6db21d81SMika Westerberg 		list_add_tail(&sdev->list, &sg->dev_list);
1370*6db21d81SMika Westerberg 
1371*6db21d81SMika Westerberg 	tbstream_dev_attach_stream(sdev, sg);
1372*6db21d81SMika Westerberg 
1373*6db21d81SMika Westerberg 	sdev->misc.name = kasprintf(GFP_KERNEL, "tbstream%d", index);
1374*6db21d81SMika Westerberg 	sdev->misc.minor = MISC_DYNAMIC_MINOR;
1375*6db21d81SMika Westerberg 	sdev->misc.fops = &tbstream_dev_fops;
1376*6db21d81SMika Westerberg 
1377*6db21d81SMika Westerberg 	ret = misc_register(&sdev->misc);
1378*6db21d81SMika Westerberg 	if (ret) {
1379*6db21d81SMika Westerberg 		tbstream_dev_detach_stream(sdev);
1380*6db21d81SMika Westerberg 		scoped_guard(mutex, &sg->lock)
1381*6db21d81SMika Westerberg 			list_del(&sdev->list);
1382*6db21d81SMika Westerberg 		/* Calls tbstream_dev_put() */
1383*6db21d81SMika Westerberg 		config_group_put(&sdev->group);
1384*6db21d81SMika Westerberg 		return ERR_PTR(ret);
1385*6db21d81SMika Westerberg 	}
1386*6db21d81SMika Westerberg 
1387*6db21d81SMika Westerberg 	return &sdev->group;
1388*6db21d81SMika Westerberg }
1389*6db21d81SMika Westerberg 
1390*6db21d81SMika Westerberg static void
1391*6db21d81SMika Westerberg tbstream_dev_drop_item(struct config_group *group, struct config_item *item)
1392*6db21d81SMika Westerberg {
1393*6db21d81SMika Westerberg 	struct config_group *sdev_group = to_config_group(item);
1394*6db21d81SMika Westerberg 	struct tbstream_dev *sdev = tbstream_dev_from_group(sdev_group);
1395*6db21d81SMika Westerberg 	struct tbstream_group *sg = to_tbstream_group(group);
1396*6db21d81SMika Westerberg 
1397*6db21d81SMika Westerberg 	scoped_guard(mutex, &sg->lock)
1398*6db21d81SMika Westerberg 		list_del(&sdev->list);
1399*6db21d81SMika Westerberg 	/* Notify any task that the underlying group was removed  */
1400*6db21d81SMika Westerberg 	sdev->removed = true;
1401*6db21d81SMika Westerberg 	wake_up_interruptible_poll(&sdev->wait, EPOLLHUP | EPOLLERR);
1402*6db21d81SMika Westerberg 	config_item_put(item);
1403*6db21d81SMika Westerberg }
1404*6db21d81SMika Westerberg 
1405*6db21d81SMika Westerberg static struct configfs_group_operations tbstream_dev_group_ops = {
1406*6db21d81SMika Westerberg 	.make_group = tbstream_dev_make_group,
1407*6db21d81SMika Westerberg 	.drop_item = tbstream_dev_drop_item,
1408*6db21d81SMika Westerberg };
1409*6db21d81SMika Westerberg 
1410*6db21d81SMika Westerberg static void tbstream_item_release(struct config_item *item)
1411*6db21d81SMika Westerberg {
1412*6db21d81SMika Westerberg 	struct config_group *group = to_config_group(item);
1413*6db21d81SMika Westerberg 	struct tbstream_group *sg = to_tbstream_group(group);
1414*6db21d81SMika Westerberg 
1415*6db21d81SMika Westerberg 	tbstream_put(sg->stream);
1416*6db21d81SMika Westerberg 	kfree(sg);
1417*6db21d81SMika Westerberg }
1418*6db21d81SMika Westerberg 
1419*6db21d81SMika Westerberg static struct configfs_item_operations tbstream_item_ops = {
1420*6db21d81SMika Westerberg 	.release = tbstream_item_release,
1421*6db21d81SMika Westerberg };
1422*6db21d81SMika Westerberg 
1423*6db21d81SMika Westerberg static const struct config_item_type tbstream_dev_group_type = {
1424*6db21d81SMika Westerberg 	.ct_owner = THIS_MODULE,
1425*6db21d81SMika Westerberg 	.ct_group_ops = &tbstream_dev_group_ops,
1426*6db21d81SMika Westerberg 	.ct_item_ops = &tbstream_item_ops,
1427*6db21d81SMika Westerberg };
1428*6db21d81SMika Westerberg 
1429*6db21d81SMika Westerberg static struct config_group *
1430*6db21d81SMika Westerberg tbstream_make_group(struct config_group *group, const char *name)
1431*6db21d81SMika Westerberg {
1432*6db21d81SMika Westerberg 	struct tbstream_group *sg;
1433*6db21d81SMika Westerberg 	struct tbstream *stream;
1434*6db21d81SMika Westerberg 	int domain, index;
1435*6db21d81SMika Westerberg 	u64 route;
1436*6db21d81SMika Westerberg 
1437*6db21d81SMika Westerberg 	/* Make sure the format is correct */
1438*6db21d81SMika Westerberg 	if (sscanf(name, "%u-%llx.%u", &domain, &route, &index) != 3)
1439*6db21d81SMika Westerberg 		return ERR_PTR(-EINVAL);
1440*6db21d81SMika Westerberg 
1441*6db21d81SMika Westerberg 	sg = kzalloc_obj(*sg, GFP_KERNEL);
1442*6db21d81SMika Westerberg 	if (!sg)
1443*6db21d81SMika Westerberg 		return ERR_PTR(-ENOMEM);
1444*6db21d81SMika Westerberg 
1445*6db21d81SMika Westerberg 	mutex_init(&sg->lock);
1446*6db21d81SMika Westerberg 	INIT_LIST_HEAD(&sg->dev_list);
1447*6db21d81SMika Westerberg 
1448*6db21d81SMika Westerberg 	guard(mutex)(&tbstream_lock);
1449*6db21d81SMika Westerberg 	list_for_each_entry(stream, &tbstream_list, list) {
1450*6db21d81SMika Westerberg 		tbstream_get(stream);
1451*6db21d81SMika Westerberg 		if (sysfs_streq(name, dev_name(&stream->svc->dev))) {
1452*6db21d81SMika Westerberg 			sg->stream = stream;
1453*6db21d81SMika Westerberg 			break;
1454*6db21d81SMika Westerberg 		}
1455*6db21d81SMika Westerberg 		tbstream_put(stream);
1456*6db21d81SMika Westerberg 	}
1457*6db21d81SMika Westerberg 
1458*6db21d81SMika Westerberg 	config_group_init_type_name(&sg->group, name, &tbstream_dev_group_type);
1459*6db21d81SMika Westerberg 	return &sg->group;
1460*6db21d81SMika Westerberg }
1461*6db21d81SMika Westerberg 
1462*6db21d81SMika Westerberg static struct configfs_group_operations tbstream_group_ops = {
1463*6db21d81SMika Westerberg 	.make_group = tbstream_make_group,
1464*6db21d81SMika Westerberg };
1465*6db21d81SMika Westerberg 
1466*6db21d81SMika Westerberg static const struct config_item_type tbstream_group_type = {
1467*6db21d81SMika Westerberg 	.ct_owner = THIS_MODULE,
1468*6db21d81SMika Westerberg 	.ct_group_ops = &tbstream_group_ops,
1469*6db21d81SMika Westerberg };
1470*6db21d81SMika Westerberg 
1471*6db21d81SMika Westerberg static struct config_group tbstream_group = {
1472*6db21d81SMika Westerberg 	.cg_item = {
1473*6db21d81SMika Westerberg 		.ci_namebuf = "stream",
1474*6db21d81SMika Westerberg 		.ci_type = &tbstream_group_type,
1475*6db21d81SMika Westerberg 	},
1476*6db21d81SMika Westerberg };
1477*6db21d81SMika Westerberg 
1478*6db21d81SMika Westerberg /* Returns reference count increased */
1479*6db21d81SMika Westerberg static struct tbstream_group *tbstream_group_find(struct tbstream *stream)
1480*6db21d81SMika Westerberg {
1481*6db21d81SMika Westerberg 	const char *name = dev_name(&stream->svc->dev);
1482*6db21d81SMika Westerberg 	struct config_item *item;
1483*6db21d81SMika Westerberg 
1484*6db21d81SMika Westerberg 	guard(mutex)(&tbstream_group.cg_subsys->su_mutex);
1485*6db21d81SMika Westerberg 	item = config_group_find_item(&tbstream_group, name);
1486*6db21d81SMika Westerberg 	if (!item)
1487*6db21d81SMika Westerberg 		return NULL;
1488*6db21d81SMika Westerberg 	return to_tbstream_group(to_config_group(item));
1489*6db21d81SMika Westerberg }
1490*6db21d81SMika Westerberg 
1491*6db21d81SMika Westerberg static void tbstream_group_attach_stream(struct tbstream *stream)
1492*6db21d81SMika Westerberg {
1493*6db21d81SMika Westerberg 	struct tbstream_group *sg;
1494*6db21d81SMika Westerberg 	struct tbstream_dev *sdev;
1495*6db21d81SMika Westerberg 
1496*6db21d81SMika Westerberg 	sg = tbstream_group_find(stream);
1497*6db21d81SMika Westerberg 	if (!sg)
1498*6db21d81SMika Westerberg 		return;
1499*6db21d81SMika Westerberg 
1500*6db21d81SMika Westerberg 	guard(mutex)(&sg->lock);
1501*6db21d81SMika Westerberg 	if (WARN_ON(sg->stream)) {
1502*6db21d81SMika Westerberg 		config_group_put(&sg->group);
1503*6db21d81SMika Westerberg 		return;
1504*6db21d81SMika Westerberg 	}
1505*6db21d81SMika Westerberg 	sg->stream = tbstream_get(stream);
1506*6db21d81SMika Westerberg 	/*
1507*6db21d81SMika Westerberg 	 * If there are existing stream devices, attach the stream to
1508*6db21d81SMika Westerberg 	 * them now.
1509*6db21d81SMika Westerberg 	 */
1510*6db21d81SMika Westerberg 	list_for_each_entry(sdev, &sg->dev_list, list) {
1511*6db21d81SMika Westerberg 		tbstream_dev_get(sdev);
1512*6db21d81SMika Westerberg 		tbstream_dev_attach_stream(sdev, sg);
1513*6db21d81SMika Westerberg 		tbstream_dev_put(sdev);
1514*6db21d81SMika Westerberg 	}
1515*6db21d81SMika Westerberg 
1516*6db21d81SMika Westerberg 	config_group_put(&sg->group);
1517*6db21d81SMika Westerberg }
1518*6db21d81SMika Westerberg 
1519*6db21d81SMika Westerberg static void tbstream_group_detach_stream(struct tbstream *stream)
1520*6db21d81SMika Westerberg {
1521*6db21d81SMika Westerberg 	struct tbstream_group *sg;
1522*6db21d81SMika Westerberg 	struct tbstream_dev *sdev;
1523*6db21d81SMika Westerberg 
1524*6db21d81SMika Westerberg 	sg = tbstream_group_find(stream);
1525*6db21d81SMika Westerberg 	if (!sg)
1526*6db21d81SMika Westerberg 		return;
1527*6db21d81SMika Westerberg 
1528*6db21d81SMika Westerberg 	guard(mutex)(&sg->lock);
1529*6db21d81SMika Westerberg 	if (sg->stream) {
1530*6db21d81SMika Westerberg 		/* Detach this stream from the stream devices */
1531*6db21d81SMika Westerberg 		list_for_each_entry_reverse(sdev, &sg->dev_list, list) {
1532*6db21d81SMika Westerberg 			tbstream_dev_get(sdev);
1533*6db21d81SMika Westerberg 			tbstream_dev_detach_stream(sdev);
1534*6db21d81SMika Westerberg 			tbstream_dev_put(sdev);
1535*6db21d81SMika Westerberg 		}
1536*6db21d81SMika Westerberg 		tbstream_put(sg->stream);
1537*6db21d81SMika Westerberg 		sg->stream = NULL;
1538*6db21d81SMika Westerberg 	}
1539*6db21d81SMika Westerberg 
1540*6db21d81SMika Westerberg 	config_group_put(&sg->group);
1541*6db21d81SMika Westerberg }
1542*6db21d81SMika Westerberg 
1543*6db21d81SMika Westerberg static int tbstream_probe(struct tb_service *svc, const struct tb_service_id *id)
1544*6db21d81SMika Westerberg {
1545*6db21d81SMika Westerberg 	struct tbstream *stream;
1546*6db21d81SMika Westerberg 
1547*6db21d81SMika Westerberg 	stream = kzalloc_obj(*stream, GFP_KERNEL);
1548*6db21d81SMika Westerberg 	if (!stream)
1549*6db21d81SMika Westerberg 		return -ENOMEM;
1550*6db21d81SMika Westerberg 
1551*6db21d81SMika Westerberg 	/* After this point, release stream by calling tbstream_put() */
1552*6db21d81SMika Westerberg 	kref_init(&stream->kref);
1553*6db21d81SMika Westerberg 	stream->svc = tb_service_get(svc);
1554*6db21d81SMika Westerberg 	INIT_LIST_HEAD(&stream->list);
1555*6db21d81SMika Westerberg 
1556*6db21d81SMika Westerberg 	scoped_guard(mutex, &tbstream_lock)
1557*6db21d81SMika Westerberg 		list_add_tail(&stream->list, &tbstream_list);
1558*6db21d81SMika Westerberg 
1559*6db21d81SMika Westerberg 	tbstream_group_attach_stream(stream);
1560*6db21d81SMika Westerberg 	tb_service_set_drvdata(svc, stream);
1561*6db21d81SMika Westerberg 	return 0;
1562*6db21d81SMika Westerberg }
1563*6db21d81SMika Westerberg 
1564*6db21d81SMika Westerberg static void tbstream_remove(struct tb_service *svc)
1565*6db21d81SMika Westerberg {
1566*6db21d81SMika Westerberg 	struct tbstream *stream = tb_service_get_drvdata(svc);
1567*6db21d81SMika Westerberg 
1568*6db21d81SMika Westerberg 	tbstream_group_detach_stream(stream);
1569*6db21d81SMika Westerberg 	scoped_guard(mutex, &tbstream_lock)
1570*6db21d81SMika Westerberg 		list_del(&stream->list);
1571*6db21d81SMika Westerberg 	tbstream_put(stream);
1572*6db21d81SMika Westerberg }
1573*6db21d81SMika Westerberg 
1574*6db21d81SMika Westerberg static int __maybe_unused tbstream_suspend(struct device *dev)
1575*6db21d81SMika Westerberg {
1576*6db21d81SMika Westerberg 	struct tb_service *svc = tb_to_service(dev);
1577*6db21d81SMika Westerberg 	struct tbstream *stream = tb_service_get_drvdata(svc);
1578*6db21d81SMika Westerberg 	struct tbstream_group *sg;
1579*6db21d81SMika Westerberg 	struct tbstream_dev *sdev;
1580*6db21d81SMika Westerberg 
1581*6db21d81SMika Westerberg 	sg = tbstream_group_find(stream);
1582*6db21d81SMika Westerberg 	if (!sg)
1583*6db21d81SMika Westerberg 		return 0;
1584*6db21d81SMika Westerberg 
1585*6db21d81SMika Westerberg 	list_for_each_entry_reverse(sdev, &sg->dev_list, list) {
1586*6db21d81SMika Westerberg 		tbstream_dev_get(sdev);
1587*6db21d81SMika Westerberg 		/* Stop the stream (if it was open) */
1588*6db21d81SMika Westerberg 		if (sdev->users)
1589*6db21d81SMika Westerberg 			tbstream_dev_stop(sdev);
1590*6db21d81SMika Westerberg 		tbstream_dev_put(sdev);
1591*6db21d81SMika Westerberg 	}
1592*6db21d81SMika Westerberg 
1593*6db21d81SMika Westerberg 	config_group_put(&sg->group);
1594*6db21d81SMika Westerberg 	return 0;
1595*6db21d81SMika Westerberg }
1596*6db21d81SMika Westerberg 
1597*6db21d81SMika Westerberg static int __maybe_unused tbstream_resume(struct device *dev)
1598*6db21d81SMika Westerberg {
1599*6db21d81SMika Westerberg 	struct tb_service *svc = tb_to_service(dev);
1600*6db21d81SMika Westerberg 	struct tbstream *stream = tb_service_get_drvdata(svc);
1601*6db21d81SMika Westerberg 	struct tbstream_group *sg;
1602*6db21d81SMika Westerberg 	struct tbstream_dev *sdev;
1603*6db21d81SMika Westerberg 
1604*6db21d81SMika Westerberg 	sg = tbstream_group_find(stream);
1605*6db21d81SMika Westerberg 	if (!sg)
1606*6db21d81SMika Westerberg 		return 0;
1607*6db21d81SMika Westerberg 
1608*6db21d81SMika Westerberg 	list_for_each_entry(sdev, &sg->dev_list, list) {
1609*6db21d81SMika Westerberg 		tbstream_dev_get(sdev);
1610*6db21d81SMika Westerberg 		if (sdev->users) {
1611*6db21d81SMika Westerberg 			int ret;
1612*6db21d81SMika Westerberg 
1613*6db21d81SMika Westerberg 			ret = tbstream_dev_start(sdev);
1614*6db21d81SMika Westerberg 			if (ret) {
1615*6db21d81SMika Westerberg 				tbstream_dev_put(sdev);
1616*6db21d81SMika Westerberg 				config_group_put(&sg->group);
1617*6db21d81SMika Westerberg 				return ret;
1618*6db21d81SMika Westerberg 			}
1619*6db21d81SMika Westerberg 		}
1620*6db21d81SMika Westerberg 		tbstream_dev_put(sdev);
1621*6db21d81SMika Westerberg 	}
1622*6db21d81SMika Westerberg 
1623*6db21d81SMika Westerberg 	config_group_put(&sg->group);
1624*6db21d81SMika Westerberg 	return 0;
1625*6db21d81SMika Westerberg }
1626*6db21d81SMika Westerberg 
1627*6db21d81SMika Westerberg static const struct dev_pm_ops tbstream_pm_ops = {
1628*6db21d81SMika Westerberg 	SET_SYSTEM_SLEEP_PM_OPS(tbstream_suspend, tbstream_resume)
1629*6db21d81SMika Westerberg };
1630*6db21d81SMika Westerberg 
1631*6db21d81SMika Westerberg static const struct tb_service_id tbstream_ids[] = {
1632*6db21d81SMika Westerberg 	{ TB_SERVICE("stream", 1) },
1633*6db21d81SMika Westerberg 	{ },
1634*6db21d81SMika Westerberg };
1635*6db21d81SMika Westerberg MODULE_DEVICE_TABLE(tbsvc, tbstream_ids);
1636*6db21d81SMika Westerberg 
1637*6db21d81SMika Westerberg static struct tb_service_driver tbstream_driver = {
1638*6db21d81SMika Westerberg 	.driver = {
1639*6db21d81SMika Westerberg 		.owner = THIS_MODULE,
1640*6db21d81SMika Westerberg 		.name = "thunderbolt_stream",
1641*6db21d81SMika Westerberg 		.pm = &tbstream_pm_ops,
1642*6db21d81SMika Westerberg 	},
1643*6db21d81SMika Westerberg 	.probe = tbstream_probe,
1644*6db21d81SMika Westerberg 	.remove = tbstream_remove,
1645*6db21d81SMika Westerberg 	.id_table = tbstream_ids,
1646*6db21d81SMika Westerberg };
1647*6db21d81SMika Westerberg 
1648*6db21d81SMika Westerberg static int __init tbstream_init(void)
1649*6db21d81SMika Westerberg {
1650*6db21d81SMika Westerberg 	int ret;
1651*6db21d81SMika Westerberg 
1652*6db21d81SMika Westerberg 	tbstream_dir = tb_property_create_dir(&tbstream_dir_uuid);
1653*6db21d81SMika Westerberg 	if (!tbstream_dir)
1654*6db21d81SMika Westerberg 		return -ENOMEM;
1655*6db21d81SMika Westerberg 
1656*6db21d81SMika Westerberg 	tb_property_add_immediate(tbstream_dir, "prtcid", 1);
1657*6db21d81SMika Westerberg 	tb_property_add_immediate(tbstream_dir, "prtcvers", 1);
1658*6db21d81SMika Westerberg 	tb_property_add_immediate(tbstream_dir, "prtcrevs", 0);
1659*6db21d81SMika Westerberg 	tb_property_add_immediate(tbstream_dir, "prtcstns", 0);
1660*6db21d81SMika Westerberg 
1661*6db21d81SMika Westerberg 	ret = tb_register_property_dir("stream", tbstream_dir);
1662*6db21d81SMika Westerberg 	if (ret)
1663*6db21d81SMika Westerberg 		goto err_free_dir;
1664*6db21d81SMika Westerberg 
1665*6db21d81SMika Westerberg 	config_group_init(&tbstream_group);
1666*6db21d81SMika Westerberg 	ret = tb_configfs_register_group(&tbstream_group);
1667*6db21d81SMika Westerberg 	if (ret)
1668*6db21d81SMika Westerberg 		goto err_unregister_dir;
1669*6db21d81SMika Westerberg 
1670*6db21d81SMika Westerberg 	ret = tb_register_service_driver(&tbstream_driver);
1671*6db21d81SMika Westerberg 	if (ret)
1672*6db21d81SMika Westerberg 		goto err_unregister_group;
1673*6db21d81SMika Westerberg 	return 0;
1674*6db21d81SMika Westerberg 
1675*6db21d81SMika Westerberg err_unregister_group:
1676*6db21d81SMika Westerberg 	tb_configfs_unregister_group(&tbstream_group);
1677*6db21d81SMika Westerberg err_unregister_dir:
1678*6db21d81SMika Westerberg 	tb_unregister_property_dir("stream", tbstream_dir);
1679*6db21d81SMika Westerberg err_free_dir:
1680*6db21d81SMika Westerberg 	tb_property_free_dir(tbstream_dir);
1681*6db21d81SMika Westerberg 	return ret;
1682*6db21d81SMika Westerberg }
1683*6db21d81SMika Westerberg module_init(tbstream_init);
1684*6db21d81SMika Westerberg 
1685*6db21d81SMika Westerberg static void __exit tbstream_exit(void)
1686*6db21d81SMika Westerberg {
1687*6db21d81SMika Westerberg 	tb_unregister_service_driver(&tbstream_driver);
1688*6db21d81SMika Westerberg 	tb_configfs_unregister_group(&tbstream_group);
1689*6db21d81SMika Westerberg 	tb_unregister_property_dir("stream", tbstream_dir);
1690*6db21d81SMika Westerberg 	tb_property_free_dir(tbstream_dir);
1691*6db21d81SMika Westerberg 	ida_destroy(&tbstream_indices);
1692*6db21d81SMika Westerberg }
1693*6db21d81SMika Westerberg module_exit(tbstream_exit);
1694*6db21d81SMika Westerberg 
1695*6db21d81SMika Westerberg MODULE_AUTHOR("Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>");
1696*6db21d81SMika Westerberg MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
1697*6db21d81SMika Westerberg MODULE_DESCRIPTION("Stream data over Thunderbolt/USB4 cable");
1698*6db21d81SMika Westerberg MODULE_LICENSE("GPL");
1699