17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*8793b36bSNick Todd * Common Development and Distribution License (the "License").
6*8793b36bSNick Todd * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*8793b36bSNick Todd * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/conf.h>
287c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
297c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
307c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
317c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
327c478bd9Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gate #include <sys/iommu.h>
357c478bd9Sstevel@tonic-gate #include <sys/iocache.h>
367c478bd9Sstevel@tonic-gate #include <sys/sysiosbus.h>
377c478bd9Sstevel@tonic-gate
387c478bd9Sstevel@tonic-gate #include <sys/nexusdebug.h>
397c478bd9Sstevel@tonic-gate #include <sys/debug.h>
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate #define IOCACHE_REGISTERS_DEBUG 0x1
427c478bd9Sstevel@tonic-gate #define IOCACHE_SYNC_DEBUG 0x2
437c478bd9Sstevel@tonic-gate #define IOCACHE_DIAG_REG_DEBUG 0x4
447c478bd9Sstevel@tonic-gate #define IOCACHE_SYNC_FAIL_DEBUG 0x8
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate #define MAX_RETRY 10
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate /* Flag which enables the streaming buffer */
497c478bd9Sstevel@tonic-gate int stream_buf_on = 1;
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate * This is the number of pages that a mapping request needs before we force
527c478bd9Sstevel@tonic-gate * the streaming buffer sync code to use diagnostic registers. This value
537c478bd9Sstevel@tonic-gate * was determined through a series of test runs measuring dma mapping
547c478bd9Sstevel@tonic-gate * setup performance.
557c478bd9Sstevel@tonic-gate */
567c478bd9Sstevel@tonic-gate int stream_buf_sync_using_diag = 36;
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate int
stream_buf_init(struct sbus_soft_state * softsp,caddr_t address)597c478bd9Sstevel@tonic-gate stream_buf_init(struct sbus_soft_state *softsp, caddr_t address)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate uchar_t version;
627c478bd9Sstevel@tonic-gate #ifdef DEBUG
637c478bd9Sstevel@tonic-gate debug_info = 1;
647c478bd9Sstevel@tonic-gate debug_print_level = 0;
657c478bd9Sstevel@tonic-gate #endif
667c478bd9Sstevel@tonic-gate version = (uchar_t)(*softsp->sysio_ctrl_reg >> SYSIO_VER_SHIFT);
677c478bd9Sstevel@tonic-gate version &= 0xf;
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate if (stream_buf_on == 0 || version == 0) {
707c478bd9Sstevel@tonic-gate softsp->stream_buf_off = STREAM_BUF_OFF;
717c478bd9Sstevel@tonic-gate if (version == 0)
727c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Disabling streaming buffer due to "
737c478bd9Sstevel@tonic-gate "SYSIO Rev %d.\n", version);
747c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate * Simply add each registers offset to the base address
797c478bd9Sstevel@tonic-gate * to calculate the already mapped virtual address of
807c478bd9Sstevel@tonic-gate * the device register...
817c478bd9Sstevel@tonic-gate *
827c478bd9Sstevel@tonic-gate * define a macro for the pointer arithmetic; all registers
837c478bd9Sstevel@tonic-gate * are 64 bits wide and are defined as uint64_t's.
847c478bd9Sstevel@tonic-gate */
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate #define REG_ADDR(b, o) (uint64_t *)((caddr_t)(b) + (o))
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate softsp->str_buf_ctrl_reg = REG_ADDR(address, OFF_STR_BUF_CTRL_REG);
897c478bd9Sstevel@tonic-gate softsp->str_buf_flush_reg = REG_ADDR(address, OFF_STR_BUF_FLUSH_REG);
907c478bd9Sstevel@tonic-gate softsp->str_buf_sync_reg = REG_ADDR(address, OFF_STR_BUF_SYNC_REG);
917c478bd9Sstevel@tonic-gate softsp->str_buf_pg_tag_diag = REG_ADDR(address, STR_BUF_PAGE_TAG_DIAG);
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate #undef REG_ADDR
947c478bd9Sstevel@tonic-gate
95ffadc26eSmike_s DPRINTF(IOCACHE_REGISTERS_DEBUG, ("Streaming buffer control reg: 0x%p, "
96ffadc26eSmike_s "Streaming buffer flush reg: 0x%p, Streaming buffer sync reg: 0x%p",
97*8793b36bSNick Todd (void *)softsp->str_buf_ctrl_reg, (void *)softsp->str_buf_flush_reg,
98*8793b36bSNick Todd (void *)softsp->str_buf_sync_reg));
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate /* Initialize stream buffer sync reg mutex */
1017c478bd9Sstevel@tonic-gate mutex_init(&softsp->sync_reg_lock, NULL, MUTEX_DEFAULT, NULL);
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate /* Turn on per instance streaming buffer flag */
1047c478bd9Sstevel@tonic-gate softsp->stream_buf_off = 0;
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate /* Set the hardware registers */
1077c478bd9Sstevel@tonic-gate (void) stream_buf_resume_init(softsp);
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
1107c478bd9Sstevel@tonic-gate }
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate int
stream_buf_uninit(struct sbus_soft_state * softsp)1137c478bd9Sstevel@tonic-gate stream_buf_uninit(struct sbus_soft_state *softsp)
1147c478bd9Sstevel@tonic-gate {
1157c478bd9Sstevel@tonic-gate /* Turn off per instance streaming buffer flag */
1167c478bd9Sstevel@tonic-gate softsp->stream_buf_off = 1;
1177c478bd9Sstevel@tonic-gate
1187c478bd9Sstevel@tonic-gate /* Turn off the streaming buffer */
1197c478bd9Sstevel@tonic-gate *softsp->str_buf_ctrl_reg = STREAM_BUF_DISABLE;
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate * Initialize stream buf hardware when the system is being resumed.
1257c478bd9Sstevel@tonic-gate * (Subset of stream_buf_init())
1267c478bd9Sstevel@tonic-gate */
1277c478bd9Sstevel@tonic-gate int
stream_buf_resume_init(struct sbus_soft_state * softsp)1287c478bd9Sstevel@tonic-gate stream_buf_resume_init(struct sbus_soft_state *softsp)
1297c478bd9Sstevel@tonic-gate {
1307c478bd9Sstevel@tonic-gate uchar_t version;
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate version = (uchar_t)(*softsp->sysio_ctrl_reg >> SYSIO_VER_SHIFT);
1337c478bd9Sstevel@tonic-gate version &= 0xf;
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate if (stream_buf_on == 0 || version == 0) {
1367c478bd9Sstevel@tonic-gate softsp->stream_buf_off = STREAM_BUF_OFF;
1377c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate /* Turn on the streaming buffer */
1417c478bd9Sstevel@tonic-gate *softsp->str_buf_ctrl_reg = STREAM_BUF_ENABLE;
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate /*
1477c478bd9Sstevel@tonic-gate * The SYSIO spec says that it will get back to us within 0.5 seconds,
1487c478bd9Sstevel@tonic-gate * but loaded systems have seen response times over 1.5 seconds. We
1497c478bd9Sstevel@tonic-gate * err on the side of caution and set the timeout to be 10 seconds.
1507c478bd9Sstevel@tonic-gate */
1517c478bd9Sstevel@tonic-gate #define SCACHE_NSEC_WAIT (10ull * NANOSEC)
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate * We want to avoid using gethrtime every time we check sync_flag,
1557c478bd9Sstevel@tonic-gate * so we take SCACHE_SPIN laps before beginning to use gethrtime.
1567c478bd9Sstevel@tonic-gate */
1577c478bd9Sstevel@tonic-gate #define SCACHE_SPIN 10000000
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate void
sync_stream_buf(struct sbus_soft_state * softsp,ioaddr_t addr,uint_t npages,int * sync_flag,uint64_t phys_sync_flag)1607c478bd9Sstevel@tonic-gate sync_stream_buf(struct sbus_soft_state *softsp, ioaddr_t addr, uint_t npages,
1617c478bd9Sstevel@tonic-gate int *sync_flag, uint64_t phys_sync_flag)
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate #ifndef lint
1647c478bd9Sstevel@tonic-gate volatile uint64_t tmp;
1657c478bd9Sstevel@tonic-gate #endif
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate int cntr = 0;
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate if (softsp->stream_buf_off != 0)
1707c478bd9Sstevel@tonic-gate return;
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate DPRINTF(IOCACHE_SYNC_DEBUG, ("sync_stream_buf: ioaddr 0x%x, page cnt "
173ffadc26eSmike_s "0x%x, sync flag 0x%p, sync flag pf 0x%lx\n", addr, npages,
174*8793b36bSNick Todd (void *)sync_flag, phys_sync_flag));
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate ASSERT(npages > (uint_t)0);
1777c478bd9Sstevel@tonic-gate
1787c478bd9Sstevel@tonic-gate /* Acquire the sync lock */
1797c478bd9Sstevel@tonic-gate mutex_enter(&softsp->sync_reg_lock);
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate *sync_flag = 0;
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate if (npages > stream_buf_sync_using_diag) {
1847c478bd9Sstevel@tonic-gate int i;
1857c478bd9Sstevel@tonic-gate volatile uint64_t *reg_addr;
1867c478bd9Sstevel@tonic-gate uint64_t reg;
1877c478bd9Sstevel@tonic-gate uint_t ioaddr;
1887c478bd9Sstevel@tonic-gate uint_t hiaddr = addr + (npages * IOMMU_PAGESIZE);
1897c478bd9Sstevel@tonic-gate int do_sync = 0;
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate for (i = 0, reg_addr = softsp->str_buf_pg_tag_diag;
1927c478bd9Sstevel@tonic-gate i < STREAM_CACHE_LINES; i++, reg_addr++) {
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate /* Read the page tag diag reg */
1957c478bd9Sstevel@tonic-gate reg = *reg_addr;
1967c478bd9Sstevel@tonic-gate #ifdef DEBUG
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate uint_t hi, lo;
1997c478bd9Sstevel@tonic-gate hi = (uint_t)(reg >> 32);
2007c478bd9Sstevel@tonic-gate lo = (uint_t)(reg & 0xffffffff);
2017c478bd9Sstevel@tonic-gate DPRINTF(IOCACHE_DIAG_REG_DEBUG,
2027c478bd9Sstevel@tonic-gate ("IO cache line diag "
203ffadc26eSmike_s "reg addr 0x%p, hi0x%x lo0x%x\n",
204*8793b36bSNick Todd (void *)reg_addr, hi, lo));
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2077c478bd9Sstevel@tonic-gate /* Check for a valid line */
2087c478bd9Sstevel@tonic-gate if (reg & STR_PG_VALID) {
2097c478bd9Sstevel@tonic-gate ioaddr = (uint_t)reg << STR_PG_SHIFT;
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate DPRINTF(IOCACHE_DIAG_REG_DEBUG, ("ioaddr 0x%x, "
2127c478bd9Sstevel@tonic-gate "range base 0x%x, range extent 0x%x\n",
2137c478bd9Sstevel@tonic-gate ioaddr, addr,
2147c478bd9Sstevel@tonic-gate addr + (npages * IOMMU_PAGESIZE)));
2157c478bd9Sstevel@tonic-gate if (ioaddr >= addr && ioaddr <= hiaddr) {
2167c478bd9Sstevel@tonic-gate *softsp->str_buf_flush_reg = (uint64_t)
2177c478bd9Sstevel@tonic-gate ioaddr;
2187c478bd9Sstevel@tonic-gate do_sync = 1;
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate if (!do_sync) {
2247c478bd9Sstevel@tonic-gate mutex_exit(&softsp->sync_reg_lock);
2257c478bd9Sstevel@tonic-gate return;
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate } else {
2287c478bd9Sstevel@tonic-gate do {
2297c478bd9Sstevel@tonic-gate *softsp->str_buf_flush_reg = (uint64_t)addr;
2307c478bd9Sstevel@tonic-gate addr += IOMMU_PAGESIZE;
2317c478bd9Sstevel@tonic-gate npages--;
2327c478bd9Sstevel@tonic-gate } while (npages > (uint_t)0);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate /* Ask the hardware to flag when the flush is complete */
2367c478bd9Sstevel@tonic-gate *softsp->str_buf_sync_reg = phys_sync_flag;
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate #ifndef lint
2397c478bd9Sstevel@tonic-gate /*
2407c478bd9Sstevel@tonic-gate * Due to the sun4u memory models, this noncached load will sync the
2417c478bd9Sstevel@tonic-gate * order of all prior loads and stores regardless of cacheability.
2427c478bd9Sstevel@tonic-gate * No membar_stst() is needed after zeroing the flush sync flag.
2437c478bd9Sstevel@tonic-gate */
2447c478bd9Sstevel@tonic-gate tmp = *softsp->sbus_ctrl_reg;
2457c478bd9Sstevel@tonic-gate #endif
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate /*
2487c478bd9Sstevel@tonic-gate * Begin spinning on the hardware sync register. We'll spin for
2497c478bd9Sstevel@tonic-gate * a while (SCACHE_SPIN) before using gethrtime, but once that time
2507c478bd9Sstevel@tonic-gate * is up we'll drop into an inner loop where we use gethrtime on
2517c478bd9Sstevel@tonic-gate * every iteration. Once SCACHE_NSEC_WAIT nanoseconds have
2527c478bd9Sstevel@tonic-gate * elapsed, we'll assume a Bad Thing has happened and toss.
2537c478bd9Sstevel@tonic-gate */
2547c478bd9Sstevel@tonic-gate while (!*((volatile int *)sync_flag)) {
2557c478bd9Sstevel@tonic-gate if (cntr++ == SCACHE_SPIN) {
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate * If we're here, then we've spun long enough
2587c478bd9Sstevel@tonic-gate * to justify use of gethrtime each iteration.
2597c478bd9Sstevel@tonic-gate */
2607c478bd9Sstevel@tonic-gate hrtime_t nsec_start, nsectowait, nsec_current;
2617c478bd9Sstevel@tonic-gate nsectowait = SCACHE_NSEC_WAIT;
2627c478bd9Sstevel@tonic-gate nsec_current = nsec_start = gethrtime();
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate while (!*((volatile int *)sync_flag)) {
2657c478bd9Sstevel@tonic-gate /*
2667c478bd9Sstevel@tonic-gate * Double check the sync flag again before
2677c478bd9Sstevel@tonic-gate * we panic in case we get preempted.
2687c478bd9Sstevel@tonic-gate * See bugid 4126896
2697c478bd9Sstevel@tonic-gate */
2707c478bd9Sstevel@tonic-gate nsec_current = gethrtime();
2717c478bd9Sstevel@tonic-gate if ((nsec_current - nsec_start) > nsectowait &&
2727c478bd9Sstevel@tonic-gate !*((volatile int *)sync_flag)) {
2737c478bd9Sstevel@tonic-gate /*
2747c478bd9Sstevel@tonic-gate * Trouble. The SYSIO chip has
2757c478bd9Sstevel@tonic-gate * seemingly gone AWOL. Vomit.
2767c478bd9Sstevel@tonic-gate */
2777c478bd9Sstevel@tonic-gate panic("streaming buffer timed out");
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate
2837c478bd9Sstevel@tonic-gate /* Finally, drop the sync lock */
2847c478bd9Sstevel@tonic-gate mutex_exit(&softsp->sync_reg_lock);
2857c478bd9Sstevel@tonic-gate }
286