MIPS: Add option to disable software I/O coherency.

Some MIPS controllers have hardware I/O coherency. This patch
detects those and turns off software coherency. A new kernel
command line option also allows the user to manually turn
software coherency on or off.

Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
This commit is contained in:
Steven J. Hill 2013-03-25 13:47:29 -05:00
parent c34c09c81d
commit b6d92b4a6b
7 changed files with 112 additions and 24 deletions

View File

@ -0,0 +1,15 @@
/*
* 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) 2006 Ralf Baechle <ralf@linux-mips.org>
*
*/
#ifndef __ASM_DMA_COHERENCE_H
#define __ASM_DMA_COHERENCE_H
extern int coherentio;
extern int hw_coherentio;
#endif

View File

@ -2,6 +2,7 @@
#define _ASM_DMA_MAPPING_H
#include <asm/scatterlist.h>
#include <asm/dma-coherence.h>
#include <asm/cache.h>
#include <asm-generic/dma-coherent.h>

View File

@ -61,9 +61,8 @@ static inline int plat_device_is_coherent(struct device *dev)
{
#ifdef CONFIG_DMA_COHERENT
return 1;
#endif
#ifdef CONFIG_DMA_NONCOHERENT
return 0;
#else
return coherentio;
#endif
}

View File

@ -33,6 +33,7 @@
#include <asm/war.h>
#include <asm/cacheflush.h> /* for run_uncached() */
#include <asm/traps.h>
#include <asm/dma-coherence.h>
/*
* Special Variant of smp_call_function for use by cache functions:
@ -1377,20 +1378,6 @@ static void __cpuinit coherency_setup(void)
}
}
#if defined(CONFIG_DMA_NONCOHERENT)
static int __cpuinitdata coherentio;
static int __init setcoherentio(char *str)
{
coherentio = 1;
return 0;
}
early_param("coherentio", setcoherentio);
#endif
static void __cpuinit r4k_cache_error_setup(void)
{
extern char __weak except_vec2_generic;
@ -1472,9 +1459,14 @@ void __cpuinit r4k_cache_init(void)
build_clear_page();
build_copy_page();
#if !defined(CONFIG_MIPS_CMP)
/*
* We want to run CMP kernels on core with and without coherent
* caches. Therefore, do not use CONFIG_MIPS_CMP to decide whether
* or not to flush caches.
*/
local_r4k___flush_cache_all(NULL);
#endif
coherency_setup();
board_cache_error_setup = r4k_cache_error_setup;
}

View File

@ -22,6 +22,26 @@
#include <dma-coherence.h>
int coherentio = 0; /* User defined DMA coherency from command line. */
EXPORT_SYMBOL_GPL(coherentio);
int hw_coherentio = 0; /* Actual hardware supported DMA coherency setting. */
static int __init setcoherentio(char *str)
{
coherentio = 1;
pr_info("Hardware DMA cache coherency (command line)\n");
return 0;
}
early_param("coherentio", setcoherentio);
static int __init setnocoherentio(char *str)
{
coherentio = 0;
pr_info("Software DMA cache coherency (command line)\n");
return 0;
}
early_param("nocoherentio", setnocoherentio);
static inline struct page *dma_addr_to_page(struct device *dev,
dma_addr_t dma_addr)
{
@ -115,6 +135,7 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
if (!plat_device_is_coherent(dev)) {
dma_cache_wback_inv((unsigned long) ret, size);
if (!hw_coherentio)
ret = UNCAC_ADDR(ret);
}
}
@ -142,7 +163,7 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL);
if (!plat_device_is_coherent(dev))
if (!plat_device_is_coherent(dev) && !hw_coherentio)
addr = CAC_ADDR(addr);
free_pages(addr, get_order(size));

View File

@ -32,6 +32,7 @@
#include <asm/mips-boards/maltaint.h>
#include <asm/dma.h>
#include <asm/traps.h>
#include <asm/gcmpregs.h>
#ifdef CONFIG_VT
#include <linux/console.h>
#endif
@ -105,6 +106,66 @@ static void __init fd_activate(void)
}
#endif
static int __init plat_enable_iocoherency(void)
{
int supported = 0;
if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO) {
if (BONITO_PCICACHECTRL & BONITO_PCICACHECTRL_CPUCOH_PRES) {
BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_CPUCOH_EN;
pr_info("Enabled Bonito CPU coherency\n");
supported = 1;
}
if (strstr(fw_getcmdline(), "iobcuncached")) {
BONITO_PCICACHECTRL &= ~BONITO_PCICACHECTRL_IOBCCOH_EN;
BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG &
~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
pr_info("Disabled Bonito IOBC coherency\n");
} else {
BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_IOBCCOH_EN;
BONITO_PCIMEMBASECFG |=
(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
pr_info("Enabled Bonito IOBC coherency\n");
}
} else if (gcmp_niocu() != 0) {
/* Nothing special needs to be done to enable coherency */
pr_info("CMP IOCU detected\n");
if ((*(unsigned int *)0xbf403000 & 0x81) != 0x81) {
pr_crit("IOCU OPERATION DISABLED BY SWITCH - DEFAULTING TO SW IO COHERENCY\n");
return 0;
}
supported = 1;
}
hw_coherentio = supported;
return supported;
}
static void __init plat_setup_iocoherency(void)
{
#ifdef CONFIG_DMA_NONCOHERENT
/*
* Kernel has been configured with software coherency
* but we might choose to turn it off and use hardware
* coherency instead.
*/
if (plat_enable_iocoherency()) {
if (coherentio == 0)
pr_info("Hardware DMA cache coherency disabled\n");
else
pr_info("Hardware DMA cache coherency enabled\n");
} else {
if (coherentio == 1)
pr_info("Hardware DMA cache coherency unsupported, but enabled from command line!\n");
else
pr_info("Software DMA cache coherency enabled\n");
}
#else
if (!plat_enable_iocoherency())
panic("Hardware DMA cache coherency not supported!");
#endif
}
#ifdef CONFIG_BLK_DEV_IDE
static void __init pci_clock_check(void)
{
@ -207,6 +268,8 @@ void __init plat_mem_setup(void)
if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO)
bonito_quirks_setup();
plat_setup_iocoherency();
#ifdef CONFIG_BLK_DEV_IDE
pci_clock_check();
#endif

View File

@ -13,9 +13,6 @@
#include <asm/mips-boards/generic.h>
#include <asm/prom.h>
int coherentio; /* 0 => no DMA cache coherency (may be set by user) */
int hw_coherentio; /* 0 => no HW DMA cache coherency (reflects real HW) */
const char *get_system_type(void)
{
return "MIPS SEAD3";