summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/sh/Kconfig14
-rw-r--r--arch/sh/boards/mach-cayman/irq.c16
-rw-r--r--arch/sh/boards/mach-dreamcast/irq.c17
-rw-r--r--arch/sh/boards/mach-landisk/irq.c15
-rw-r--r--arch/sh/boards/mach-microdev/irq.c30
-rw-r--r--arch/sh/boards/mach-se/7206/irq.c20
-rw-r--r--arch/sh/boards/mach-se/7343/irq.c15
-rw-r--r--arch/sh/boards/mach-se/7722/irq.c15
-rw-r--r--arch/sh/boards/mach-se/7724/irq.c13
-rw-r--r--arch/sh/boards/mach-systemh/irq.c57
-rw-r--r--arch/sh/boards/mach-x3proto/gpio.c7
-rw-r--r--arch/sh/cchips/hd6446x/hd64461.c19
-rw-r--r--arch/sh/include/asm/pgtable.h2
-rw-r--r--arch/sh/include/asm/pgtable_32.h2
-rw-r--r--arch/sh/include/asm/pgtable_64.h9
-rw-r--r--arch/sh/include/asm/processor.h1
-rw-r--r--arch/sh/kernel/cpu/init.c2
-rw-r--r--arch/sh/kernel/cpu/irq/imask.c14
-rw-r--r--arch/sh/kernel/cpu/irq/intc-sh5.c49
-rw-r--r--arch/sh/kernel/cpu/irq/ipr.c29
-rw-r--r--arch/sh/kernel/cpu/sh4/perf_event.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/perf_event.c2
-rw-r--r--arch/sh/kernel/irq.c37
-rw-r--r--arch/sh/kernel/irq_64.c16
-rw-r--r--arch/sh/kernel/setup.c4
-rw-r--r--arch/sh/mm/Makefile2
-rw-r--r--arch/sh/mm/gup.c273
-rw-r--r--arch/sh/oprofile/Makefile2
-rw-r--r--arch/sh/oprofile/backtrace.c2
-rw-r--r--arch/sh/oprofile/common.c35
30 files changed, 478 insertions, 243 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 0f40fc35d0a2..792cf902743a 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -25,8 +25,11 @@ config SUPERH
select HAVE_KERNEL_LZO
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_REGS_AND_STACK_ACCESS_API
+ select HAVE_GENERIC_HARDIRQS
+ select HAVE_SPARSE_IRQ
select RTC_LIB
select GENERIC_ATOMIC64
+ select GENERIC_HARDIRQS_NO_DEPRECATED
help
The SuperH is a RISC processor targeted for use in embedded systems
and consumer electronics; it was also used in the Sega Dreamcast
@@ -49,6 +52,7 @@ config SUPERH32
select HAVE_MIXED_BREAKPOINTS_REGS
select PERF_EVENTS
select ARCH_HIBERNATION_POSSIBLE if MMU
+ select SPARSE_IRQ
config SUPERH64
def_bool ARCH = "sh64"
@@ -78,19 +82,9 @@ config GENERIC_FIND_NEXT_BIT
config GENERIC_HWEIGHT
def_bool y
-config GENERIC_HARDIRQS
- def_bool y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
- def_bool y
-
config IRQ_PER_CPU
def_bool y
-config SPARSE_IRQ
- def_bool y
- depends on SUPERH32
-
config GENERIC_GPIO
def_bool n
diff --git a/arch/sh/boards/mach-cayman/irq.c b/arch/sh/boards/mach-cayman/irq.c
index 1394b078db36..d7ac5af9d102 100644
--- a/arch/sh/boards/mach-cayman/irq.c
+++ b/arch/sh/boards/mach-cayman/irq.c
@@ -55,8 +55,9 @@ static struct irqaction cayman_action_pci2 = {
.flags = IRQF_DISABLED,
};
-static void enable_cayman_irq(unsigned int irq)
+static void enable_cayman_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
unsigned long flags;
unsigned long mask;
unsigned int reg;
@@ -72,8 +73,9 @@ static void enable_cayman_irq(unsigned int irq)
local_irq_restore(flags);
}
-void disable_cayman_irq(unsigned int irq)
+static void disable_cayman_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
unsigned long flags;
unsigned long mask;
unsigned int reg;
@@ -89,16 +91,10 @@ void disable_cayman_irq(unsigned int irq)
local_irq_restore(flags);
}
-static void ack_cayman_irq(unsigned int irq)
-{
- disable_cayman_irq(irq);
-}
-
struct irq_chip cayman_irq_type = {
.name = "Cayman-IRQ",
- .unmask = enable_cayman_irq,
- .mask = disable_cayman_irq,
- .mask_ack = ack_cayman_irq,
+ .irq_unmask = enable_cayman_irq,
+ .irq_mask = disable_cayman_irq,
};
int cayman_irq_demux(int evt)
diff --git a/arch/sh/boards/mach-dreamcast/irq.c b/arch/sh/boards/mach-dreamcast/irq.c
index d932667410ab..72e7ac9549da 100644
--- a/arch/sh/boards/mach-dreamcast/irq.c
+++ b/arch/sh/boards/mach-dreamcast/irq.c
@@ -60,8 +60,9 @@
*/
/* Disable the hardware event by masking its bit in its EMR */
-static inline void disable_systemasic_irq(unsigned int irq)
+static inline void disable_systemasic_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
__u32 mask;
@@ -71,8 +72,9 @@ static inline void disable_systemasic_irq(unsigned int irq)
}
/* Enable the hardware event by setting its bit in its EMR */
-static inline void enable_systemasic_irq(unsigned int irq)
+static inline void enable_systemasic_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
__u32 mask;
@@ -82,18 +84,19 @@ static inline void enable_systemasic_irq(unsigned int irq)
}
/* Acknowledge a hardware event by writing its bit back to its ESR */
-static void mask_ack_systemasic_irq(unsigned int irq)
+static void mask_ack_systemasic_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
__u32 esr = ESR_BASE + (LEVEL(irq) << 2);
- disable_systemasic_irq(irq);
+ disable_systemasic_irq(data);
outl((1 << EVENT_BIT(irq)), esr);
}
struct irq_chip systemasic_int = {
.name = "System ASIC",
- .mask = disable_systemasic_irq,
- .mask_ack = mask_ack_systemasic_irq,
- .unmask = enable_systemasic_irq,
+ .irq_mask = disable_systemasic_irq,
+ .irq_mask_ack = mask_ack_systemasic_irq,
+ .irq_unmask = enable_systemasic_irq,
};
/*
diff --git a/arch/sh/boards/mach-landisk/irq.c b/arch/sh/boards/mach-landisk/irq.c
index 96f38a4187d0..e79412a40490 100644
--- a/arch/sh/boards/mach-landisk/irq.c
+++ b/arch/sh/boards/mach-landisk/irq.c
@@ -18,25 +18,24 @@
#include <linux/io.h>
#include <mach-landisk/mach/iodata_landisk.h>
-static void disable_landisk_irq(unsigned int irq)
+static void disable_landisk_irq(struct irq_data *data)
{
- unsigned char mask = 0xff ^ (0x01 << (irq - 5));
+ unsigned char mask = 0xff ^ (0x01 << (data->irq - 5));
__raw_writeb(__raw_readb(PA_IMASK) & mask, PA_IMASK);
}
-static void enable_landisk_irq(unsigned int irq)
+static void enable_landisk_irq(struct irq_data *data)
{
- unsigned char value = (0x01 << (irq - 5));
+ unsigned char value = (0x01 << (data->irq - 5));
__raw_writeb(__raw_readb(PA_IMASK) | value, PA_IMASK);
}
static struct irq_chip landisk_irq_chip __read_mostly = {
.name = "LANDISK",
- .mask = disable_landisk_irq,
- .unmask = enable_landisk_irq,
- .mask_ack = disable_landisk_irq,
+ .irq_mask = disable_landisk_irq,
+ .irq_unmask = enable_landisk_irq,
};
/*
@@ -50,7 +49,7 @@ void __init init_landisk_IRQ(void)
disable_irq_nosync(i);
set_irq_chip_and_handler_name(i, &landisk_irq_chip,
handle_level_irq, "level");
- enable_landisk_irq(i);
+ enable_landisk_irq(irq_get_irq_data(i));
}
__raw_writeb(0x00, PA_PWRINT_CLR);
}
diff --git a/arch/sh/boards/mach-microdev/irq.c b/arch/sh/boards/mach-microdev/irq.c
index a26d16669aa2..c35001fd9032 100644
--- a/arch/sh/boards/mach-microdev/irq.c
+++ b/arch/sh/boards/mach-microdev/irq.c
@@ -65,19 +65,9 @@ static const struct {
# error Inconsistancy in defining the IRQ# for primary IDE!
#endif
-static void enable_microdev_irq(unsigned int irq);
-static void disable_microdev_irq(unsigned int irq);
-static void mask_and_ack_microdev(unsigned int);
-
-static struct irq_chip microdev_irq_type = {
- .name = "MicroDev-IRQ",
- .unmask = enable_microdev_irq,
- .mask = disable_microdev_irq,
- .ack = mask_and_ack_microdev,
-};
-
-static void disable_microdev_irq(unsigned int irq)
+static void disable_microdev_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
unsigned int fpgaIrq;
if (irq >= NUM_EXTERNAL_IRQS)
@@ -91,8 +81,9 @@ static void disable_microdev_irq(unsigned int irq)
__raw_writel(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTDSB_REG);
}
-static void enable_microdev_irq(unsigned int irq)
+static void enable_microdev_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
unsigned long priorityReg, priorities, pri;
unsigned int fpgaIrq;
@@ -116,17 +107,18 @@ static void enable_microdev_irq(unsigned int irq)
__raw_writel(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTENB_REG);
}
+static struct irq_chip microdev_irq_type = {
+ .name = "MicroDev-IRQ",
+ .irq_unmask = enable_microdev_irq,
+ .irq_mask = disable_microdev_irq,
+};
+
/* This function sets the desired irq handler to be a MicroDev type */
static void __init make_microdev_irq(unsigned int irq)
{
disable_irq_nosync(irq);
set_irq_chip_and_handler(irq, &microdev_irq_type, handle_level_irq);
- disable_microdev_irq(irq);
-}
-
-static void mask_and_ack_microdev(unsigned int irq)
-{
- disable_microdev_irq(irq);
+ disable_microdev_irq(irq_get_irq_data(irq));
}
extern void __init init_microdev_irq(void)
diff --git a/arch/sh/boards/mach-se/7206/irq.c b/arch/sh/boards/mach-se/7206/irq.c
index 8d82175d83ab..883b21eacaa6 100644
--- a/arch/sh/boards/mach-se/7206/irq.c
+++ b/arch/sh/boards/mach-se/7206/irq.c
@@ -25,8 +25,9 @@
#define INTC_IPR01 0xfffe0818
#define INTC_ICR1 0xfffe0802
-static void disable_se7206_irq(unsigned int irq)
+static void disable_se7206_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
unsigned short val;
unsigned short mask = 0xffff ^ (0x0f << 4 * (3 - (IRQ0_IRQ - irq)));
unsigned short msk0,msk1;
@@ -55,8 +56,9 @@ static void disable_se7206_irq(unsigned int irq)
__raw_writew(msk1, INTMSK1);
}
-static void enable_se7206_irq(unsigned int irq)
+static void enable_se7206_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
unsigned short val;
unsigned short value = (0x0001 << 4 * (3 - (IRQ0_IRQ - irq)));
unsigned short msk0,msk1;
@@ -86,13 +88,14 @@ static void enable_se7206_irq(unsigned int irq)
__raw_writew(msk1, INTMSK1);
}
-static void eoi_se7206_irq(unsigned int irq)
+static void eoi_se7206_irq(struct irq_data *data)
{
unsigned short sts0,sts1;
+ unsigned int irq = data->irq;
struct irq_desc *desc = irq_to_desc(irq);
if (!(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- enable_se7206_irq(irq);
+ enable_se7206_irq(data);
/* FPGA isr clear */
sts0 = __raw_readw(INTSTS0);
sts1 = __raw_readw(INTSTS1);
@@ -115,10 +118,9 @@ static void eoi_se7206_irq(unsigned int irq)
static struct irq_chip se7206_irq_chip __read_mostly = {
.name = "SE7206-FPGA",
- .mask = disable_se7206_irq,
- .unmask = enable_se7206_irq,
- .mask_ack = disable_se7206_irq,
- .eoi = eoi_se7206_irq,
+ .irq_mask = disable_se7206_irq,
+ .irq_unmask = enable_se7206_irq,
+ .irq_eoi = eoi_se7206_irq,
};
static void make_se7206_irq(unsigned int irq)
@@ -126,7 +128,7 @@ static void make_se7206_irq(unsigned int irq)
disable_irq_nosync(irq);
set_irq_chip_and_handler_name(irq, &se7206_irq_chip,
handle_level_irq, "level");
- disable_se7206_irq(irq);
+ disable_se7206_irq(irq_get_irq_data(irq));
}
/*
diff --git a/arch/sh/boards/mach-se/7343/irq.c b/arch/sh/boards/mach-se/7343/irq.c
index d4305c26e9f7..76255a19417f 100644
--- a/arch/sh/boards/mach-se/7343/irq.c
+++ b/arch/sh/boards/mach-se/7343/irq.c
@@ -18,23 +18,22 @@
unsigned int se7343_fpga_irq[SE7343_FPGA_IRQ_NR] = { 0, };
-static void disable_se7343_irq(unsigned int irq)
+static void disable_se7343_irq(struct irq_data *data)
{
- unsigned int bit = (unsigned int)get_irq_chip_data(irq);
+ unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
__raw_writew(__raw_readw(PA_CPLD_IMSK) | 1 << bit, PA_CPLD_IMSK);
}
-static void enable_se7343_irq(unsigned int irq)
+static void enable_se7343_irq(struct irq_data *data)
{
- unsigned int bit = (unsigned int)get_irq_chip_data(irq);
+ unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
__raw_writew(__raw_readw(PA_CPLD_IMSK) & ~(1 << bit), PA_CPLD_IMSK);
}
static struct irq_chip se7343_irq_chip __read_mostly = {
- .name = "SE7343-FPGA",
- .mask = disable_se7343_irq,
- .unmask = enable_se7343_irq,
- .mask_ack = disable_se7343_irq,
+ .name = "SE7343-FPGA",
+ .irq_mask = disable_se7343_irq,
+ .irq_unmask = enable_se7343_irq,
};
static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc)
diff --git a/arch/sh/boards/mach-se/7722/irq.c b/arch/sh/boards/mach-se/7722/irq.c
index 61605db04ee6..c013f95628ed 100644
--- a/arch/sh/boards/mach-se/7722/irq.c
+++ b/arch/sh/boards/mach-se/7722/irq.c
@@ -18,23 +18,22 @@
unsigned int se7722_fpga_irq[SE7722_FPGA_IRQ_NR] = { 0, };
-static void disable_se7722_irq(unsigned int irq)
+static void disable_se7722_irq(struct irq_data *data)
{
- unsigned int bit = (unsigned int)get_irq_chip_data(irq);
+ unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
__raw_writew(__raw_readw(IRQ01_MASK) | 1 << bit, IRQ01_MASK);
}
-static void enable_se7722_irq(unsigned int irq)
+static void enable_se7722_irq(struct irq_data *data)
{
- unsigned int bit = (unsigned int)get_irq_chip_data(irq);
+ unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
__raw_writew(__raw_readw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK);
}
static struct irq_chip se7722_irq_chip __read_mostly = {
- .name = "SE7722-FPGA",
- .mask = disable_se7722_irq,
- .unmask = enable_se7722_irq,
- .mask_ack = disable_se7722_irq,
+ .name = "SE7722-FPGA",
+ .irq_mask = disable_se7722_irq,
+ .irq_unmask = enable_se7722_irq,
};
static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
diff --git a/arch/sh/boards/mach-se/7724/irq.c b/arch/sh/boards/mach-se/7724/irq.c
index 0942be2daef6..5bd87c22b65b 100644
--- a/arch/sh/boards/mach-se/7724/irq.c
+++ b/arch/sh/boards/mach-se/7724/irq.c
@@ -68,25 +68,26 @@ static struct fpga_irq get_fpga_irq(unsigned int irq)
return set;
}
-static void disable_se7724_irq(unsigned int irq)
+static void disable_se7724_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
unsigned int bit = irq - set.base;
__raw_writew(__raw_readw(set.mraddr) | 0x0001 << bit, set.mraddr);
}
-static void enable_se7724_irq(unsigned int irq)
+static void enable_se7724_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
unsigned int bit = irq - set.base;
__raw_writew(__raw_readw(set.mraddr) & ~(0x0001 << bit), set.mraddr);
}
static struct irq_chip se7724_irq_chip __read_mostly = {
- .name = "SE7724-FPGA",
- .mask = disable_se7724_irq,
- .unmask = enable_se7724_irq,
- .mask_ack = disable_se7724_irq,
+ .name = "SE7724-FPGA",
+ .irq_mask = disable_se7724_irq,
+ .irq_unmask = enable_se7724_irq,
};
static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc)
diff --git a/arch/sh/boards/mach-systemh/irq.c b/arch/sh/boards/mach-systemh/irq.c
index 523aea5dc94e..e5ee13adeff4 100644
--- a/arch/sh/boards/mach-systemh/irq.c
+++ b/arch/sh/boards/mach-systemh/irq.c
@@ -23,54 +23,39 @@
static unsigned long *systemh_irq_mask_register = (unsigned long *)0xB3F10004;
static unsigned long *systemh_irq_request_register = (unsigned long *)0xB3F10000;
-/* forward declaration */
-static void enable_systemh_irq(unsigned int irq);
-static void disable_systemh_irq(unsigned int irq);
-static void mask_and_ack_systemh(unsigned int);
-
-static struct irq_chip systemh_irq_type = {
- .name = " SystemH Register",
- .unmask = enable_systemh_irq,
- .mask = disable_systemh_irq,
- .ack = mask_and_ack_systemh,
-};
-
-static void disable_systemh_irq(unsigned int irq)
+static void disable_systemh_irq(struct irq_data *data)
{
- if (systemh_irq_mask_register) {
- unsigned long val, mask = 0x01 << 1;
+ unsigned long val, mask = 0x01 << 1;
- /* Clear the "irq"th bit in the mask and set it in the request */
- val = __raw_readl((unsigned long)systemh_irq_mask_register);
- val &= ~mask;
- __raw_writel(val, (unsigned long)systemh_irq_mask_register);
+ /* Clear the "irq"th bit in the mask and set it in the request */
+ val = __raw_readl((unsigned long)systemh_irq_mask_register);
+ val &= ~mask;
+ __raw_writel(val, (unsigned long)systemh_irq_mask_register);
- val = __raw_readl((unsigned long)systemh_irq_request_register);
- val |= mask;
- __raw_writel(val, (unsigned long)systemh_irq_request_register);
- }
+ val = __raw_readl((unsigned long)systemh_irq_request_register);
+ val |= mask;
+ __raw_writel(val, (unsigned long)systemh_irq_request_register);
}
-static void enable_systemh_irq(unsigned int irq)
+static void enable_systemh_irq(struct irq_data *data)
{
- if (systemh_irq_mask_register) {
- unsigned long val, mask = 0x01 << 1;
+ unsigned long val, mask = 0x01 << 1;
- /* Set "irq"th bit in the mask register */
- val = __raw_readl((unsigned long)systemh_irq_mask_register);
- val |= mask;
- __raw_writel(val, (unsigned long)systemh_irq_mask_register);
- }
+ /* Set "irq"th bit in the mask register */
+ val = __raw_readl((unsigned long)systemh_irq_mask_register);
+ val |= mask;
+ __raw_writel(val, (unsigned long)systemh_irq_mask_register);
}
-static void mask_and_ack_systemh(unsigned int irq)
-{
- disable_systemh_irq(irq);
-}
+static struct irq_chip systemh_irq_type = {
+ .name = "SystemH Register",
+ .irq_unmask = enable_systemh_irq,
+ .irq_mask = disable_systemh_irq,
+};
void make_systemh_irq(unsigned int irq)
{
disable_irq_nosync(irq);
set_irq_chip_and_handler(irq, &systemh_irq_type, handle_level_irq);
- disable_systemh_irq(irq);
+ disable_systemh_irq(irq_get_irq_data(irq));
}
diff --git a/arch/sh/boards/mach-x3proto/gpio.c b/arch/sh/boards/mach-x3proto/gpio.c
index 594adf76e46a..239e74066253 100644
--- a/arch/sh/boards/mach-x3proto/gpio.c
+++ b/arch/sh/boards/mach-x3proto/gpio.c
@@ -54,18 +54,19 @@ static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
{
- struct irq_chip *chip = get_irq_desc_chip(desc);
+ struct irq_data *data = irq_get_irq_data(irq);
+ struct irq_chip *chip = irq_data_get_irq_chip(data);
unsigned long mask;
int pin;
- chip->mask_ack(irq);
+ chip->irq_mask_ack(data);
mask = __raw_readw(KEYDETR);
for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS)
generic_handle_irq(x3proto_gpio_to_irq(NULL, pin));
- chip->unmask(irq);
+ chip->irq_unmask(data);
}
struct gpio_chip x3proto_gpio_chip = {
diff --git a/arch/sh/cchips/hd6446x/hd64461.c b/arch/sh/cchips/hd6446x/hd64461.c
index bcb31ae84a51..177a10b25cad 100644
--- a/arch/sh/cchips/hd6446x/hd64461.c
+++ b/arch/sh/cchips/hd6446x/hd64461.c
@@ -17,8 +17,9 @@
/* This belongs in cpu specific */
#define INTC_ICR1 0xA4140010UL
-static void hd64461_mask_irq(unsigned int irq)
+static void hd64461_mask_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
unsigned short nimr;
unsigned short mask = 1 << (irq - HD64461_IRQBASE);
@@ -27,8 +28,9 @@ static void hd64461_mask_irq(unsigned int irq)
__raw_writew(nimr, HD64461_NIMR);
}
-static void hd64461_unmask_irq(unsigned int irq)
+static void hd64461_unmask_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
unsigned short nimr;
unsigned short mask = 1 << (irq - HD64461_IRQBASE);
@@ -37,20 +39,21 @@ static void hd64461_unmask_irq(unsigned int irq)
__raw_writew(nimr, HD64461_NIMR);
}
-static void hd64461_mask_and_ack_irq(unsigned int irq)
+static void hd64461_mask_and_ack_irq(struct irq_data *data)
{
- hd64461_mask_irq(irq);
+ hd64461_mask_irq(data);
+
#ifdef CONFIG_HD64461_ENABLER
- if (irq == HD64461_IRQBASE + 13)
+ if (data->irq == HD64461_IRQBASE + 13)
__raw_writeb(0x00, HD64461_PCC1CSCR);
#endif
}
static struct irq_chip hd64461_irq_chip = {
.name = "HD64461-IRQ",
- .mask = hd64461_mask_irq,
- .mask_ack = hd64461_mask_and_ack_irq,
- .unmask = hd64461_unmask_irq,
+ .irq_mask = hd64461_mask_irq,
+ .irq_mask_ack = hd64461_mask_and_ack_irq,
+ .irq_unmask = hd64461_unmask_irq,
};
static void hd64461_irq_demux(unsigned int irq, struct irq_desc *desc)
diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h
index 02f77450cd8f..a15f1058bbf4 100644
--- a/arch/sh/include/asm/pgtable.h
+++ b/arch/sh/include/asm/pgtable.h
@@ -169,6 +169,8 @@ extern void page_table_range_init(unsigned long start, unsigned long end,
#define HAVE_ARCH_UNMAPPED_AREA
#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
+#define __HAVE_ARCH_PTE_SPECIAL
+
#include <asm-generic/pgtable.h>
#endif /* __ASM_SH_PGTABLE_H */
diff --git a/arch/sh/include/asm/pgtable_32.h b/arch/sh/include/asm/pgtable_32.h
index 69fdfbf14ea5..43528ec656ba 100644
--- a/arch/sh/include/asm/pgtable_32.h
+++ b/arch/sh/include/asm/pgtable_32.h
@@ -378,8 +378,6 @@ PTE_BIT_FUNC(low, mkold, &= ~_PAGE_ACCESSED);
PTE_BIT_FUNC(low, mkyoung, |= _PAGE_ACCESSED);
PTE_BIT_FUNC(low, mkspecial, |= _PAGE_SPECIAL);
-#define __HAVE_ARCH_PTE_SPECIAL
-
/*
* Macro and implementation to make a page protection as uncachable.
*/
diff --git a/arch/sh/include/asm/pgtable_64.h b/arch/sh/include/asm/pgtable_64.h
index 10a48111226d..42cb9dd52161 100644
--- a/arch/sh/include/asm/pgtable_64.h
+++ b/arch/sh/include/asm/pgtable_64.h
@@ -130,6 +130,7 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
* anything above the PPN field.
*/
#define _PAGE_WIRED _PAGE_EXT(0x001) /* software: wire the tlb entry */
+#define _PAGE_SPECIAL _PAGE_EXT(0x002)
#define _PAGE_CLEAR_FLAGS (_PAGE_PRESENT | _PAGE_FILE | _PAGE_SHARED | \
_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_WIRED)
@@ -173,7 +174,8 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
/* Default flags for a User page */
#define _PAGE_TABLE (_KERNPG_TABLE | _PAGE_USER)
-#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | \
+ _PAGE_SPECIAL)
/*
* We have full permissions (Read/Write/Execute/Shared).
@@ -263,7 +265,7 @@ static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; }
-static inline int pte_special(pte_t pte){ return 0; }
+static inline int pte_special(pte_t pte){ return pte_val(pte) & _PAGE_SPECIAL; }
static inline pte_t pte_wrprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_WRITE)); return pte; }
static inline pte_t pte_mkclean(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
@@ -272,8 +274,7 @@ static inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) |
static inline pte_t pte_mkdirty(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
static inline pte_t pte_mkyoung(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
static inline pte_t pte_mkhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; }
-static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
-
+static inline pte_t pte_mkspecial(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_SPECIAL)); return pte; }
/*
* Conversion functions: convert a page and protection to a page entry.
diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h
index 0a58cb25a658..c9e7cbc4768a 100644
--- a/arch/sh/include/asm/processor.h
+++ b/arch/sh/include/asm/processor.h
@@ -89,6 +89,7 @@ struct sh_cpuinfo {
struct task_struct *idle;
#endif
+ unsigned int phys_bits;
unsigned long flags;
} __attribute__ ((aligned(L1_CACHE_BYTES)));
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 97661061ff20..fac742e514ee 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -340,6 +340,8 @@ asmlinkage void __cpuinit cpu_init(void)
*/
current_cpu_data.asid_cache = NO_CONTEXT;
+ current_cpu_data.phys_bits = __in_29bit_mode() ? 29 : 32;
+
speculative_execution_init();
expmask_init();
diff --git a/arch/sh/kernel/cpu/irq/imask.c b/arch/sh/kernel/cpu/irq/imask.c
index a351ed84eec5..32c825c9488e 100644
--- a/arch/sh/kernel/cpu/irq/imask.c
+++ b/arch/sh/kernel/cpu/irq/imask.c
@@ -51,16 +51,20 @@ static inline void set_interrupt_registers(int ip)
: "t");
}
-static void mask_imask_irq(unsigned int irq)
+static void mask_imask_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
+
clear_bit(irq, imask_mask);
if (interrupt_priority < IMASK_PRIORITY - irq)
interrupt_priority = IMASK_PRIORITY - irq;
set_interrupt_registers(interrupt_priority);
}
-static void unmask_imask_irq(unsigned int irq)
+static void unmask_imask_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
+
set_bit(irq, imask_mask);
interrupt_priority = IMASK_PRIORITY -
find_first_zero_bit(imask_mask, IMASK_PRIORITY);
@@ -69,9 +73,9 @@ static void unmask_imask_irq(unsigned int irq)
static struct irq_chip imask_irq_chip = {
.name = "SR.IMASK",
- .mask = mask_imask_irq,
- .unmask = unmask_imask_irq,
- .mask_ack = mask_imask_irq,
+ .irq_mask = mask_imask_irq,
+ .irq_unmask = unmask_imask_irq,
+ .irq_mask_ack = mask_imask_irq,
};
void make_imask_irq(unsigned int irq)
diff --git a/arch/sh/kernel/cpu/irq/intc-sh5.c b/arch/sh/kernel/cpu/irq/intc-sh5.c
index 96a239583948..5af48f8357e5 100644
--- a/arch/sh/kernel/cpu/irq/intc-sh5.c
+++ b/arch/sh/kernel/cpu/irq/intc-sh5.c
@@ -76,39 +76,11 @@ int intc_evt_to_irq[(0xE20/0x20)+1] = {
};
static unsigned long intc_virt;
-
-static unsigned int startup_intc_irq(unsigned int irq);
-static void shutdown_intc_irq(unsigned int irq);
-static void enable_intc_irq(unsigned int irq);
-static void disable_intc_irq(unsigned int irq);
-static void mask_and_ack_intc(unsigned int);
-static void end_intc_irq(unsigned int irq);
-
-static struct irq_chip intc_irq_type = {
- .name = "INTC",
- .startup = startup_intc_irq,
- .shutdown = shutdown_intc_irq,
- .enable = enable_intc_irq,
- .disable = disable_intc_irq,
- .ack = mask_and_ack_intc,
- .end = end_intc_irq
-};
-
static int irlm; /* IRL mode */
-static unsigned int startup_intc_irq(unsigned int irq)
-{
- enable_intc_irq(irq);
- return 0; /* never anything pending */
-}
-
-static void shutdown_intc_irq(unsigned int irq)
-{
- disable_intc_irq(irq);
-}
-
-static void enable_intc_irq(unsigned int irq)
+static void enable_intc_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
unsigned long reg;
unsigned long bitmask;
@@ -126,8 +98,9 @@ static void enable_intc_irq(unsigned int irq)
__raw_writel(bitmask, reg);
}
-static void disable_intc_irq(unsigned int irq)
+static void disable_intc_irq(struct irq_data *data)
{
+ unsigned int irq = data->irq;
unsigned long reg;
unsigned long bitmask;
@@ -142,15 +115,11 @@ static void disable_intc_irq(unsigned int irq)
__raw_writel(bitmask, reg);
}
-static void mask_and_ack_intc(unsigned int irq)
-{
- disable_intc_irq(irq);
-}
-
-static void end_intc_irq(unsigned int irq)
-{
- enable_intc_irq(irq);
-}
+static struct irq_chip intc_irq_type = {
+ .name = "INTC",
+ .irq_enable = enable_intc_irq,
+ .irq_disable = disable_intc_irq,
+};
void __init plat_irq_setup(void)
{
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c
index 9282d965a1b6..7516c35ee514 100644
--- a/arch/sh/kernel/cpu/irq/ipr.c
+++ b/arch/sh/kernel/cpu/irq/ipr.c
@@ -24,25 +24,25 @@
#include <linux/module.h>
#include <linux/topology.h>
-static inline struct ipr_desc *get_ipr_desc(unsigned int irq)
+static inline struct ipr_desc *get_ipr_desc(struct irq_data *data)
{
- struct irq_chip *chip = get_irq_chip(irq);
+ struct irq_chip *chip = irq_data_get_irq_chip(data);
return container_of(chip, struct ipr_desc, chip);
}
-static void disable_ipr_irq(unsigned int irq)
+static void disable_ipr_irq(struct irq_data *data)
{
- struct ipr_data *p = get_irq_chip_data(irq);
- unsigned long addr = get_ipr_desc(irq)->ipr_offsets[p->ipr_idx];
+ struct ipr_data *p = irq_data_get_irq_chip_data(data);
+ unsigned long addr = get_ipr_desc(data)->ipr_offsets[p->ipr_idx];
/* Set the priority in IPR to 0 */
__raw_writew(__raw_readw(addr) & (0xffff ^ (0xf << p->shift)), addr);
(void)__raw_readw(addr); /* Read back to flush write posting */
}
-static void enable_ipr_irq(unsigned int irq)
+static void enable_ipr_irq(struct irq_data *data)
{
- struct ipr_data *p = get_irq_chip_data(irq);
- unsigned long addr = get_ipr_desc(irq)->ipr_offsets[p->ipr_idx];
+ struct ipr_data *p = irq_data_get_irq_chip_data(data);
+ unsigned long addr = get_ipr_desc(data)->ipr_offsets[p->ipr_idx];
/* Set priority in IPR back to original value */
__raw_writew(__raw_readw(addr) | (p->priority << p->shift), addr);
}
@@ -56,19 +56,18 @@ void register_ipr_controller(struct ipr_desc *desc)
{
int i;
- desc->chip.mask = disable_ipr_irq;
- desc->chip.unmask = enable_ipr_irq;
- desc->chip.mask_ack = disable_ipr_irq;
+ desc->chip.irq_mask = disable_ipr_irq;
+ desc->chip.irq_unmask = enable_ipr_irq;
for (i = 0; i < desc->nr_irqs; i++) {
struct ipr_data *p = desc->ipr_data + i;
- struct irq_desc *irq_desc;
+ int res;
BUG_ON(p->ipr_idx >= desc->nr_offsets);
BUG_ON(!desc->ipr_offsets[p->ipr_idx]);
- irq_desc = irq_to_desc_alloc_node(p->irq, numa_node_id());
- if (unlikely(!irq_desc)) {
+ res = irq_alloc_desc_at(p->irq, numa_node_id());
+ if (unlikely(res != p->irq && res != -EEXIST)) {
printk(KERN_INFO "can not get irq_desc for %d\n",
p->irq);
continue;
@@ -78,7 +77,7 @@ void register_ipr_controller(struct ipr_desc *desc)
set_irq_chip_and_handler_name(p->irq, &desc->chip,
handle_level_irq, "level");
set_irq_chip_data(p->irq, p);
- disable_ipr_irq(p->irq);
+ disable_ipr_irq(irq_get_irq_data(p->irq));
}
}
EXPORT_SYMBOL(register_ipr_controller);
diff --git a/arch/sh/kernel/cpu/sh4/perf_event.c b/arch/sh/kernel/cpu/sh4/perf_event.c
index 7f9ecc9c2d02..dbf3b4bb71fe 100644
--- a/arch/sh/kernel/cpu/sh4/perf_event.c
+++ b/arch/sh/kernel/cpu/sh4/perf_event.c
@@ -225,7 +225,7 @@ static void sh7750_pmu_enable_all(void)
}
static struct sh_pmu sh7750_pmu = {
- .name = "SH7750",
+ .name = "sh7750",
.num_events = 2,
.event_map = sh7750_event_map,
.max_events = ARRAY_SIZE(sh7750_general_events),
diff --git a/arch/sh/kernel/cpu/sh4a/perf_event.c b/arch/sh/kernel/cpu/sh4a/perf_event.c
index b8b873d8d6b5..580276525731 100644
--- a/arch/sh/kernel/cpu/sh4a/perf_event.c
+++ b/arch/sh/kernel/cpu/sh4a/perf_event.c
@@ -259,7 +259,7 @@ static void sh4a_pmu_enable_all(void)
}
static struct sh_pmu sh4a_pmu = {
- .name = "SH-4A",
+ .name = "sh4a",
.num_events = 2,
.event_map = sh4a_event_map,
.max_events = ARRAY_SIZE(sh4a_general_events),
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 9dc447db8a44..68ecbe6c881a 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -56,6 +56,8 @@ int show_interrupts(struct seq_file *p, void *v)
int i = *(loff_t *)v, j, prec;
struct irqaction *action;
struct irq_desc *desc;
+ struct irq_data *data;
+ struct irq_chip *chip;
if (i > nr_irqs)
return 0;
@@ -77,6 +79,9 @@ int show_interrupts(struct seq_file *p, void *v)
if (!desc)
return 0;
+ data = irq_get_irq_data(i);
+ chip = irq_data_get_irq_chip(data);
+
raw_spin_lock_irqsave(&desc->lock, flags);
for_each_online_cpu(j)
any_count |= kstat_irqs_cpu(i, j);
@@ -87,7 +92,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%*d: ", prec, i);
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
- seq_printf(p, " %14s", desc->chip->name);
+ seq_printf(p, " %14s", chip->name);
seq_printf(p, "-%-8s", desc->name);
if (action) {
@@ -273,12 +278,6 @@ void __init init_IRQ(void)
{
plat_irq_setup();
- /*
- * Pin any of the legacy IRQ vectors that haven't already been
- * grabbed by the platform
- */
- reserve_irq_legacy();
-
/* Perform the machine specific initialisation */
if (sh_mv.mv_init_irq)
sh_mv.mv_init_irq();
@@ -297,13 +296,16 @@ int __init arch_probe_nr_irqs(void)
#endif
#ifdef CONFIG_HOTPLUG_CPU
-static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu)
+static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
{
+ struct irq_desc *desc = irq_to_desc(irq);
+ struct irq_chip *chip = irq_data_get_irq_chip(data);
+
printk(KERN_INFO "IRQ%u: moving from cpu%u to cpu%u\n",
- irq, desc->node, cpu);
+ irq, data->node, cpu);
raw_spin_lock_irq(&desc->lock);
- desc->chip->set_affinity(irq, cpumask_of(cpu));
+ chip->irq_set_affinity(data, cpumask_of(cpu), false);
raw_spin_unlock_irq(&desc->lock);
}
@@ -314,24 +316,25 @@ static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu)
*/
void migrate_irqs(void)
{
- struct irq_desc *desc;
unsigned int irq, cpu = smp_processor_id();
- for_each_irq_desc(irq, desc) {
- if (desc->node == cpu) {
- unsigned int newcpu = cpumask_any_and(desc->affinity,
+ for_each_active_irq(irq) {
+ struct irq_data *data = irq_get_irq_data(irq);
+
+ if (data->node == cpu) {
+ unsigned int newcpu = cpumask_any_and(data->affinity,
cpu_online_mask);
if (newcpu >= nr_cpu_ids) {
if (printk_ratelimit())
printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n",
irq, cpu);
- cpumask_setall(desc->affinity);
- newcpu = cpumask_any_and(desc->affinity,
+ cpumask_setall(data->affinity);
+ newcpu = cpumask_any_and(data->affinity,
cpu_online_mask);
}
- route_irq(desc, irq, newcpu);
+ route_irq(data, irq, newcpu);
}
}
}
diff --git a/arch/sh/kernel/irq_64.c b/arch/sh/kernel/irq_64.c
index 32365ba0e039..8fc05b997b6d 100644
--- a/arch/sh/kernel/irq_64.c
+++ b/arch/sh/kernel/irq_64.c
@@ -11,17 +11,17 @@
#include <linux/module.h>
#include <cpu/registers.h>
-void notrace raw_local_irq_restore(unsigned long flags)
+void notrace arch_local_irq_restore(unsigned long flags)
{
unsigned long long __dummy;
- if (flags == RAW_IRQ_DISABLED) {
+ if (flags == ARCH_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)
+ : "r" (ARCH_IRQ_DISABLED)
);
} else {
__asm__ __volatile__ (
@@ -29,13 +29,13 @@ void notrace raw_local_irq_restore(unsigned long flags)
"and %0, %1, %0\n\t"
"putcon %0, " __SR "\n\t"
: "=&r" (__dummy)
- : "r" (~RAW_IRQ_DISABLED)
+ : "r" (~ARCH_IRQ_DISABLED)
);
}
}
-EXPORT_SYMBOL(raw_local_irq_restore);
+EXPORT_SYMBOL(arch_local_irq_restore);
-unsigned long notrace __raw_local_save_flags(void)
+unsigned long notrace arch_local_save_flags(void)
{
unsigned long flags;
@@ -43,9 +43,9 @@ unsigned long notrace __raw_local_save_flags(void)
"getcon " __SR ", %0\n\t"
"and %0, %1, %0"
: "=&r" (flags)
- : "r" (RAW_IRQ_DISABLED)
+ : "r" (ARCH_IRQ_DISABLED)
);
return flags;
}
-EXPORT_SYMBOL(__raw_local_save_flags);
+EXPORT_SYMBOL(arch_local_save_flags);
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 4e278467f76c..d6b018c7ebdc 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -41,6 +41,7 @@
#include <asm/smp.h>
#include <asm/mmu_context.h>
#include <asm/mmzone.h>
+#include <asm/sparsemem.h>
/*
* Initialize loops_per_jiffy as 10000000 (1000MIPS).
@@ -52,6 +53,7 @@ struct sh_cpuinfo cpu_data[NR_CPUS] __read_mostly = {
.type = CPU_SH_NONE,
.family = CPU_FAMILY_UNKNOWN,
.loops_per_jiffy = 10000000,
+ .phys_bits = MAX_PHYSMEM_BITS,
},
};
EXPORT_SYMBOL(cpu_data);
@@ -432,6 +434,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
if (c->flags & CPU_HAS_L2_CACHE)
show_cacheinfo(m, "scache", c->scache);
+ seq_printf(m, "address sizes\t: %u bits physical\n", c->phys_bits);
+
seq_printf(m, "bogomips\t: %lu.%02lu\n",
c->loops_per_jiffy/(500000/HZ),
(c->loops_per_jiffy/(5000/HZ)) % 100);
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index ab89ea4f9414..150aa326afff 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -15,7 +15,7 @@ cacheops-$(CONFIG_CPU_SHX3) += cache-shx3.o
obj-y += $(cacheops-y)
mmu-y := nommu.o extable_32.o
-mmu-$(CONFIG_MMU) := extable_$(BITS).o fault_$(BITS).o \
+mmu-$(CONFIG_MMU) := extable_$(BITS).o fault_$(BITS).o gup.o \
ioremap.o kmap.o pgtable.o tlbflush_$(BITS).o
obj-y += $(mmu-y)
diff --git a/arch/sh/mm/gup.c b/arch/sh/mm/gup.c
new file mode 100644
index 000000000000..bf8daf9d9c9b
--- /dev/null
+++ b/arch/sh/mm/gup.c
@@ -0,0 +1,273 @@
+/*
+ * Lockless get_user_pages_fast for SuperH
+ *
+ * Copyright (C) 2009 - 2010 Paul Mundt
+ *
+ * Cloned from the x86 and PowerPC versions, by:
+ *
+ * Copyright (C) 2008 Nick Piggin
+ * Copyright (C) 2008 Novell Inc.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmstat.h>
+#include <linux/highmem.h>
+#include <asm/pgtable.h>
+
+static inline pte_t gup_get_pte(pte_t *ptep)
+{
+#ifndef CONFIG_X2TLB
+ return ACCESS_ONCE(*ptep);
+#else
+ /*
+ * With get_user_pages_fast, we walk down the pagetables without
+ * taking any locks. For this we would like to load the pointers
+ * atomically, but that is not possible with 64-bit PTEs. What
+ * we do have is the guarantee that a pte will only either go
+ * from not present to present, or present to not present or both
+ * -- it will not switch to a completely different present page
+ * without a TLB flush in between; something that we are blocking
+ * by holding interrupts off.
+ *
+ * Setting ptes from not present to present goes:
+ * ptep->pte_high = h;
+ * smp_wmb();
+ * ptep->pte_low = l;
+ *
+ * And present to not present goes:
+ * ptep->pte_low = 0;
+ * smp_wmb();
+ * ptep->pte_high = 0;
+ *
+ * We must ensure here that the load of pte_low sees l iff pte_high
+ * sees h. We load pte_high *after* loading pte_low, which ensures we
+ * don't see an older value of pte_high. *Then* we recheck pte_low,
+ * which ensures that we haven't picked up a changed pte high. We might
+ * have got rubbish values from pte_low and pte_high, but we are
+ * guaranteed that pte_low will not have the present bit set *unless*
+ * it is 'l'. And get_user_pages_fast only operates on present ptes, so
+ * we're safe.
+ *
+ * gup_get_pte should not be used or copied outside gup.c without being
+ * very careful -- it does not atomically load the pte or anything that
+ * is likely to be useful for you.
+ */
+ pte_t pte;
+
+retry:
+ pte.pte_low = ptep->pte_low;
+ smp_rmb();
+ pte.pte_high = ptep->pte_high;
+ smp_rmb();
+ if (unlikely(pte.pte_low != ptep->pte_low))
+ goto retry;
+
+ return pte;
+#endif
+}
+
+/*
+ * The performance critical leaf functions are made noinline otherwise gcc
+ * inlines everything into a single function which results in too much
+ * register pressure.
+ */
+static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
+ unsigned long end, int write, struct page **pages, int *nr)
+{
+ u64 mask, result;
+ pte_t *ptep;
+
+#ifdef CONFIG_X2TLB
+ result = _PAGE_PRESENT | _PAGE_EXT(_PAGE_EXT_KERN_READ | _PAGE_EXT_USER_READ);
+ if (write)
+ result |= _PAGE_EXT(_PAGE_EXT_KERN_WRITE | _PAGE_EXT_USER_WRITE);
+#elif defined(CONFIG_SUPERH64)
+ result = _PAGE_PRESENT | _PAGE_USER | _PAGE_READ;
+ if (write)
+ result |= _PAGE_WRITE;
+#else
+ result = _PAGE_PRESENT | _PAGE_USER;
+ if (write)
+ result |= _PAGE_RW;
+#endif
+
+ mask = result | _PAGE_SPECIAL;
+
+ ptep = pte_offset_map(&pmd, addr);
+ do {
+ pte_t pte = gup_get_pte(ptep);
+ struct page *page;
+
+ if ((pte_val(pte) & mask) != result) {
+ pte_unmap(ptep);
+ return 0;
+ }
+ VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+ page = pte_page(pte);
+ get_page(page);
+ pages[*nr] = page;
+ (*nr)++;
+
+ } while (ptep++, addr += PAGE_SIZE, addr != end);
+ pte_unmap(ptep - 1);
+
+ return 1;
+}
+
+static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
+ int write, struct page **pages, int *nr)
+{
+ unsigned long next;
+ pmd_t *pmdp;
+
+ pmdp = pmd_offset(&pud, addr);
+ do {
+ pmd_t pmd = *pmdp;
+
+ next = pmd_addr_end(addr, end);
+ if (pmd_none(pmd))
+ return 0;
+ if (!gup_pte_range(pmd, addr, next, write, pages, nr))
+ return 0;
+ } while (pmdp++, addr = next, addr != end);
+
+ return 1;
+}
+
+static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
+ int write, struct page **pages, int *nr)
+{
+ unsigned long next;
+ pud_t *pudp;
+
+ pudp = pud_offset(&pgd, addr);
+ do {
+ pud_t pud = *pudp;
+
+ next = pud_addr_end(addr, end);
+ if (pud_none(pud))
+ return 0;
+ if (!gup_pmd_range(pud, addr, next, write, pages, nr))
+ return 0;
+ } while (pudp++, addr = next, addr != end);
+
+ return 1;
+}
+
+/*
+ * Like get_user_pages_fast() except its IRQ-safe in that it won't fall
+ * back to the regular GUP.
+ */
+int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
+ struct page **pages)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long addr, len, end;
+ unsigned long next;
+ unsigned long flags;
+ pgd_t *pgdp;
+ int nr = 0;
+
+ start &= PAGE_MASK;
+ addr = start;
+ len = (unsigned long) nr_pages << PAGE_SHIFT;
+ end = start + len;
+ if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
+ (void __user *)start, len)))
+ return 0;
+
+ /*
+ * This doesn't prevent pagetable teardown, but does prevent
+ * the pagetables and pages from being freed.
+ */
+ local_irq_save(flags);
+ pgdp = pgd_offset(mm, addr);
+ do {
+ pgd_t pgd = *pgdp;
+
+ next = pgd_addr_end(addr, end);
+ if (pgd_none(pgd))
+ break;
+ if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+ break;
+ } while (pgdp++, addr = next, addr != end);
+ local_irq_restore(flags);
+
+ return nr;
+}
+
+/**
+ * get_user_pages_fast() - pin user pages in memory
+ * @start: starting user address
+ * @nr_pages: number of pages from start to pin
+ * @write: whether pages will be written to
+ * @pages: array that receives pointers to the pages pinned.
+ * Should be at least nr_pages long.
+ *
+ * Attempt to pin user pages in memory without taking mm->mmap_sem.
+ * If not successful, it will fall back to taking the lock and
+ * calling get_user_pages().
+ *
+ * Returns number of pages pinned. This may be fewer than the number
+ * requested. If nr_pages is 0 or negative, returns 0. If no pages
+ * were pinned, returns -errno.
+ */
+int get_user_pages_fast(unsigned long start, int nr_pages, int write,
+ struct page **pages)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long addr, len, end;
+ unsigned long next;
+ pgd_t *pgdp;
+ int nr = 0;
+
+ start &= PAGE_MASK;
+ addr = start;
+ len = (unsigned long) nr_pages << PAGE_SHIFT;
+
+ end = start + len;
+ if (end < start)
+ goto slow_irqon;
+
+ local_irq_disable();
+ pgdp = pgd_offset(mm, addr);
+ do {
+ pgd_t pgd = *pgdp;
+
+ next = pgd_addr_end(addr, end);
+ if (pgd_none(pgd))
+ goto slow;
+ if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+ goto slow;
+ } while (pgdp++, addr = next, addr != end);
+ local_irq_enable();
+
+ VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
+ return nr;
+
+ {
+ int ret;
+
+slow:
+ local_irq_enable();
+slow_irqon:
+ /* Try to get the remaining pages with get_user_pages */
+ start += nr << PAGE_SHIFT;
+ pages += nr;
+
+ down_read(&mm->mmap_sem);
+ ret = get_user_pages(current, mm, start,
+ (end - start) >> PAGE_SHIFT, write, 0, pages, NULL);
+ up_read(&mm->mmap_sem);
+
+ /* Have to be a bit careful with return values */
+ if (nr > 0) {
+ if (ret < 0)
+ ret = nr;
+ else
+ ret += nr;
+ }
+
+ return ret;
+ }
+}
diff --git a/arch/sh/oprofile/Makefile b/arch/sh/oprofile/Makefile
index e85aae73e3dc..ce3b119021e7 100644
--- a/arch/sh/oprofile/Makefile
+++ b/arch/sh/oprofile/Makefile
@@ -1,5 +1,7 @@
obj-$(CONFIG_OPROFILE) += oprofile.o
+CFLAGS_common.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
+
DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprof.o cpu_buffer.o buffer_sync.o \
event_buffer.o oprofile_files.o \
diff --git a/arch/sh/oprofile/backtrace.c b/arch/sh/oprofile/backtrace.c
index 2bc74de23f08..37f3a75ea6cb 100644
--- a/arch/sh/oprofile/backtrace.c
+++ b/arch/sh/oprofile/backtrace.c
@@ -91,7 +91,7 @@ void sh_backtrace(struct pt_regs * const regs, unsigned int depth)
if (depth > backtrace_limit)
depth = backtrace_limit;
- stackaddr = (unsigned long *)regs->regs[15];
+ stackaddr = (unsigned long *)kernel_stack_pointer(regs);
if (!user_mode(regs)) {
if (depth)
unwind_stack(NULL, regs, stackaddr,
diff --git a/arch/sh/oprofile/common.c b/arch/sh/oprofile/common.c
index e10d89376f9b..b4c2d2b946dd 100644
--- a/arch/sh/oprofile/common.c
+++ b/arch/sh/oprofile/common.c
@@ -1,7 +1,7 @@
/*
* arch/sh/oprofile/init.c
*
- * Copyright (C) 2003 - 2008 Paul Mundt
+ * Copyright (C) 2003 - 2010 Paul Mundt
*
* Based on arch/mips/oprofile/common.c:
*
@@ -18,43 +18,46 @@
#include <linux/errno.h>
#include <linux/smp.h>
#include <linux/perf_event.h>
+#include <linux/slab.h>
#include <asm/processor.h>
-#ifdef CONFIG_HW_PERF_EVENTS
extern void sh_backtrace(struct pt_regs * const regs, unsigned int depth);
+#ifdef CONFIG_HW_PERF_EVENTS
+/*
+ * This will need to be reworked when multiple PMUs are supported.
+ */
+static char *sh_pmu_op_name;
+
char *op_name_from_perf_id(void)
{
- const char *pmu;
- char buf[20];
- int size;
-
- pmu = perf_pmu_name();
- if (!pmu)
- return NULL;
-
- size = snprintf(buf, sizeof(buf), "sh/%s", pmu);
- if (size > -1 && size < sizeof(buf))
- return buf;
-
- return NULL;
+ return sh_pmu_op_name;
}
int __init oprofile_arch_init(struct oprofile_operations *ops)
{
ops->backtrace = sh_backtrace;
+ if (perf_num_counters() == 0)
+ return -ENODEV;
+
+ sh_pmu_op_name = kasprintf(GFP_KERNEL, "%s/%s",
+ UTS_MACHINE, perf_pmu_name());
+ if (unlikely(!sh_pmu_op_name))
+ return -ENOMEM;
+
return oprofile_perf_init(ops);
}
void __exit oprofile_arch_exit(void)
{
oprofile_perf_exit();
+ kfree(sh_pmu_op_name);
}
#else
int __init oprofile_arch_init(struct oprofile_operations *ops)
{
- pr_info("oprofile: hardware counters not available\n");
+ ops->backtrace = sh_backtrace;
return -ENODEV;
}
void __exit oprofile_arch_exit(void) {}