Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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