aboutsummaryrefslogtreecommitdiff
path: root/arch/sh
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh')
-rw-r--r--arch/sh/Kconfig29
-rw-r--r--arch/sh/boards/board-ap325rxa.c52
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c115
-rw-r--r--arch/sh/boards/mach-kfr2r09/setup.c172
-rw-r--r--arch/sh/boards/mach-migor/setup.c52
-rw-r--r--arch/sh/boards/mach-se/7724/setup.c33
-rw-r--r--arch/sh/boot/compressed/misc.c2
-rw-r--r--arch/sh/drivers/pci/Kconfig19
-rw-r--r--arch/sh/include/asm/addrspace.h9
-rw-r--r--arch/sh/include/asm/atomic.h9
-rw-r--r--arch/sh/include/asm/bitops.h4
-rw-r--r--arch/sh/include/asm/bugs.h4
-rw-r--r--arch/sh/include/asm/dma-mapping.h233
-rw-r--r--arch/sh/include/asm/dwarf.h28
-rw-r--r--arch/sh/include/asm/fixmap.h6
-rw-r--r--arch/sh/include/asm/ftrace.h17
-rw-r--r--arch/sh/include/asm/hardirq.h13
-rw-r--r--arch/sh/include/asm/io.h4
-rw-r--r--arch/sh/include/asm/irqflags.h31
-rw-r--r--arch/sh/include/asm/irqflags_32.h99
-rw-r--r--arch/sh/include/asm/irqflags_64.h85
-rw-r--r--arch/sh/include/asm/mmu.h13
-rw-r--r--arch/sh/include/asm/pci.h30
-rw-r--r--arch/sh/include/asm/pgtable.h26
-rw-r--r--arch/sh/include/asm/pgtable_32.h2
-rw-r--r--arch/sh/include/asm/scatterlist.h2
-rw-r--r--arch/sh/include/asm/system_32.h29
-rw-r--r--arch/sh/include/asm/system_64.h26
-rw-r--r--arch/sh/include/asm/thread_info.h26
-rw-r--r--arch/sh/include/asm/topology.h8
-rw-r--r--arch/sh/include/asm/ubc.h11
-rw-r--r--arch/sh/include/asm/watchdog.h59
-rw-r--r--arch/sh/include/cpu-sh4/cpu/watchdog.h13
-rw-r--r--arch/sh/kernel/Makefile8
-rw-r--r--arch/sh/kernel/cpu/Makefile1
-rw-r--r--arch/sh/kernel/cpu/init.c11
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S33
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-shx3.c45
-rw-r--r--arch/sh/kernel/cpu/sh4a/smp-shx3.c37
-rw-r--r--arch/sh/kernel/cpu/sh5/entry.S2
-rw-r--r--arch/sh/kernel/cpu/ubc.S59
-rw-r--r--arch/sh/kernel/dma-nommu.c82
-rw-r--r--arch/sh/kernel/dwarf.c222
-rw-r--r--arch/sh/kernel/entry-common.S2
-rw-r--r--arch/sh/kernel/ftrace.c146
-rw-r--r--arch/sh/kernel/head_32.S2
-rw-r--r--arch/sh/kernel/idle.c78
-rw-r--r--arch/sh/kernel/irq.c8
-rw-r--r--arch/sh/kernel/irq_32.c57
-rw-r--r--arch/sh/kernel/irq_64.c51
-rw-r--r--arch/sh/kernel/machine_kexec.c6
-rw-r--r--arch/sh/kernel/module.c9
-rw-r--r--arch/sh/kernel/process_32.c2
-rw-r--r--arch/sh/kernel/process_64.c2
-rw-r--r--arch/sh/kernel/return_address.c54
-rw-r--r--arch/sh/kernel/setup.c4
-rw-r--r--arch/sh/kernel/sh_ksyms_32.c67
-rw-r--r--arch/sh/kernel/sh_ksyms_64.c10
-rw-r--r--arch/sh/kernel/signal_32.c24
-rw-r--r--arch/sh/kernel/signal_64.c13
-rw-r--r--arch/sh/kernel/smp.c4
-rw-r--r--arch/sh/kernel/topology.c26
-rw-r--r--arch/sh/kernel/traps.c2
-rw-r--r--arch/sh/kernel/traps_32.c5
-rw-r--r--arch/sh/mm/Kconfig11
-rw-r--r--arch/sh/mm/Makefile3
-rw-r--r--arch/sh/mm/cache-sh4.c504
-rw-r--r--arch/sh/mm/cache-sh7705.c2
-rw-r--r--arch/sh/mm/cache.c12
-rw-r--r--arch/sh/mm/consistent.c28
-rw-r--r--arch/sh/mm/init.c19
-rw-r--r--arch/sh/mm/kmap.c4
-rw-r--r--arch/sh/mm/pmb-fixed.c45
-rw-r--r--arch/sh/mm/pmb.c268
74 files changed, 1728 insertions, 1501 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 88cdeb9f72d..0031a6979f3 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -16,7 +16,9 @@ config SUPERH
select HAVE_IOREMAP_PROT if MMU
select HAVE_ARCH_TRACEHOOK
select HAVE_DMA_API_DEBUG
+ select HAVE_DMA_ATTRS
select HAVE_PERF_EVENTS
+ select PERF_USE_VMALLOC
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_LZMA
@@ -37,6 +39,7 @@ config SUPERH32
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_DYNAMIC_FTRACE
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+ select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_ARCH_KGDB
select ARCH_HIBERNATION_POSSIBLE if MMU
@@ -170,6 +173,12 @@ config ARCH_HAS_CPU_IDLE_WAIT
config IO_TRAPPED
bool
+config DMA_COHERENT
+ bool
+
+config DMA_NONCOHERENT
+ def_bool !DMA_COHERENT
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
@@ -220,6 +229,7 @@ config CPU_SHX2
config CPU_SHX3
bool
+ select DMA_COHERENT
config ARCH_SHMOBILE
bool
@@ -761,17 +771,6 @@ config ENTRY_OFFSET
default "0x00010000" if PAGE_SIZE_64KB
default "0x00000000"
-config UBC_WAKEUP
- bool "Wakeup UBC on startup"
- depends on CPU_SH4 && !CPU_SH4A
- help
- Selecting this option will wakeup the User Break Controller (UBC) on
- startup. Although the UBC is left in an awake state when the processor
- comes up, some boot loaders misbehave by putting the UBC to sleep in a
- power saving state, which causes issues with things like ptrace().
-
- If unsure, say N.
-
choice
prompt "Kernel command line"
optional
@@ -818,7 +817,13 @@ config MAPLE
Dreamcast with a serial line terminal or a remote network
connection.
-source "arch/sh/drivers/pci/Kconfig"
+config PCI
+ bool "PCI support"
+ depends on SYS_SUPPORTS_PCI
+ help
+ Find out whether you have a PCI motherboard. PCI is the name of a
+ bus system, i.e. the way the CPU talks to the other stuff inside
+ your box. If you have PCI, say Y, otherwise N.
source "drivers/pci/pcie/Kconfig"
diff --git a/arch/sh/boards/board-ap325rxa.c b/arch/sh/boards/board-ap325rxa.c
index 2d080732a96..b95deee35e0 100644
--- a/arch/sh/boards/board-ap325rxa.c
+++ b/arch/sh/boards/board-ap325rxa.c
@@ -20,8 +20,6 @@
#include <linux/i2c.h>
#include <linux/smsc911x.h>
#include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_gpio.h>
#include <media/ov772x.h>
#include <media/soc_camera.h>
#include <media/soc_camera_platform.h>
@@ -409,17 +407,25 @@ static struct platform_device ceu_device = {
},
};
-struct spi_gpio_platform_data sdcard_cn3_platform_data = {
- .sck = GPIO_PTD0,
- .mosi = GPIO_PTD1,
- .miso = GPIO_PTD2,
- .num_chipselect = 1,
+static struct resource sdhi0_cn3_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
};
-static struct platform_device sdcard_cn3_device = {
- .name = "spi_gpio",
- .dev = {
- .platform_data = &sdcard_cn3_platform_data,
+static struct platform_device sdhi0_cn3_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi0_cn3_resources),
+ .resource = sdhi0_cn3_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI0,
},
};
@@ -470,20 +476,11 @@ static struct platform_device *ap325rxa_devices[] __initdata = {
&lcdc_device,
&ceu_device,
&nand_flash_device,
- &sdcard_cn3_device,
+ &sdhi0_cn3_device,
&ap325rxa_camera[0],
&ap325rxa_camera[1],
};
-static struct spi_board_info ap325rxa_spi_devices[] = {
- {
- .modalias = "mmc_spi",
- .max_speed_hz = 5000000,
- .chip_select = 0,
- .controller_data = (void *) GPIO_PTD5,
- },
-};
-
static int __init ap325rxa_devices_setup(void)
{
/* LD3 and LD4 LEDs */
@@ -578,12 +575,19 @@ static int __init ap325rxa_devices_setup(void)
platform_resource_setup_memory(&ceu_device, "ceu", 4 << 20);
+ /* SDHI0 */
+ gpio_request(GPIO_FN_SDHI0CD_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0WP_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0D3_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0D2_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0D1_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0D0_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0CMD_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0CLK_PTD, NULL);
+
i2c_register_board_info(0, ap325rxa_i2c_devices,
ARRAY_SIZE(ap325rxa_i2c_devices));
- spi_register_board_info(ap325rxa_spi_devices,
- ARRAY_SIZE(ap325rxa_spi_devices));
-
return platform_add_devices(ap325rxa_devices,
ARRAY_SIZE(ap325rxa_devices));
}
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 3b1ceb46fa5..da851a3b714 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -147,6 +147,9 @@ static struct platform_device sh_eth_device = {
},
.num_resources = ARRAY_SIZE(sh_eth_resources),
.resource = sh_eth_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_ETHER,
+ },
};
/* USB0 host */
@@ -428,6 +431,54 @@ static struct i2c_board_info ts_i2c_clients = {
.irq = IRQ0,
};
+/* SHDI0 */
+static struct resource sdhi0_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi0_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi0_resources),
+ .resource = sdhi0_resources,
+ .id = 0,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI0,
+ },
+};
+
+/* SHDI1 */
+static struct resource sdhi1_resources[] = {
+ [0] = {
+ .name = "SDHI1",
+ .start = 0x04cf0000,
+ .end = 0x04cf01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 24,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi1_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi1_resources),
+ .resource = sdhi1_resources,
+ .id = 1,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI1,
+ },
+};
+
static struct platform_device *ecovec_devices[] __initdata = {
&heartbeat_device,
&nor_flash_device,
@@ -438,6 +489,8 @@ static struct platform_device *ecovec_devices[] __initdata = {
&ceu0_device,
&ceu1_device,
&keysc_device,
+ &sdhi0_device,
+ &sdhi1_device,
};
#define EEPROM_ADDR 0x50
@@ -466,12 +519,9 @@ static u8 mac_read(struct i2c_adapter *a, u8 command)
return buf;
}
-#define MAC_LEN 6
-static void __init sh_eth_init(void)
+static void __init sh_eth_init(struct sh_eth_plat_data *pd)
{
struct i2c_adapter *a = i2c_get_adapter(1);
- struct clk *eth_clk;
- u8 mac[MAC_LEN];
int i;
if (!a) {
@@ -479,33 +529,11 @@ static void __init sh_eth_init(void)
return;
}
- eth_clk = clk_get(NULL, "eth0");
- if (!eth_clk) {
- pr_err("can not get eth0 clk\n");
- return;
- }
-
/* read MAC address frome EEPROM */
- for (i = 0; i < MAC_LEN; i++) {
- mac[i] = mac_read(a, 0x10 + i);
+ for (i = 0; i < sizeof(pd->mac_addr); i++) {
+ pd->mac_addr[i] = mac_read(a, 0x10 + i);
msleep(10);
}
-
- /* clock enable */
- clk_enable(eth_clk);
-
- /* reset sh-eth */
- ctrl_outl(0x1, SH_ETH_ADDR + 0x0);
-
- /* set MAC addr */
- ctrl_outl((mac[0] << 24) |
- (mac[1] << 16) |
- (mac[2] << 8) |
- (mac[3] << 0), SH_ETH_MAHR);
- ctrl_outl((mac[4] << 8) |
- (mac[5] << 0), SH_ETH_MALR);
-
- clk_put(eth_clk);
}
#define PORT_HIZA 0xA4050158
@@ -710,6 +738,34 @@ static int __init arch_setup(void)
gpio_direction_input(GPIO_PTR5);
gpio_direction_input(GPIO_PTR6);
+ /* enable SDHI0 */
+ gpio_request(GPIO_FN_SDHI0CD, NULL);
+ gpio_request(GPIO_FN_SDHI0WP, NULL);
+ gpio_request(GPIO_FN_SDHI0CMD, NULL);
+ gpio_request(GPIO_FN_SDHI0CLK, NULL);
+ gpio_request(GPIO_FN_SDHI0D3, NULL);
+ gpio_request(GPIO_FN_SDHI0D2, NULL);
+ gpio_request(GPIO_FN_SDHI0D1, NULL);
+ gpio_request(GPIO_FN_SDHI0D0, NULL);
+
+ /* enable SDHI1 */
+ gpio_request(GPIO_FN_SDHI1CD, NULL);
+ gpio_request(GPIO_FN_SDHI1WP, NULL);
+ gpio_request(GPIO_FN_SDHI1CMD, NULL);
+ gpio_request(GPIO_FN_SDHI1CLK, NULL);
+ gpio_request(GPIO_FN_SDHI1D3, NULL);
+ gpio_request(GPIO_FN_SDHI1D2, NULL);
+ gpio_request(GPIO_FN_SDHI1D1, NULL);
+ gpio_request(GPIO_FN_SDHI1D0, NULL);
+
+ gpio_request(GPIO_PTB6, NULL);
+ gpio_request(GPIO_PTB7, NULL);
+ gpio_direction_output(GPIO_PTB6, 1);
+ gpio_direction_output(GPIO_PTB7, 1);
+
+ /* I/O buffer drive ability is high for SDHI1 */
+ ctrl_outw((ctrl_inw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA);
+
/* enable I2C device */
i2c_register_board_info(1, i2c1_devices,
ARRAY_SIZE(i2c1_devices));
@@ -721,12 +777,11 @@ arch_initcall(arch_setup);
static int __init devices_setup(void)
{
- sh_eth_init();
+ sh_eth_init(&sh_eth_plat);
return 0;
}
device_initcall(devices_setup);
-
static struct sh_machine_vector mv_ecovec __initmv = {
.mv_name = "R0P7724 (EcoVec)",
};
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index c08d33fe210..43d75ee9335 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -18,6 +18,8 @@
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/usb/r8a66597.h>
+#include <media/soc_camera.h>
+#include <media/sh_mobile_ceu.h>
#include <video/sh_mobile_lcdc.h>
#include <asm/clock.h>
#include <asm/machvec.h>
@@ -212,11 +214,154 @@ static struct platform_device kfr2r09_usb0_gadget_device = {
.resource = kfr2r09_usb0_gadget_resources,
};
+static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
+ .flags = SH_CEU_FLAG_USE_8BIT_BUS,
+};
+
+static struct resource kfr2r09_ceu_resources[] = {
+ [0] = {
+ .name = "CEU",
+ .start = 0xfe910000,
+ .end = 0xfe91009f,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 52,
+ .end = 52,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ /* place holder for contiguous memory */
+ },
+};
+
+static struct platform_device kfr2r09_ceu_device = {
+ .name = "sh_mobile_ceu",
+ .id = 0, /* "ceu0" clock */
+ .num_resources = ARRAY_SIZE(kfr2r09_ceu_resources),
+ .resource = kfr2r09_ceu_resources,
+ .dev = {
+ .platform_data = &sh_mobile_ceu_info,
+ },
+ .archdata = {
+ .hwblk_id = HWBLK_CEU0,
+ },
+};
+
+static struct i2c_board_info kfr2r09_i2c_camera = {
+ I2C_BOARD_INFO("rj54n1cb0c", 0x50),
+};
+
+static struct clk *camera_clk;
+
+#define DRVCRB 0xA405018C
+static int camera_power(struct device *dev, int mode)
+{
+ int ret;
+
+ if (mode) {
+ long rate;
+
+ camera_clk = clk_get(NULL, "video_clk");
+ if (IS_ERR(camera_clk))
+ return PTR_ERR(camera_clk);
+
+ /* set VIO_CKO clock to 25MHz */
+ rate = clk_round_rate(camera_clk, 25000000);
+ ret = clk_set_rate(camera_clk, rate);
+ if (ret < 0)
+ goto eclkrate;
+
+ /* set DRVCRB
+ *
+ * use 1.8 V for VccQ_VIO
+ * use 2.85V for VccQ_SR
+ */
+ ctrl_outw((ctrl_inw(DRVCRB) & ~0x0003) | 0x0001, DRVCRB);
+
+ /* reset clear */
+ ret = gpio_request(GPIO_PTB4, NULL);
+ if (ret < 0)
+ goto eptb4;
+ ret = gpio_request(GPIO_PTB7, NULL);
+ if (ret < 0)
+ goto eptb7;
+
+ ret = gpio_direction_output(GPIO_PTB4, 1);
+ if (!ret)
+ ret = gpio_direction_output(GPIO_PTB7, 1);
+ if (ret < 0)
+ goto egpioout;
+ msleep(1);
+
+ ret = clk_enable(camera_clk); /* start VIO_CKO */
+ if (ret < 0)
+ goto eclkon;
+
+ return 0;
+ }
+
+ ret = 0;
+
+ clk_disable(camera_clk);
+eclkon:
+ gpio_set_value(GPIO_PTB7, 0);
+egpioout:
+ gpio_set_value(GPIO_PTB4, 0);
+ gpio_free(GPIO_PTB7);
+eptb7:
+ gpio_free(GPIO_PTB4);
+eptb4:
+eclkrate:
+ clk_put(camera_clk);
+ return ret;
+}
+
+static struct soc_camera_link rj54n1_link = {
+ .power = camera_power,
+ .board_info = &kfr2r09_i2c_camera,
+ .i2c_adapter_id = 1,
+ .module_name = "rj54n1cb0c",
+};
+
+static struct platform_device kfr2r09_camera = {
+ .name = "soc-camera-pdrv",
+ .id = 0,
+ .dev = {
+ .platform_data = &rj54n1_link,
+ },
+};
+
+static struct resource kfr2r09_sh_sdhi0_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device kfr2r09_sh_sdhi0_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(kfr2r09_sh_sdhi0_resources),
+ .resource = kfr2r09_sh_sdhi0_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI0,
+ },
+};
+
static struct platform_device *kfr2r09_devices[] __initdata = {
&kfr2r09_nor_flash_device,
&kfr2r09_nand_flash_device,
&kfr2r09_sh_keysc_device,
&kfr2r09_sh_lcdc_device,
+ &kfr2r09_ceu_device,
+ &kfr2r09_camera,
+ &kfr2r09_sh_sdhi0_device,
};
#define BSC_CS0BCR 0xfec10004
@@ -361,6 +506,33 @@ static int __init kfr2r09_devices_setup(void)
if (kfr2r09_usb0_gadget_setup() == 0)
platform_device_register(&kfr2r09_usb0_gadget_device);
+ /* CEU */
+ gpio_request(GPIO_FN_VIO_CKO, NULL);
+ gpio_request(GPIO_FN_VIO0_CLK, NULL);
+ gpio_request(GPIO_FN_VIO0_VD, NULL);
+ gpio_request(GPIO_FN_VIO0_HD, NULL);
+ gpio_request(GPIO_FN_VIO0_FLD, NULL);
+ gpio_request(GPIO_FN_VIO0_D7, NULL);
+ gpio_request(GPIO_FN_VIO0_D6, NULL);
+ gpio_request(GPIO_FN_VIO0_D5, NULL);
+ gpio_request(GPIO_FN_VIO0_D4, NULL);
+ gpio_request(GPIO_FN_VIO0_D3, NULL);
+ gpio_request(GPIO_FN_VIO0_D2, NULL);
+ gpio_request(GPIO_FN_VIO0_D1, NULL);
+ gpio_request(GPIO_FN_VIO0_D0, NULL);
+
+ platform_resource_setup_memory(&kfr2r09_ceu_device, "ceu", 4 << 20);
+
+ /* SDHI0 connected to yc304 */
+ gpio_request(GPIO_FN_SDHI0CD, NULL);
+ gpio_request(GPIO_FN_SDHI0WP, NULL);
+ gpio_request(GPIO_FN_SDHI0D3, NULL);
+ gpio_request(GPIO_FN_SDHI0D2, NULL);
+ gpio_request(GPIO_FN_SDHI0D1, NULL);
+ gpio_request(GPIO_FN_SDHI0D0, NULL);
+ gpio_request(GPIO_FN_SDHI0CMD, NULL);
+ gpio_request(GPIO_FN_SDHI0CLK, NULL);
+
return platform_add_devices(kfr2r09_devices,
ARRAY_SIZE(kfr2r09_devices));
}
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 6ed1fd32369..8e911360c91 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -18,8 +18,6 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_gpio.h>
#include <video/sh_mobile_lcdc.h>
#include <media/sh_mobile_ceu.h>
#include <media/ov772x.h>
@@ -390,17 +388,25 @@ static struct platform_device migor_ceu_device = {
},
};
-struct spi_gpio_platform_data sdcard_cn9_platform_data = {
- .sck = GPIO_PTD0,
- .mosi = GPIO_PTD1,
- .miso = GPIO_PTD2,
- .num_chipselect = 1,
+static struct resource sdhi_cn9_resources[] = {
+ [0] = {
+ .name = "SDHI",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
};
-static struct platform_device sdcard_cn9_device = {
- .name = "spi_gpio",
- .dev = {
- .platform_data = &sdcard_cn9_platform_data,
+static struct platform_device sdhi_cn9_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi_cn9_resources),
+ .resource = sdhi_cn9_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI,
},
};
@@ -467,20 +473,11 @@ static struct platform_device *migor_devices[] __initdata = {
&migor_ceu_device,
&migor_nor_flash_device,
&migor_nand_flash_device,
- &sdcard_cn9_device,
+ &sdhi_cn9_device,
&migor_camera[0],
&migor_camera[1],
};
-static struct spi_board_info migor_spi_devices[] = {
- {
- .modalias = "mmc_spi",
- .max_speed_hz = 5000000,
- .chip_select = 0,
- .controller_data = (void *) GPIO_PTD5,
- },
-};
-
static int __init migor_devices_setup(void)
{
@@ -525,6 +522,16 @@ static int __init migor_devices_setup(void)
gpio_request(GPIO_PTA1, NULL);
gpio_direction_input(GPIO_PTA1);
+ /* SDHI */
+ gpio_request(GPIO_FN_SDHICD, NULL);
+ gpio_request(GPIO_FN_SDHIWP, NULL);
+ gpio_request(GPIO_FN_SDHID3, NULL);
+ gpio_request(GPIO_FN_SDHID2, NULL);
+ gpio_request(GPIO_FN_SDHID1, NULL);
+ gpio_request(GPIO_FN_SDHID0, NULL);
+ gpio_request(GPIO_FN_SDHICMD, NULL);
+ gpio_request(GPIO_FN_SDHICLK, NULL);
+
/* Touch Panel */
gpio_request(GPIO_FN_IRQ6, NULL);
@@ -612,9 +619,6 @@ static int __init migor_devices_setup(void)
i2c_register_board_info(0, migor_i2c_devices,
ARRAY_SIZE(migor_i2c_devices));
- spi_register_board_info(migor_spi_devices,
- ARRAY_SIZE(migor_spi_devices));
-
return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices));
}
arch_initcall(migor_devices_setup);
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index e78c3be8ad2..ce6b36ebe64 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -448,6 +448,28 @@ static struct platform_device sh7724_usb1_gadget_device = {
.resource = sh7724_usb1_gadget_resources,
};
+static struct resource sdhi0_cn7_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi0_cn7_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi0_cn7_resources),
+ .resource = sdhi0_cn7_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI0,
+ },
+};
+
static struct platform_device *ms7724se_devices[] __initdata = {
&heartbeat_device,
&smc91x_eth_device,
@@ -460,6 +482,7 @@ static struct platform_device *ms7724se_devices[] __initdata = {
&sh7724_usb0_host_device,
&sh7724_usb1_gadget_device,
&fsi_device,
+ &sdhi0_cn7_device,
};
#define EEPROM_OP 0xBA206000
@@ -698,6 +721,16 @@ static int __init devices_setup(void)
clk_set_rate(&fsimcka_clk, 11000);
clk_put(fsia_clk);
+ /* SDHI0 connected to cn7 */
+ gpio_request(GPIO_FN_SDHI0CD, NULL);
+ gpio_request(GPIO_FN_SDHI0WP, NULL);
+ gpio_request(GPIO_FN_SDHI0D3, NULL);
+ gpio_request(GPIO_FN_SDHI0D2, NULL);
+ gpio_request(GPIO_FN_SDHI0D1, NULL);
+ gpio_request(GPIO_FN_SDHI0D0, NULL);
+ gpio_request(GPIO_FN_SDHI0CMD, NULL);
+ gpio_request(GPIO_FN_SDHI0CLK, NULL);
+
/*
* enable SH-Eth
*
diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c
index fd56a71ca9d..b51b1fc4baa 100644
--- a/arch/sh/boot/compressed/misc.c
+++ b/arch/sh/boot/compressed/misc.c
@@ -131,7 +131,7 @@ void decompress_kernel(void)
#ifdef CONFIG_SUPERH64
output_addr = (CONFIG_MEMORY_START + 0x2000);
#else
- output_addr = PHYSADDR((unsigned long)&_text+PAGE_SIZE);
+ output_addr = __pa((unsigned long)&_text+PAGE_SIZE);
#ifdef CONFIG_29BIT
output_addr |= P2SEG;
#endif
diff --git a/arch/sh/drivers/pci/Kconfig b/arch/sh/drivers/pci/Kconfig
deleted file mode 100644
index e8db585a663..00000000000
--- a/arch/sh/drivers/pci/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-config PCI
- bool "PCI support"
- depends on SYS_SUPPORTS_PCI
- help
- Find out whether you have a PCI motherboard. PCI is the name of a
- bus system, i.e. the way the CPU talks to the other stuff inside
- your box. If you have PCI, say Y, otherwise N.
-
-config SH_PCIDMA_NONCOHERENT
- bool "Cache and PCI noncoherent"
- depends on PCI
- default y
- help
- Enable this option if your platform does not have a CPU cache which
- remains coherent with PCI DMA. It is safest to say 'Y', although you
- will see better performance if you can say 'N', because the PCI DMA
- code will not have to flush the CPU's caches. If you have a PCI host
- bridge integrated with your SH CPU, refer carefully to the chip specs
- to see if you can say 'N' here. Otherwise, leave it as 'Y'.
diff --git a/arch/sh/include/asm/addrspace.h b/arch/sh/include/asm/addrspace.h
index 80d40813e05..99d6b3ecbe2 100644
--- a/arch/sh/include/asm/addrspace.h
+++ b/arch/sh/include/asm/addrspace.h
@@ -28,9 +28,6 @@
/* Returns the privileged segment base of a given address */
#define PXSEG(a) (((unsigned long)(a)) & 0xe0000000)
-/* Returns the physical address of a PnSEG (n=1,2) address */
-#define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff)
-
#if defined(CONFIG_29BIT) || defined(CONFIG_PMB_FIXED)
/*
* Map an address to a certain privileged segment
@@ -60,5 +57,11 @@
#define P3_ADDR_MAX P4SEG
#endif
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_PMB
+extern int __in_29bit_mode(void);
+#endif /* CONFIG_PMB */
+#endif /* __ASSEMBLY__ */
+
#endif /* __KERNEL__ */
#endif /* __ASM_SH_ADDRSPACE_H */
diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h
index e8e78137c6f..b16388d7195 100644
--- a/arch/sh/include/asm/atomic.h
+++ b/arch/sh/include/asm/atomic.h
@@ -78,11 +78,10 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
-/* Atomic operations are already serializing on SH */
-#define smp_mb__before_atomic_dec() barrier()
-#define smp_mb__after_atomic_dec() barrier()
-#define smp_mb__before_atomic_inc() barrier()
-#define smp_mb__after_atomic_inc() barrier()
+#define smp_mb__before_atomic_dec() smp_mb()
+#define smp_mb__after_atomic_dec() smp_mb()
+#define smp_mb__before_atomic_inc() smp_mb()
+#define smp_mb__after_atomic_inc() smp_mb()
#include <asm-generic/atomic-long.h>
#include <asm-generic/atomic64.h>
diff --git a/arch/sh/include/asm/bitops.h b/arch/sh/include/asm/bitops.h
index ebe595b7ab1..98511e4d28c 100644
--- a/arch/sh/include/asm/bitops.h
+++ b/arch/sh/include/asm/bitops.h
@@ -26,8 +26,8 @@
/*
* clear_bit() doesn't provide any barrier for the compiler.
*/
-#define smp_mb__before_clear_bit() barrier()
-#define smp_mb__after_clear_bit() barrier()
+#define smp_mb__before_clear_bit() smp_mb()
+#define smp_mb__after_clear_bit() smp_mb()
#ifdef CONFIG_SUPERH32
static inline unsigned long ffz(unsigned long word)
diff --git a/arch/sh/include/asm/bugs.h b/arch/sh/include/asm/bugs.h
index 46260fcbdf4..02a19a1c033 100644
--- a/arch/sh/include/asm/bugs.h
+++ b/arch/sh/include/asm/bugs.h
@@ -14,11 +14,15 @@
#include <asm/processor.h>
+extern void select_idle_routine(void);
+
static void __init check_bugs(void)
{
extern unsigned long loops_per_jiffy;
char *p = &init_utsname()->machine[2]; /* "sh" */
+ select_idle_routine();
+
current_cpu_data.loops_per_jiffy = loops_per_jiffy;
switch (current_cpu_data.family) {
diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h
index 69d56dd4c96..87ced133a36 100644
--- a/arch/sh/include/asm/dma-mapping.h
+++ b/arch/sh/include/asm/dma-mapping.h
@@ -1,219 +1,108 @@
#ifndef __ASM_SH_DMA_MAPPING_H
#define __ASM_SH_DMA_MAPPING_H
-#include <linux/mm.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-debug.h>
-#include <asm/cacheflush.h>
-#include <asm/io.h>
+extern struct dma_map_ops *dma_ops;
+extern void no_iommu_init(void);
+
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+{
+ return dma_ops;
+}
+
#include <asm-generic/dma-coherent.h>
+#include <asm-generic/dma-mapping-common.h>
+
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
-extern struct bus_type pci_bus_type;
+ if (ops->dma_supported)
+ return ops->dma_supported(dev, mask);
-#define dma_supported(dev, mask) (1)
+ return 1;
+}
static inline int dma_set_mask(struct device *dev, u64 mask)
{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
if (!dev->dma_mask || !dma_supported(dev, mask))
return -EIO;
+ if (ops->set_dma_mask)
+ return ops->set_dma_mask(dev, mask);
*dev->dma_mask = mask;
return 0;
}
-void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag);
-
-void dma_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle);
-
void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction dir);
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-#define dma_is_consistent(d, h) (1)
-
-static inline dma_addr_t dma_map_single(struct device *dev,
- void *ptr, size_t size,
- enum dma_data_direction dir)
-{
- dma_addr_t addr = virt_to_phys(ptr);
-
-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- if (dev->bus == &pci_bus_type)
- return addr;
-#endif
- dma_cache_sync(dev, ptr, size, dir);
-
- debug_dma_map_page(dev, virt_to_page(ptr),
- (unsigned long)ptr & ~PAGE_MASK, size,
- dir, addr, true);
-
- return addr;
-}
-
-static inline void dma_unmap_single(struct device *dev, dma_addr_t addr,
- size_t size, enum dma_data_direction dir)
-{
- debug_dma_unmap_page(dev, addr, size, dir, true);
-}
-static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction dir)
-{
- int i;
-
- for (i = 0; i < nents; i++) {
-#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
+#ifdef CONFIG_DMA_COHERENT
+#define dma_is_consistent(d, h) (1)
+#else
+#define dma_is_consistent(d, h) (0)
#endif
- sg[i].dma_address = sg_phys(&sg[i]);
- sg[i].dma_length = sg[i].length;
- }
- debug_dma_map_sg(dev, sg, nents, i, dir);
-
- return nents;
-}
-
-static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction dir)
-{
- debug_dma_unmap_sg(dev, sg, nents, dir);
-}
-
-static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size,
- enum dma_data_direction dir)
-{
- return dma_map_single(dev, page_address(page) + offset, size, dir);
-}
-
-static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
- size_t size, enum dma_data_direction dir)
-{
- dma_unmap_single(dev, dma_address, size, dir);
-}
-
-static inline void __dma_sync_single(struct device *dev, dma_addr_t dma_handle,
- size_t size, enum dma_data_direction dir)
+static inline int dma_get_cache_alignment(void)
{
-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- if (dev->bus == &pci_bus_type)
- return;
-#endif
- dma_cache_sync(dev, phys_to_virt(dma_handle), size, dir);
+ /*
+ * Each processor family will define its own L1_CACHE_SHIFT,
+ * L1_CACHE_BYTES wraps to this, so this is always safe.
+ */
+ return L1_CACHE_BYTES;
}
-static inline void dma_sync_single_range(struct device *dev,
- dma_addr_t dma_handle,
- unsigned long offset, size_t size,
- enum dma_data_direction dir)
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- if (dev->bus == &pci_bus_type)
- return;
-#endif
- dma_cache_sync(dev, phys_to_virt(dma_handle) + offset, size, dir);
-}
+ struct dma_map_ops *ops = get_dma_ops(dev);
-static inline void __dma_sync_sg(struct device *dev, struct scatterlist *sg,
- int nelems, enum dma_data_direction dir)
-{
- int i;
+ if (ops->mapping_error)
+ return ops->mapping_error(dev, dma_addr);
- for (i = 0; i < nelems; i++) {
-#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
-#endif
- sg[i].dma_address = sg_phys(&sg[i]);
- sg[i].dma_length = sg[i].length;
- }
+ return dma_addr == 0;
}
-static inline void dma_sync_single_for_cpu(struct device *dev,
- dma_addr_t dma_handle, size_t size,
- enum dma_data_direction dir)
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
{
- __dma_sync_single(dev, dma_handle, size, dir);
- debug_dma_sync_single_for_cpu(dev, dma_handle, size, dir);
-}
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ void *memory;
-static inline void dma_sync_single_for_device(struct device *dev,
- dma_addr_t dma_handle,
- size_t size,
- enum dma_data_direction dir)
-{
- __dma_sync_single(dev, dma_handle, size, dir);
- debug_dma_sync_single_for_device(dev, dma_handle, size, dir);
-}
+ if (dma_alloc_from_coherent(dev, size, dma_handle, &memory))
+ return memory;
+ if (!ops->alloc_coherent)
+ return NULL;
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
- dma_addr_t dma_handle,
- unsigned long offset,
- size_t size,
- enum dma_data_direction direction)
-{
- dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
- debug_dma_sync_single_range_for_cpu(dev, dma_handle,
- offset, size, direction);
-}
+ memory = ops->alloc_coherent(dev, size, dma_handle, gfp);
+ debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
-static inline void dma_sync_single_range_for_device(struct device *dev,
- dma_addr_t dma_handle,
- unsigned long offset,
- size_t size,
- enum dma_data_direction direction)
-{
- dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
- debug_dma_sync_single_range_for_device(dev, dma_handle,
- offset, size, direction);
+ return memory;
}
-
-static inline void dma_sync_sg_for_cpu(struct device *dev,
- struct scatterlist *sg, int nelems,
- enum dma_data_direction dir)
+static inline void dma_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
{
- __dma_sync_sg(dev, sg, nelems, dir);
- debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir);
-}
+ struct dma_map_ops *ops = get_dma_ops(dev);
-static inline void dma_sync_sg_for_device(struct device *dev,
- struct scatterlist *sg, int nelems,
- enum dma_data_direction dir)
-{
- __dma_sync_sg(dev, sg, nelems, dir);
- debug_dma_sync_sg_for_device(dev, sg, nelems, dir);
-}
+ WARN_ON(irqs_disabled()); /* for portability */
-static inline int dma_get_cache_alignment(void)
-{
- /*
- * Each processor family will define its own L1_CACHE_SHIFT,
- * L1_CACHE_BYTES wraps to this, so this is always safe.
- */
- return L1_CACHE_BYTES;
-}
+ if (dma_release_from_coherent(dev, get_order(size), vaddr))
+ return;
-static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
- return dma_addr == 0;
+ debug_dma_free_coherent(dev, size, vaddr, dma_handle);
+ if (ops->free_coherent)
+ ops->free_coherent(dev, size, vaddr, dma_handle);
}
-#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
-
-extern int
-dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
- dma_addr_t device_addr, size_t size, int flags);
-
-extern void
-dma_release_declared_memory(struct device *dev);
-
-extern void *
-dma_mark_declared_memory_occupied(struct device *dev,
- dma_addr_t device_addr, size_t size);
+/* arch/sh/mm/consistent.c */
+extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_addr, gfp_t flag);
+extern void dma_generic_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle);
#endif /* __ASM_SH_DMA_MAPPING_H */
diff --git a/arch/sh/include/asm/dwarf.h b/arch/sh/include/asm/dwarf.h
index ced6795891a..bdccbbfdc0b 100644
--- a/arch/sh/include/asm/dwarf.h
+++ b/arch/sh/include/asm/dwarf.h
@@ -194,6 +194,12 @@
#define DWARF_ARCH_RA_REG 17
#ifndef __ASSEMBLY__
+
+#include <linux/compiler.h>
+#include <linux/bug.h>
+#include <linux/list.h>
+#include <linux/module.h>
+
/*
* Read either the frame pointer (r14) or the stack pointer (r15).
* NOTE: this MUST be inlined.
@@ -241,6 +247,12 @@ struct dwarf_cie {
unsigned long flags;
#define DWARF_CIE_Z_AUGMENTATION (1 << 0)
+
+ /*
+ * 'mod' will be non-NULL if this CIE came from a module's
+ * .eh_frame section.
+ */
+ struct module *mod;
};
/**
@@ -255,6 +267,12 @@ struct dwarf_fde {
unsigned char *instructions;
unsigned char *end;
struct list_head link;
+
+ /*
+ * 'mod' will be non-NULL if this FDE came from a module's
+ * .eh_frame section.
+ */
+ struct module *mod;
};
/**
@@ -364,6 +382,12 @@ static inline unsigned int DW_CFA_operand(unsigned long insn)
extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
struct dwarf_frame *);
+extern void dwarf_free_frame(struct dwarf_frame *);
+
+extern int module_dwarf_finalize(const Elf_Ehdr *, const Elf_Shdr *,
+ struct module *);
+extern void module_dwarf_cleanup(struct module *);
+
#endif /* !__ASSEMBLY__ */
#define CFI_STARTPROC .cfi_startproc
@@ -391,6 +415,10 @@ extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
static inline void dwarf_unwinder_init(void)
{
}
+
+#define module_dwarf_finalize(hdr, sechdrs, me) (0)
+#define module_dwarf_cleanup(mod) do { } while (0)
+
#endif
#endif /* CONFIG_DWARF_UNWINDER */
diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h
index 721fcc4d5e9..76c5a3099cb 100644
--- a/arch/sh/include/asm/fixmap.h
+++ b/arch/sh/include/asm/fixmap.h
@@ -14,9 +14,9 @@
#define _ASM_FIXMAP_H
#include <linux/kernel.h>
+#include <linux/threads.h>
#include <asm/page.h>
#ifdef CONFIG_HIGHMEM
-#include <linux/threads.h>
#include <asm/kmap_types.h>
#endif
@@ -46,9 +46,9 @@
* fix-mapped?
*/
enum fixed_addresses {
-#define FIX_N_COLOURS 16
+#define FIX_N_COLOURS 8
FIX_CMAP_BEGIN,
- FIX_CMAP_END = FIX_CMAP_BEGIN + FIX_N_COLOURS,
+ FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS),
FIX_UNCACHED,
#ifdef CONFIG_HIGHMEM
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
diff --git a/arch/sh/include/asm/ftrace.h b/arch/sh/include/asm/ftrace.h
index 12f3a31f20a..13e9966464c 100644
--- a/arch/sh/include/asm/ftrace.h
+++ b/arch/sh/include/asm/ftrace.h
@@ -35,4 +35,21 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_FUNCTION_TRACER */
+#ifndef __ASSEMBLY__
+
+/* arch/sh/kernel/return_address.c */
+extern void *return_address(unsigned int);
+
+#define HAVE_ARCH_CALLER_ADDR
+
+#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0))
+#define CALLER_ADDR1 ((unsigned long)return_address(1))
+#define CALLER_ADDR2 ((unsigned long)return_address(2))
+#define CALLER_ADDR3 ((unsigned long)return_address(3))
+#define CALLER_ADDR4 ((unsigned long)return_address(4))
+#define CALLER_ADDR5 ((unsigned long)return_address(5))
+#define CALLER_ADDR6 ((unsigned long)return_address(6))
+
+#endif /* __ASSEMBLY__ */
+
#endif /* __ASM_SH_FTRACE_H */
diff --git a/arch/sh/include/asm/hardirq.h b/arch/sh/include/asm/hardirq.h
index a5be4afa790..48b191313a9 100644
--- a/arch/sh/include/asm/hardirq.h
+++ b/arch/sh/include/asm/hardirq.h
@@ -1,9 +1,16 @@
#ifndef __ASM_SH_HARDIRQ_H
#define __ASM_SH_HARDIRQ_H
-extern void ack_bad_irq(unsigned int irq);
-#define ack_bad_irq ack_bad_irq
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+typedef struct {
+ unsigned int __softirq_pending;
+ unsigned int __nmi_count; /* arch dependent */
+} ____cacheline_aligned irq_cpustat_t;
-#include <asm-generic/hardirq.h>
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+
+extern void ack_bad_irq(unsigned int irq);
#endif /* __ASM_SH_HARDIRQ_H */
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index 5be45ea4dfe..0cf2a5708e2 100644
--- a/arch/sh/include/asm/io.h
+++ b/arch/sh/include/asm/io.h
@@ -246,7 +246,7 @@ void __iounmap(void __iomem *addr);
static inline void __iomem *
__ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
{
-#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED)
+#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) && !defined(CONFIG_PMB)
unsigned long last_addr = offset + size - 1;
#endif
void __iomem *ret;
@@ -255,7 +255,7 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
if (ret)
return ret;
-#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED)
+#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) && !defined(CONFIG_PMB)
/*
* For P1 and P2 space this is trivial, as everything is already
* mapped. Uncached access for P1 addresses are done through P2.
diff --git a/arch/sh/include/asm/irqflags.h b/arch/sh/include/asm/irqflags.h
index 46e71da5be6..a741153b41c 100644
--- a/arch/sh/include/asm/irqflags.h
+++ b/arch/sh/include/asm/irqflags.h
@@ -1,34 +1,9 @@
#ifndef __ASM_SH_IRQFLAGS_H
#define __ASM_SH_IRQFLAGS_H
-#ifdef CONFIG_SUPERH32
-#include "irqflags_32.h"
-#else
-#include "irqflags_64.h"
-#endif
+#define RAW_IRQ_DISABLED 0xf0
+#define RAW_IRQ_ENABLED 0x00
-#define raw_local_save_flags(flags) \
- do { (flags) = __raw_local_save_flags(); } while (0)
-
-static inline int raw_irqs_disabled_flags(unsigned long flags)
-{
- return (flags != 0);
-}
-
-static inline int raw_irqs_disabled(void)
-{
- unsigned long flags = __raw_local_save_flags();
-
- return raw_irqs_disabled_flags(flags);
-}
-
-#define raw_local_irq_save(flags) \
- do { (flags) = __raw_local_irq_save(); } while (0)
-
-static inline void raw_local_irq_restore(unsigned long flags)
-{
- if ((flags & 0xf0) != 0xf0)
- raw_local_irq_enable();
-}
+#include <asm-generic/irqflags.h>
#endif /* __ASM_SH_IRQFLAGS_H */
diff --git a/arch/sh/include/asm/irqflags_32.h b/arch/sh/include/asm/irqflags_32.h
deleted file mode 100644
index 60218f54134..00000000000
--- a/arch/sh/include/asm/irqflags_32.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef __ASM_SH_IRQFLAGS_32_H
-#define __ASM_SH_IRQFLAGS_32_H
-
-static inline void raw_local_irq_enable(void)
-{
- unsigned long __dummy0, __dummy1;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "and %1, %0\n\t"
-#ifdef CONFIG_CPU_HAS_SR_RB
- "stc r6_bank, %1\n\t"
- "or %1, %0\n\t"
-#endif
- "ldc %0, sr\n\t"
- : "=&r" (__dummy0), "=r" (__dummy1)
- : "1" (~0x000000f0)
- : "memory"
- );
-}
-
-static inline void raw_local_irq_disable(void)
-{
- unsigned long flags;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "or #0xf0, %0\n\t"
- "ldc %0, sr\n\t"
- : "=&z" (flags)
- : /* no inputs */
- : "memory"
- );
-}
-
-static inline void set_bl_bit(void)
-{
- unsigned long __dummy0, __dummy1;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "or %2, %0\n\t"
- "and %3, %0\n\t"
- "ldc %0, sr\n\t"
- : "=&r" (__dummy0), "=r" (__dummy1)
- : "r" (0x10000000), "r" (0xffffff0f)
- : "memory"
- );
-}
-
-static inline void clear_bl_bit(void)
-{
- unsigned long __dummy0, __dummy1;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "and %2, %0\n\t"
- "ldc %0, sr\n\t"
- : "=&r" (__dummy0), "=r" (__dummy1)
- : "1" (~0x10000000)
- : "memory"
- );
-}
-
-static inline unsigned long __raw_local_save_flags(void)
-{
- unsigned long flags;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "and #0xf0, %0\n\t"
- : "=&z" (flags)
- : /* no inputs */
- : "memory"
- );
-
- return flags;
-}
-
-static inline unsigned long __raw_local_irq_save(void)
-{
- unsigned long flags, __dummy;
-
- __asm__ __volatile__ (
- "stc sr, %1\n\t"
- "mov %1, %0\n\t"
- "or #0xf0, %0\n\t"
- "ldc %0, sr\n\t"
- "mov %1, %0\n\t"
- "and #0xf0, %0\n\t"
- : "=&z" (flags), "=&r" (__dummy)
- : /* no inputs */
- : "memory"
- );
-
- return flags;
-}
-
-#endif /* __ASM_SH_IRQFLAGS_32_H */
diff --git a/arch/sh/include/asm/irqflags_64.h b/arch/sh/include/asm/irqflags_64.h
deleted file mode 100644
index 88f65222c1d..00000000000
--- a/arch/sh/include/asm/irqflags_64.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef __ASM_SH_IRQFLAGS_64_H
-#define __ASM_SH_IRQFLAGS_64_H
-
-#include <cpu/registers.h>
-
-#define SR_MASK_LL 0x00000000000000f0LL
-#define SR_BL_LL 0x0000000010000000LL
-
-static inline void raw_local_irq_enable(void)
-{
- unsigned long long __dummy0, __dummy1 = ~SR_MASK_LL;
-
- __asm__ __volatile__("getcon " __SR ", %0\n\t"
- "and %0, %1, %0\n\t"
- "putcon %0, " __SR "\n\t"
- : "=&r" (__dummy0)
- : "r" (__dummy1));
-}
-
-static inline void raw_local_irq_disable(void)
-{
- unsigned long long __dummy0, __dummy1 = SR_MASK_LL;
-
- __asm__ __volatile__("getcon " __SR ", %0\n\t"
- "or %0, %1, %0\n\t"
- "putcon %0, " __SR "\n\t"
- : "=&r" (__dummy0)
- : "r" (__dummy1));
-}
-
-static inline void set_bl_bit(void)
-{
- unsigned long long __dummy0, __dummy1 = SR_BL_LL;
-
- __asm__ __volatile__("getcon " __SR ", %0\n\t"
- "or %0, %1, %0\n\t"
- "putcon %0, " __SR "\n\t"
- : "=&r" (__dummy0)
- : "r" (__dummy1));
-
-}
-
-static inline void clear_bl_bit(void)
-{
- unsigned long long __dummy0, __dummy1 = ~SR_BL_LL;
-
- __asm__ __volatile__("getcon " __SR ", %0\n\t"
- "and %0, %1, %0\n\t"
- "putcon %0, " __SR "\n\t"
- : "=&r" (__dummy0)
- : "r" (__dummy1));
-}
-
-static inline unsigned long __raw_local_save_flags(void)
-{
- unsigned long long __dummy = SR_MASK_LL;
- unsigned long flags;
-
- __asm__ __volatile__ (
- "getcon " __SR ", %0\n\t"
- "and %0, %1, %0"
- : "=&r" (flags)
- : "r" (__dummy));
-
- return flags;
-}
-
-static inline unsigned long __raw_local_irq_save(void)
-{
- unsigned long long __dummy0, __dummy1 = SR_MASK_LL;
- unsigned long flags;
-
- __asm__ __volatile__ (
- "getcon " __SR ", %1\n\t"
- "or %1, r63, %0\n\t"
- "or %1, %2, %1\n\t"
- "putcon %1, " __SR "\n\t"
- "and %0, %2, %0"
- : "=&r" (flags), "=&r" (__dummy0)
- : "r" (__dummy1));
-
- return flags;
-}
-
-#endif /* __ASM_SH_IRQFLAGS_64_H */
diff --git a/arch/sh/include/asm/mmu.h b/arch/sh/include/asm/mmu.h
index f5963037c9d..c7426ad9926 100644
--- a/arch/sh/include/asm/mmu.h
+++ b/arch/sh/include/asm/mmu.h
@@ -7,12 +7,16 @@
#define PMB_PASCR 0xff000070
#define PMB_IRMCR 0xff000078
+#define PASCR_SE 0x80000000
+
#define PMB_ADDR 0xf6100000
#define PMB_DATA 0xf7100000
#define PMB_ENTRY_MAX 16
#define PMB_E_MASK 0x0000000f
#define PMB_E_SHIFT 8
+#define PMB_PFN_MASK 0xff000000
+
#define PMB_SZ_16M 0x00000000
#define PMB_SZ_64M 0x00000010
#define PMB_SZ_128M 0x00000080
@@ -62,17 +66,10 @@ struct pmb_entry {
};
/* arch/sh/mm/pmb.c */
-int __set_pmb_entry(unsigned long vpn, unsigned long ppn,
- unsigned long flags, int *entry);
-int set_pmb_entry(struct pmb_entry *pmbe);
-void clear_pmb_entry(struct pmb_entry *pmbe);
-struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
- unsigned long flags);
-void pmb_free(struct pmb_entry *pmbe);
long pmb_remap(unsigned long virt, unsigned long phys,
unsigned long size, unsigned long flags);
void pmb_unmap(unsigned long addr);
+int pmb_init(void);
#endif /* __ASSEMBLY__ */
#endif /* __MMU_H */
-
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 4163950cd1c..67f3999b544 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -3,8 +3,6 @@
#ifdef __KERNEL__
-#include <linux/dma-mapping.h>
-
/* Can be used to override the logic in pci_scan_bus for skipping
already-configured bus numbers - to be used for buggy BIOSes
or architectures with incomplete PCI setup by the loader */
@@ -54,30 +52,18 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
* address space. The networking and block device layers use
* this boolean for bounce buffer decisions.
*/
-#define PCI_DMA_BUS_IS_PHYS (1)
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <asm/scatterlist.h>
-#include <linux/string.h>
-#include <asm/io.h>
+#define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys)
/* pci_unmap_{single,page} being a nop depends upon the
* configuration.
*/
-#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
- dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
- __u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME) \
- ((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
- (((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME) \
- ((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
- (((PTR)->LEN_NAME) = (VAL))
+#ifdef CONFIG_DMA_NONCOHERENT
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) __u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME) ((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) (((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL))
#else
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h
index 4f3efa7d5a6..ba3046e4f06 100644
--- a/arch/sh/include/asm/pgtable.h
+++ b/arch/sh/include/asm/pgtable.h
@@ -75,13 +75,31 @@ static inline unsigned long long neff_sign_extend(unsigned long val)
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
#define FIRST_USER_ADDRESS 0
-#ifdef CONFIG_32BIT
-#define PHYS_ADDR_MASK 0xffffffff
+#define PHYS_ADDR_MASK29 0x1fffffff
+#define PHYS_ADDR_MASK32 0xffffffff
+
+#ifdef CONFIG_PMB
+static inline unsigned long phys_addr_mask(void)
+{
+ /* Is the MMU in 29bit mode? */
+ if (__in_29bit_mode())
+ return PHYS_ADDR_MASK29;
+
+ return PHYS_ADDR_MASK32;
+}
+#elif defined(CONFIG_32BIT)
+static inline unsigned long phys_addr_mask(void)
+{
+ return PHYS_ADDR_MASK32;
+}
#else
-#define PHYS_ADDR_MASK 0x1fffffff
+static inline unsigned long phys_addr_mask(void)
+{
+ return PHYS_ADDR_MASK29;
+}
#endif
-#define PTE_PHYS_MASK (PHYS_ADDR_MASK & PAGE_MASK)
+#define PTE_PHYS_MASK (phys_addr_mask() & PAGE_MASK)
#define PTE_FLAGS_MASK (~(PTE_PHYS_MASK) << PAGE_SHIFT)
#ifdef CONFIG_SUPERH32
diff --git a/arch/sh/include/asm/pgtable_32.h b/arch/sh/include/asm/pgtable_32.h
index c0d359ce337..b3543551620 100644
--- a/arch/sh/include/asm/pgtable_32.h
+++ b/arch/sh/include/asm/pgtable_32.h
@@ -108,7 +108,7 @@ static inline unsigned long copy_ptea_attributes(unsigned long x)
#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE)
#endif
-#define _PAGE_FLAGS_HARDWARE_MASK (PHYS_ADDR_MASK & ~(_PAGE_CLEAR_FLAGS))
+#define _PAGE_FLAGS_HARDWARE_MASK (phys_addr_mask() & ~(_PAGE_CLEAR_FLAGS))
/* Hardware flags, page size encoding */
#if !defined(CONFIG_MMU)
diff --git a/arch/sh/include/asm/scatterlist.h b/arch/sh/include/asm/scatterlist.h
index 327cc2e4c97..e38d1d4c7f6 100644
--- a/arch/sh/include/asm/scatterlist.h
+++ b/arch/sh/include/asm/scatterlist.h
@@ -1,7 +1,7 @@
#ifndef __ASM_SH_SCATTERLIST_H
#define __ASM_SH_SCATTERLIST_H
-#define ISA_DMA_THRESHOLD PHYS_ADDR_MASK
+#define ISA_DMA_THRESHOLD phys_addr_mask()
#include <asm-generic/scatterlist.h>
diff --git a/arch/sh/include/asm/system_32.h b/arch/sh/include/asm/system_32.h
index 607d413f616..06814f5b59c 100644
--- a/arch/sh/include/asm/system_32.h
+++ b/arch/sh/include/asm/system_32.h
@@ -232,4 +232,33 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs __regs);
+static inline void set_bl_bit(void)
+{
+ unsigned long __dummy0, __dummy1;
+
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "or %2, %0\n\t"
+ "and %3, %0\n\t"
+ "ldc %0, sr\n\t"
+ : "=&r" (__dummy0), "=r" (__dummy1)
+ : "r" (0x10000000), "r" (0xffffff0f)
+ : "memory"
+ );
+}
+
+static inline void clear_bl_bit(void)
+{
+ unsigned long __dummy0, __dummy1;
+
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "and %2, %0\n\t"
+ "ldc %0, sr\n\t"
+ : "=&r" (__dummy0), "=r" (__dummy1)
+ : "1" (~0x10000000)
+ : "memory"
+ );
+}
+
#endif /* __ASM_SH_SYSTEM_32_H */
diff --git a/arch/sh/include/asm/system_64.h b/arch/sh/include/asm/system_64.h
index 8e4a03e7966..ab1dd917ea8 100644
--- a/arch/sh/include/asm/system_64.h
+++ b/arch/sh/include/asm/system_64.h
@@ -12,6 +12,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#include <cpu/registers.h>
#include <asm/processor.h>
/*
@@ -47,4 +48,29 @@ static inline reg_size_t register_align(void *val)
return (unsigned long long)(signed long long)(signed long)val;
}
+#define SR_BL_LL 0x0000000010000000LL
+
+static inline void set_bl_bit(void)
+{
+ unsigned long long __dummy0, __dummy1 = SR_BL_LL;
+
+ __asm__ __volatile__("getcon " __SR ", %0\n\t"
+ "or %0, %1, %0\n\t"
+ "putcon %0, " __SR "\n\t"
+ : "=&r" (__dummy0)
+ : "r" (__dummy1));
+
+}
+
+static inline void clear_bl_bit(void)
+{
+ unsigned long long __dummy0, __dummy1 = ~SR_BL_LL;
+
+ __asm__ __volatile__("getcon " __SR ", %0\n\t"
+ "and %0, %1, %0\n\t"
+ "putcon %0, " __SR "\n\t"
+ : "=&r" (__dummy0)
+ : "r" (__dummy1));
+}
+
#endif /* __ASM_SH_SYSTEM_64_H */
diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h
index bdeb9d46d17..23eeed89467 100644
--- a/arch/sh/include/asm/thread_info.h
+++ b/arch/sh/include/asm/thread_info.h
@@ -19,6 +19,7 @@ struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
unsigned long flags; /* low level flags */
+ __u32 status; /* thread synchronous flags */
__u32 cpu;
int preempt_count; /* 0 => preemptable, <0 => BUG */
mm_segment_t addr_limit; /* thread address space */
@@ -111,7 +112,6 @@ extern void free_thread_info(struct thread_info *ti);
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_SIGPENDING 1 /* signal pending */
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
-#define TIF_RESTORE_SIGMASK 3 /* restore signal mask in do_signal() */
#define TIF_SINGLESTEP 4 /* singlestepping active */
#define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */
#define TIF_SECCOMP 6 /* secure computing */
@@ -125,7 +125,6 @@ extern void free_thread_info(struct thread_info *ti);
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
-#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
@@ -149,13 +148,32 @@ extern void free_thread_info(struct thread_info *ti);
/* work to do on any return to u-space */
#define _TIF_ALLWORK_MASK (_TIF_SYSCALL_TRACE | _TIF_SIGPENDING | \
_TIF_NEED_RESCHED | _TIF_SYSCALL_AUDIT | \
- _TIF_SINGLESTEP | _TIF_RESTORE_SIGMASK | \
- _TIF_NOTIFY_RESUME | _TIF_SYSCALL_TRACEPOINT)
+ _TIF_SINGLESTEP | _TIF_NOTIFY_RESUME | \
+ _TIF_SYSCALL_TRACEPOINT)
/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \
_TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP))
+/*
+ * Thread-synchronous status.
+ *
+ * This is different from the flags in that nobody else
+ * ever touches our thread-synchronous status, so we don't
+ * have to worry about atomic accesses.
+ */
+#define TS_RESTORE_SIGMASK 0x0001 /* restore signal mask in do_signal() */
+
+#ifndef __ASSEMBLY__
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+ struct thread_info *ti = current_thread_info();
+ ti->status |= TS_RESTORE_SIGMASK;
+ set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags);
+}
+#endif /* !__ASSEMBLY__ */
+
#endif /* __KERNEL__ */
#endif /* __ASM_SH_THREAD_INFO_H */
diff --git a/arch/sh/include/asm/topology.h b/arch/sh/include/asm/topology.h
index 65e7bd2f224..37cdadd975a 100644
--- a/arch/sh/include/asm/topology.h
+++ b/arch/sh/include/asm/topology.h
@@ -40,6 +40,14 @@
#endif
+#define mc_capable() (1)
+
+const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
+
+extern cpumask_t cpu_core_map[NR_CPUS];
+
+#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
+
#include <asm-generic/topology.h>
#endif /* _ASM_SH_TOPOLOGY_H */
diff --git a/arch/sh/include/asm/ubc.h b/arch/sh/include/asm/ubc.h
index 4ca4b771737..9bf96168443 100644
--- a/arch/sh/include/asm/ubc.h
+++ b/arch/sh/include/asm/ubc.h
@@ -60,16 +60,5 @@
#define BRCR_UBDE (1 << 0)
#endif
-#ifndef __ASSEMBLY__
-/* arch/sh/kernel/cpu/ubc.S */
-extern void ubc_sleep(void);
-
-#ifdef CONFIG_UBC_WAKEUP
-extern void ubc_wakeup(void);
-#else
-#define ubc_wakeup() do { } while (0)
-#endif
-#endif
-
#endif /* __KERNEL__ */
#endif /* __ASM_SH_UBC_H */
diff --git a/arch/sh/include/asm/watchdog.h b/arch/sh/include/asm/watchdog.h
index 2fe7cee9e43..19dfff5c851 100644
--- a/arch/sh/include/asm/watchdog.h
+++ b/arch/sh/include/asm/watchdog.h
@@ -2,6 +2,8 @@
* include/asm-sh/watchdog.h
*
* Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2009 Siemens AG
+ * Copyright (C) 2009 Valentin Sitdikov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -61,6 +63,61 @@
#define WTCSR_CKS_2048 0x06
#define WTCSR_CKS_4096 0x07
+#if defined(CONFIG_CPU_SUBTYPE_SH7785) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+/**
+ * sh_wdt_read_cnt - Read from Counter
+ * Reads back the WTCNT value.
+ */
+static inline __u32 sh_wdt_read_cnt(void)
+{
+ return ctrl_inl(WTCNT_R);
+}
+
+/**
+ * sh_wdt_write_cnt - Write to Counter
+ * @val: Value to write
+ *
+ * Writes the given value @val to the lower byte of the timer counter.
+ * The upper byte is set manually on each write.
+ */
+static inline void sh_wdt_write_cnt(__u32 val)
+{
+ ctrl_outl((WTCNT_HIGH << 24) | (__u32)val, WTCNT);
+}
+
+/**
+ * sh_wdt_write_bst - Write to Counter
+ * @val: Value to write
+ *
+ * Writes the given value @val to the lower byte of the timer counter.
+ * The upper byte is set manually on each write.
+ */
+static inline void sh_wdt_write_bst(__u32 val)
+{
+ ctrl_outl((WTBST_HIGH << 24) | (__u32)val, WTBST);
+}
+/**
+ * sh_wdt_read_csr - Read from Control/Status Register
+ *
+ * Reads back the WTCSR value.
+ */
+static inline __u32 sh_wdt_read_csr(void)
+{
+ return ctrl_inl(WTCSR_R);
+}
+
+/**
+ * sh_wdt_write_csr - Write to Control/Status Register
+ * @val: Value to write
+ *
+ * Writes the given value @val to the lower byte of the control/status
+ * register. The upper byte is set manually on each write.
+ */
+static inline void sh_wdt_write_csr(__u32 val)
+{
+ ctrl_outl((WTCSR_HIGH << 24) | (__u32)val, WTCSR);
+}
+#else
/**
* sh_wdt_read_cnt - Read from Counter
* Reads back the WTCNT value.
@@ -103,6 +160,6 @@ static inline void sh_wdt_write_csr(__u8 val)
{
ctrl_outw((WTCSR_HIGH << 8) | (__u16)val, WTCSR);
}
-
+#endif /* CONFIG_CPU_SUBTYPE_SH7785 || CONFIG_CPU_SUBTYPE_SH7780 */
#endif /* __KERNEL__ */
#endif /* __ASM_SH_WATCHDOG_H */
diff --git a/arch/sh/include/cpu-sh4/cpu/watchdog.h b/arch/sh/include/cpu-sh4/cpu/watchdog.h
index 259f6a0ce23..7672301d0c7 100644
--- a/arch/sh/include/cpu-sh4/cpu/watchdog.h
+++ b/arch/sh/include/cpu-sh4/cpu/watchdog.h
@@ -2,6 +2,8 @@
* include/asm-sh/cpu-sh4/watchdog.h
*
* Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2009 Siemens AG
+ * Copyright (C) 2009 Sitdikov Valentin
*
* 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
@@ -10,9 +12,20 @@
#ifndef __ASM_CPU_SH4_WATCHDOG_H
#define __ASM_CPU_SH4_WATCHDOG_H
+#if defined(CONFIG_CPU_SUBTYPE_SH7785) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+/* Prefix definition */
+#define WTBST_HIGH 0x55
+/* Register definitions */
+#define WTCNT_R 0xffcc0010 /*WDTCNT*/
+#define WTCSR 0xffcc0004 /*WDTCSR*/
+#define WTCNT 0xffcc0000 /*WDTST*/
+#define WTST WTCNT
+#define WTBST 0xffcc0008 /*WDTBST*/
+#else
/* Register definitions */
#define WTCNT 0xffc00008
#define WTCSR 0xffc0000c
+#endif
/* Bit definitions */
#define WTCSR_TME 0x80
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index a2d0a40f384..097ae5ceb0e 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -9,8 +9,12 @@ ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_ftrace.o = -pg
endif
-obj-y := debugtraps.o dumpstack.o idle.o io.o io_generic.o irq.o \
- machvec.o nmi_debug.o process_$(BITS).o ptrace_$(BITS).o \
+CFLAGS_REMOVE_return_address.o = -pg
+
+obj-y := debugtraps.o dma-nommu.o dumpstack.o \
+ idle.o io.o io_generic.o irq.o \
+ irq_$(BITS).o machvec.o nmi_debug.o process_$(BITS).o \
+ ptrace_$(BITS).o return_address.o \
setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \
syscalls_$(BITS).o time.o topology.o traps.o \
traps_$(BITS).o unwinder.o
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index 3d6b9312dc4..d97c803719e 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/
# Common interfaces.
-obj-$(CONFIG_UBC_WAKEUP) += ubc.o
obj-$(CONFIG_SH_ADC) += adc.o
obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index e932ebef473..580d58b94cc 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -338,17 +338,6 @@ asmlinkage void __init sh_cpu_init(void)
}
#endif
- /*
- * Some brain-damaged loaders decided it would be a good idea to put
- * the UBC to sleep. This causes some issues when it comes to things
- * like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB. So ..
- * we wake it up and hope that all is well.
- */
-#ifdef CONFIG_SUPERH32
- if (raw_smp_processor_id() == 0)
- ubc_wakeup();
-#endif
-
speculative_execution_init();
expmask_init();
}
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index bb407ef0b91..3f7e2a22c7c 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -297,41 +297,8 @@ ENTRY(vbr_base)
!
.balign 256,0,256
general_exception:
-#ifndef CONFIG_CPU_SUBTYPE_SHX3
bra handle_exception
sts pr, k3 ! save original pr value in k3
-#else
- mov.l 1f, k4
- mov.l @k4, k4
-
- ! Is EXPEVT larger than 0x800?
- mov #0x8, k0
- shll8 k0
- cmp/hs k0, k4
- bf 0f
-
- ! then add 0x580 (k2 is 0xd80 or 0xda0)
- mov #0x58, k0
- shll2 k0
- shll2 k0
- add k0, k4
-0:
- ! Setup stack and save DSP context (k0 contains original r15 on return)
- bsr prepare_stack
- nop
-
- ! Save registers / Switch to bank 0
- mov k4, k2 ! keep vector in k2
- mov.l 1f, k4 ! SR bits to clear in k4
- bsr save_regs ! needs original pr value in k3
- nop
-
- bra handle_exception_special
- nop
-
- .align 2
-1: .long EXPEVT
-#endif
! prepare_stack()
! - roll back gRB
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index e848443deeb..c7ba9166e18 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -15,6 +15,15 @@
#include <linux/sh_timer.h>
#include <asm/mmzone.h>
+/*
+ * This intentionally only registers SCIF ports 0, 1, and 3. SCIF 2
+ * INTEVT values overlap with the FPU EXPEVT ones, requiring special
+ * demuxing in the exception dispatch path.
+ *
+ * As this overlap is something that never should have made it in to
+ * silicon in the first place, we just refuse to deal with the port at
+ * all rather than adding infrastructure to hack around it.
+ */
static struct plat_sci_port sci_platform_data[] = {
{
.mapbase = 0xffc30000,
@@ -27,11 +36,6 @@ static struct plat_sci_port sci_platform_data[] = {
.type = PORT_SCIF,
.irqs = { 44, 45, 47, 46 },
}, {
- .mapbase = 0xffc50000,
- .flags = UPF_BOOT_AUTOCONF,
- .type = PORT_SCIF,
- .irqs = { 48, 49, 51, 50 },
- }, {
.mapbase = 0xffc60000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
@@ -268,7 +272,11 @@ enum {
UNUSED = 0,
/* interrupt sources */
- IRL, IRQ0, IRQ1, IRQ2, IRQ3,
+ IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+ IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+ IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+ IRL_HHLL, IRL_HHLH, IRL_HHHL,
+ IRQ0, IRQ1, IRQ2, IRQ3,
HUDII,
TMU0, TMU1, TMU2, TMU3, TMU4, TMU5,
PCII0, PCII1, PCII2, PCII3, PCII4,
@@ -291,7 +299,7 @@ enum {
INTICI4, INTICI5, INTICI6, INTICI7,
/* interrupt groups */
- PCII56789, SCIF0, SCIF1, SCIF2, SCIF3,
+ IRL, PCII56789, SCIF0, SCIF1, SCIF2, SCIF3,
DMAC0, DMAC1,
};
@@ -309,8 +317,6 @@ static struct intc_vect vectors[] __initdata = {
INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0),
INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0),
- INTC_VECT(SCIF2_ERI, 0x800), INTC_VECT(SCIF2_RXI, 0x820),
- INTC_VECT(SCIF2_BRI, 0x840), INTC_VECT(SCIF2_TXI, 0x860),
INTC_VECT(SCIF3_ERI, 0x880), INTC_VECT(SCIF3_RXI, 0x8a0),
INTC_VECT(SCIF3_BRI, 0x8c0), INTC_VECT(SCIF3_TXI, 0x8e0),
INTC_VECT(DMAC0_DMINT0, 0x900), INTC_VECT(DMAC0_DMINT1, 0x920),
@@ -344,10 +350,13 @@ static struct intc_vect vectors[] __initdata = {
};
static struct intc_group groups[] __initdata = {
+ INTC_GROUP(IRL, IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+ IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+ IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+ IRL_HHLL, IRL_HHLH, IRL_HHHL),
INTC_GROUP(PCII56789, PCII5, PCII6, PCII7, PCII8, PCII9),
INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
- INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
INTC_GROUP(SCIF3, SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI),
INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
@@ -419,14 +428,14 @@ static DECLARE_INTC_DESC(intc_desc_irq, "shx3-irq", vectors_irq, groups,
/* External interrupt pins in IRL mode */
static struct intc_vect vectors_irl[] __initdata = {
- INTC_VECT(IRL, 0x200), INTC_VECT(IRL, 0x220),
- INTC_VECT(IRL, 0x240), INTC_VECT(IRL, 0x260),
- INTC_VECT(IRL, 0x280), INTC_VECT(IRL, 0x2a0),
- INTC_VECT(IRL, 0x2c0), INTC_VECT(IRL, 0x2e0),
- INTC_VECT(IRL, 0x300), INTC_VECT(IRL, 0x320),
- INTC_VECT(IRL, 0x340), INTC_VECT(IRL, 0x360),
- INTC_VECT(IRL, 0x380), INTC_VECT(IRL, 0x3a0),
- INTC_VECT(IRL, 0x3c0),
+ INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
+ INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
+ INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
+ INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0),
+ INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320),
+ INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360),
+ INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0),
+ INTC_VECT(IRL_HHHL, 0x3c0),
};
static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups,
diff --git a/arch/sh/kernel/cpu/sh4a/smp-shx3.c b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
index 185ec3976a2..5863e0c4d02 100644
--- a/arch/sh/kernel/cpu/sh4a/smp-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
@@ -14,6 +14,13 @@
#include <linux/interrupt.h>
#include <linux/io.h>
+#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))
+#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12))
+
+#define STBCR_MSTP 0x00000001
+#define STBCR_RESET 0x00000002
+#define STBCR_LTSLP 0x80000000
+
static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
{
unsigned int message = (unsigned int)(long)arg;
@@ -21,9 +28,9 @@ static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
unsigned int offs = 4 * cpu;
unsigned int x;
- x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
+ x = __raw_readl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
x &= (1 << (message << 2));
- ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
+ __raw_writel(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
smp_message_recv(message);
@@ -37,6 +44,9 @@ void __init plat_smp_setup(void)
init_cpu_possible(cpumask_of(cpu));
+ /* Enable light sleep for the boot CPU */
+ __raw_writel(__raw_readl(STBCR_REG(cpu)) | STBCR_LTSLP, STBCR_REG(cpu));
+
__cpu_number_map[0] = 0;
__cpu_logical_map[0] = 0;
@@ -66,32 +76,23 @@ void __init plat_prepare_cpus(unsigned int max_cpus)
"IPI", (void *)(long)i);
}
-#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))
-#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12))
-
-#define STBCR_MSTP 0x00000001
-#define STBCR_RESET 0x00000002
-#define STBCR_LTSLP 0x80000000
-
-#define STBCR_AP_VAL (STBCR_RESET | STBCR_LTSLP)
-
void plat_start_cpu(unsigned int cpu, unsigned long entry_point)
{
- ctrl_outl(entry_point, RESET_REG(cpu));
+ __raw_writel(entry_point, RESET_REG(cpu));
- if (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
- ctrl_outl(STBCR_MSTP, STBCR_REG(cpu));
+ if (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))
+ __raw_writel(STBCR_MSTP, STBCR_REG(cpu));
- while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
+ while (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))
cpu_relax();
/* Start up secondary processor by sending a reset */
- ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu));
+ __raw_writel(STBCR_RESET | STBCR_LTSLP, STBCR_REG(cpu));
}
int plat_smp_processor_id(void)
{
- return ctrl_inl(0xff000048); /* CPIDR */
+ return __raw_readl(0xff000048); /* CPIDR */
}
void plat_send_ipi(unsigned int cpu, unsigned int message)
@@ -100,5 +101,5 @@ void plat_send_ipi(unsigned int cpu, unsigned int message)
BUG_ON(cpu >= 4);
- ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
+ __raw_writel(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
}
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
index b0aacf67525..8f13f73cb2c 100644
--- a/arch/sh/kernel/cpu/sh5/entry.S
+++ b/arch/sh/kernel/cpu/sh5/entry.S
@@ -933,7 +933,7 @@ ret_with_reschedule:
pta restore_all, tr1
- movi (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r8
+ movi _TIF_SIGPENDING, r8
and r8, r7, r8
pta work_notifysig, tr0
bne r8, ZERO, tr0
diff --git a/arch/sh/kernel/cpu/ubc.S b/arch/sh/kernel/cpu/ubc.S
deleted file mode 100644
index 81923079fa1..00000000000
--- a/arch/sh/kernel/cpu/ubc.S
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * arch/sh/kernel/cpu/ubc.S
- *
- * Set of management routines for the User Break Controller (UBC)
- *
- * Copyright (C) 2002 Paul Mundt
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-#include <linux/linkage.h>
-#include <asm/ubc.h>
-
-#define STBCR2 0xffc00010
-
-ENTRY(ubc_sleep)
- mov #0, r0
-
- mov.l 1f, r1 ! Zero out UBC_BBRA ..
- mov.w r0, @r1
-
- mov.l 2f, r1 ! .. same for BBRB ..
- mov.w r0, @r1
-
- mov.l 3f, r1 ! .. and again for BRCR.
- mov.w r0, @r1
-
- mov.w @r1, r0 ! Dummy read BRCR
-
- mov.l 4f, r1 ! Set MSTP5 in STBCR2
- mov.b @r1, r0
- or #0x01, r0
- mov.b r0, @r1
-
- mov.b @r1, r0 ! Two dummy reads ..
- mov.b @r1, r0
-
- rts
- nop
-
-ENTRY(ubc_wakeup)
- mov.l 4f, r1 ! Clear MSTP5
- mov.b @r1, r0
- and #0xfe, r0
- mov.b r0, @r1
-
- mov.b @r1, r0 ! Two more dummy reads ..
- mov.b @r1, r0
-
- rts
- nop
-
-1: .long UBC_BBRA
-2: .long UBC_BBRB
-3: .long UBC_BRCR
-4: .long STBCR2
-
diff --git a/arch/sh/kernel/dma-nommu.c b/arch/sh/kernel/dma-nommu.c
new file mode 100644
index 00000000000..3c55b87f8b6
--- /dev/null
+++ b/arch/sh/kernel/dma-nommu.c
@@ -0,0 +1,82 @@
+/*
+ * DMA mapping support for platforms lacking IOMMUs.
+ *
+ * Copyright (C) 2009 Paul Mundt
+ *
+ * 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.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+
+static dma_addr_t nommu_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ dma_addr_t addr = page_to_phys(page) + offset;
+
+ WARN_ON(size == 0);
+ dma_cache_sync(dev, page_address(page) + offset, size, dir);
+
+ return addr;
+}
+
+static int nommu_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct scatterlist *s;
+ int i;
+
+ WARN_ON(nents == 0 || sg[0].length == 0);
+
+ for_each_sg(sg, s, nents, i) {
+ BUG_ON(!sg_page(s));
+
+ dma_cache_sync(dev, sg_virt(s), s->length, dir);
+
+ s->dma_address = sg_phys(s);
+ s->dma_length = s->length;
+ }
+
+ return nents;
+}
+
+#ifdef CONFIG_DMA_NONCOHERENT
+static void nommu_sync_single(struct device *dev, dma_addr_t addr,
+ size_t size, enum dma_data_direction dir)
+{
+ dma_cache_sync(dev, phys_to_virt(addr), size, dir);
+}
+
+static void nommu_sync_sg(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction dir)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nelems, i)
+ dma_cache_sync(dev, sg_virt(s), s->length, dir);
+}
+#endif
+
+struct dma_map_ops nommu_dma_ops = {
+ .alloc_coherent = dma_generic_alloc_coherent,
+ .free_coherent = dma_generic_free_coherent,
+ .map_page = nommu_map_page,
+ .map_sg = nommu_map_sg,
+#ifdef CONFIG_DMA_NONCOHERENT
+ .sync_single_for_device = nommu_sync_single,
+ .sync_sg_for_device = nommu_sync_sg,
+#endif
+ .is_phys = 1,
+};
+
+void __init no_iommu_init(void)
+{
+ if (dma_ops)
+ return;
+ dma_ops = &nommu_dma_ops;
+}
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c
index 2d07084e488..6c9d0c10f2b 100644
--- a/arch/sh/kernel/dwarf.c
+++ b/arch/sh/kernel/dwarf.c
@@ -20,6 +20,7 @@
#include <linux/list.h>
#include <linux/mempool.h>
#include <linux/mm.h>
+#include <linux/elf.h>
#include <linux/ftrace.h>
#include <asm/dwarf.h>
#include <asm/unwinder.h>
@@ -530,7 +531,18 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
}
/**
- * dwarf_unwind_stack - recursively unwind the stack
+ * dwarf_free_frame - free the memory allocated for @frame
+ * @frame: the frame to free
+ */
+void dwarf_free_frame(struct dwarf_frame *frame)
+{
+ dwarf_frame_free_regs(frame);
+ mempool_free(frame, dwarf_frame_pool);
+}
+
+/**
+ * dwarf_unwind_stack - unwind the stack
+ *
* @pc: address of the function to unwind
* @prev: struct dwarf_frame of the previous stackframe on the callstack
*
@@ -548,9 +560,9 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
unsigned long addr;
/*
- * If this is the first invocation of this recursive function we
- * need get the contents of a physical register to get the CFA
- * in order to begin the virtual unwinding of the stack.
+ * If we're starting at the top of the stack we need get the
+ * contents of a physical register to get the CFA in order to
+ * begin the virtual unwinding of the stack.
*
* NOTE: the return address is guaranteed to be setup by the
* time this function makes its first function call.
@@ -593,9 +605,8 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
fde = dwarf_lookup_fde(pc);
if (!fde) {
/*
- * This is our normal exit path - the one that stops the
- * recursion. There's two reasons why we might exit
- * here,
+ * This is our normal exit path. There are two reasons
+ * why we might exit here,
*
* a) pc has no asscociated DWARF frame info and so
* we don't know how to unwind this frame. This is
@@ -637,10 +648,10 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
} else {
/*
- * Again, this is the first invocation of this
- * recurisve function. We need to physically
- * read the contents of a register in order to
- * get the Canonical Frame Address for this
+ * Again, we're starting from the top of the
+ * stack. We need to physically read
+ * the contents of a register in order to get
+ * the Canonical Frame Address for this
* function.
*/
frame->cfa = dwarf_read_arch_reg(frame->cfa_register);
@@ -670,13 +681,12 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
return frame;
bail:
- dwarf_frame_free_regs(frame);
- mempool_free(frame, dwarf_frame_pool);
+ dwarf_free_frame(frame);
return NULL;
}
static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
- unsigned char *end)
+ unsigned char *end, struct module *mod)
{
struct dwarf_cie *cie;
unsigned long flags;
@@ -772,6 +782,8 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
cie->initial_instructions = p;
cie->instructions_end = end;
+ cie->mod = mod;
+
/* Add to list */
spin_lock_irqsave(&dwarf_cie_lock, flags);
list_add_tail(&cie->link, &dwarf_cie_list);
@@ -782,7 +794,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
static int dwarf_parse_fde(void *entry, u32 entry_type,
void *start, unsigned long len,
- unsigned char *end)
+ unsigned char *end, struct module *mod)
{
struct dwarf_fde *fde;
struct dwarf_cie *cie;
@@ -831,6 +843,8 @@ static int dwarf_parse_fde(void *entry, u32 entry_type,
fde->instructions = p;
fde->end = end;
+ fde->mod = mod;
+
/* Add to list. */
spin_lock_irqsave(&dwarf_fde_lock, flags);
list_add_tail(&fde->link, &dwarf_fde_list);
@@ -854,10 +868,8 @@ static void dwarf_unwinder_dump(struct task_struct *task,
while (1) {
frame = dwarf_unwind_stack(return_addr, _frame);
- if (_frame) {
- dwarf_frame_free_regs(_frame);
- mempool_free(_frame, dwarf_frame_pool);
- }
+ if (_frame)
+ dwarf_free_frame(_frame);
_frame = frame;
@@ -867,6 +879,9 @@ static void dwarf_unwinder_dump(struct task_struct *task,
return_addr = frame->return_addr;
ops->address(data, return_addr, 1);
}
+
+ if (frame)
+ dwarf_free_frame(frame);
}
static struct unwinder dwarf_unwinder = {
@@ -896,48 +911,28 @@ static void dwarf_unwinder_cleanup(void)
}
/**
- * dwarf_unwinder_init - initialise the dwarf unwinder
+ * dwarf_parse_section - parse DWARF section
+ * @eh_frame_start: start address of the .eh_frame section
+ * @eh_frame_end: end address of the .eh_frame section
+ * @mod: the kernel module containing the .eh_frame section
*
- * Build the data structures describing the .dwarf_frame section to
- * make it easier to lookup CIE and FDE entries. Because the
- * .eh_frame section is packed as tightly as possible it is not
- * easy to lookup the FDE for a given PC, so we build a list of FDE
- * and CIE entries that make it easier.
+ * Parse the information in a .eh_frame section.
*/
-static int __init dwarf_unwinder_init(void)
+static int dwarf_parse_section(char *eh_frame_start, char *eh_frame_end,
+ struct module *mod)
{
u32 entry_type;
void *p, *entry;
int count, err = 0;
- unsigned long len;
+ unsigned long len = 0;
unsigned int c_entries, f_entries;
unsigned char *end;
- INIT_LIST_HEAD(&dwarf_cie_list);
- INIT_LIST_HEAD(&dwarf_fde_list);
c_entries = 0;
f_entries = 0;
- entry = &__start_eh_frame;
-
- dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
- sizeof(struct dwarf_frame), 0,
- SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
-
- dwarf_reg_cachep = kmem_cache_create("dwarf_regs",
- sizeof(struct dwarf_reg), 0,
- SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
+ entry = eh_frame_start;
- dwarf_frame_pool = mempool_create(DWARF_FRAME_MIN_REQ,
- mempool_alloc_slab,
- mempool_free_slab,
- dwarf_frame_cachep);
-
- dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
- mempool_alloc_slab,
- mempool_free_slab,
- dwarf_reg_cachep);
-
- while ((char *)entry < __stop_eh_frame) {
+ while ((char *)entry < eh_frame_end) {
p = entry;
count = dwarf_entry_len(p, &len);
@@ -949,6 +944,7 @@ static int __init dwarf_unwinder_init(void)
* entry and move to the next one because 'len'
* tells us where our next entry is.
*/
+ err = -EINVAL;
goto out;
} else
p += count;
@@ -960,13 +956,14 @@ static int __init dwarf_unwinder_init(void)
p += 4;
if (entry_type == DW_EH_FRAME_CIE) {
- err = dwarf_parse_cie(entry, p, len, end);
+ err = dwarf_parse_cie(entry, p, len, end, mod);
if (err < 0)
goto out;
else
c_entries++;
} else {
- err = dwarf_parse_fde(entry, entry_type, p, len, end);
+ err = dwarf_parse_fde(entry, entry_type, p, len,
+ end, mod);
if (err < 0)
goto out;
else
@@ -979,6 +976,129 @@ static int __init dwarf_unwinder_init(void)
printk(KERN_INFO "DWARF unwinder initialised: read %u CIEs, %u FDEs\n",
c_entries, f_entries);
+ return 0;
+
+out:
+ return err;
+}
+
+#ifdef CONFIG_MODULES
+int module_dwarf_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
+ struct module *me)
+{
+ unsigned int i, err;
+ unsigned long start, end;
+ char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+ start = end = 0;
+
+ for (i = 1; i < hdr->e_shnum; i++) {
+ /* Alloc bit cleared means "ignore it." */
+ if ((sechdrs[i].sh_flags & SHF_ALLOC)
+ && !strcmp(secstrings+sechdrs[i].sh_name, ".eh_frame")) {
+ start = sechdrs[i].sh_addr;
+ end = start + sechdrs[i].sh_size;
+ break;
+ }
+ }
+
+ /* Did we find the .eh_frame section? */
+ if (i != hdr->e_shnum) {
+ err = dwarf_parse_section((char *)start, (char *)end, me);
+ if (err) {
+ printk(KERN_WARNING "%s: failed to parse DWARF info\n",
+ me->name);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * module_dwarf_cleanup - remove FDE/CIEs associated with @mod
+ * @mod: the module that is being unloaded
+ *
+ * Remove any FDEs and CIEs from the global lists that came from
+ * @mod's .eh_frame section because @mod is being unloaded.
+ */
+void module_dwarf_cleanup(struct module *mod)
+{
+ struct dwarf_fde *fde;
+ struct dwarf_cie *cie;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwarf_cie_lock, flags);
+
+again_cie:
+ list_for_each_entry(cie, &dwarf_cie_list, link) {
+ if (cie->mod == mod)
+ break;
+ }
+
+ if (&cie->link != &dwarf_cie_list) {
+ list_del(&cie->link);
+ kfree(cie);
+ goto again_cie;
+ }
+
+ spin_unlock_irqrestore(&dwarf_cie_lock, flags);
+
+ spin_lock_irqsave(&dwarf_fde_lock, flags);
+
+again_fde:
+ list_for_each_entry(fde, &dwarf_fde_list, link) {
+ if (fde->mod == mod)
+ break;
+ }
+
+ if (&fde->link != &dwarf_fde_list) {
+ list_del(&fde->link);
+ kfree(fde);
+ goto again_fde;
+ }
+
+ spin_unlock_irqrestore(&dwarf_fde_lock, flags);
+}
+#endif /* CONFIG_MODULES */
+
+/**
+ * dwarf_unwinder_init - initialise the dwarf unwinder
+ *
+ * Build the data structures describing the .dwarf_frame section to
+ * make it easier to lookup CIE and FDE entries. Because the
+ * .eh_frame section is packed as tightly as possible it is not
+ * easy to lookup the FDE for a given PC, so we build a list of FDE
+ * and CIE entries that make it easier.
+ */
+static int __init dwarf_unwinder_init(void)
+{
+ int err;
+ INIT_LIST_HEAD(&dwarf_cie_list);
+ INIT_LIST_HEAD(&dwarf_fde_list);
+
+ dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
+ sizeof(struct dwarf_frame), 0,
+ SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
+
+ dwarf_reg_cachep = kmem_cache_create("dwarf_regs",
+ sizeof(struct dwarf_reg), 0,
+ SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
+
+ dwarf_frame_pool = mempool_create(DWARF_FRAME_MIN_REQ,
+ mempool_alloc_slab,
+ mempool_free_slab,
+ dwarf_frame_cachep);
+
+ dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
+ mempool_alloc_slab,
+ mempool_free_slab,
+ dwarf_reg_cachep);
+
+ err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL);
+ if (err)
+ goto out;
+
err = unwinder_register(&dwarf_unwinder);
if (err)
goto out;
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index 3eb84931d2a..f0abd58c3a6 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -133,7 +133,7 @@ work_pending:
! r8: current_thread_info
! t: result of "tst #_TIF_NEED_RESCHED, r0"
bf/s work_resched
- tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
+ tst #_TIF_SIGPENDING, r0
work_notifysig:
bt/s __restore_all
mov r15, r4
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c
index 2c48e267256..b6f41c109be 100644
--- a/arch/sh/kernel/ftrace.c
+++ b/arch/sh/kernel/ftrace.c
@@ -62,6 +62,150 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
return ftrace_replaced_code;
}
+/*
+ * Modifying code must take extra care. On an SMP machine, if
+ * the code being modified is also being executed on another CPU
+ * that CPU will have undefined results and possibly take a GPF.
+ * We use kstop_machine to stop other CPUS from exectuing code.
+ * But this does not stop NMIs from happening. We still need
+ * to protect against that. We separate out the modification of
+ * the code to take care of this.
+ *
+ * Two buffers are added: An IP buffer and a "code" buffer.
+ *
+ * 1) Put the instruction pointer into the IP buffer
+ * and the new code into the "code" buffer.
+ * 2) Wait for any running NMIs to finish and set a flag that says
+ * we are modifying code, it is done in an atomic operation.
+ * 3) Write the code
+ * 4) clear the flag.
+ * 5) Wait for any running NMIs to finish.
+ *
+ * If an NMI is executed, the first thing it does is to call
+ * "ftrace_nmi_enter". This will check if the flag is set to write
+ * and if it is, it will write what is in the IP and "code" buffers.
+ *
+ * The trick is, it does not matter if everyone is writing the same
+ * content to the code location. Also, if a CPU is executing code
+ * it is OK to write to that code location if the contents being written
+ * are the same as what exists.
+ */
+#define MOD_CODE_WRITE_FLAG (1 << 31) /* set when NMI should do the write */
+static atomic_t nmi_running = ATOMIC_INIT(0);
+static int mod_code_status; /* holds return value of text write */
+static void *mod_code_ip; /* holds the IP to write to */
+static void *mod_code_newcode; /* holds the text to write to the IP */
+
+static unsigned nmi_wait_count;
+static atomic_t nmi_update_count = ATOMIC_INIT(0);
+
+int ftrace_arch_read_dyn_info(char *buf, int size)
+{
+ int r;
+
+ r = snprintf(buf, size, "%u %u",
+ nmi_wait_count,
+ atomic_read(&nmi_update_count));
+ return r;
+}
+
+static void clear_mod_flag(void)
+{
+ int old = atomic_read(&nmi_running);
+
+ for (;;) {
+ int new = old & ~MOD_CODE_WRITE_FLAG;
+
+ if (old == new)
+ break;
+
+ old = atomic_cmpxchg(&nmi_running, old, new);
+ }
+}
+
+static void ftrace_mod_code(void)
+{
+ /*
+ * Yes, more than one CPU process can be writing to mod_code_status.
+ * (and the code itself)
+ * But if one were to fail, then they all should, and if one were
+ * to succeed, then they all should.
+ */
+ mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
+ MCOUNT_INSN_SIZE);
+
+ /* if we fail, then kill any new writers */
+ if (mod_code_status)
+ clear_mod_flag();
+}
+
+void ftrace_nmi_enter(void)
+{
+ if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) {
+ smp_rmb();
+ ftrace_mod_code();
+ atomic_inc(&nmi_update_count);
+ }
+ /* Must have previous changes seen before executions */
+ smp_mb();
+}
+
+void ftrace_nmi_exit(void)
+{
+ /* Finish all executions before clearing nmi_running */
+ smp_mb();
+ atomic_dec(&nmi_running);
+}
+
+static void wait_for_nmi_and_set_mod_flag(void)
+{
+ if (!atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG))
+ return;
+
+ do {
+ cpu_relax();
+ } while (atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG));
+
+ nmi_wait_count++;
+}
+
+static void wait_for_nmi(void)
+{
+ if (!atomic_read(&nmi_running))
+ return;
+
+ do {
+ cpu_relax();
+ } while (atomic_read(&nmi_running));
+
+ nmi_wait_count++;
+}
+
+static int
+do_ftrace_mod_code(unsigned long ip, void *new_code)
+{
+ mod_code_ip = (void *)ip;
+ mod_code_newcode = new_code;
+
+ /* The buffers need to be visible before we let NMIs write them */
+ smp_mb();
+
+ wait_for_nmi_and_set_mod_flag();
+
+ /* Make sure all running NMIs have finished before we write the code */
+ smp_mb();
+
+ ftrace_mod_code();
+
+ /* Make sure the write happens before clearing the bit */
+ smp_mb();
+
+ clear_mod_flag();
+ wait_for_nmi();
+
+ return mod_code_status;
+}
+
static int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
unsigned char *new_code)
{
@@ -86,7 +230,7 @@ static int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
return -EINVAL;
/* replace the text with the new text */
- if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))
+ if (do_ftrace_mod_code(ip, new_code))
return -EPERM;
flush_icache_range(ip, ip + MCOUNT_INSN_SIZE);
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S
index a78be74b8d3..1151ecdffa7 100644
--- a/arch/sh/kernel/head_32.S
+++ b/arch/sh/kernel/head_32.S
@@ -33,7 +33,7 @@ ENTRY(empty_zero_page)
.long 1 /* LOADER_TYPE */
.long 0x00000000 /* INITRD_START */
.long 0x00000000 /* INITRD_SIZE */
-#ifdef CONFIG_32BIT
+#if defined(CONFIG_32BIT) && defined(CONFIG_PMB_FIXED)
.long 0x53453f00 + 32 /* "SE?" = 32 bit */
#else
.long 0x53453f00 + 29 /* "SE?" = 29 bit */
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c
index 27ff2dc093c..aaff0037fcd 100644
--- a/arch/sh/kernel/idle.c
+++ b/arch/sh/kernel/idle.c
@@ -21,7 +21,7 @@
#include <asm/atomic.h>
static int hlt_counter;
-void (*pm_idle)(void);
+void (*pm_idle)(void) = NULL;
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
@@ -39,48 +39,92 @@ static int __init hlt_setup(char *__unused)
}
__setup("hlt", hlt_setup);
+static inline int hlt_works(void)
+{
+ return !hlt_counter;
+}
+
+/*
+ * On SMP it's slightly faster (but much more power-consuming!)
+ * to poll the ->work.need_resched flag instead of waiting for the
+ * cross-CPU IPI to arrive. Use this option with caution.
+ */
+static void poll_idle(void)
+{
+ local_irq_enable();
+ while (!need_resched())
+ cpu_relax();
+}
+
void default_idle(void)
{
- if (!hlt_counter) {
+ if (hlt_works()) {
clear_thread_flag(TIF_POLLING_NRFLAG);
smp_mb__after_clear_bit();
- set_bl_bit();
- stop_critical_timings();
- while (!need_resched())
+ if (!need_resched()) {
+ local_irq_enable();
cpu_sleep();
+ } else
+ local_irq_enable();
- start_critical_timings();
- clear_bl_bit();
set_thread_flag(TIF_POLLING_NRFLAG);
} else
- while (!need_resched())
- cpu_relax();
+ poll_idle();
}
+/*
+ * The idle thread. There's no useful work to be done, so just try to conserve
+ * power and have a low exit latency (ie sit in a loop waiting for somebody to
+ * say that they'd like to reschedule)
+ */
void cpu_idle(void)
{
+ unsigned int cpu = smp_processor_id();
+
set_thread_flag(TIF_POLLING_NRFLAG);
/* endless idle loop with no priority at all */
while (1) {
- void (*idle)(void) = pm_idle;
+ tick_nohz_stop_sched_tick(1);
- if (!idle)
- idle = default_idle;
+ while (!need_resched() && cpu_online(cpu)) {
+ check_pgt_cache();
+ rmb();
- tick_nohz_stop_sched_tick(1);
- while (!need_resched())
- idle();
- tick_nohz_restart_sched_tick();
+ local_irq_disable();
+ /* Don't trace irqs off for idle */
+ stop_critical_timings();
+ pm_idle();
+ /*
+ * Sanity check to ensure that pm_idle() returns
+ * with IRQs enabled
+ */
+ WARN_ON(irqs_disabled());
+ start_critical_timings();
+ }
+ tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
preempt_disable();
- check_pgt_cache();
}
}
+void __cpuinit select_idle_routine(void)
+{
+ /*
+ * If a platform has set its own idle routine, leave it alone.
+ */
+ if (pm_idle)
+ return;
+
+ if (hlt_works())
+ pm_idle = default_idle;
+ else
+ pm_idle = poll_idle;
+}
+
static void do_nothing(void *unused)
{
}
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index eac7da772fc..7aa89fac1f8 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -37,7 +37,15 @@ void ack_bad_irq(unsigned int irq)
*/
static int show_other_interrupts(struct seq_file *p, int prec)
{
+ int j;
+
+ seq_printf(p, "%*s: ", prec, "NMI");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stat[j].__nmi_count);
+ seq_printf(p, " Non-maskable interrupts\n");
+
seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
+
return 0;
}
diff --git a/arch/sh/kernel/irq_32.c b/arch/sh/kernel/irq_32.c
new file mode 100644
index 00000000000..e33ab15831f
--- /dev/null
+++ b/arch/sh/kernel/irq_32.c
@@ -0,0 +1,57 @@
+/*
+ * SHcompact irqflags support
+ *
+ * Copyright (C) 2006 - 2009 Paul Mundt
+ *
+ * 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.
+ */
+#include <linux/irqflags.h>
+#include <linux/module.h>
+
+void notrace raw_local_irq_restore(unsigned long flags)
+{
+ unsigned long __dummy0, __dummy1;
+
+ if (flags == RAW_IRQ_DISABLED) {
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "or #0xf0, %0\n\t"
+ "ldc %0, sr\n\t"
+ : "=&z" (__dummy0)
+ : /* no inputs */
+ : "memory"
+ );
+ } else {
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "and %1, %0\n\t"
+#ifdef CONFIG_CPU_HAS_SR_RB
+ "stc r6_bank, %1\n\t"
+ "or %1, %0\n\t"
+#endif
+ "ldc %0, sr\n\t"
+ : "=&r" (__dummy0), "=r" (__dummy1)
+ : "1" (~RAW_IRQ_DISABLED)
+ : "memory"
+ );
+ }
+}
+EXPORT_SYMBOL(raw_local_irq_restore);
+
+unsigned long notrace __raw_local_save_flags(void)
+{
+ unsigned long flags;
+
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "and #0xf0, %0\n\t"
+ : "=&z" (flags)
+ : /* no inputs */
+ : "memory"
+ );
+
+ return flags;
+}
+EXPORT_SYMBOL(__raw_local_save_flags);
diff --git a/arch/sh/kernel/irq_64.c b/arch/sh/kernel/irq_64.c
new file mode 100644
index 00000000000..32365ba0e03
--- /dev/null
+++ b/arch/sh/kernel/irq_64.c
@@ -0,0 +1,51 @@
+/*
+ * SHmedia irqflags support
+ *
+ * Copyright (C) 2006 - 2009 Paul Mundt
+ *
+ * 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.
+ */
+#include <linux/irqflags.h>
+#include <linux/module.h>
+#include <cpu/registers.h>
+
+void notrace raw_local_irq_restore(unsigned long flags)
+{
+ unsigned long long __dummy;
+
+ if (flags == RAW_IRQ_DISABLED) {
+ __asm__ __volatile__ (
+ "getcon " __SR ", %0\n\t"
+ "or %0, %1, %0\n\t"
+ "putcon %0, " __SR "\n\t"
+ : "=&r" (__dummy)
+ : "r" (RAW_IRQ_DISABLED)
+ );
+ } else {
+ __asm__ __volatile__ (
+ "getcon " __SR ", %0\n\t"
+ "and %0, %1, %0\n\t"
+ "putcon %0, " __SR "\n\t"
+ : "=&r" (__dummy)
+ : "r" (~RAW_IRQ_DISABLED)
+ );
+ }
+}
+EXPORT_SYMBOL(raw_local_irq_restore);
+
+unsigned long notrace __raw_local_save_flags(void)
+{
+ unsigned long flags;
+
+ __asm__ __volatile__ (
+ "getcon " __SR ", %0\n\t"
+ "and %0, %1, %0"
+ : "=&r" (flags)
+ : "r" (RAW_IRQ_DISABLED)
+ );
+
+ return flags;
+}
+EXPORT_SYMBOL(__raw_local_save_flags);
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
index 7ea2704ea03..76f280223eb 100644
--- a/arch/sh/kernel/machine_kexec.c
+++ b/arch/sh/kernel/machine_kexec.c
@@ -46,12 +46,6 @@ void machine_crash_shutdown(struct pt_regs *regs)
*/
int machine_kexec_prepare(struct kimage *image)
{
- /* older versions of kexec-tools are passing
- * the zImage entry point as a virtual address.
- */
- if (image->start != PHYSADDR(image->start))
- return -EINVAL; /* upgrade your kexec-tools */
-
return 0;
}
diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c
index c2efdcde266..43adddfe4c0 100644
--- a/arch/sh/kernel/module.c
+++ b/arch/sh/kernel/module.c
@@ -32,6 +32,7 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <asm/unaligned.h>
+#include <asm/dwarf.h>
void *module_alloc(unsigned long size)
{
@@ -145,10 +146,16 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *me)
{
- return module_bug_finalize(hdr, sechdrs, me);
+ int ret = 0;
+
+ ret |= module_dwarf_finalize(hdr, sechdrs, me);
+ ret |= module_bug_finalize(hdr, sechdrs, me);
+
+ return ret;
}
void module_arch_cleanup(struct module *mod)
{
module_bug_cleanup(mod);
+ module_dwarf_cleanup(mod);
}
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 0673c4746be..a40342be32b 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -142,6 +142,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
return pid;
}
+EXPORT_SYMBOL(kernel_thread);
/*
* Free current thread data structures etc..
@@ -186,6 +187,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
return fpvalid;
}
+EXPORT_SYMBOL(dump_fpu);
asmlinkage void ret_from_fork(void);
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c
index 1192398ef58..359b8a2f4d2 100644
--- a/arch/sh/kernel/process_64.c
+++ b/arch/sh/kernel/process_64.c
@@ -335,6 +335,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
&regs, 0, NULL, NULL);
}
+EXPORT_SYMBOL(kernel_thread);
/*
* Free current thread data structures etc..
@@ -417,6 +418,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
return 0; /* Task didn't use the fpu at all. */
#endif
}
+EXPORT_SYMBOL(dump_fpu);
asmlinkage void ret_from_fork(void);
diff --git a/arch/sh/kernel/return_address.c b/arch/sh/kernel/return_address.c
new file mode 100644
index 00000000000..df3ab581107
--- /dev/null
+++ b/arch/sh/kernel/return_address.c
@@ -0,0 +1,54 @@
+/*
+ * arch/sh/kernel/return_address.c
+ *
+ * Copyright (C) 2009 Matt Fleming
+ * Copyright (C) 2009 Paul Mundt
+ *
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <asm/dwarf.h>
+
+#ifdef CONFIG_DWARF_UNWINDER
+
+void *return_address(unsigned int depth)
+{
+ struct dwarf_frame *frame;
+ unsigned long ra;
+ int i;
+
+ for (i = 0, frame = NULL, ra = 0; i <= depth; i++) {
+ struct dwarf_frame *tmp;
+
+ tmp = dwarf_unwind_stack(ra, frame);
+
+ if (frame)
+ dwarf_free_frame(frame);
+
+ frame = tmp;
+
+ if (!frame || !frame->return_addr)
+ break;
+
+ ra = frame->return_addr;
+ }
+
+ /* Failed to unwind the stack to the specified depth. */
+ WARN_ON(i != depth + 1);
+
+ if (frame)
+ dwarf_free_frame(frame);
+
+ return (void *)ra;
+}
+
+#else
+
+void *return_address(unsigned int depth)
+{
+ return NULL;
+}
+
+#endif
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 99b4fb553bf..5a947a2567e 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -453,6 +453,10 @@ void __init setup_arch(char **cmdline_p)
paging_init();
+#ifdef CONFIG_PMB_ENABLE
+ pmb_init();
+#endif
+
#ifdef CONFIG_SMP
plat_smp_setup();
#endif
diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c
index 444cce3ae92..3896f26efa4 100644
--- a/arch/sh/kernel/sh_ksyms_32.c
+++ b/arch/sh/kernel/sh_ksyms_32.c
@@ -1,37 +1,11 @@
#include <linux/module.h>
-#include <linux/smp.h>
-#include <linux/user.h>
-#include <linux/elfcore.h>
-#include <linux/sched.h>
-#include <linux/in6.h>
-#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <linux/pci.h>
-#include <linux/irq.h>
-#include <asm/sections.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
#include <asm/checksum.h>
-#include <asm/io.h>
-#include <asm/delay.h>
-#include <asm/tlbflush.h>
-#include <asm/cacheflush.h>
-#include <asm/ftrace.h>
-
-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-
-/* platform dependent support */
-EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(strlen);
-
-/* PCI exports */
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(pci_alloc_consistent);
-EXPORT_SYMBOL(pci_free_consistent);
-#endif
+#include <asm/sections.h>
-/* mem exports */
EXPORT_SYMBOL(memchr);
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memset);
@@ -40,6 +14,13 @@ EXPORT_SYMBOL(__copy_user);
EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(__ndelay);
EXPORT_SYMBOL(__const_udelay);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(csum_partial_copy_generic);
+EXPORT_SYMBOL(copy_page);
+EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(_ebss);
+EXPORT_SYMBOL(empty_zero_page);
#define DECLARE_EXPORT(name) \
extern void name(void);EXPORT_SYMBOL(name)
@@ -107,30 +88,6 @@ DECLARE_EXPORT(__sdivsi3_i4);
DECLARE_EXPORT(__udivsi3_i4);
DECLARE_EXPORT(__sdivsi3_i4i);
DECLARE_EXPORT(__udivsi3_i4i);
-
-#if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \
- defined(CONFIG_SH7705_CACHE_32KB))
-/* needed by some modules */
-EXPORT_SYMBOL(flush_cache_all);
-EXPORT_SYMBOL(flush_cache_range);
-EXPORT_SYMBOL(flush_dcache_page);
-#endif
-
#ifdef CONFIG_MCOUNT
DECLARE_EXPORT(mcount);
#endif
-EXPORT_SYMBOL(csum_partial);
-EXPORT_SYMBOL(csum_partial_copy_generic);
-#ifdef CONFIG_IPV6
-EXPORT_SYMBOL(csum_ipv6_magic);
-#endif
-EXPORT_SYMBOL(copy_page);
-EXPORT_SYMBOL(__clear_user);
-EXPORT_SYMBOL(_ebss);
-EXPORT_SYMBOL(empty_zero_page);
-
-#ifndef CONFIG_CACHE_OFF
-EXPORT_SYMBOL(__flush_purge_region);
-EXPORT_SYMBOL(__flush_wback_region);
-EXPORT_SYMBOL(__flush_invalidate_region);
-#endif
diff --git a/arch/sh/kernel/sh_ksyms_64.c b/arch/sh/kernel/sh_ksyms_64.c
index d008e17eb25..45afa5c51f6 100644
--- a/arch/sh/kernel/sh_ksyms_64.c
+++ b/arch/sh/kernel/sh_ksyms_64.c
@@ -24,16 +24,6 @@
#include <asm/delay.h>
#include <asm/irq.h>
-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-
-/* platform dependent support */
-EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(kernel_thread);
-
-#ifdef CONFIG_VT
-EXPORT_SYMBOL(screen_info);
-#endif
-
EXPORT_SYMBOL(__put_user_asm_b);
EXPORT_SYMBOL(__put_user_asm_w);
EXPORT_SYMBOL(__put_user_asm_l);
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index 3db37425210..12815ce01ec 100644
--- a/arch/sh/kernel/signal_32.c
+++ b/arch/sh/kernel/signal_32.c
@@ -67,7 +67,8 @@ sys_sigsuspend(old_sigset_t mask,
current->state = TASK_INTERRUPTIBLE;
schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
+
return -ERESTARTNOHAND;
}
@@ -590,7 +591,7 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
if (try_to_freeze())
goto no_signal;
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask;
else
oldset = &current->blocked;
@@ -602,12 +603,13 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
/* Whee! Actually deliver the signal. */
if (handle_signal(signr, &ka, &info, oldset,
regs, save_r0) == 0) {
- /* a signal was successfully delivered; the saved
+ /*
+ * A signal was successfully delivered; the saved
* sigmask will have been stored in the signal frame,
* and will be restored by sigreturn, so we can simply
- * clear the TIF_RESTORE_SIGMASK flag */
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ * clear the TS_RESTORE_SIGMASK flag
+ */
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
tracehook_signal_handler(signr, &info, &ka, regs,
test_thread_flag(TIF_SINGLESTEP));
@@ -631,10 +633,12 @@ no_signal:
}
}
- /* if there's no signal to deliver, we just put the saved sigmask
- * back */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ /*
+ * If there's no signal to deliver, we just put the saved sigmask
+ * back.
+ */
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
}
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index 74793c80a57..feb3dddd319 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -101,7 +101,7 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
if (try_to_freeze())
goto no_signal;
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask;
else if (!oldset)
oldset = &current->blocked;
@@ -115,11 +115,9 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
/*
* If a signal was successfully delivered, the
* saved sigmask is in its frame, and we can
- * clear the TIF_RESTORE_SIGMASK flag.
+ * clear the TS_RESTORE_SIGMASK flag.
*/
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
-
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
tracehook_signal_handler(signr, &info, &ka, regs, 0);
return 1;
}
@@ -146,8 +144,8 @@ no_signal:
}
/* No signal to deliver -- put the saved sigmask back */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
@@ -176,6 +174,7 @@ sys_sigsuspend(old_sigset_t mask,
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
+ set_restore_sigmask();
regs->pc += 4; /* because sys_sigreturn decrements the pc */
if (do_signal(regs, &saveset)) {
/* pc now points at signal handler. Need to decrement
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index 160db1003cf..983e0792d5f 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -122,7 +122,9 @@ int __cpuinit __cpu_up(unsigned int cpu)
stack_start.bss_start = 0; /* don't clear bss for secondary cpus */
stack_start.start_kernel_fn = start_secondary;
- flush_cache_all();
+ flush_icache_range((unsigned long)&stack_start,
+ (unsigned long)&stack_start + sizeof(stack_start));
+ wmb();
plat_start_cpu(cpu, (unsigned long)_stext);
diff --git a/arch/sh/kernel/topology.c b/arch/sh/kernel/topology.c
index 0838942b708..9b0b633b6c9 100644
--- a/arch/sh/kernel/topology.c
+++ b/arch/sh/kernel/topology.c
@@ -16,6 +16,32 @@
static DEFINE_PER_CPU(struct cpu, cpu_devices);
+cpumask_t cpu_core_map[NR_CPUS];
+
+static cpumask_t cpu_coregroup_map(unsigned int cpu)
+{
+ /*
+ * Presently all SH-X3 SMP cores are multi-cores, so just keep it
+ * simple until we have a method for determining topology..
+ */
+ return cpu_possible_map;
+}
+
+const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
+{
+ return &cpu_core_map[cpu];
+}
+
+int arch_update_cpu_topology(void)
+{
+ unsigned int cpu;
+
+ for_each_possible_cpu(cpu)
+ cpu_core_map[cpu] = cpu_coregroup_map(cpu);
+
+ return 0;
+}
+
static int __init topology_init(void)
{
int i, ret;
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index a8396f36bd1..d52695df270 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -95,9 +95,11 @@ BUILD_TRAP_HANDLER(bug)
BUILD_TRAP_HANDLER(nmi)
{
+ unsigned int cpu = smp_processor_id();
TRAP_HANDLER_DECL;
nmi_enter();
+ nmi_count(cpu)++;
switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) {
case NOTIFY_OK:
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index 7a2ee3a6b8e..114d2176182 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -945,14 +945,9 @@ void __init trap_init(void)
set_exception_table_evt(0x800, do_reserved_inst);
set_exception_table_evt(0x820, do_illegal_slot_inst);
#elif defined(CONFIG_SH_FPU)
-#ifdef CONFIG_CPU_SUBTYPE_SHX3
- set_exception_table_evt(0xd80, fpu_state_restore_trap_handler);
- set_exception_table_evt(0xda0, fpu_state_restore_trap_handler);
-#else
set_exception_table_evt(0x800, fpu_state_restore_trap_handler);
set_exception_table_evt(0x820, fpu_state_restore_trap_handler);
#endif
-#endif
#ifdef CONFIG_CPU_SH2
set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler);
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 7f7b52f9beb..a5e0867d8ae 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -83,7 +83,6 @@ config 32BIT
config PMB_ENABLE
bool "Support 32-bit physical addressing through PMB"
depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7757 || CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785)
- select 32BIT
default y
help
If you say Y here, physical addressing will be extended to
@@ -98,7 +97,6 @@ choice
config PMB
bool "PMB"
depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7757 || CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785)
- select 32BIT
help
If you say Y here, physical addressing will be extended to
32-bits through the SH-4A PMB. If this is not set, legacy
@@ -258,6 +256,15 @@ endchoice
source "mm/Kconfig"
+config SCHED_MC
+ bool "Multi-core scheduler support"
+ depends on SMP
+ default y
+ help
+ Multi-core scheduler support improves the CPU scheduler's decision
+ making when dealing with multi-core CPU chips at a cost of slightly
+ increased overhead in some places. If unsure say N here.
+
endmenu
menu "Cache configuration"
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index 3759bf85329..8a70535fa7c 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -33,8 +33,7 @@ obj-y += $(tlb-y)
endif
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
-obj-$(CONFIG_PMB) += pmb.o
-obj-$(CONFIG_PMB_FIXED) += pmb-fixed.o
+obj-$(CONFIG_PMB_ENABLE) += pmb.o
obj-$(CONFIG_NUMA) += numa.o
# Special flags for fault_64.o. This puts restrictions on the number of
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
index 519e2d16cd0..4a2fbf2864d 100644
--- a/arch/sh/mm/cache-sh4.c
+++ b/arch/sh/mm/cache-sh4.c
@@ -2,7 +2,7 @@
* arch/sh/mm/cache-sh4.c
*
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
- * Copyright (C) 2001 - 2007 Paul Mundt
+ * Copyright (C) 2001 - 2009 Paul Mundt
* Copyright (C) 2003 Richard Curnow
* Copyright (c) 2007 STMicroelectronics (R&D) Ltd.
*
@@ -15,6 +15,8 @@
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/fs.h>
+#include <linux/highmem.h>
+#include <asm/pgtable.h>
#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
@@ -23,21 +25,12 @@
* flushing. Anything exceeding this will simply flush the dcache in its
* entirety.
*/
-#define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */
#define MAX_ICACHE_PAGES 32
static void __flush_cache_one(unsigned long addr, unsigned long phys,
unsigned long exec_offset);
/*
- * This is initialised here to ensure that it is not placed in the BSS. If
- * that were to happen, note that cache_init gets called before the BSS is
- * cleared, so this would get nulled out which would be hopeless.
- */
-static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) =
- (void (*)(unsigned long, unsigned long))0xdeadbeef;
-
-/*
* Write back the range of D-cache, and purge the I-cache.
*
* Called from kernel/module.c:sys_init_module and routine for a.out format,
@@ -94,15 +87,16 @@ static inline void flush_cache_one(unsigned long start, unsigned long phys)
unsigned long flags, exec_offset = 0;
/*
- * All types of SH-4 require PC to be in P2 to operate on the I-cache.
- * Some types of SH-4 require PC to be in P2 to operate on the D-cache.
+ * All types of SH-4 require PC to be uncached to operate on the I-cache.
+ * Some types of SH-4 require PC to be uncached to operate on the D-cache.
*/
if ((boot_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) ||
(start < CACHE_OC_ADDRESS_ARRAY))
- exec_offset = 0x20000000;
+ exec_offset = cached_to_uncached;
local_irq_save(flags);
- __flush_cache_one(start | SH_CACHE_ASSOC, P1SEGADDR(phys), exec_offset);
+ __flush_cache_one(start | SH_CACHE_ASSOC,
+ virt_to_phys(phys), exec_offset);
local_irq_restore(flags);
}
@@ -121,13 +115,13 @@ static void sh4_flush_dcache_page(void *arg)
else
#endif
{
- unsigned long phys = PHYSADDR(page_address(page));
+ unsigned long phys = page_to_phys(page);
unsigned long addr = CACHE_OC_ADDRESS_ARRAY;
int i, n;
/* Loop all the D-cache */
n = boot_cpu_data.dcache.n_aliases;
- for (i = 0; i < n; i++, addr += PAGE_SIZE)
+ for (i = 0; i <= n; i++, addr += PAGE_SIZE)
flush_cache_one(addr, phys);
}
@@ -156,10 +150,27 @@ static void __uses_jump_to_uncached flush_icache_all(void)
local_irq_restore(flags);
}
-static inline void flush_dcache_all(void)
+static void flush_dcache_all(void)
{
- (*__flush_dcache_segment_fn)(0UL, boot_cpu_data.dcache.way_size);
- wmb();
+ unsigned long addr, end_addr, entry_offset;
+
+ end_addr = CACHE_OC_ADDRESS_ARRAY +
+ (current_cpu_data.dcache.sets <<
+ current_cpu_data.dcache.entry_shift) *
+ current_cpu_data.dcache.ways;
+
+ entry_offset = 1 << current_cpu_data.dcache.entry_shift;
+
+ for (addr = CACHE_OC_ADDRESS_ARRAY; addr < end_addr; ) {
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ }
}
static void sh4_flush_cache_all(void *unused)
@@ -168,89 +179,13 @@ static void sh4_flush_cache_all(void *unused)
flush_icache_all();
}
-static void __flush_cache_mm(struct mm_struct *mm, unsigned long start,
- unsigned long end)
-{
- unsigned long d = 0, p = start & PAGE_MASK;
- unsigned long alias_mask = boot_cpu_data.dcache.alias_mask;
- unsigned long n_aliases = boot_cpu_data.dcache.n_aliases;
- unsigned long select_bit;
- unsigned long all_aliases_mask;
- unsigned long addr_offset;
- pgd_t *dir;
- pmd_t *pmd;
- pud_t *pud;
- pte_t *pte;
- int i;
-
- dir = pgd_offset(mm, p);
- pud = pud_offset(dir, p);
- pmd = pmd_offset(pud, p);
- end = PAGE_ALIGN(end);
-
- all_aliases_mask = (1 << n_aliases) - 1;
-
- do {
- if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) {
- p &= PMD_MASK;
- p += PMD_SIZE;
- pmd++;
-
- continue;
- }
-
- pte = pte_offset_kernel(pmd, p);
-
- do {
- unsigned long phys;
- pte_t entry = *pte;
-
- if (!(pte_val(entry) & _PAGE_PRESENT)) {
- pte++;
- p += PAGE_SIZE;
- continue;
- }
-
- phys = pte_val(entry) & PTE_PHYS_MASK;
-
- if ((p ^ phys) & alias_mask) {
- d |= 1 << ((p & alias_mask) >> PAGE_SHIFT);
- d |= 1 << ((phys & alias_mask) >> PAGE_SHIFT);
-
- if (d == all_aliases_mask)
- goto loop_exit;
- }
-
- pte++;
- p += PAGE_SIZE;
- } while (p < end && ((unsigned long)pte & ~PAGE_MASK));
- pmd++;
- } while (p < end);
-
-loop_exit:
- addr_offset = 0;
- select_bit = 1;
-
- for (i = 0; i < n_aliases; i++) {
- if (d & select_bit) {
- (*__flush_dcache_segment_fn)(addr_offset, PAGE_SIZE);
- wmb();
- }
-
- select_bit <<= 1;
- addr_offset += PAGE_SIZE;
- }
-}
-
/*
* Note : (RPC) since the caches are physically tagged, the only point
* of flush_cache_mm for SH-4 is to get rid of aliases from the
* D-cache. The assumption elsewhere, e.g. flush_cache_range, is that
* lines can stay resident so long as the virtual address they were
* accessed with (hence cache set) is in accord with the physical
- * address (i.e. tag). It's no different here. So I reckon we don't
- * need to flush the I-cache, since aliases don't matter for that. We
- * should try that.
+ * address (i.e. tag). It's no different here.
*
* Caller takes mm->mmap_sem.
*/
@@ -261,33 +196,7 @@ static void sh4_flush_cache_mm(void *arg)
if (cpu_context(smp_processor_id(), mm) == NO_CONTEXT)
return;
- /*
- * If cache is only 4k-per-way, there are never any 'aliases'. Since
- * the cache is physically tagged, the data can just be left in there.
- */
- if (boot_cpu_data.dcache.n_aliases == 0)
- return;
-
- /*
- * Don't bother groveling around the dcache for the VMA ranges
- * if there are too many PTEs to make it worthwhile.
- */
- if (mm->nr_ptes >= MAX_DCACHE_PAGES)
- flush_dcache_all();
- else {
- struct vm_area_struct *vma;
-
- /*
- * In this case there are reasonably sized ranges to flush,
- * iterate through the VMA list and take care of any aliases.
- */
- for (vma = mm->mmap; vma; vma = vma->vm_next)
- __flush_cache_mm(mm, vma->vm_start, vma->vm_end);
- }
-
- /* Only touch the icache if one of the VMAs has VM_EXEC set. */
- if (mm->exec_vm)
- flush_icache_all();
+ flush_dcache_all();
}
/*
@@ -300,44 +209,63 @@ static void sh4_flush_cache_page(void *args)
{
struct flusher_data *data = args;
struct vm_area_struct *vma;
+ struct page *page;
unsigned long address, pfn, phys;
- unsigned int alias_mask;
+ int map_coherent = 0;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ void *vaddr;
vma = data->vma;
- address = data->addr1;
+ address = data->addr1 & PAGE_MASK;
pfn = data->addr2;
phys = pfn << PAGE_SHIFT;
+ page = pfn_to_page(pfn);
if (cpu_context(smp_processor_id(), vma->vm_mm) == NO_CONTEXT)
return;
- alias_mask = boot_cpu_data.dcache.alias_mask;
-
- /* We only need to flush D-cache when we have alias */
- if ((address^phys) & alias_mask) {
- /* Loop 4K of the D-cache */
- flush_cache_one(
- CACHE_OC_ADDRESS_ARRAY | (address & alias_mask),
- phys);
- /* Loop another 4K of the D-cache */
- flush_cache_one(
- CACHE_OC_ADDRESS_ARRAY | (phys & alias_mask),
- phys);
- }
+ pgd = pgd_offset(vma->vm_mm, address);
+ pud = pud_offset(pgd, address);
+ pmd = pmd_offset(pud, address);
+ pte = pte_offset_kernel(pmd, address);
+
+ /* If the page isn't present, there is nothing to do here. */
+ if (!(pte_val(*pte) & _PAGE_PRESENT))
+ return;
- alias_mask = boot_cpu_data.icache.alias_mask;
- if (vma->vm_flags & VM_EXEC) {
+ if ((vma->vm_mm == current->active_mm))
+ vaddr = NULL;
+ else {
/*
- * Evict entries from the portion of the cache from which code
- * may have been executed at this address (virtual). There's
- * no need to evict from the portion corresponding to the
- * physical address as for the D-cache, because we know the
- * kernel has never executed the code through its identity
- * translation.
+ * Use kmap_coherent or kmap_atomic to do flushes for
+ * another ASID than the current one.
*/
- flush_cache_one(
- CACHE_IC_ADDRESS_ARRAY | (address & alias_mask),
- phys);
+ map_coherent = (current_cpu_data.dcache.n_aliases &&
+ !test_bit(PG_dcache_dirty, &page->flags) &&
+ page_mapped(page));
+ if (map_coherent)
+ vaddr = kmap_coherent(page, address);
+ else
+ vaddr = kmap_atomic(page, KM_USER0);
+
+ address = (unsigned long)vaddr;
+ }
+
+ if (pages_do_alias(address, phys))
+ flush_cache_one(CACHE_OC_ADDRESS_ARRAY |
+ (address & shm_align_mask), phys);
+
+ if (vma->vm_flags & VM_EXEC)
+ flush_icache_all();
+
+ if (vaddr) {
+ if (map_coherent)
+ kunmap_coherent(vaddr);
+ else
+ kunmap_atomic(vaddr, KM_USER0);
}
}
@@ -370,24 +298,10 @@ static void sh4_flush_cache_range(void *args)
if (boot_cpu_data.dcache.n_aliases == 0)
return;
- /*
- * Don't bother with the lookup and alias check if we have a
- * wide range to cover, just blow away the dcache in its
- * entirety instead. -- PFM.
- */
- if (((end - start) >> PAGE_SHIFT) >= MAX_DCACHE_PAGES)
- flush_dcache_all();
- else
- __flush_cache_mm(vma->vm_mm, start, end);
+ flush_dcache_all();
- if (vma->vm_flags & VM_EXEC) {
- /*
- * TODO: Is this required??? Need to look at how I-cache
- * coherency is assured when new programs are loaded to see if
- * this matters.
- */
+ if (vma->vm_flags & VM_EXEC)
flush_icache_all();
- }
}
/**
@@ -461,245 +375,6 @@ static void __flush_cache_one(unsigned long addr, unsigned long phys,
} while (--way_count != 0);
}
-/*
- * Break the 1, 2 and 4 way variants of this out into separate functions to
- * avoid nearly all the overhead of having the conditional stuff in the function
- * bodies (+ the 1 and 2 way cases avoid saving any registers too).
- *
- * We want to eliminate unnecessary bus transactions, so this code uses
- * a non-obvious technique.
- *
- * Loop over a cache way sized block of, one cache line at a time. For each
- * line, use movca.a to cause the current cache line contents to be written
- * back, but without reading anything from main memory. However this has the
- * side effect that the cache is now caching that memory location. So follow
- * this with a cache invalidate to mark the cache line invalid. And do all
- * this with interrupts disabled, to avoid the cache line being accidently
- * evicted while it is holding garbage.
- *
- * This also breaks in a number of circumstances:
- * - if there are modifications to the region of memory just above
- * empty_zero_page (for example because a breakpoint has been placed
- * there), then these can be lost.
- *
- * This is because the the memory address which the cache temporarily
- * caches in the above description is empty_zero_page. So the
- * movca.l hits the cache (it is assumed that it misses, or at least
- * isn't dirty), modifies the line and then invalidates it, losing the
- * required change.
- *
- * - If caches are disabled or configured in write-through mode, then
- * the movca.l writes garbage directly into memory.
- */
-static void __flush_dcache_segment_writethrough(unsigned long start,
- unsigned long extent_per_way)
-{
- unsigned long addr;
- int i;
-
- addr = CACHE_OC_ADDRESS_ARRAY | (start & cpu_data->dcache.entry_mask);
-
- while (extent_per_way) {
- for (i = 0; i < cpu_data->dcache.ways; i++)
- __raw_writel(0, addr + cpu_data->dcache.way_incr * i);
-
- addr += cpu_data->dcache.linesz;
- extent_per_way -= cpu_data->dcache.linesz;
- }
-}
-
-static void __flush_dcache_segment_1way(unsigned long start,
- unsigned long extent_per_way)
-{
- unsigned long orig_sr, sr_with_bl;
- unsigned long base_addr;
- unsigned long way_incr, linesz, way_size;
- struct cache_info *dcache;
- register unsigned long a0, a0e;
-
- asm volatile("stc sr, %0" : "=r" (orig_sr));
- sr_with_bl = orig_sr | (1<<28);
- base_addr = ((unsigned long)&empty_zero_page[0]);
-
- /*
- * The previous code aligned base_addr to 16k, i.e. the way_size of all
- * existing SH-4 D-caches. Whilst I don't see a need to have this
- * aligned to any better than the cache line size (which it will be
- * anyway by construction), let's align it to at least the way_size of
- * any existing or conceivable SH-4 D-cache. -- RPC
- */
- base_addr = ((base_addr >> 16) << 16);
- base_addr |= start;
-
- dcache = &boot_cpu_data.dcache;
- linesz = dcache->linesz;
- way_incr = dcache->way_incr;
- way_size = dcache->way_size;
-
- a0 = base_addr;
- a0e = base_addr + extent_per_way;
- do {
- asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
- asm volatile("movca.l r0, @%0\n\t"
- "ocbi @%0" : : "r" (a0));
- a0 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "ocbi @%0" : : "r" (a0));
- a0 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "ocbi @%0" : : "r" (a0));
- a0 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "ocbi @%0" : : "r" (a0));
- asm volatile("ldc %0, sr" : : "r" (orig_sr));
- a0 += linesz;
- } while (a0 < a0e);
-}
-
-static void __flush_dcache_segment_2way(unsigned long start,
- unsigned long extent_per_way)
-{
- unsigned long orig_sr, sr_with_bl;
- unsigned long base_addr;
- unsigned long way_incr, linesz, way_size;
- struct cache_info *dcache;
- register unsigned long a0, a1, a0e;
-
- asm volatile("stc sr, %0" : "=r" (orig_sr));
- sr_with_bl = orig_sr | (1<<28);
- base_addr = ((unsigned long)&empty_zero_page[0]);
-
- /* See comment under 1-way above */
- base_addr = ((base_addr >> 16) << 16);
- base_addr |= start;
-
- dcache = &boot_cpu_data.dcache;
- linesz = dcache->linesz;
- way_incr = dcache->way_incr;
- way_size = dcache->way_size;
-
- a0 = base_addr;
- a1 = a0 + way_incr;
- a0e = base_addr + extent_per_way;
- do {
- asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1" : :
- "r" (a0), "r" (a1));
- a0 += linesz;
- a1 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1" : :
- "r" (a0), "r" (a1));
- a0 += linesz;
- a1 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1" : :
- "r" (a0), "r" (a1));
- a0 += linesz;
- a1 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1" : :
- "r" (a0), "r" (a1));
- asm volatile("ldc %0, sr" : : "r" (orig_sr));
- a0 += linesz;
- a1 += linesz;
- } while (a0 < a0e);
-}
-
-static void __flush_dcache_segment_4way(unsigned long start,
- unsigned long extent_per_way)
-{
- unsigned long orig_sr, sr_with_bl;
- unsigned long base_addr;
- unsigned long way_incr, linesz, way_size;
- struct cache_info *dcache;
- register unsigned long a0, a1, a2, a3, a0e;
-
- asm volatile("stc sr, %0" : "=r" (orig_sr));
- sr_with_bl = orig_sr | (1<<28);
- base_addr = ((unsigned long)&empty_zero_page[0]);
-
- /* See comment under 1-way above */
- base_addr = ((base_addr >> 16) << 16);
- base_addr |= start;
-
- dcache = &boot_cpu_data.dcache;
- linesz = dcache->linesz;
- way_incr = dcache->way_incr;
- way_size = dcache->way_size;
-
- a0 = base_addr;
- a1 = a0 + way_incr;
- a2 = a1 + way_incr;
- a3 = a2 + way_incr;
- a0e = base_addr + extent_per_way;
- do {
- asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "movca.l r0, @%2\n\t"
- "movca.l r0, @%3\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1\n\t"
- "ocbi @%2\n\t"
- "ocbi @%3\n\t" : :
- "r" (a0), "r" (a1), "r" (a2), "r" (a3));
- a0 += linesz;
- a1 += linesz;
- a2 += linesz;
- a3 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "movca.l r0, @%2\n\t"
- "movca.l r0, @%3\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1\n\t"
- "ocbi @%2\n\t"
- "ocbi @%3\n\t" : :
- "r" (a0), "r" (a1), "r" (a2), "r" (a3));
- a0 += linesz;
- a1 += linesz;
- a2 += linesz;
- a3 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "movca.l r0, @%2\n\t"
- "movca.l r0, @%3\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1\n\t"
- "ocbi @%2\n\t"
- "ocbi @%3\n\t" : :
- "r" (a0), "r" (a1), "r" (a2), "r" (a3));
- a0 += linesz;
- a1 += linesz;
- a2 += linesz;
- a3 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "movca.l r0, @%2\n\t"
- "movca.l r0, @%3\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1\n\t"
- "ocbi @%2\n\t"
- "ocbi @%3\n\t" : :
- "r" (a0), "r" (a1), "r" (a2), "r" (a3));
- asm volatile("ldc %0, sr" : : "r" (orig_sr));
- a0 += linesz;
- a1 += linesz;
- a2 += linesz;
- a3 += linesz;
- } while (a0 < a0e);
-}
-
extern void __weak sh4__flush_region_init(void);
/*
@@ -707,32 +382,11 @@ extern void __weak sh4__flush_region_init(void);
*/
void __init sh4_cache_init(void)
{
- unsigned int wt_enabled = !!(__raw_readl(CCR) & CCR_CACHE_WT);
-
printk("PVR=%08x CVR=%08x PRR=%08x\n",
ctrl_inl(CCN_PVR),
ctrl_inl(CCN_CVR),
ctrl_inl(CCN_PRR));
- if (wt_enabled)
- __flush_dcache_segment_fn = __flush_dcache_segment_writethrough;
- else {
- switch (boot_cpu_data.dcache.ways) {
- case 1:
- __flush_dcache_segment_fn = __flush_dcache_segment_1way;
- break;
- case 2:
- __flush_dcache_segment_fn = __flush_dcache_segment_2way;
- break;
- case 4:
- __flush_dcache_segment_fn = __flush_dcache_segment_4way;
- break;
- default:
- panic("unknown number of cache ways\n");
- break;
- }
- }
-
local_flush_icache_range = sh4_flush_icache_range;
local_flush_dcache_page = sh4_flush_dcache_page;
local_flush_cache_all = sh4_flush_cache_all;
diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c
index 2601935eb58..f527fb70fce 100644
--- a/arch/sh/mm/cache-sh7705.c
+++ b/arch/sh/mm/cache-sh7705.c
@@ -141,7 +141,7 @@ static void sh7705_flush_dcache_page(void *arg)
if (mapping && !mapping_mapped(mapping))
set_bit(PG_dcache_dirty, &page->flags);
else
- __flush_dcache_page(PHYSADDR(page_address(page)));
+ __flush_dcache_page(__pa(page_address(page)));
}
static void __uses_jump_to_uncached sh7705_flush_cache_all(void *args)
diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c
index a2dc7f9ecc5..63c132998f2 100644
--- a/arch/sh/mm/cache.c
+++ b/arch/sh/mm/cache.c
@@ -27,8 +27,11 @@ void (*local_flush_icache_page)(void *args) = cache_noop;
void (*local_flush_cache_sigtramp)(void *args) = cache_noop;
void (*__flush_wback_region)(void *start, int size);
+EXPORT_SYMBOL(__flush_wback_region);
void (*__flush_purge_region)(void *start, int size);
+EXPORT_SYMBOL(__flush_purge_region);
void (*__flush_invalidate_region)(void *start, int size);
+EXPORT_SYMBOL(__flush_invalidate_region);
static inline void noop__flush_region(void *start, int size)
{
@@ -161,14 +164,21 @@ void flush_cache_all(void)
{
cacheop_on_each_cpu(local_flush_cache_all, NULL, 1);
}
+EXPORT_SYMBOL(flush_cache_all);
void flush_cache_mm(struct mm_struct *mm)
{
+ if (boot_cpu_data.dcache.n_aliases == 0)
+ return;
+
cacheop_on_each_cpu(local_flush_cache_mm, mm, 1);
}
void flush_cache_dup_mm(struct mm_struct *mm)
{
+ if (boot_cpu_data.dcache.n_aliases == 0)
+ return;
+
cacheop_on_each_cpu(local_flush_cache_dup_mm, mm, 1);
}
@@ -195,11 +205,13 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
cacheop_on_each_cpu(local_flush_cache_range, (void *)&data, 1);
}
+EXPORT_SYMBOL(flush_cache_range);
void flush_dcache_page(struct page *page)
{
cacheop_on_each_cpu(local_flush_dcache_page, page, 1);
}
+EXPORT_SYMBOL(flush_dcache_page);
void flush_icache_range(unsigned long start, unsigned long end)
{
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index e098ec158dd..902967e3f84 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -15,11 +15,15 @@
#include <linux/dma-mapping.h>
#include <linux/dma-debug.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <asm/cacheflush.h>
#include <asm/addrspace.h>
#define PREALLOC_DMA_DEBUG_ENTRIES 4096
+struct dma_map_ops *dma_ops;
+EXPORT_SYMBOL(dma_ops);
+
static int __init dma_init(void)
{
dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
@@ -27,15 +31,12 @@ static int __init dma_init(void)
}
fs_initcall(dma_init);
-void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp)
+void *dma_generic_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
{
void *ret, *ret_nocache;
int order = get_order(size);
- if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
- return ret;
-
ret = (void *)__get_free_pages(gfp, order);
if (!ret)
return NULL;
@@ -57,35 +58,26 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
*dma_handle = virt_to_phys(ret);
- debug_dma_alloc_coherent(dev, size, *dma_handle, ret_nocache);
-
return ret_nocache;
}
-EXPORT_SYMBOL(dma_alloc_coherent);
-void dma_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+void dma_generic_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
{
int order = get_order(size);
unsigned long pfn = dma_handle >> PAGE_SHIFT;
int k;
- WARN_ON(irqs_disabled()); /* for portability */
-
- if (dma_release_from_coherent(dev, order, vaddr))
- return;
-
- debug_dma_free_coherent(dev, size, vaddr, dma_handle);
for (k = 0; k < (1 << order); k++)
__free_pages(pfn_to_page(pfn + k), 0);
+
iounmap(vaddr);
}
-EXPORT_SYMBOL(dma_free_coherent);
void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction)
{
-#ifdef CONFIG_CPU_SH5
+#if defined(CONFIG_CPU_SH5) || defined(CONFIG_PMB)
void *p1addr = vaddr;
#else
void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 8173e38afd3..432acd07e76 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -15,6 +15,7 @@
#include <linux/pagemap.h>
#include <linux/percpu.h>
#include <linux/io.h>
+#include <linux/dma-mapping.h>
#include <asm/mmu_context.h>
#include <asm/tlb.h>
#include <asm/cacheflush.h>
@@ -186,11 +187,21 @@ void __init paging_init(void)
set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start));
}
+/*
+ * Early initialization for any I/O MMUs we might have.
+ */
+static void __init iommu_init(void)
+{
+ no_iommu_init();
+}
+
void __init mem_init(void)
{
int codesize, datasize, initsize;
int nid;
+ iommu_init();
+
num_physpages = 0;
high_memory = NULL;
@@ -323,4 +334,12 @@ int memory_add_physaddr_to_nid(u64 addr)
}
EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
#endif
+
#endif /* CONFIG_MEMORY_HOTPLUG */
+
+#ifdef CONFIG_PMB
+int __in_29bit_mode(void)
+{
+ return !(ctrl_inl(PMB_PASCR) & PASCR_SE);
+}
+#endif /* CONFIG_PMB */
diff --git a/arch/sh/mm/kmap.c b/arch/sh/mm/kmap.c
index 16e01b5fed0..15d74ea4209 100644
--- a/arch/sh/mm/kmap.c
+++ b/arch/sh/mm/kmap.c
@@ -39,7 +39,9 @@ void *kmap_coherent(struct page *page, unsigned long addr)
pagefault_disable();
idx = FIX_CMAP_END -
- ((addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT);
+ (((addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1)) +
+ (FIX_N_COLOURS * smp_processor_id()));
+
vaddr = __fix_to_virt(idx);
BUG_ON(!pte_none(*(kmap_coherent_pte - idx)));
diff --git a/arch/sh/mm/pmb-fixed.c b/arch/sh/mm/pmb-fixed.c
deleted file mode 100644
index 43c8eac4d8a..00000000000
--- a/arch/sh/mm/pmb-fixed.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * arch/sh/mm/fixed_pmb.c
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- *
- * 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.
- */
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/io.h>
-#include <asm/mmu.h>
-#include <asm/mmu_context.h>
-
-static int __uses_jump_to_uncached fixed_pmb_init(void)
-{
- int i;
- unsigned long addr, data;
-
- jump_to_uncached();
-
- for (i = 0; i < PMB_ENTRY_MAX; i++) {
- addr = PMB_DATA + (i << PMB_E_SHIFT);
- data = ctrl_inl(addr);
- if (!(data & PMB_V))
- continue;
-
- if (data & PMB_C) {
-#if defined(CONFIG_CACHE_WRITETHROUGH)
- data |= PMB_WT;
-#elif defined(CONFIG_CACHE_WRITEBACK)
- data &= ~PMB_WT;
-#else
- data &= ~(PMB_C | PMB_WT);
-#endif
- }
- ctrl_outl(data, addr);
- }
-
- back_to_cached();
-
- return 0;
-}
-arch_initcall(fixed_pmb_init);
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index aade3110211..280f6a16603 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -35,29 +35,9 @@
static void __pmb_unmap(struct pmb_entry *);
-static struct kmem_cache *pmb_cache;
+static struct pmb_entry pmb_entry_list[NR_PMB_ENTRIES];
static unsigned long pmb_map;
-static struct pmb_entry pmb_init_map[] = {
- /* vpn ppn flags (ub/sz/c/wt) */
-
- /* P1 Section Mappings */
- { 0x80000000, 0x00000000, PMB_SZ_64M | PMB_C, },
- { 0x84000000, 0x04000000, PMB_SZ_64M | PMB_C, },
- { 0x88000000, 0x08000000, PMB_SZ_128M | PMB_C, },
- { 0x90000000, 0x10000000, PMB_SZ_64M | PMB_C, },
- { 0x94000000, 0x14000000, PMB_SZ_64M | PMB_C, },
- { 0x98000000, 0x18000000, PMB_SZ_64M | PMB_C, },
-
- /* P2 Section Mappings */
- { 0xa0000000, 0x00000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
- { 0xa4000000, 0x04000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
- { 0xa8000000, 0x08000000, PMB_UB | PMB_SZ_128M | PMB_WT, },
- { 0xb0000000, 0x10000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
- { 0xb4000000, 0x14000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
- { 0xb8000000, 0x18000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
-};
-
static inline unsigned long mk_pmb_entry(unsigned int entry)
{
return (entry & PMB_E_MASK) << PMB_E_SHIFT;
@@ -73,81 +53,68 @@ static inline unsigned long mk_pmb_data(unsigned int entry)
return mk_pmb_entry(entry) | PMB_DATA;
}
-static DEFINE_SPINLOCK(pmb_list_lock);
-static struct pmb_entry *pmb_list;
-
-static inline void pmb_list_add(struct pmb_entry *pmbe)
+static int pmb_alloc_entry(void)
{
- struct pmb_entry **p, *tmp;
+ unsigned int pos;
- p = &pmb_list;
- while ((tmp = *p) != NULL)
- p = &tmp->next;
+repeat:
+ pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
- pmbe->next = tmp;
- *p = pmbe;
-}
+ if (unlikely(pos > NR_PMB_ENTRIES))
+ return -ENOSPC;
-static inline void pmb_list_del(struct pmb_entry *pmbe)
-{
- struct pmb_entry **p, *tmp;
+ if (test_and_set_bit(pos, &pmb_map))
+ goto repeat;
- for (p = &pmb_list; (tmp = *p); p = &tmp->next)
- if (tmp == pmbe) {
- *p = tmp->next;
- return;
- }
+ return pos;
}
-struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
- unsigned long flags)
+static struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
+ unsigned long flags, int entry)
{
struct pmb_entry *pmbe;
+ int pos;
+
+ if (entry == PMB_NO_ENTRY) {
+ pos = pmb_alloc_entry();
+ if (pos < 0)
+ return ERR_PTR(pos);
+ } else {
+ if (test_bit(entry, &pmb_map))
+ return ERR_PTR(-ENOSPC);
+ pos = entry;
+ }
- pmbe = kmem_cache_alloc(pmb_cache, GFP_KERNEL);
+ pmbe = &pmb_entry_list[pos];
if (!pmbe)
return ERR_PTR(-ENOMEM);
pmbe->vpn = vpn;
pmbe->ppn = ppn;
pmbe->flags = flags;
-
- spin_lock_irq(&pmb_list_lock);
- pmb_list_add(pmbe);
- spin_unlock_irq(&pmb_list_lock);
+ pmbe->entry = pos;
return pmbe;
}
-void pmb_free(struct pmb_entry *pmbe)
+static void pmb_free(struct pmb_entry *pmbe)
{
- spin_lock_irq(&pmb_list_lock);
- pmb_list_del(pmbe);
- spin_unlock_irq(&pmb_list_lock);
+ int pos = pmbe->entry;
- kmem_cache_free(pmb_cache, pmbe);
+ pmbe->vpn = 0;
+ pmbe->ppn = 0;
+ pmbe->flags = 0;
+ pmbe->entry = 0;
+
+ clear_bit(pos, &pmb_map);
}
/*
* Must be in P2 for __set_pmb_entry()
*/
-int __set_pmb_entry(unsigned long vpn, unsigned long ppn,
- unsigned long flags, int *entry)
+static void __set_pmb_entry(unsigned long vpn, unsigned long ppn,
+ unsigned long flags, int pos)
{
- unsigned int pos = *entry;
-
- if (unlikely(pos == PMB_NO_ENTRY))
- pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
-
-repeat:
- if (unlikely(pos > NR_PMB_ENTRIES))
- return -ENOSPC;
-
- if (test_and_set_bit(pos, &pmb_map)) {
- pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
- goto repeat;
- }
-
ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos));
#ifdef CONFIG_CACHE_WRITETHROUGH
@@ -161,35 +128,21 @@ repeat:
#endif
ctrl_outl(ppn | flags | PMB_V, mk_pmb_data(pos));
-
- *entry = pos;
-
- return 0;
}
-int __uses_jump_to_uncached set_pmb_entry(struct pmb_entry *pmbe)
+static void __uses_jump_to_uncached set_pmb_entry(struct pmb_entry *pmbe)
{
- int ret;
-
jump_to_uncached();
- ret = __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &pmbe->entry);
+ __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, pmbe->entry);
back_to_cached();
-
- return ret;
}
-void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe)
+static void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe)
{
unsigned int entry = pmbe->entry;
unsigned long addr;
- /*
- * Don't allow clearing of wired init entries, P1 or P2 access
- * without a corresponding mapping in the PMB will lead to reset
- * by the TLB.
- */
- if (unlikely(entry < ARRAY_SIZE(pmb_init_map) ||
- entry >= NR_PMB_ENTRIES))
+ if (unlikely(entry >= NR_PMB_ENTRIES))
return;
jump_to_uncached();
@@ -202,8 +155,6 @@ void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe)
ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr);
back_to_cached();
-
- clear_bit(entry, &pmb_map);
}
@@ -239,23 +190,17 @@ long pmb_remap(unsigned long vaddr, unsigned long phys,
again:
for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) {
- int ret;
-
if (size < pmb_sizes[i].size)
continue;
- pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag);
+ pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag,
+ PMB_NO_ENTRY);
if (IS_ERR(pmbe)) {
err = PTR_ERR(pmbe);
goto out;
}
- ret = set_pmb_entry(pmbe);
- if (ret != 0) {
- pmb_free(pmbe);
- err = -EBUSY;
- goto out;
- }
+ set_pmb_entry(pmbe);
phys += pmb_sizes[i].size;
vaddr += pmb_sizes[i].size;
@@ -292,11 +237,16 @@ out:
void pmb_unmap(unsigned long addr)
{
- struct pmb_entry **p, *pmbe;
+ struct pmb_entry *pmbe = NULL;
+ int i;
- for (p = &pmb_list; (pmbe = *p); p = &pmbe->next)
- if (pmbe->vpn == addr)
- break;
+ for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) {
+ if (test_bit(i, &pmb_map)) {
+ pmbe = &pmb_entry_list[i];
+ if (pmbe->vpn == addr)
+ break;
+ }
+ }
if (unlikely(!pmbe))
return;
@@ -306,13 +256,22 @@ void pmb_unmap(unsigned long addr)
static void __pmb_unmap(struct pmb_entry *pmbe)
{
- WARN_ON(!test_bit(pmbe->entry, &pmb_map));
+ BUG_ON(!test_bit(pmbe->entry, &pmb_map));
do {
struct pmb_entry *pmblink = pmbe;
- if (pmbe->entry != PMB_NO_ENTRY)
- clear_pmb_entry(pmbe);
+ /*
+ * We may be called before this pmb_entry has been
+ * entered into the PMB table via set_pmb_entry(), but
+ * that's OK because we've allocated a unique slot for
+ * this entry in pmb_alloc() (even if we haven't filled
+ * it yet).
+ *
+ * Therefore, calling clear_pmb_entry() is safe as no
+ * other mapping can be using that slot.
+ */
+ clear_pmb_entry(pmbe);
pmbe = pmblink->link;
@@ -320,42 +279,34 @@ static void __pmb_unmap(struct pmb_entry *pmbe)
} while (pmbe);
}
-static void pmb_cache_ctor(void *pmb)
+#ifdef CONFIG_PMB
+int __uses_jump_to_uncached pmb_init(void)
{
- struct pmb_entry *pmbe = pmb;
-
- memset(pmb, 0, sizeof(struct pmb_entry));
-
- pmbe->entry = PMB_NO_ENTRY;
-}
-
-static int __uses_jump_to_uncached pmb_init(void)
-{
- unsigned int nr_entries = ARRAY_SIZE(pmb_init_map);
- unsigned int entry, i;
-
- BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES));
-
- pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0,
- SLAB_PANIC, pmb_cache_ctor);
+ unsigned int i;
+ long size, ret;
jump_to_uncached();
/*
- * Ordering is important, P2 must be mapped in the PMB before we
- * can set PMB.SE, and P1 must be mapped before we jump back to
- * P1 space.
+ * Insert PMB entries for the P1 and P2 areas so that, after
+ * we've switched the MMU to 32-bit mode, the semantics of P1
+ * and P2 are the same as in 29-bit mode, e.g.
+ *
+ * P1 - provides a cached window onto physical memory
+ * P2 - provides an uncached window onto physical memory
*/
- for (entry = 0; entry < nr_entries; entry++) {
- struct pmb_entry *pmbe = pmb_init_map + entry;
+ size = __MEMORY_START + __MEMORY_SIZE;
- __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &entry);
- }
+ ret = pmb_remap(P1SEG, 0x00000000, size, PMB_C);
+ BUG_ON(ret != size);
+
+ ret = pmb_remap(P2SEG, 0x00000000, size, PMB_WT | PMB_UB);
+ BUG_ON(ret != size);
ctrl_outl(0, PMB_IRMCR);
/* PMB.SE and UB[7] */
- ctrl_outl((1 << 31) | (1 << 7), PMB_PASCR);
+ ctrl_outl(PASCR_SE | (1 << 7), PMB_PASCR);
/* Flush out the TLB */
i = ctrl_inl(MMUCR);
@@ -366,7 +317,53 @@ static int __uses_jump_to_uncached pmb_init(void)
return 0;
}
-arch_initcall(pmb_init);
+#else
+int __uses_jump_to_uncached pmb_init(void)
+{
+ int i;
+ unsigned long addr, data;
+
+ jump_to_uncached();
+
+ for (i = 0; i < PMB_ENTRY_MAX; i++) {
+ struct pmb_entry *pmbe;
+ unsigned long vpn, ppn, flags;
+
+ addr = PMB_DATA + (i << PMB_E_SHIFT);
+ data = ctrl_inl(addr);
+ if (!(data & PMB_V))
+ continue;
+
+ if (data & PMB_C) {
+#if defined(CONFIG_CACHE_WRITETHROUGH)
+ data |= PMB_WT;
+#elif defined(CONFIG_CACHE_WRITEBACK)
+ data &= ~PMB_WT;
+#else
+ data &= ~(PMB_C | PMB_WT);
+#endif
+ }
+ ctrl_outl(data, addr);
+
+ ppn = data & PMB_PFN_MASK;
+
+ flags = data & (PMB_C | PMB_WT | PMB_UB);
+ flags |= data & PMB_SZ_MASK;
+
+ addr = PMB_ADDR + (i << PMB_E_SHIFT);
+ data = ctrl_inl(addr);
+
+ vpn = data & PMB_PFN_MASK;
+
+ pmbe = pmb_alloc(vpn, ppn, flags, i);
+ WARN_ON(IS_ERR(pmbe));
+ }
+
+ back_to_cached();
+
+ return 0;
+}
+#endif /* CONFIG_PMB */
static int pmb_seq_show(struct seq_file *file, void *iter)
{
@@ -434,15 +431,18 @@ postcore_initcall(pmb_debugfs_init);
static int pmb_sysdev_suspend(struct sys_device *dev, pm_message_t state)
{
static pm_message_t prev_state;
+ int i;
/* Restore the PMB after a resume from hibernation */
if (state.event == PM_EVENT_ON &&
prev_state.event == PM_EVENT_FREEZE) {
struct pmb_entry *pmbe;
- spin_lock_irq(&pmb_list_lock);
- for (pmbe = pmb_list; pmbe; pmbe = pmbe->next)
- set_pmb_entry(pmbe);
- spin_unlock_irq(&pmb_list_lock);
+ for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) {
+ if (test_bit(i, &pmb_map)) {
+ pmbe = &pmb_entry_list[i];
+ set_pmb_entry(pmbe);
+ }
+ }
}
prev_state = state;
return 0;