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