iocache.c revision ffadc26e3de00e4c5377fd016a1ffc5dfbb4ff9c
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/ddi_impldefs.h>
#include <vm/hat_sfmmu.h>
#include <sys/sysiosbus.h>
#include <sys/nexusdebug.h>
#define IOCACHE_REGISTERS_DEBUG 0x1
#define IOCACHE_SYNC_DEBUG 0x2
#define IOCACHE_DIAG_REG_DEBUG 0x4
#define IOCACHE_SYNC_FAIL_DEBUG 0x8
#define MAX_RETRY 10
/* Flag which enables the streaming buffer */
int stream_buf_on = 1;
/*
* This is the number of pages that a mapping request needs before we force
* the streaming buffer sync code to use diagnostic registers. This value
* was determined through a series of test runs measuring dma mapping
* setup performance.
*/
int stream_buf_sync_using_diag = 36;
int
{
#ifdef DEBUG
debug_info = 1;
debug_print_level = 0;
#endif
version &= 0xf;
if (stream_buf_on == 0 || version == 0) {
if (version == 0)
"SYSIO Rev %d.\n", version);
return (DDI_SUCCESS);
}
/*
* Simply add each registers offset to the base address
* to calculate the already mapped virtual address of
* the device register...
*
* define a macro for the pointer arithmetic; all registers
* are 64 bits wide and are defined as uint64_t's.
*/
"Streaming buffer flush reg: 0x%p, Streaming buffer sync reg: 0x%p",
/* Initialize stream buffer sync reg mutex */
/* Turn on per instance streaming buffer flag */
softsp->stream_buf_off = 0;
/* Set the hardware registers */
(void) stream_buf_resume_init(softsp);
return (DDI_SUCCESS);
}
int
{
/* Turn off per instance streaming buffer flag */
/* Turn off the streaming buffer */
return (DDI_SUCCESS);
}
/*
* Initialize stream buf hardware when the system is being resumed.
* (Subset of stream_buf_init())
*/
int
{
version &= 0xf;
if (stream_buf_on == 0 || version == 0) {
return (DDI_SUCCESS);
}
/* Turn on the streaming buffer */
return (DDI_SUCCESS);
}
/*
* The SYSIO spec says that it will get back to us within 0.5 seconds,
* but loaded systems have seen response times over 1.5 seconds. We
* err on the side of caution and set the timeout to be 10 seconds.
*/
/*
* We want to avoid using gethrtime every time we check sync_flag,
* so we take SCACHE_SPIN laps before beginning to use gethrtime.
*/
#define SCACHE_SPIN 10000000
void
{
#ifndef lint
#endif
int cntr = 0;
if (softsp->stream_buf_off != 0)
return;
/* Acquire the sync lock */
*sync_flag = 0;
if (npages > stream_buf_sync_using_diag) {
int i;
int do_sync = 0;
i < STREAM_CACHE_LINES; i++, reg_addr++) {
/* Read the page tag diag reg */
#ifdef DEBUG
{
("IO cache line diag "
"reg addr 0x%p, hi0x%x lo0x%x\n",
}
#endif /* DEBUG */
/* Check for a valid line */
if (reg & STR_PG_VALID) {
"range base 0x%x, range extent 0x%x\n",
do_sync = 1;
}
}
}
if (!do_sync) {
return;
}
} else {
do {
addr += IOMMU_PAGESIZE;
npages--;
}
/* Ask the hardware to flag when the flush is complete */
#ifndef lint
/*
* Due to the sun4u memory models, this noncached load will sync the
* order of all prior loads and stores regardless of cacheability.
* No membar_stst() is needed after zeroing the flush sync flag.
*/
#endif
/*
* Begin spinning on the hardware sync register. We'll spin for
* a while (SCACHE_SPIN) before using gethrtime, but once that time
* is up we'll drop into an inner loop where we use gethrtime on
* every iteration. Once SCACHE_NSEC_WAIT nanoseconds have
* elapsed, we'll assume a Bad Thing has happened and toss.
*/
while (!*((volatile int *)sync_flag)) {
if (cntr++ == SCACHE_SPIN) {
/*
* If we're here, then we've spun long enough
* to justify use of gethrtime each iteration.
*/
while (!*((volatile int *)sync_flag)) {
/*
* Double check the sync flag again before
* we panic in case we get preempted.
* See bugid 4126896
*/
nsec_current = gethrtime();
!*((volatile int *)sync_flag)) {
/*
* Trouble. The SYSIO chip has
* seemingly gone AWOL. Vomit.
*/
panic("streaming buffer timed out");
}
}
}
}
/* Finally, drop the sync lock */
}