]> git.sur5r.net Git - u-boot/blob - arch/arm/mach-tegra/ivc.c
ARM: uniphier: move spl_boot_mode() to a separate file
[u-boot] / arch / arm / mach-tegra / ivc.c
1 /*
2  * Copyright (c) 2016, NVIDIA CORPORATION.
3  *
4  * SPDX-License-Identifier: GPL-2.0
5  */
6
7 #include <common.h>
8 #include <asm/io.h>
9 #include <asm/arch-tegra/ivc.h>
10
11 #define TEGRA_IVC_ALIGN 64
12
13 /*
14  * IVC channel reset protocol.
15  *
16  * Each end uses its tx_channel.state to indicate its synchronization state.
17  */
18 enum ivc_state {
19         /*
20          * This value is zero for backwards compatibility with services that
21          * assume channels to be initially zeroed. Such channels are in an
22          * initially valid state, but cannot be asynchronously reset, and must
23          * maintain a valid state at all times.
24          *
25          * The transmitting end can enter the established state from the sync or
26          * ack state when it observes the receiving endpoint in the ack or
27          * established state, indicating that has cleared the counters in our
28          * rx_channel.
29          */
30         ivc_state_established = 0,
31
32         /*
33          * If an endpoint is observed in the sync state, the remote endpoint is
34          * allowed to clear the counters it owns asynchronously with respect to
35          * the current endpoint. Therefore, the current endpoint is no longer
36          * allowed to communicate.
37          */
38         ivc_state_sync,
39
40         /*
41          * When the transmitting end observes the receiving end in the sync
42          * state, it can clear the w_count and r_count and transition to the ack
43          * state. If the remote endpoint observes us in the ack state, it can
44          * return to the established state once it has cleared its counters.
45          */
46         ivc_state_ack
47 };
48
49 /*
50  * This structure is divided into two-cache aligned parts, the first is only
51  * written through the tx_channel pointer, while the second is only written
52  * through the rx_channel pointer. This delineates ownership of the cache lines,
53  * which is critical to performance and necessary in non-cache coherent
54  * implementations.
55  */
56 struct tegra_ivc_channel_header {
57         union {
58                 /* fields owned by the transmitting end */
59                 struct {
60                         uint32_t w_count;
61                         uint32_t state;
62                 };
63                 uint8_t w_align[TEGRA_IVC_ALIGN];
64         };
65         union {
66                 /* fields owned by the receiving end */
67                 uint32_t r_count;
68                 uint8_t r_align[TEGRA_IVC_ALIGN];
69         };
70 };
71
72 static inline void tegra_ivc_invalidate_counter(struct tegra_ivc *ivc,
73                                         struct tegra_ivc_channel_header *h,
74                                         ulong offset)
75 {
76         ulong base = ((ulong)h) + offset;
77         invalidate_dcache_range(base, base + TEGRA_IVC_ALIGN);
78 }
79
80 static inline void tegra_ivc_flush_counter(struct tegra_ivc *ivc,
81                                            struct tegra_ivc_channel_header *h,
82                                            ulong offset)
83 {
84         ulong base = ((ulong)h) + offset;
85         flush_dcache_range(base, base + TEGRA_IVC_ALIGN);
86 }
87
88 static inline ulong tegra_ivc_frame_addr(struct tegra_ivc *ivc,
89                                          struct tegra_ivc_channel_header *h,
90                                          uint32_t frame)
91 {
92         BUG_ON(frame >= ivc->nframes);
93
94         return ((ulong)h) + sizeof(struct tegra_ivc_channel_header) +
95                (ivc->frame_size * frame);
96 }
97
98 static inline void *tegra_ivc_frame_pointer(struct tegra_ivc *ivc,
99                                             struct tegra_ivc_channel_header *ch,
100                                             uint32_t frame)
101 {
102         return (void *)tegra_ivc_frame_addr(ivc, ch, frame);
103 }
104
105 static inline void tegra_ivc_invalidate_frame(struct tegra_ivc *ivc,
106                                         struct tegra_ivc_channel_header *h,
107                                         unsigned frame)
108 {
109         ulong base = tegra_ivc_frame_addr(ivc, h, frame);
110         invalidate_dcache_range(base, base + ivc->frame_size);
111 }
112
113 static inline void tegra_ivc_flush_frame(struct tegra_ivc *ivc,
114                                          struct tegra_ivc_channel_header *h,
115                                          unsigned frame)
116 {
117         ulong base = tegra_ivc_frame_addr(ivc, h, frame);
118         flush_dcache_range(base, base + ivc->frame_size);
119 }
120
121 static inline int tegra_ivc_channel_empty(struct tegra_ivc *ivc,
122                                           struct tegra_ivc_channel_header *ch)
123 {
124         /*
125          * This function performs multiple checks on the same values with
126          * security implications, so create snapshots with ACCESS_ONCE() to
127          * ensure that these checks use the same values.
128          */
129         uint32_t w_count = ACCESS_ONCE(ch->w_count);
130         uint32_t r_count = ACCESS_ONCE(ch->r_count);
131
132         /*
133          * Perform an over-full check to prevent denial of service attacks where
134          * a server could be easily fooled into believing that there's an
135          * extremely large number of frames ready, since receivers are not
136          * expected to check for full or over-full conditions.
137          *
138          * Although the channel isn't empty, this is an invalid case caused by
139          * a potentially malicious peer, so returning empty is safer, because it
140          * gives the impression that the channel has gone silent.
141          */
142         if (w_count - r_count > ivc->nframes)
143                 return 1;
144
145         return w_count == r_count;
146 }
147
148 static inline int tegra_ivc_channel_full(struct tegra_ivc *ivc,
149                                          struct tegra_ivc_channel_header *ch)
150 {
151         /*
152          * Invalid cases where the counters indicate that the queue is over
153          * capacity also appear full.
154          */
155         return (ACCESS_ONCE(ch->w_count) - ACCESS_ONCE(ch->r_count)) >=
156                ivc->nframes;
157 }
158
159 static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc)
160 {
161         ACCESS_ONCE(ivc->rx_channel->r_count) =
162                         ACCESS_ONCE(ivc->rx_channel->r_count) + 1;
163
164         if (ivc->r_pos == ivc->nframes - 1)
165                 ivc->r_pos = 0;
166         else
167                 ivc->r_pos++;
168 }
169
170 static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc)
171 {
172         ACCESS_ONCE(ivc->tx_channel->w_count) =
173                         ACCESS_ONCE(ivc->tx_channel->w_count) + 1;
174
175         if (ivc->w_pos == ivc->nframes - 1)
176                 ivc->w_pos = 0;
177         else
178                 ivc->w_pos++;
179 }
180
181 static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
182 {
183         ulong offset;
184
185         /*
186          * tx_channel->state is set locally, so it is not synchronized with
187          * state from the remote peer. The remote peer cannot reset its
188          * transmit counters until we've acknowledged its synchronization
189          * request, so no additional synchronization is required because an
190          * asynchronous transition of rx_channel->state to ivc_state_ack is not
191          * allowed.
192          */
193         if (ivc->tx_channel->state != ivc_state_established)
194                 return -ECONNRESET;
195
196         /*
197          * Avoid unnecessary invalidations when performing repeated accesses to
198          * an IVC channel by checking the old queue pointers first.
199          * Synchronization is only necessary when these pointers indicate empty
200          * or full.
201          */
202         if (!tegra_ivc_channel_empty(ivc, ivc->rx_channel))
203                 return 0;
204
205         offset = offsetof(struct tegra_ivc_channel_header, w_count);
206         tegra_ivc_invalidate_counter(ivc, ivc->rx_channel, offset);
207         return tegra_ivc_channel_empty(ivc, ivc->rx_channel) ? -ENOMEM : 0;
208 }
209
210 static inline int tegra_ivc_check_write(struct tegra_ivc *ivc)
211 {
212         ulong offset;
213
214         if (ivc->tx_channel->state != ivc_state_established)
215                 return -ECONNRESET;
216
217         if (!tegra_ivc_channel_full(ivc, ivc->tx_channel))
218                 return 0;
219
220         offset = offsetof(struct tegra_ivc_channel_header, r_count);
221         tegra_ivc_invalidate_counter(ivc, ivc->tx_channel, offset);
222         return tegra_ivc_channel_full(ivc, ivc->tx_channel) ? -ENOMEM : 0;
223 }
224
225 static inline uint32_t tegra_ivc_channel_avail_count(struct tegra_ivc *ivc,
226         struct tegra_ivc_channel_header *ch)
227 {
228         /*
229          * This function isn't expected to be used in scenarios where an
230          * over-full situation can lead to denial of service attacks. See the
231          * comment in tegra_ivc_channel_empty() for an explanation about
232          * special over-full considerations.
233          */
234         return ACCESS_ONCE(ch->w_count) - ACCESS_ONCE(ch->r_count);
235 }
236
237 int tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc, void **frame)
238 {
239         int result = tegra_ivc_check_read(ivc);
240         if (result < 0)
241                 return result;
242
243         /*
244          * Order observation of w_pos potentially indicating new data before
245          * data read.
246          */
247         mb();
248
249         tegra_ivc_invalidate_frame(ivc, ivc->rx_channel, ivc->r_pos);
250         *frame = tegra_ivc_frame_pointer(ivc, ivc->rx_channel, ivc->r_pos);
251
252         return 0;
253 }
254
255 int tegra_ivc_read_advance(struct tegra_ivc *ivc)
256 {
257         ulong offset;
258         int result;
259
260         /*
261          * No read barriers or synchronization here: the caller is expected to
262          * have already observed the channel non-empty. This check is just to
263          * catch programming errors.
264          */
265         result = tegra_ivc_check_read(ivc);
266         if (result)
267                 return result;
268
269         tegra_ivc_advance_rx(ivc);
270         offset = offsetof(struct tegra_ivc_channel_header, r_count);
271         tegra_ivc_flush_counter(ivc, ivc->rx_channel, offset);
272
273         /*
274          * Ensure our write to r_pos occurs before our read from w_pos.
275          */
276         mb();
277
278         offset = offsetof(struct tegra_ivc_channel_header, w_count);
279         tegra_ivc_invalidate_counter(ivc, ivc->rx_channel, offset);
280
281         if (tegra_ivc_channel_avail_count(ivc, ivc->rx_channel) ==
282             ivc->nframes - 1)
283                 ivc->notify(ivc);
284
285         return 0;
286 }
287
288 int tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc, void **frame)
289 {
290         int result = tegra_ivc_check_write(ivc);
291         if (result)
292                 return result;
293
294         *frame = tegra_ivc_frame_pointer(ivc, ivc->tx_channel, ivc->w_pos);
295
296         return 0;
297 }
298
299 int tegra_ivc_write_advance(struct tegra_ivc *ivc)
300 {
301         ulong offset;
302         int result;
303
304         result = tegra_ivc_check_write(ivc);
305         if (result)
306                 return result;
307
308         tegra_ivc_flush_frame(ivc, ivc->tx_channel, ivc->w_pos);
309
310         /*
311          * Order any possible stores to the frame before update of w_pos.
312          */
313         mb();
314
315         tegra_ivc_advance_tx(ivc);
316         offset = offsetof(struct tegra_ivc_channel_header, w_count);
317         tegra_ivc_flush_counter(ivc, ivc->tx_channel, offset);
318
319         /*
320          * Ensure our write to w_pos occurs before our read from r_pos.
321          */
322         mb();
323
324         offset = offsetof(struct tegra_ivc_channel_header, r_count);
325         tegra_ivc_invalidate_counter(ivc, ivc->tx_channel, offset);
326
327         if (tegra_ivc_channel_avail_count(ivc, ivc->tx_channel) == 1)
328                 ivc->notify(ivc);
329
330         return 0;
331 }
332
333 /*
334  * ===============================================================
335  *  IVC State Transition Table - see tegra_ivc_channel_notified()
336  * ===============================================================
337  *
338  *      local   remote  action
339  *      -----   ------  -----------------------------------
340  *      SYNC    EST     <none>
341  *      SYNC    ACK     reset counters; move to EST; notify
342  *      SYNC    SYNC    reset counters; move to ACK; notify
343  *      ACK     EST     move to EST; notify
344  *      ACK     ACK     move to EST; notify
345  *      ACK     SYNC    reset counters; move to ACK; notify
346  *      EST     EST     <none>
347  *      EST     ACK     <none>
348  *      EST     SYNC    reset counters; move to ACK; notify
349  *
350  * ===============================================================
351  */
352 int tegra_ivc_channel_notified(struct tegra_ivc *ivc)
353 {
354         ulong offset;
355         enum ivc_state peer_state;
356
357         /* Copy the receiver's state out of shared memory. */
358         offset = offsetof(struct tegra_ivc_channel_header, w_count);
359         tegra_ivc_invalidate_counter(ivc, ivc->rx_channel, offset);
360         peer_state = ACCESS_ONCE(ivc->rx_channel->state);
361
362         if (peer_state == ivc_state_sync) {
363                 /*
364                  * Order observation of ivc_state_sync before stores clearing
365                  * tx_channel.
366                  */
367                 mb();
368
369                 /*
370                  * Reset tx_channel counters. The remote end is in the SYNC
371                  * state and won't make progress until we change our state,
372                  * so the counters are not in use at this time.
373                  */
374                 ivc->tx_channel->w_count = 0;
375                 ivc->rx_channel->r_count = 0;
376
377                 ivc->w_pos = 0;
378                 ivc->r_pos = 0;
379
380                 /*
381                  * Ensure that counters appear cleared before new state can be
382                  * observed.
383                  */
384                 mb();
385
386                 /*
387                  * Move to ACK state. We have just cleared our counters, so it
388                  * is now safe for the remote end to start using these values.
389                  */
390                 ivc->tx_channel->state = ivc_state_ack;
391                 offset = offsetof(struct tegra_ivc_channel_header, w_count);
392                 tegra_ivc_flush_counter(ivc, ivc->tx_channel, offset);
393
394                 /*
395                  * Notify remote end to observe state transition.
396                  */
397                 ivc->notify(ivc);
398         } else if (ivc->tx_channel->state == ivc_state_sync &&
399                         peer_state == ivc_state_ack) {
400                 /*
401                  * Order observation of ivc_state_sync before stores clearing
402                  * tx_channel.
403                  */
404                 mb();
405
406                 /*
407                  * Reset tx_channel counters. The remote end is in the ACK
408                  * state and won't make progress until we change our state,
409                  * so the counters are not in use at this time.
410                  */
411                 ivc->tx_channel->w_count = 0;
412                 ivc->rx_channel->r_count = 0;
413
414                 ivc->w_pos = 0;
415                 ivc->r_pos = 0;
416
417                 /*
418                  * Ensure that counters appear cleared before new state can be
419                  * observed.
420                  */
421                 mb();
422
423                 /*
424                  * Move to ESTABLISHED state. We know that the remote end has
425                  * already cleared its counters, so it is safe to start
426                  * writing/reading on this channel.
427                  */
428                 ivc->tx_channel->state = ivc_state_established;
429                 offset = offsetof(struct tegra_ivc_channel_header, w_count);
430                 tegra_ivc_flush_counter(ivc, ivc->tx_channel, offset);
431
432                 /*
433                  * Notify remote end to observe state transition.
434                  */
435                 ivc->notify(ivc);
436         } else if (ivc->tx_channel->state == ivc_state_ack) {
437                 /*
438                  * At this point, we have observed the peer to be in either
439                  * the ACK or ESTABLISHED state. Next, order observation of
440                  * peer state before storing to tx_channel.
441                  */
442                 mb();
443
444                 /*
445                  * Move to ESTABLISHED state. We know that we have previously
446                  * cleared our counters, and we know that the remote end has
447                  * cleared its counters, so it is safe to start writing/reading
448                  * on this channel.
449                  */
450                 ivc->tx_channel->state = ivc_state_established;
451                 offset = offsetof(struct tegra_ivc_channel_header, w_count);
452                 tegra_ivc_flush_counter(ivc, ivc->tx_channel, offset);
453
454                 /*
455                  * Notify remote end to observe state transition.
456                  */
457                 ivc->notify(ivc);
458         } else {
459                 /*
460                  * There is no need to handle any further action. Either the
461                  * channel is already fully established, or we are waiting for
462                  * the remote end to catch up with our current state. Refer
463                  * to the diagram in "IVC State Transition Table" above.
464                  */
465         }
466
467         if (ivc->tx_channel->state != ivc_state_established)
468                 return -EAGAIN;
469
470         return 0;
471 }
472
473 void tegra_ivc_channel_reset(struct tegra_ivc *ivc)
474 {
475         ulong offset;
476
477         ivc->tx_channel->state = ivc_state_sync;
478         offset = offsetof(struct tegra_ivc_channel_header, w_count);
479         tegra_ivc_flush_counter(ivc, ivc->tx_channel, offset);
480         ivc->notify(ivc);
481 }
482
483 static int check_ivc_params(ulong qbase1, ulong qbase2, uint32_t nframes,
484                             uint32_t frame_size)
485 {
486         int ret = 0;
487
488         BUG_ON(offsetof(struct tegra_ivc_channel_header, w_count) &
489                (TEGRA_IVC_ALIGN - 1));
490         BUG_ON(offsetof(struct tegra_ivc_channel_header, r_count) &
491                (TEGRA_IVC_ALIGN - 1));
492         BUG_ON(sizeof(struct tegra_ivc_channel_header) &
493                (TEGRA_IVC_ALIGN - 1));
494
495         if ((uint64_t)nframes * (uint64_t)frame_size >= 0x100000000) {
496                 error("tegra_ivc: nframes * frame_size overflows\n");
497                 return -EINVAL;
498         }
499
500         /*
501          * The headers must at least be aligned enough for counters
502          * to be accessed atomically.
503          */
504         if ((qbase1 & (TEGRA_IVC_ALIGN - 1)) ||
505             (qbase2 & (TEGRA_IVC_ALIGN - 1))) {
506                 error("tegra_ivc: channel start not aligned\n");
507                 return -EINVAL;
508         }
509
510         if (frame_size & (TEGRA_IVC_ALIGN - 1)) {
511                 error("tegra_ivc: frame size not adequately aligned\n");
512                 return -EINVAL;
513         }
514
515         if (qbase1 < qbase2) {
516                 if (qbase1 + frame_size * nframes > qbase2)
517                         ret = -EINVAL;
518         } else {
519                 if (qbase2 + frame_size * nframes > qbase1)
520                         ret = -EINVAL;
521         }
522
523         if (ret) {
524                 error("tegra_ivc: queue regions overlap\n");
525                 return ret;
526         }
527
528         return 0;
529 }
530
531 int tegra_ivc_init(struct tegra_ivc *ivc, ulong rx_base, ulong tx_base,
532                    uint32_t nframes, uint32_t frame_size,
533                    void (*notify)(struct tegra_ivc *))
534 {
535         int ret;
536
537         if (!ivc)
538                 return -EINVAL;
539
540         ret = check_ivc_params(rx_base, tx_base, nframes, frame_size);
541         if (ret)
542                 return ret;
543
544         ivc->rx_channel = (struct tegra_ivc_channel_header *)rx_base;
545         ivc->tx_channel = (struct tegra_ivc_channel_header *)tx_base;
546         ivc->w_pos = 0;
547         ivc->r_pos = 0;
548         ivc->nframes = nframes;
549         ivc->frame_size = frame_size;
550         ivc->notify = notify;
551
552         return 0;
553 }