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