[BACK]Return to m88110.c CVS log [TXT][DIR] Up to [local] / sys / arch / mvme88k / mvme88k

File: [local] / sys / arch / mvme88k / mvme88k / m88110.c (download)

Revision 1.1, Tue Mar 4 16:04:33 2008 UTC (16 years, 2 months ago) by nbrk
Branch point for: MAIN

Initial revision

/*	$OpenBSD: m88110.c,v 1.38 2007/02/11 12:49:38 miod Exp $	*/
/*
 * Copyright (c) 1998 Steve Murphree, Jr.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Nivas Madhur.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/*
 * Mach Operating System
 * Copyright (c) 1993-1991 Carnegie Mellon University
 * Copyright (c) 1991 OMRON Corporation
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include <sys/param.h>
#include <sys/systm.h>

#include <uvm/uvm_extern.h>

#include <machine/asm_macro.h>
#include <machine/cmmu.h>
#include <machine/cpu.h>
#include <machine/lock.h>
#include <machine/m88110.h>
#include <machine/m88410.h>
#include <machine/psl.h>

#include <mvme88k/dev/busswreg.h>

cpuid_t	m88110_init(void);
void	m88110_setup_board_config(void);
void	m88110_cpu_configuration_print(int);
void	m88110_shutdown(void);
cpuid_t	m88110_cpu_number(void);
void	m88110_set_sapr(cpuid_t, apr_t);
void	m88110_set_uapr(apr_t);
void	m88110_flush_tlb(cpuid_t, unsigned, vaddr_t, u_int);
void	m88110_flush_cache(cpuid_t, paddr_t, psize_t);
void	m88110_flush_inst_cache(cpuid_t, paddr_t, psize_t);
void	m88110_flush_data_page(cpuid_t, paddr_t);
void	m88110_dma_cachectl(pmap_t, vaddr_t, vsize_t, int);
void	m88110_dma_cachectl_pa(paddr_t, psize_t, int);
void	m88110_initialize_cpu(cpuid_t);

/* This is the function table for the MC88110 built-in CMMUs */
struct cmmu_p cmmu88110 = {
        m88110_init,
	m88110_setup_board_config,
	m88110_cpu_configuration_print,
	m88110_shutdown,
	m88110_cpu_number,
	m88110_set_sapr,
	m88110_set_uapr,
	m88110_flush_tlb,
	m88110_flush_cache,
	m88110_flush_inst_cache,
	m88110_flush_data_page,
	m88110_dma_cachectl,
	m88110_dma_cachectl_pa,
#ifdef MULTIPROCESSOR
	m88110_initialize_cpu,
#endif
};

void patc_clear(void);
void m88110_cmmu_sync_cache(paddr_t, psize_t);
void m88110_cmmu_sync_inval_cache(paddr_t, psize_t);
void m88110_cmmu_inval_cache(paddr_t, psize_t);

void
patc_clear(void)
{
	int i;

	for (i = 0; i < 32; i++) {
		set_dir(i << 5);
		set_dppu(0);
		set_dppl(0);

		set_iir(i << 5);
		set_ippu(0);
		set_ippl(0);
	}
}

void
m88110_setup_board_config(void)
{
#ifdef MULTIPROCESSOR
	max_cpus = 2;
#else
	max_cpus = 1;
#endif
}

/*
 * Should only be called after the calling cpus knows its cpu
 * number and master/slave status . Should be called first
 * by the master, before the slaves are started.
 */
void
m88110_cpu_configuration_print(int master)
{
	int pid = get_cpu_pid();
	int proctype = (pid & PID_ARN) >> ARN_SHIFT;
	int procvers = (pid & PID_VN) >> VN_SHIFT;
	int cpu = cpu_number();

	printf("cpu%d: ", cpu);
	switch (proctype) {
	default:
		printf("unknown model arch 0x%x version 0x%x",
		    proctype, procvers);
		break;
	case ARN_88110:
		printf("M88110 version 0x%x", procvers);
		if (mc88410_present())
			printf(", external M88410 cache controller");
		break;
	}
	printf("\n");
}

/*
 * CMMU initialization routine
 */
cpuid_t
m88110_init(void)
{
	cpuid_t cpu;

	cpu = m88110_cpu_number();
	m88110_initialize_cpu(cpu);
	return (cpu);
}

void
m88110_initialize_cpu(cpuid_t cpu)
{
	int i;

	/* clear BATCs */
	for (i = 0; i < 8; i++) {
		set_dir(i);
		set_dbp(0);
		set_iir(i);
		set_ibp(0);
	}

	/* clear PATCs */
	patc_clear();

	/* Do NOT enable ICTL_PREN (branch prediction) */
	set_ictl(BATC_32M
		 | CMMU_ICTL_DID	/* Double instruction disable */
		 | CMMU_ICTL_MEN
		 | CMMU_ICTL_CEN
		 | CMMU_ICTL_BEN
		 | CMMU_ICTL_HTEN);

	set_dctl(BATC_32M
                 | CMMU_DCTL_RSVD1	/* Data Matching Disable */
                 | CMMU_DCTL_MEN
		 | CMMU_DCTL_CEN
		 | CMMU_DCTL_SEN
		 | CMMU_DCTL_ADS
		 | CMMU_DCTL_HTEN);

	mc88110_inval_inst();		/* clear instruction cache & TIC */
	mc88110_inval_data();		/* clear data cache */
	if (mc88410_present())
		mc88410_inval();	/* clear external data cache */

	set_dcmd(CMMU_DCMD_INV_SATC);	/* invalidate ATCs */

	set_isr(0);
	set_dsr(0);
}

/*
 * Just before poweroff or reset....
 */
void
m88110_shutdown(void)
{
}

cpuid_t
m88110_cpu_number(void)
{
	u_int16_t gcsr;

	gcsr = *(volatile u_int16_t *)(BS_BASE + BS_GCSR);

	return ((gcsr & BS_GCSR_CPUID) != 0 ? 1 : 0);
}

void
m88110_set_sapr(cpuid_t cpu, apr_t ap)
{
	u_int ictl, dctl;

	CMMU_LOCK;

	set_icmd(CMMU_ICMD_INV_SATC);
	set_dcmd(CMMU_DCMD_INV_SATC);

	ictl = get_ictl();
	dctl = get_dctl();

	/* disable translation */
	set_ictl((ictl & ~CMMU_ICTL_MEN));
	set_dctl((dctl & ~CMMU_DCTL_MEN));

	set_isap(ap);
	set_dsap(ap);

	patc_clear();

	set_icmd(CMMU_ICMD_INV_UATC);
	set_icmd(CMMU_ICMD_INV_SATC);
	set_dcmd(CMMU_DCMD_INV_UATC);
	set_dcmd(CMMU_DCMD_INV_SATC);

	/* restore MMU settings */
	set_ictl(ictl);
	set_dctl(dctl);

	CMMU_UNLOCK;
}

void
m88110_set_uapr(apr_t ap)
{
	CMMU_LOCK;
	set_iuap(ap);
	set_duap(ap);

	set_icmd(CMMU_ICMD_INV_UATC);
	set_dcmd(CMMU_DCMD_INV_UATC);

	/* We need to at least invalidate the TIC, as it is va-addressed */
	mc88110_inval_inst();
	CMMU_UNLOCK;
}

/*
 *	Functions that invalidate TLB entries.
 */

/*
 *	flush any tlb
 */
void
m88110_flush_tlb(cpuid_t cpu, unsigned kernel, vaddr_t vaddr, u_int count)
{
	u_int32_t psr;

	disable_interrupt(psr);

	CMMU_LOCK;
	if (kernel) {
		set_icmd(CMMU_ICMD_INV_SATC);
		set_dcmd(CMMU_DCMD_INV_SATC);
	} else {
		set_icmd(CMMU_ICMD_INV_UATC);
		set_dcmd(CMMU_DCMD_INV_UATC);
	}
	CMMU_UNLOCK;

	set_psr(psr);
}

/*
 *	Functions that invalidate caches.
 *
 * Cache invalidates require physical addresses.  Care must be exercised when
 * using segment invalidates.  This implies that the starting physical address
 * plus the segment length should be invalidated.  A typical mistake is to
 * extract the first physical page of a segment from a virtual address, and
 * then expecting to invalidate when the pages are not physically contiguous.
 *
 * We don't push Instruction Caches prior to invalidate because they are not
 * snooped and never modified (I guess it doesn't matter then which form
 * of the command we use then).
 */

/*
 * Care must be taken to avoid flushing the data cache when
 * the data cache is not on!  From the 0F92L Errata Documentation
 * Package, Version 1.1
 */

/*
 * XXX These routines are really suboptimal because they invalidate
 * way too much...
 * Improve them once the 197 support is really working...
 */

/*
 *	flush both Instruction and Data caches
 */
void
m88110_flush_cache(cpuid_t cpu, paddr_t pa, psize_t size)
{
	u_int32_t psr;

	disable_interrupt(psr);

	mc88110_inval_inst();
	mc88110_flush_data();
	if (mc88410_present())
		mc88410_flush();
	set_psr(psr);
}

/*
 *	flush Instruction caches
 */
void
m88110_flush_inst_cache(cpuid_t cpu, paddr_t pa, psize_t size)
{
	u_int32_t psr;

	disable_interrupt(psr);

	mc88110_inval_inst();
	set_psr(psr);
}

/*
 * flush data cache
 */
void
m88110_flush_data_page(cpuid_t cpu, paddr_t pa)
{
	u_int32_t psr;

	disable_interrupt(psr);

	mc88110_flush_data();
	if (mc88410_present())
		mc88410_flush();
	set_psr(psr);
}

/*
 * sync dcache (and icache too)
 */
void
m88110_cmmu_sync_cache(paddr_t pa, psize_t size)
{
	u_int32_t psr;

	disable_interrupt(psr);

	mc88110_inval_inst();
	mc88110_flush_data();
	if (mc88410_present())
		mc88410_flush();
	set_psr(psr);
}

void
m88110_cmmu_sync_inval_cache(paddr_t pa, psize_t size)
{
	u_int32_t psr;

	disable_interrupt(psr);

	mc88110_sync_data();
	if (mc88410_present())
		mc88410_sync();
	set_psr(psr);
}

void
m88110_cmmu_inval_cache(paddr_t pa, psize_t size)
{
	u_int32_t psr;

	disable_interrupt(psr);

	mc88110_inval_inst();
	mc88110_inval_data();
	if (mc88410_present())
		mc88410_inval();
	set_psr(psr);
}

void
m88110_dma_cachectl(pmap_t pmap, vaddr_t va, vsize_t size, int op)
{
	paddr_t pa;

	if (pmap_extract(pmap, va, &pa) == FALSE) {
#ifdef DIAGNOSTIC
		printf("cachectl: pmap_extract(%p, %p) failed\n", pmap, va);
#endif
		pa = 0;
		size = ~0;
	}

	switch (op) {
	case DMA_CACHE_SYNC:
		m88110_cmmu_sync_cache(pa, size);
		break;
	case DMA_CACHE_SYNC_INVAL:
		m88110_cmmu_sync_inval_cache(pa, size);
		break;
	default:
		m88110_cmmu_inval_cache(pa, size);
		break;
	}
}

void
m88110_dma_cachectl_pa(paddr_t pa, psize_t size, int op)
{
	switch (op) {
	case DMA_CACHE_SYNC:
		m88110_cmmu_sync_cache(pa, size);
		break;
	case DMA_CACHE_SYNC_INVAL:
		m88110_cmmu_sync_inval_cache(pa, size);
		break;
	default:
		m88110_cmmu_inval_cache(pa, size);
		break;
	}
}