The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/altera/jtag_uart/altera_jtag_uart_cons.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2011-2012 Robert N. M. Watson
    5  * All rights reserved.
    6  *
    7  * This software was developed by SRI International and the University of
    8  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
    9  * ("CTSRD"), as part of the DARPA CRASH research programme.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include <sys/param.h>
   37 #include <sys/bus.h>
   38 #include <sys/cons.h>
   39 #include <sys/endian.h>
   40 #include <sys/kdb.h>
   41 #include <sys/kernel.h>
   42 #include <sys/lock.h>
   43 #include <sys/mutex.h>
   44 #include <sys/reboot.h>
   45 #include <sys/sysctl.h>
   46 #include <sys/systm.h>
   47 #include <sys/tty.h>
   48 
   49 #include <ddb/ddb.h>
   50 
   51 #include <dev/altera/jtag_uart/altera_jtag_uart.h>
   52 
   53 static SYSCTL_NODE(_hw, OID_AUTO, altera_jtag_uart,
   54     CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
   55     "Altera JTAG UART configuration knobs");
   56 
   57 /*
   58  * One-byte buffer as we can't check whether the UART is readable without
   59  * actually reading from it, synchronised by a spinlock; this lock also
   60  * synchronises access to the I/O ports for non-atomic sequences.  These
   61  * symbols are public so that the TTY layer can use them when working on an
   62  * instance of the UART that is also a low-level console.
   63  */
   64 char            aju_cons_buffer_data;
   65 int             aju_cons_buffer_valid;
   66 int             aju_cons_jtag_present;
   67 u_int           aju_cons_jtag_missed;
   68 struct mtx      aju_cons_lock;
   69 
   70 /*
   71  * Low-level console driver functions.
   72  */
   73 static cn_probe_t       aju_cnprobe;
   74 static cn_init_t        aju_cninit;
   75 static cn_term_t        aju_cnterm;
   76 static cn_getc_t        aju_cngetc;
   77 static cn_putc_t        aju_cnputc;
   78 static cn_grab_t        aju_cngrab;
   79 static cn_ungrab_t      aju_cnungrab;
   80 
   81 /*
   82  * JTAG sets the ALTERA_JTAG_UART_CONTROL_AC bit whenever it accesses the
   83  * FIFO.  This allows us to (sort of) tell when JTAG is present, so that we
   84  * can adopt lossy, rather than blocking, behaviour when JTAG isn't there.
   85  * When it is present, we do full flow control.  This delay is how long we
   86  * wait to see if JTAG has really disappeared when finding a full buffer and
   87  * no AC bit set.
   88  */
   89 #define ALTERA_JTAG_UART_AC_POLL_DELAY  10000
   90 static u_int    altera_jtag_uart_ac_poll_delay =
   91                     ALTERA_JTAG_UART_AC_POLL_DELAY;
   92 SYSCTL_UINT(_hw_altera_jtag_uart, OID_AUTO, ac_poll_delay,
   93     CTLFLAG_RW, &altera_jtag_uart_ac_poll_delay, 0,
   94     "Maximum delay waiting for JTAG present flag when buffer is full");
   95 
   96 /*
   97  * I/O routines lifted from Deimos.  This is not only MIPS-specific, but also
   98  * BERI-specific, as we're hard coding the address at which we expect to
   99  * find the Altera JTAG UART and using it unconditionally.  We use these
  100  * low-level routines so that we can perform console I/O long before newbus
  101  * has initialised and devices have attached.  The TTY layer of the driver
  102  * knows about this, and uses the console-layer spinlock instead of the
  103  * TTY-layer lock to avoid confusion between layers for the console UART.
  104  *
  105  * XXXRW: The only place this inter-layer behaviour breaks down is if the
  106  * low-level console is used for polled read while the TTY driver is also
  107  * looking for input.  Probably we should also share buffers between layers.
  108  */
  109 #define MIPS_XKPHYS_UNCACHED_BASE       0x9000000000000000
  110 
  111 typedef uint64_t        paddr_t;
  112 typedef uint64_t        vaddr_t;
  113 
  114 static inline vaddr_t
  115 mips_phys_to_uncached(paddr_t phys)            
  116 {
  117 
  118         return (phys | MIPS_XKPHYS_UNCACHED_BASE);
  119 }
  120 
  121 static inline uint32_t
  122 mips_ioread_uint32(vaddr_t vaddr)
  123 {
  124         uint32_t v;
  125 
  126         __asm__ __volatile__ ("lw %0, 0(%1)" : "=r" (v) : "r" (vaddr));
  127         return (v);
  128 }
  129 
  130 static inline void
  131 mips_iowrite_uint32(vaddr_t vaddr, uint32_t v)
  132 {
  133 
  134         __asm__ __volatile__ ("sw %0, 0(%1)" : : "r" (v), "r" (vaddr));
  135 }
  136 
  137 /*
  138  * Little-endian versions of 32-bit I/O routines.
  139  */
  140 static inline uint32_t
  141 mips_ioread_uint32le(vaddr_t vaddr)
  142 {
  143 
  144         return (le32toh(mips_ioread_uint32(vaddr)));
  145 }
  146 
  147 static inline void
  148 mips_iowrite_uint32le(vaddr_t vaddr, uint32_t v)
  149 {
  150 
  151         mips_iowrite_uint32(vaddr, htole32(v));
  152 }
  153 
  154 /*
  155  * Low-level read and write register routines; the Altera UART is little
  156  * endian, so we byte swap 32-bit reads and writes.
  157  */
  158 static inline uint32_t
  159 aju_cons_data_read(void)
  160 {
  161 
  162         return (mips_ioread_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
  163             ALTERA_JTAG_UART_DATA_OFF)));
  164 }
  165 
  166 static inline void
  167 aju_cons_data_write(uint32_t v)
  168 {
  169 
  170         mips_iowrite_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
  171             ALTERA_JTAG_UART_DATA_OFF), v);
  172 }
  173 
  174 static inline uint32_t
  175 aju_cons_control_read(void)
  176 {
  177 
  178         return (mips_ioread_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
  179             ALTERA_JTAG_UART_CONTROL_OFF)));
  180 }
  181 
  182 static inline void
  183 aju_cons_control_write(uint32_t v)
  184 {
  185 
  186         mips_iowrite_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
  187             ALTERA_JTAG_UART_CONTROL_OFF), v);
  188 }
  189 
  190 /*
  191  * Slightly higher-level routines aware of buffering and flow control.
  192  */
  193 static int
  194 aju_cons_readable(void)
  195 {
  196         uint32_t v;
  197 
  198         AJU_CONSOLE_LOCK_ASSERT();
  199 
  200         if (aju_cons_buffer_valid)
  201                 return (1);
  202         v = aju_cons_data_read();
  203         if ((v & ALTERA_JTAG_UART_DATA_RVALID) != 0) {
  204                 aju_cons_buffer_valid = 1;
  205                 aju_cons_buffer_data = (v & ALTERA_JTAG_UART_DATA_DATA);
  206                 return (1);
  207         }
  208         return (0);
  209 }
  210 
  211 static void
  212 aju_cons_write(char ch)
  213 {
  214         uint32_t v;
  215 
  216         AJU_CONSOLE_LOCK_ASSERT();
  217 
  218         /*
  219          * The flow control logic here is somewhat subtle: we want to wait for
  220          * write buffer space only while JTAG is present.  However, we can't
  221          * directly ask if JTAG is present -- just whether it's been seen
  222          * since we last cleared the ALTERA_JTAG_UART_CONTROL_AC bit.  As
  223          * such, implement a polling loop in which we both wait for space and
  224          * try to decide whether JTAG has disappeared on us.  We will have to
  225          * wait one complete polling delay to detect that JTAG has gone away,
  226          * but otherwise shouldn't wait any further once it has gone.  And we
  227          * had to wait for buffer space anyway, if it was there.
  228          *
  229          * If JTAG is spotted, reset the TTY-layer miss counter so console-
  230          * layer clearing of the bit doesn't trigger a TTY-layer
  231          * disconnection.
  232          *
  233          * XXXRW: Notice the inherent race with hardware: in clearing the
  234          * bit, we may race with hardware setting the same bit.  This can
  235          * cause real-world reliability problems due to lost output on the
  236          * console.
  237          */
  238         v = aju_cons_control_read();
  239         if (v & ALTERA_JTAG_UART_CONTROL_AC) {
  240                 aju_cons_jtag_present = 1;
  241                 aju_cons_jtag_missed = 0;
  242                 v &= ~ALTERA_JTAG_UART_CONTROL_AC;
  243                 aju_cons_control_write(v);
  244         }
  245         while ((v & ALTERA_JTAG_UART_CONTROL_WSPACE) == 0) {
  246                 if (!aju_cons_jtag_present)
  247                         return;
  248                 DELAY(altera_jtag_uart_ac_poll_delay);
  249                 v = aju_cons_control_read();
  250                 if (v & ALTERA_JTAG_UART_CONTROL_AC) {
  251                         aju_cons_jtag_present = 1;
  252                         v &= ~ALTERA_JTAG_UART_CONTROL_AC;
  253                         aju_cons_control_write(v);
  254                 } else
  255                         aju_cons_jtag_present = 0;
  256         }
  257         aju_cons_data_write(ch);
  258 }
  259 
  260 static char
  261 aju_cons_read(void)
  262 {
  263 
  264         AJU_CONSOLE_LOCK_ASSERT();
  265 
  266         while (!aju_cons_readable());
  267         aju_cons_buffer_valid = 0;
  268         return (aju_cons_buffer_data);
  269 }
  270 
  271 /*
  272  * Implementation of a FreeBSD low-level, polled console driver.
  273  */
  274 static void
  275 aju_cnprobe(struct consdev *cp)
  276 {
  277 
  278         sprintf(cp->cn_name, "%s%d", AJU_TTYNAME, 0);
  279         cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
  280 }
  281 
  282 static void
  283 aju_cninit(struct consdev *cp)
  284 {
  285         uint32_t v;
  286 
  287         AJU_CONSOLE_LOCK_INIT();
  288 
  289         AJU_CONSOLE_LOCK();
  290         v = aju_cons_control_read();
  291         v &= ~ALTERA_JTAG_UART_CONTROL_AC;
  292         aju_cons_control_write(v);
  293         AJU_CONSOLE_UNLOCK();
  294 }
  295 
  296 static void
  297 aju_cnterm(struct consdev *cp)
  298 {
  299 
  300 }
  301 
  302 static int
  303 aju_cngetc(struct consdev *cp)
  304 {
  305         int ret;
  306 
  307         AJU_CONSOLE_LOCK();
  308         ret = aju_cons_read();
  309         AJU_CONSOLE_UNLOCK();
  310         return (ret);
  311 }
  312 
  313 static void
  314 aju_cnputc(struct consdev *cp, int c)
  315 {
  316 
  317         AJU_CONSOLE_LOCK();
  318         aju_cons_write(c);
  319         AJU_CONSOLE_UNLOCK();
  320 }
  321 
  322 static void
  323 aju_cngrab(struct consdev *cp)
  324 {
  325 
  326 }
  327 
  328 static void
  329 aju_cnungrab(struct consdev *cp)
  330 {
  331 
  332 }
  333 
  334 CONSOLE_DRIVER(aju);

Cache object: 65f59a4a0ab94f825cadad3edd75c899


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.