Commit ba5187db authored by Thiemo Seufer's avatar Thiemo Seufer Committed by Ralf Baechle
Browse files

Better interface to run uncached cache setup code.

parent 7de8d232
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -2,8 +2,8 @@
# Makefile for MIPS-specific library files..
#

lib-y	+= csum_partial_copy.o memcpy.o promlib.o \
	   strlen_user.o strncpy_user.o strnlen_user.o
lib-y	+= csum_partial_copy.o memcpy.o promlib.o strlen_user.o strncpy_user.o \
	   strnlen_user.o uncached.o

obj-y	+= iomap.o

+76 −0
Original line number Diff line number Diff line
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 2005 Thiemo Seufer
 * Copyright (C) 2005  MIPS Technologies, Inc.  All rights reserved.
 *	Author: Maciej W. Rozycki <macro@mips.com>
 */

#include <linux/init.h>

#include <asm/addrspace.h>
#include <asm/bug.h>

#ifndef CKSEG2
#define CKSEG2 CKSSEG
#endif
#ifndef TO_PHYS_MASK
#define TO_PHYS_MASK -1
#endif

/*
 * FUNC is executed in one of the uncached segments, depending on its
 * original address as follows:
 *
 * 1. If the original address is in CKSEG0 or CKSEG1, then the uncached
 *    segment used is CKSEG1.
 * 2. If the original address is in XKPHYS, then the uncached segment
 *    used is XKPHYS(2).
 * 3. Otherwise it's a bug.
 *
 * The same remapping is done with the stack pointer.  Stack handling
 * works because we don't handle stack arguments or more complex return
 * values, so we can avoid sharing the same stack area between a cached
 * and the uncached mode.
 */
unsigned long __init run_uncached(void *func)
{
	register long sp __asm__("$sp");
	register long ret __asm__("$2");
	long lfunc = (long)func, ufunc;
	long usp;

	if (sp >= (long)CKSEG0 && sp < (long)CKSEG2)
		usp = CKSEG1ADDR(sp);
	else if ((long long)sp >= (long long)PHYS_TO_XKPHYS(0LL, 0) &&
		 (long long)sp < (long long)PHYS_TO_XKPHYS(8LL, 0))
		usp = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
				     XKPHYS_TO_PHYS((long long)sp));
	else {
		BUG();
		usp = sp;
	}
	if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2)
		ufunc = CKSEG1ADDR(lfunc);
	else if ((long long)lfunc >= (long long)PHYS_TO_XKPHYS(0LL, 0) &&
		 (long long)lfunc < (long long)PHYS_TO_XKPHYS(8LL, 0))
		ufunc = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
				       XKPHYS_TO_PHYS((long long)lfunc));
	else {
		BUG();
		ufunc = lfunc;
	}

	__asm__ __volatile__ (
		"	move	$16, $sp\n"
		"	move	$sp, %1\n"
		"	jalr	%2\n"
		"	move	$sp, $16"
		: "=r" (ret)
		: "r" (usp), "r" (ufunc)
		: "$16", "$31");

	return ret;
}
+2 −4
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <asm/system.h>
#include <asm/mmu_context.h>
#include <asm/war.h>
#include <asm/cacheflush.h> /* for run_uncached() */

static unsigned long icache_size, dcache_size, scache_size;

@@ -1119,7 +1120,6 @@ static int __init probe_scache(void)
	return 1;
}

typedef int (*probe_func_t)(unsigned long);
extern int r5k_sc_init(void);
extern int rm7k_sc_init(void);

@@ -1127,7 +1127,6 @@ static void __init setup_scache(void)
{
	struct cpuinfo_mips *c = &current_cpu_data;
	unsigned int config = read_c0_config();
	probe_func_t probe_scache_kseg1;
	int sc_present = 0;

	/*
@@ -1140,8 +1139,7 @@ static void __init setup_scache(void)
	case CPU_R4000MC:
	case CPU_R4400SC:
	case CPU_R4400MC:
		probe_scache_kseg1 = (probe_func_t) (CKSEG1ADDR(&probe_scache));
		sc_present = probe_scache_kseg1(config);
		sc_present = run_uncached(probe_scache);
		if (sc_present)
			c->options |= MIPS_CPU_CACHE_CDEX_S;
		break;
+8 −21
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <asm/cacheops.h>
#include <asm/mipsregs.h>
#include <asm/processor.h>
#include <asm/cacheflush.h> /* for run_uncached() */

/* Primary cache parameters. */
#define sc_lsize	32
@@ -96,25 +97,13 @@ static void rm7k_sc_inv(unsigned long addr, unsigned long size)
}

/*
 * This function is executed in the uncached segment CKSEG1.
 * It must not touch the stack, because the stack pointer still points
 * into CKSEG0.
 *
 * Three options:
 *	- Write it in assembly and guarantee that we don't use the stack.
 *	- Disable caching for CKSEG0 before calling it.
 *	- Pray that GCC doesn't randomly start using the stack.
 *
 * This being Linux, we obviously take the least sane of those options -
 * following DaveM's lead in c-r4k.c
 *
 * It seems we get our kicks from relying on unguaranteed behaviour in GCC
 * This function is executed in uncached address space.
 */
static __init void __rm7k_sc_enable(void)
{
	int i;

	set_c0_config(1 << 3);				/* CONF_SE */
	set_c0_config(R7K_CONF_SE);

	write_c0_taglo(0);
	write_c0_taghi(0);
@@ -127,24 +116,22 @@ static __init void __rm7k_sc_enable(void)
		      ".set mips0\n\t"
		      ".set reorder"
		      :
		      : "r" (KSEG0ADDR(i)), "i" (Index_Store_Tag_SD));
		      : "r" (CKSEG0ADDR(i)), "i" (Index_Store_Tag_SD));
	}
}

static __init void rm7k_sc_enable(void)
{
	void (*func)(void) = (void *) KSEG1ADDR(&__rm7k_sc_enable);

	if (read_c0_config() & 0x08)			/* CONF_SE */
	if (read_c0_config() & R7K_CONF_SE)
		return;

	printk(KERN_INFO "Enabling secondary cache...");
	func();
	run_uncached(__rm7k_sc_enable);
}

static void rm7k_sc_disable(void)
{
	clear_c0_config(1<<3);				/* CONF_SE */
	clear_c0_config(R7K_CONF_SE);
}

struct bcache_ops rm7k_sc_ops = {
@@ -164,7 +151,7 @@ void __init rm7k_sc_init(void)
	printk(KERN_INFO "Secondary cache size %dK, linesize %d bytes.\n",
	       (scache_size >> 10), sc_lsize);

	if (!((config >> 3) & 1))	/* CONF_SE */
	if (!(config & R7K_CONF_SE))
		rm7k_sc_enable();

	/*
+3 −0
Original line number Diff line number Diff line
@@ -90,4 +90,7 @@ extern void (*flush_data_cache_page)(unsigned long addr);
#define ClearPageDcacheDirty(page)	\
	clear_bit(PG_dcache_dirty, &(page)->flags)

/* Run kernel code uncached, useful for cache probing functions. */
unsigned long __init run_uncached(void *func);

#endif /* _ASM_CACHEFLUSH_H */
Loading