From 8aff4e5fdd689ff748806cb5acf556c9b2cd69d0 Mon Sep 17 00:00:00 2001 From: Juli Mallett Date: Mon, 19 Nov 2012 01:58:20 +0000 Subject: [PATCH] Add basic support for the Radisys-specific PCI console mechanism found on the Radisys ATCA-7220. --- sys/mips/cavium/octeon_pci_console.c | 134 +++++++++++++++++++++++++-- 1 file changed, 124 insertions(+), 10 deletions(-) diff --git a/sys/mips/cavium/octeon_pci_console.c b/sys/mips/cavium/octeon_pci_console.c index 3558d5272b4b..cc381fb110bd 100644 --- a/sys/mips/cavium/octeon_pci_console.c +++ b/sys/mips/cavium/octeon_pci_console.c @@ -39,8 +39,22 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include +#ifdef OCTEON_VENDOR_RADISYS +#define OPCIC_FLAG_RSYS (0x00000001) + +#define OPCIC_RSYS_FIFO_SIZE (0x2000) +#endif + +struct opcic_softc { + unsigned sc_flags; + uint64_t sc_base_addr; +}; + +static struct opcic_softc opcic_instance; + static cn_probe_t opcic_cnprobe; static cn_init_t opcic_cninit; static cn_term_t opcic_cnterm; @@ -49,20 +63,46 @@ static cn_putc_t opcic_cnputc; static cn_grab_t opcic_cngrab; static cn_ungrab_t opcic_cnungrab; +#ifdef OCTEON_VENDOR_RADISYS +static int opcic_rsys_cngetc(struct opcic_softc *); +static void opcic_rsys_cnputc(struct opcic_softc *, int); +#endif + CONSOLE_DRIVER(opcic); static void opcic_cnprobe(struct consdev *cp) { const struct cvmx_bootmem_named_block_desc *pci_console_block; + struct opcic_softc *sc; + + sc = &opcic_instance; + sc->sc_flags = 0; + sc->sc_base_addr = 0; cp->cn_pri = CN_DEAD; - pci_console_block = cvmx_bootmem_find_named_block(OCTEON_PCI_CONSOLE_BLOCK_NAME); - if (pci_console_block == NULL) - return; + switch (cvmx_sysinfo_get()->board_type) { +#ifdef OCTEON_VENDOR_RADISYS + case CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE: + pci_console_block = + cvmx_bootmem_find_named_block("rsys_gbl_memory"); + if (pci_console_block != NULL) { + sc->sc_flags |= OPCIC_FLAG_RSYS; + sc->sc_base_addr = pci_console_block->base_addr; + break; + } +#endif + default: + pci_console_block = + cvmx_bootmem_find_named_block(OCTEON_PCI_CONSOLE_BLOCK_NAME); + if (pci_console_block == NULL) + return; + sc->sc_base_addr = pci_console_block->base_addr; + break; + } - cp->cn_arg = (void *)(uintptr_t)pci_console_block->base_addr; + cp->cn_arg = sc; snprintf(cp->cn_name, sizeof cp->cn_name, "opcic@%p", cp->cn_arg); cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL; } @@ -82,13 +122,19 @@ opcic_cnterm(struct consdev *cp) static int opcic_cngetc(struct consdev *cp) { - uint64_t console_desc_addr; + struct opcic_softc *sc; char ch; int rv; - console_desc_addr = (uintptr_t)cp->cn_arg; + sc = cp->cn_arg; - rv = octeon_pci_console_read(console_desc_addr, 0, &ch, 1, OCT_PCI_CON_FLAG_NONBLOCK); +#ifdef OCTEON_VENDOR_RADISYS + if ((sc->sc_flags & OPCIC_FLAG_RSYS) != 0) + return (opcic_rsys_cngetc(sc)); +#endif + + rv = octeon_pci_console_read(sc->sc_base_addr, 0, &ch, 1, + OCT_PCI_CON_FLAG_NONBLOCK); if (rv != 1) return (-1); return (ch); @@ -97,14 +143,21 @@ opcic_cngetc(struct consdev *cp) static void opcic_cnputc(struct consdev *cp, int c) { - uint64_t console_desc_addr; + struct opcic_softc *sc; char ch; int rv; - console_desc_addr = (uintptr_t)cp->cn_arg; + sc = cp->cn_arg; ch = c; - rv = octeon_pci_console_write(console_desc_addr, 0, &ch, 1, 0); +#ifdef OCTEON_VENDOR_RADISYS + if ((sc->sc_flags & OPCIC_FLAG_RSYS) != 0) { + opcic_rsys_cnputc(sc, c); + return; + } +#endif + + rv = octeon_pci_console_write(sc->sc_base_addr, 0, &ch, 1, 0); if (rv == -1) panic("%s: octeon_pci_console_write failed.", __func__); } @@ -120,3 +173,64 @@ opcic_cnungrab(struct consdev *cp) { (void)cp; } + +#ifdef OCTEON_VENDOR_RADISYS +static int +opcic_rsys_cngetc(struct opcic_softc *sc) +{ + uint64_t gbl_base; + uint64_t console_base; + uint64_t console_rbuf; + uint64_t console_rcnt[2]; + uint16_t rcnt[2]; + uint16_t roff; + int c; + + gbl_base = CVMX_ADD_IO_SEG(sc->sc_base_addr); + console_base = gbl_base + 0x10; + + console_rbuf = console_base + 0x2018; + console_rcnt[0] = console_base + 0x08; + console_rcnt[1] = console_base + 0x0a; + + /* Check if there is anything new in the FIFO. */ + rcnt[0] = cvmx_read64_uint16(console_rcnt[0]); + rcnt[1] = cvmx_read64_uint16(console_rcnt[1]); + if (rcnt[0] == rcnt[1]) + return (-1); + + /* Get first new character in the FIFO. */ + if (rcnt[0] != 0) + roff = rcnt[0] - 1; + else + roff = OPCIC_RSYS_FIFO_SIZE - 1; + c = cvmx_read64_uint8(console_rbuf + roff); + + /* Advance FIFO. */ + rcnt[1] = (rcnt[1] + 1) % OPCIC_RSYS_FIFO_SIZE; + cvmx_write64_uint16(console_rcnt[1], rcnt[1]); + + return (c); +} + +static void +opcic_rsys_cnputc(struct opcic_softc *sc, int c) +{ + uint64_t gbl_base; + uint64_t console_base; + uint64_t console_wbuf; + uint64_t console_wcnt; + uint16_t wcnt; + + gbl_base = CVMX_ADD_IO_SEG(sc->sc_base_addr); + console_base = gbl_base + 0x10; + + console_wbuf = console_base + 0x0018; + console_wcnt = console_base + 0x0c; + + /* Append character to FIFO. */ + wcnt = cvmx_read64_uint16(console_wcnt) % OPCIC_RSYS_FIFO_SIZE; + cvmx_write64_uint8(console_wbuf + wcnt, (uint8_t)c); + cvmx_write64_uint16(console_wcnt, wcnt + 1); +} +#endif