cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ivc.c (18294B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2014-2016, NVIDIA CORPORATION.  All rights reserved.
      4 */
      5
      6#include <soc/tegra/ivc.h>
      7
      8#define TEGRA_IVC_ALIGN 64
      9
     10/*
     11 * IVC channel reset protocol.
     12 *
     13 * Each end uses its tx_channel.state to indicate its synchronization state.
     14 */
     15enum tegra_ivc_state {
     16	/*
     17	 * This value is zero for backwards compatibility with services that
     18	 * assume channels to be initially zeroed. Such channels are in an
     19	 * initially valid state, but cannot be asynchronously reset, and must
     20	 * maintain a valid state at all times.
     21	 *
     22	 * The transmitting end can enter the established state from the sync or
     23	 * ack state when it observes the receiving endpoint in the ack or
     24	 * established state, indicating that has cleared the counters in our
     25	 * rx_channel.
     26	 */
     27	TEGRA_IVC_STATE_ESTABLISHED = 0,
     28
     29	/*
     30	 * If an endpoint is observed in the sync state, the remote endpoint is
     31	 * allowed to clear the counters it owns asynchronously with respect to
     32	 * the current endpoint. Therefore, the current endpoint is no longer
     33	 * allowed to communicate.
     34	 */
     35	TEGRA_IVC_STATE_SYNC,
     36
     37	/*
     38	 * When the transmitting end observes the receiving end in the sync
     39	 * state, it can clear the w_count and r_count and transition to the ack
     40	 * state. If the remote endpoint observes us in the ack state, it can
     41	 * return to the established state once it has cleared its counters.
     42	 */
     43	TEGRA_IVC_STATE_ACK
     44};
     45
     46/*
     47 * This structure is divided into two-cache aligned parts, the first is only
     48 * written through the tx.channel pointer, while the second is only written
     49 * through the rx.channel pointer. This delineates ownership of the cache
     50 * lines, which is critical to performance and necessary in non-cache coherent
     51 * implementations.
     52 */
     53struct tegra_ivc_header {
     54	union {
     55		struct {
     56			/* fields owned by the transmitting end */
     57			u32 count;
     58			u32 state;
     59		};
     60
     61		u8 pad[TEGRA_IVC_ALIGN];
     62	} tx;
     63
     64	union {
     65		/* fields owned by the receiving end */
     66		u32 count;
     67		u8 pad[TEGRA_IVC_ALIGN];
     68	} rx;
     69};
     70
     71static inline void tegra_ivc_invalidate(struct tegra_ivc *ivc, dma_addr_t phys)
     72{
     73	if (!ivc->peer)
     74		return;
     75
     76	dma_sync_single_for_cpu(ivc->peer, phys, TEGRA_IVC_ALIGN,
     77				DMA_FROM_DEVICE);
     78}
     79
     80static inline void tegra_ivc_flush(struct tegra_ivc *ivc, dma_addr_t phys)
     81{
     82	if (!ivc->peer)
     83		return;
     84
     85	dma_sync_single_for_device(ivc->peer, phys, TEGRA_IVC_ALIGN,
     86				   DMA_TO_DEVICE);
     87}
     88
     89static inline bool tegra_ivc_empty(struct tegra_ivc *ivc,
     90				   struct tegra_ivc_header *header)
     91{
     92	/*
     93	 * This function performs multiple checks on the same values with
     94	 * security implications, so create snapshots with READ_ONCE() to
     95	 * ensure that these checks use the same values.
     96	 */
     97	u32 tx = READ_ONCE(header->tx.count);
     98	u32 rx = READ_ONCE(header->rx.count);
     99
    100	/*
    101	 * Perform an over-full check to prevent denial of service attacks
    102	 * where a server could be easily fooled into believing that there's
    103	 * an extremely large number of frames ready, since receivers are not
    104	 * expected to check for full or over-full conditions.
    105	 *
    106	 * Although the channel isn't empty, this is an invalid case caused by
    107	 * a potentially malicious peer, so returning empty is safer, because
    108	 * it gives the impression that the channel has gone silent.
    109	 */
    110	if (tx - rx > ivc->num_frames)
    111		return true;
    112
    113	return tx == rx;
    114}
    115
    116static inline bool tegra_ivc_full(struct tegra_ivc *ivc,
    117				  struct tegra_ivc_header *header)
    118{
    119	u32 tx = READ_ONCE(header->tx.count);
    120	u32 rx = READ_ONCE(header->rx.count);
    121
    122	/*
    123	 * Invalid cases where the counters indicate that the queue is over
    124	 * capacity also appear full.
    125	 */
    126	return tx - rx >= ivc->num_frames;
    127}
    128
    129static inline u32 tegra_ivc_available(struct tegra_ivc *ivc,
    130				      struct tegra_ivc_header *header)
    131{
    132	u32 tx = READ_ONCE(header->tx.count);
    133	u32 rx = READ_ONCE(header->rx.count);
    134
    135	/*
    136	 * This function isn't expected to be used in scenarios where an
    137	 * over-full situation can lead to denial of service attacks. See the
    138	 * comment in tegra_ivc_empty() for an explanation about special
    139	 * over-full considerations.
    140	 */
    141	return tx - rx;
    142}
    143
    144static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc)
    145{
    146	WRITE_ONCE(ivc->tx.channel->tx.count,
    147		   READ_ONCE(ivc->tx.channel->tx.count) + 1);
    148
    149	if (ivc->tx.position == ivc->num_frames - 1)
    150		ivc->tx.position = 0;
    151	else
    152		ivc->tx.position++;
    153}
    154
    155static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc)
    156{
    157	WRITE_ONCE(ivc->rx.channel->rx.count,
    158		   READ_ONCE(ivc->rx.channel->rx.count) + 1);
    159
    160	if (ivc->rx.position == ivc->num_frames - 1)
    161		ivc->rx.position = 0;
    162	else
    163		ivc->rx.position++;
    164}
    165
    166static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
    167{
    168	unsigned int offset = offsetof(struct tegra_ivc_header, tx.count);
    169
    170	/*
    171	 * tx.channel->state is set locally, so it is not synchronized with
    172	 * state from the remote peer. The remote peer cannot reset its
    173	 * transmit counters until we've acknowledged its synchronization
    174	 * request, so no additional synchronization is required because an
    175	 * asynchronous transition of rx.channel->state to
    176	 * TEGRA_IVC_STATE_ACK is not allowed.
    177	 */
    178	if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED)
    179		return -ECONNRESET;
    180
    181	/*
    182	 * Avoid unnecessary invalidations when performing repeated accesses
    183	 * to an IVC channel by checking the old queue pointers first.
    184	 *
    185	 * Synchronization is only necessary when these pointers indicate
    186	 * empty or full.
    187	 */
    188	if (!tegra_ivc_empty(ivc, ivc->rx.channel))
    189		return 0;
    190
    191	tegra_ivc_invalidate(ivc, ivc->rx.phys + offset);
    192
    193	if (tegra_ivc_empty(ivc, ivc->rx.channel))
    194		return -ENOSPC;
    195
    196	return 0;
    197}
    198
    199static inline int tegra_ivc_check_write(struct tegra_ivc *ivc)
    200{
    201	unsigned int offset = offsetof(struct tegra_ivc_header, rx.count);
    202
    203	if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED)
    204		return -ECONNRESET;
    205
    206	if (!tegra_ivc_full(ivc, ivc->tx.channel))
    207		return 0;
    208
    209	tegra_ivc_invalidate(ivc, ivc->tx.phys + offset);
    210
    211	if (tegra_ivc_full(ivc, ivc->tx.channel))
    212		return -ENOSPC;
    213
    214	return 0;
    215}
    216
    217static void *tegra_ivc_frame_virt(struct tegra_ivc *ivc,
    218				  struct tegra_ivc_header *header,
    219				  unsigned int frame)
    220{
    221	if (WARN_ON(frame >= ivc->num_frames))
    222		return ERR_PTR(-EINVAL);
    223
    224	return (void *)(header + 1) + ivc->frame_size * frame;
    225}
    226
    227static inline dma_addr_t tegra_ivc_frame_phys(struct tegra_ivc *ivc,
    228					      dma_addr_t phys,
    229					      unsigned int frame)
    230{
    231	unsigned long offset;
    232
    233	offset = sizeof(struct tegra_ivc_header) + ivc->frame_size * frame;
    234
    235	return phys + offset;
    236}
    237
    238static inline void tegra_ivc_invalidate_frame(struct tegra_ivc *ivc,
    239					      dma_addr_t phys,
    240					      unsigned int frame,
    241					      unsigned int offset,
    242					      size_t size)
    243{
    244	if (!ivc->peer || WARN_ON(frame >= ivc->num_frames))
    245		return;
    246
    247	phys = tegra_ivc_frame_phys(ivc, phys, frame) + offset;
    248
    249	dma_sync_single_for_cpu(ivc->peer, phys, size, DMA_FROM_DEVICE);
    250}
    251
    252static inline void tegra_ivc_flush_frame(struct tegra_ivc *ivc,
    253					 dma_addr_t phys,
    254					 unsigned int frame,
    255					 unsigned int offset,
    256					 size_t size)
    257{
    258	if (!ivc->peer || WARN_ON(frame >= ivc->num_frames))
    259		return;
    260
    261	phys = tegra_ivc_frame_phys(ivc, phys, frame) + offset;
    262
    263	dma_sync_single_for_device(ivc->peer, phys, size, DMA_TO_DEVICE);
    264}
    265
    266/* directly peek at the next frame rx'ed */
    267void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc)
    268{
    269	int err;
    270
    271	if (WARN_ON(ivc == NULL))
    272		return ERR_PTR(-EINVAL);
    273
    274	err = tegra_ivc_check_read(ivc);
    275	if (err < 0)
    276		return ERR_PTR(err);
    277
    278	/*
    279	 * Order observation of ivc->rx.position potentially indicating new
    280	 * data before data read.
    281	 */
    282	smp_rmb();
    283
    284	tegra_ivc_invalidate_frame(ivc, ivc->rx.phys, ivc->rx.position, 0,
    285				   ivc->frame_size);
    286
    287	return tegra_ivc_frame_virt(ivc, ivc->rx.channel, ivc->rx.position);
    288}
    289EXPORT_SYMBOL(tegra_ivc_read_get_next_frame);
    290
    291int tegra_ivc_read_advance(struct tegra_ivc *ivc)
    292{
    293	unsigned int rx = offsetof(struct tegra_ivc_header, rx.count);
    294	unsigned int tx = offsetof(struct tegra_ivc_header, tx.count);
    295	int err;
    296
    297	/*
    298	 * No read barriers or synchronization here: the caller is expected to
    299	 * have already observed the channel non-empty. This check is just to
    300	 * catch programming errors.
    301	 */
    302	err = tegra_ivc_check_read(ivc);
    303	if (err < 0)
    304		return err;
    305
    306	tegra_ivc_advance_rx(ivc);
    307
    308	tegra_ivc_flush(ivc, ivc->rx.phys + rx);
    309
    310	/*
    311	 * Ensure our write to ivc->rx.position occurs before our read from
    312	 * ivc->tx.position.
    313	 */
    314	smp_mb();
    315
    316	/*
    317	 * Notify only upon transition from full to non-full. The available
    318	 * count can only asynchronously increase, so the worst possible
    319	 * side-effect will be a spurious notification.
    320	 */
    321	tegra_ivc_invalidate(ivc, ivc->rx.phys + tx);
    322
    323	if (tegra_ivc_available(ivc, ivc->rx.channel) == ivc->num_frames - 1)
    324		ivc->notify(ivc, ivc->notify_data);
    325
    326	return 0;
    327}
    328EXPORT_SYMBOL(tegra_ivc_read_advance);
    329
    330/* directly poke at the next frame to be tx'ed */
    331void *tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc)
    332{
    333	int err;
    334
    335	err = tegra_ivc_check_write(ivc);
    336	if (err < 0)
    337		return ERR_PTR(err);
    338
    339	return tegra_ivc_frame_virt(ivc, ivc->tx.channel, ivc->tx.position);
    340}
    341EXPORT_SYMBOL(tegra_ivc_write_get_next_frame);
    342
    343/* advance the tx buffer */
    344int tegra_ivc_write_advance(struct tegra_ivc *ivc)
    345{
    346	unsigned int tx = offsetof(struct tegra_ivc_header, tx.count);
    347	unsigned int rx = offsetof(struct tegra_ivc_header, rx.count);
    348	int err;
    349
    350	err = tegra_ivc_check_write(ivc);
    351	if (err < 0)
    352		return err;
    353
    354	tegra_ivc_flush_frame(ivc, ivc->tx.phys, ivc->tx.position, 0,
    355			      ivc->frame_size);
    356
    357	/*
    358	 * Order any possible stores to the frame before update of
    359	 * ivc->tx.position.
    360	 */
    361	smp_wmb();
    362
    363	tegra_ivc_advance_tx(ivc);
    364	tegra_ivc_flush(ivc, ivc->tx.phys + tx);
    365
    366	/*
    367	 * Ensure our write to ivc->tx.position occurs before our read from
    368	 * ivc->rx.position.
    369	 */
    370	smp_mb();
    371
    372	/*
    373	 * Notify only upon transition from empty to non-empty. The available
    374	 * count can only asynchronously decrease, so the worst possible
    375	 * side-effect will be a spurious notification.
    376	 */
    377	tegra_ivc_invalidate(ivc, ivc->tx.phys + rx);
    378
    379	if (tegra_ivc_available(ivc, ivc->tx.channel) == 1)
    380		ivc->notify(ivc, ivc->notify_data);
    381
    382	return 0;
    383}
    384EXPORT_SYMBOL(tegra_ivc_write_advance);
    385
    386void tegra_ivc_reset(struct tegra_ivc *ivc)
    387{
    388	unsigned int offset = offsetof(struct tegra_ivc_header, tx.count);
    389
    390	ivc->tx.channel->tx.state = TEGRA_IVC_STATE_SYNC;
    391	tegra_ivc_flush(ivc, ivc->tx.phys + offset);
    392	ivc->notify(ivc, ivc->notify_data);
    393}
    394EXPORT_SYMBOL(tegra_ivc_reset);
    395
    396/*
    397 * =======================================================
    398 *  IVC State Transition Table - see tegra_ivc_notified()
    399 * =======================================================
    400 *
    401 *	local	remote	action
    402 *	-----	------	-----------------------------------
    403 *	SYNC	EST	<none>
    404 *	SYNC	ACK	reset counters; move to EST; notify
    405 *	SYNC	SYNC	reset counters; move to ACK; notify
    406 *	ACK	EST	move to EST; notify
    407 *	ACK	ACK	move to EST; notify
    408 *	ACK	SYNC	reset counters; move to ACK; notify
    409 *	EST	EST	<none>
    410 *	EST	ACK	<none>
    411 *	EST	SYNC	reset counters; move to ACK; notify
    412 *
    413 * ===============================================================
    414 */
    415
    416int tegra_ivc_notified(struct tegra_ivc *ivc)
    417{
    418	unsigned int offset = offsetof(struct tegra_ivc_header, tx.count);
    419	enum tegra_ivc_state state;
    420
    421	/* Copy the receiver's state out of shared memory. */
    422	tegra_ivc_invalidate(ivc, ivc->rx.phys + offset);
    423	state = READ_ONCE(ivc->rx.channel->tx.state);
    424
    425	if (state == TEGRA_IVC_STATE_SYNC) {
    426		offset = offsetof(struct tegra_ivc_header, tx.count);
    427
    428		/*
    429		 * Order observation of TEGRA_IVC_STATE_SYNC before stores
    430		 * clearing tx.channel.
    431		 */
    432		smp_rmb();
    433
    434		/*
    435		 * Reset tx.channel counters. The remote end is in the SYNC
    436		 * state and won't make progress until we change our state,
    437		 * so the counters are not in use at this time.
    438		 */
    439		ivc->tx.channel->tx.count = 0;
    440		ivc->rx.channel->rx.count = 0;
    441
    442		ivc->tx.position = 0;
    443		ivc->rx.position = 0;
    444
    445		/*
    446		 * Ensure that counters appear cleared before new state can be
    447		 * observed.
    448		 */
    449		smp_wmb();
    450
    451		/*
    452		 * Move to ACK state. We have just cleared our counters, so it
    453		 * is now safe for the remote end to start using these values.
    454		 */
    455		ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ACK;
    456		tegra_ivc_flush(ivc, ivc->tx.phys + offset);
    457
    458		/*
    459		 * Notify remote end to observe state transition.
    460		 */
    461		ivc->notify(ivc, ivc->notify_data);
    462
    463	} else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_SYNC &&
    464		   state == TEGRA_IVC_STATE_ACK) {
    465		offset = offsetof(struct tegra_ivc_header, tx.count);
    466
    467		/*
    468		 * Order observation of ivc_state_sync before stores clearing
    469		 * tx_channel.
    470		 */
    471		smp_rmb();
    472
    473		/*
    474		 * Reset tx.channel counters. The remote end is in the ACK
    475		 * state and won't make progress until we change our state,
    476		 * so the counters are not in use at this time.
    477		 */
    478		ivc->tx.channel->tx.count = 0;
    479		ivc->rx.channel->rx.count = 0;
    480
    481		ivc->tx.position = 0;
    482		ivc->rx.position = 0;
    483
    484		/*
    485		 * Ensure that counters appear cleared before new state can be
    486		 * observed.
    487		 */
    488		smp_wmb();
    489
    490		/*
    491		 * Move to ESTABLISHED state. We know that the remote end has
    492		 * already cleared its counters, so it is safe to start
    493		 * writing/reading on this channel.
    494		 */
    495		ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED;
    496		tegra_ivc_flush(ivc, ivc->tx.phys + offset);
    497
    498		/*
    499		 * Notify remote end to observe state transition.
    500		 */
    501		ivc->notify(ivc, ivc->notify_data);
    502
    503	} else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_ACK) {
    504		offset = offsetof(struct tegra_ivc_header, tx.count);
    505
    506		/*
    507		 * At this point, we have observed the peer to be in either
    508		 * the ACK or ESTABLISHED state. Next, order observation of
    509		 * peer state before storing to tx.channel.
    510		 */
    511		smp_rmb();
    512
    513		/*
    514		 * Move to ESTABLISHED state. We know that we have previously
    515		 * cleared our counters, and we know that the remote end has
    516		 * cleared its counters, so it is safe to start writing/reading
    517		 * on this channel.
    518		 */
    519		ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED;
    520		tegra_ivc_flush(ivc, ivc->tx.phys + offset);
    521
    522		/*
    523		 * Notify remote end to observe state transition.
    524		 */
    525		ivc->notify(ivc, ivc->notify_data);
    526
    527	} else {
    528		/*
    529		 * There is no need to handle any further action. Either the
    530		 * channel is already fully established, or we are waiting for
    531		 * the remote end to catch up with our current state. Refer
    532		 * to the diagram in "IVC State Transition Table" above.
    533		 */
    534	}
    535
    536	if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED)
    537		return -EAGAIN;
    538
    539	return 0;
    540}
    541EXPORT_SYMBOL(tegra_ivc_notified);
    542
    543size_t tegra_ivc_align(size_t size)
    544{
    545	return ALIGN(size, TEGRA_IVC_ALIGN);
    546}
    547EXPORT_SYMBOL(tegra_ivc_align);
    548
    549unsigned tegra_ivc_total_queue_size(unsigned queue_size)
    550{
    551	if (!IS_ALIGNED(queue_size, TEGRA_IVC_ALIGN)) {
    552		pr_err("%s: queue_size (%u) must be %u-byte aligned\n",
    553		       __func__, queue_size, TEGRA_IVC_ALIGN);
    554		return 0;
    555	}
    556
    557	return queue_size + sizeof(struct tegra_ivc_header);
    558}
    559EXPORT_SYMBOL(tegra_ivc_total_queue_size);
    560
    561static int tegra_ivc_check_params(unsigned long rx, unsigned long tx,
    562				  unsigned int num_frames, size_t frame_size)
    563{
    564	BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct tegra_ivc_header, tx.count),
    565				 TEGRA_IVC_ALIGN));
    566	BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct tegra_ivc_header, rx.count),
    567				 TEGRA_IVC_ALIGN));
    568	BUILD_BUG_ON(!IS_ALIGNED(sizeof(struct tegra_ivc_header),
    569				 TEGRA_IVC_ALIGN));
    570
    571	if ((uint64_t)num_frames * (uint64_t)frame_size >= 0x100000000UL) {
    572		pr_err("num_frames * frame_size overflows\n");
    573		return -EINVAL;
    574	}
    575
    576	if (!IS_ALIGNED(frame_size, TEGRA_IVC_ALIGN)) {
    577		pr_err("frame size not adequately aligned: %zu\n", frame_size);
    578		return -EINVAL;
    579	}
    580
    581	/*
    582	 * The headers must at least be aligned enough for counters
    583	 * to be accessed atomically.
    584	 */
    585	if (!IS_ALIGNED(rx, TEGRA_IVC_ALIGN)) {
    586		pr_err("IVC channel start not aligned: %#lx\n", rx);
    587		return -EINVAL;
    588	}
    589
    590	if (!IS_ALIGNED(tx, TEGRA_IVC_ALIGN)) {
    591		pr_err("IVC channel start not aligned: %#lx\n", tx);
    592		return -EINVAL;
    593	}
    594
    595	if (rx < tx) {
    596		if (rx + frame_size * num_frames > tx) {
    597			pr_err("queue regions overlap: %#lx + %zx > %#lx\n",
    598			       rx, frame_size * num_frames, tx);
    599			return -EINVAL;
    600		}
    601	} else {
    602		if (tx + frame_size * num_frames > rx) {
    603			pr_err("queue regions overlap: %#lx + %zx > %#lx\n",
    604			       tx, frame_size * num_frames, rx);
    605			return -EINVAL;
    606		}
    607	}
    608
    609	return 0;
    610}
    611
    612int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx,
    613		   dma_addr_t rx_phys, void *tx, dma_addr_t tx_phys,
    614		   unsigned int num_frames, size_t frame_size,
    615		   void (*notify)(struct tegra_ivc *ivc, void *data),
    616		   void *data)
    617{
    618	size_t queue_size;
    619	int err;
    620
    621	if (WARN_ON(!ivc || !notify))
    622		return -EINVAL;
    623
    624	/*
    625	 * All sizes that can be returned by communication functions should
    626	 * fit in an int.
    627	 */
    628	if (frame_size > INT_MAX)
    629		return -E2BIG;
    630
    631	err = tegra_ivc_check_params((unsigned long)rx, (unsigned long)tx,
    632				     num_frames, frame_size);
    633	if (err < 0)
    634		return err;
    635
    636	queue_size = tegra_ivc_total_queue_size(num_frames * frame_size);
    637
    638	if (peer) {
    639		ivc->rx.phys = dma_map_single(peer, rx, queue_size,
    640					      DMA_BIDIRECTIONAL);
    641		if (dma_mapping_error(peer, ivc->rx.phys))
    642			return -ENOMEM;
    643
    644		ivc->tx.phys = dma_map_single(peer, tx, queue_size,
    645					      DMA_BIDIRECTIONAL);
    646		if (dma_mapping_error(peer, ivc->tx.phys)) {
    647			dma_unmap_single(peer, ivc->rx.phys, queue_size,
    648					 DMA_BIDIRECTIONAL);
    649			return -ENOMEM;
    650		}
    651	} else {
    652		ivc->rx.phys = rx_phys;
    653		ivc->tx.phys = tx_phys;
    654	}
    655
    656	ivc->rx.channel = rx;
    657	ivc->tx.channel = tx;
    658	ivc->peer = peer;
    659	ivc->notify = notify;
    660	ivc->notify_data = data;
    661	ivc->frame_size = frame_size;
    662	ivc->num_frames = num_frames;
    663
    664	/*
    665	 * These values aren't necessarily correct until the channel has been
    666	 * reset.
    667	 */
    668	ivc->tx.position = 0;
    669	ivc->rx.position = 0;
    670
    671	return 0;
    672}
    673EXPORT_SYMBOL(tegra_ivc_init);
    674
    675void tegra_ivc_cleanup(struct tegra_ivc *ivc)
    676{
    677	if (ivc->peer) {
    678		size_t size = tegra_ivc_total_queue_size(ivc->num_frames *
    679							 ivc->frame_size);
    680
    681		dma_unmap_single(ivc->peer, ivc->rx.phys, size,
    682				 DMA_BIDIRECTIONAL);
    683		dma_unmap_single(ivc->peer, ivc->tx.phys, size,
    684				 DMA_BIDIRECTIONAL);
    685	}
    686}
    687EXPORT_SYMBOL(tegra_ivc_cleanup);