diff options
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r-- | arch/sparc/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/apc.c | 1 | ||||
-rw-r--r-- | arch/sparc/kernel/auxio_32.c | 4 | ||||
-rw-r--r-- | arch/sparc/kernel/btext.c | 4 | ||||
-rw-r--r-- | arch/sparc/kernel/devices.c | 23 | ||||
-rw-r--r-- | arch/sparc/kernel/irq_32.c | 13 | ||||
-rw-r--r-- | arch/sparc/kernel/jump_label.c | 47 | ||||
-rw-r--r-- | arch/sparc/kernel/leon_kernel.c | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/mdesc.c | 1 | ||||
-rw-r--r-- | arch/sparc/kernel/module.c | 6 | ||||
-rw-r--r-- | arch/sparc/kernel/pci_msi.c | 8 | ||||
-rw-r--r-- | arch/sparc/kernel/pcic.c | 4 | ||||
-rw-r--r-- | arch/sparc/kernel/pcr.c | 8 | ||||
-rw-r--r-- | arch/sparc/kernel/perf_event.c | 240 | ||||
-rw-r--r-- | arch/sparc/kernel/prom.h | 6 | ||||
-rw-r--r-- | arch/sparc/kernel/prom_common.c | 202 | ||||
-rw-r--r-- | arch/sparc/kernel/setup_64.c | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/starfire.c | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/tadpole.c | 2 |
19 files changed, 244 insertions, 333 deletions
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 0c2dc1f..599398f 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -119,3 +119,5 @@ obj-$(CONFIG_COMPAT) += $(audit--y) pc--$(CONFIG_PERF_EVENTS) := perf_event.o obj-$(CONFIG_SPARC64) += $(pc--y) + +obj-$(CONFIG_SPARC64) += jump_label.o diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c index 2c0046e..52de4a9 100644 --- a/arch/sparc/kernel/apc.c +++ b/arch/sparc/kernel/apc.c @@ -132,6 +132,7 @@ static const struct file_operations apc_fops = { .unlocked_ioctl = apc_ioctl, .open = apc_open, .release = apc_release, + .llseek = noop_llseek, }; static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops }; diff --git a/arch/sparc/kernel/auxio_32.c b/arch/sparc/kernel/auxio_32.c index ee8d214..35f4883 100644 --- a/arch/sparc/kernel/auxio_32.c +++ b/arch/sparc/kernel/auxio_32.c @@ -23,7 +23,7 @@ static DEFINE_SPINLOCK(auxio_lock); void __init auxio_probe(void) { - int node, auxio_nd; + phandle node, auxio_nd; struct linux_prom_registers auxregs[1]; struct resource r; @@ -113,7 +113,7 @@ volatile unsigned char * auxio_power_register = NULL; void __init auxio_power_probe(void) { struct linux_prom_registers regs; - int node; + phandle node; struct resource r; /* Attempt to find the sun4m power control node. */ diff --git a/arch/sparc/kernel/btext.c b/arch/sparc/kernel/btext.c index 8cc2d56..89aa4eb 100644 --- a/arch/sparc/kernel/btext.c +++ b/arch/sparc/kernel/btext.c @@ -40,7 +40,7 @@ static unsigned char *dispDeviceBase __force_data; static unsigned char vga_font[cmapsz]; -static int __init btext_initialize(unsigned int node) +static int __init btext_initialize(phandle node) { unsigned int width, height, depth, pitch; unsigned long address = 0; @@ -309,7 +309,7 @@ static struct console btext_console = { int __init btext_find_display(void) { - unsigned int node; + phandle node; char type[32]; int ret; diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c index 62dc7a0..d2eddd6 100644 --- a/arch/sparc/kernel/devices.c +++ b/arch/sparc/kernel/devices.c @@ -31,9 +31,9 @@ static char *cpu_mid_prop(void) return "mid"; } -static int check_cpu_node(int nd, int *cur_inst, - int (*compare)(int, int, void *), void *compare_arg, - int *prom_node, int *mid) +static int check_cpu_node(phandle nd, int *cur_inst, + int (*compare)(phandle, int, void *), void *compare_arg, + phandle *prom_node, int *mid) { if (!compare(nd, *cur_inst, compare_arg)) { if (prom_node) @@ -51,8 +51,8 @@ static int check_cpu_node(int nd, int *cur_inst, return -ENODEV; } -static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg, - int *prom_node, int *mid) +static int __cpu_find_by(int (*compare)(phandle, int, void *), + void *compare_arg, phandle *prom_node, int *mid) { struct device_node *dp; int cur_inst; @@ -71,7 +71,7 @@ static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg, return -ENODEV; } -static int cpu_instance_compare(int nd, int instance, void *_arg) +static int cpu_instance_compare(phandle nd, int instance, void *_arg) { int desired_instance = (int) _arg; @@ -80,13 +80,13 @@ static int cpu_instance_compare(int nd, int instance, void *_arg) return -ENODEV; } -int cpu_find_by_instance(int instance, int *prom_node, int *mid) +int cpu_find_by_instance(int instance, phandle *prom_node, int *mid) { return __cpu_find_by(cpu_instance_compare, (void *)instance, prom_node, mid); } -static int cpu_mid_compare(int nd, int instance, void *_arg) +static int cpu_mid_compare(phandle nd, int instance, void *_arg) { int desired_mid = (int) _arg; int this_mid; @@ -98,7 +98,7 @@ static int cpu_mid_compare(int nd, int instance, void *_arg) return -ENODEV; } -int cpu_find_by_mid(int mid, int *prom_node) +int cpu_find_by_mid(int mid, phandle *prom_node) { return __cpu_find_by(cpu_mid_compare, (void *)mid, prom_node, NULL); @@ -108,7 +108,7 @@ int cpu_find_by_mid(int mid, int *prom_node) * address (0-3). This gives us the true hardware mid, which might have * some other bits set. On 4d hardware and software mids are the same. */ -int cpu_get_hwmid(int prom_node) +int cpu_get_hwmid(phandle prom_node) { return prom_getintdefault(prom_node, cpu_mid_prop(), -ENODEV); } @@ -119,7 +119,8 @@ void __init device_scan(void) #ifndef CONFIG_SMP { - int err, cpu_node; + phandle cpu_node; + int err; err = cpu_find_by_instance(0, &cpu_node, NULL); if (err) { /* Probably a sun4e, Sun is trying to trick us ;-) */ diff --git a/arch/sparc/kernel/irq_32.c b/arch/sparc/kernel/irq_32.c index e1af437..0116d8d 100644 --- a/arch/sparc/kernel/irq_32.c +++ b/arch/sparc/kernel/irq_32.c @@ -57,7 +57,7 @@ #define SMP_NOP2 #define SMP_NOP3 #endif /* SMP */ -unsigned long __raw_local_irq_save(void) +unsigned long arch_local_irq_save(void) { unsigned long retval; unsigned long tmp; @@ -74,8 +74,9 @@ unsigned long __raw_local_irq_save(void) return retval; } +EXPORT_SYMBOL(arch_local_irq_save); -void raw_local_irq_enable(void) +void arch_local_irq_enable(void) { unsigned long tmp; @@ -89,8 +90,9 @@ void raw_local_irq_enable(void) : "i" (PSR_PIL) : "memory"); } +EXPORT_SYMBOL(arch_local_irq_enable); -void raw_local_irq_restore(unsigned long old_psr) +void arch_local_irq_restore(unsigned long old_psr) { unsigned long tmp; @@ -105,10 +107,7 @@ void raw_local_irq_restore(unsigned long old_psr) : "i" (PSR_PIL), "r" (old_psr) : "memory"); } - -EXPORT_SYMBOL(__raw_local_irq_save); -EXPORT_SYMBOL(raw_local_irq_enable); -EXPORT_SYMBOL(raw_local_irq_restore); +EXPORT_SYMBOL(arch_local_irq_restore); /* * Dave Redman (djhr@tadpole.co.uk) diff --git a/arch/sparc/kernel/jump_label.c b/arch/sparc/kernel/jump_label.c new file mode 100644 index 0000000..ea2dafc --- /dev/null +++ b/arch/sparc/kernel/jump_label.c @@ -0,0 +1,47 @@ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mutex.h> +#include <linux/cpu.h> + +#include <linux/jump_label.h> +#include <linux/memory.h> + +#ifdef HAVE_JUMP_LABEL + +void arch_jump_label_transform(struct jump_entry *entry, + enum jump_label_type type) +{ + u32 val; + u32 *insn = (u32 *) (unsigned long) entry->code; + + if (type == JUMP_LABEL_ENABLE) { + s32 off = (s32)entry->target - (s32)entry->code; + +#ifdef CONFIG_SPARC64 + /* ba,pt %xcc, . + (off << 2) */ + val = 0x10680000 | ((u32) off >> 2); +#else + /* ba . + (off << 2) */ + val = 0x10800000 | ((u32) off >> 2); +#endif + } else { + val = 0x01000000; + } + + get_online_cpus(); + mutex_lock(&text_mutex); + *insn = val; + flushi(insn); + mutex_unlock(&text_mutex); + put_online_cpus(); +} + +void arch_jump_label_text_poke_early(jump_label_t addr) +{ + u32 *insn_p = (u32 *) (unsigned long) addr; + + *insn_p = 0x01000000; + flushi(insn_p); +} + +#endif diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 6a7b4db..2d51527 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -282,5 +282,5 @@ void __init leon_init_IRQ(void) void __init leon_init(void) { - prom_build_more = &leon_node_init; + of_pdt_build_more = &leon_node_init; } diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index 83e85c2..6addb91 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -890,6 +890,7 @@ static ssize_t mdesc_read(struct file *file, char __user *buf, static const struct file_operations mdesc_fops = { .read = mdesc_read, .owner = THIS_MODULE, + .llseek = noop_llseek, }; static struct miscdevice mdesc_misc = { diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index f848aad..ee3c7dd 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -18,6 +18,9 @@ #include <asm/spitfire.h> #ifdef CONFIG_SPARC64 + +#include <linux/jump_label.h> + static void *module_map(unsigned long size) { struct vm_struct *area; @@ -227,6 +230,9 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *me) { + /* make jump label nops */ + jump_label_apply_nops(me); + /* Cheetah's I-cache is fully coherent. */ if (tlb_type == spitfire) { unsigned long va; diff --git a/arch/sparc/kernel/pci_msi.c b/arch/sparc/kernel/pci_msi.c index 548b8ca..b210416 100644 --- a/arch/sparc/kernel/pci_msi.c +++ b/arch/sparc/kernel/pci_msi.c @@ -114,10 +114,10 @@ static void free_msi(struct pci_pbm_info *pbm, int msi_num) static struct irq_chip msi_irq = { .name = "PCI-MSI", - .mask = mask_msi_irq, - .unmask = unmask_msi_irq, - .enable = unmask_msi_irq, - .disable = mask_msi_irq, + .irq_mask = mask_msi_irq, + .irq_unmask = unmask_msi_irq, + .irq_enable = unmask_msi_irq, + .irq_disable = mask_msi_irq, /* XXX affinity XXX */ }; diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index d36a8d3..aeaa09a 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -284,7 +284,7 @@ int __init pcic_probe(void) struct linux_prom_registers regs[PROMREG_MAX]; struct linux_pbm_info* pbm; char namebuf[64]; - int node; + phandle node; int err; if (pcic0_up) { @@ -440,7 +440,7 @@ static int __devinit pdev_to_pnode(struct linux_pbm_info *pbm, { struct linux_prom_pci_registers regs[PROMREG_MAX]; int err; - int node = prom_getchild(pbm->prom_node); + phandle node = prom_getchild(pbm->prom_node); while(node) { err = prom_getproperty(node, "reg", diff --git a/arch/sparc/kernel/pcr.c b/arch/sparc/kernel/pcr.c index c4a6a50..b87873c 100644 --- a/arch/sparc/kernel/pcr.c +++ b/arch/sparc/kernel/pcr.c @@ -7,7 +7,7 @@ #include <linux/init.h> #include <linux/irq.h> -#include <linux/perf_event.h> +#include <linux/irq_work.h> #include <linux/ftrace.h> #include <asm/pil.h> @@ -43,14 +43,14 @@ void __irq_entry deferred_pcr_work_irq(int irq, struct pt_regs *regs) old_regs = set_irq_regs(regs); irq_enter(); -#ifdef CONFIG_PERF_EVENTS - perf_event_do_pending(); +#ifdef CONFIG_IRQ_WORK + irq_work_run(); #endif irq_exit(); set_irq_regs(old_regs); } -void set_perf_event_pending(void) +void arch_irq_work_raise(void) { set_softint(1 << PIL_DEFERRED_PCR_WORK); } diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 6318e62..0d6deb5 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -658,13 +658,16 @@ static u64 maybe_change_configuration(struct cpu_hw_events *cpuc, u64 pcr) enc = perf_event_get_enc(cpuc->events[i]); pcr &= ~mask_for_index(idx); - pcr |= event_encoding(enc, idx); + if (hwc->state & PERF_HES_STOPPED) + pcr |= nop_for_index(idx); + else + pcr |= event_encoding(enc, idx); } out: return pcr; } -void hw_perf_enable(void) +static void sparc_pmu_enable(struct pmu *pmu) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); u64 pcr; @@ -691,7 +694,7 @@ void hw_perf_enable(void) pcr_ops->write(cpuc->pcr); } -void hw_perf_disable(void) +static void sparc_pmu_disable(struct pmu *pmu) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); u64 val; @@ -710,19 +713,65 @@ void hw_perf_disable(void) pcr_ops->write(cpuc->pcr); } -static void sparc_pmu_disable(struct perf_event *event) +static int active_event_index(struct cpu_hw_events *cpuc, + struct perf_event *event) +{ + int i; + + for (i = 0; i < cpuc->n_events; i++) { + if (cpuc->event[i] == event) + break; + } + BUG_ON(i == cpuc->n_events); + return cpuc->current_idx[i]; +} + +static void sparc_pmu_start(struct perf_event *event, int flags) +{ + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + int idx = active_event_index(cpuc, event); + + if (flags & PERF_EF_RELOAD) { + WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE)); + sparc_perf_event_set_period(event, &event->hw, idx); + } + + event->hw.state = 0; + + sparc_pmu_enable_event(cpuc, &event->hw, idx); +} + +static void sparc_pmu_stop(struct perf_event *event, int flags) +{ + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + int idx = active_event_index(cpuc, event); + + if (!(event->hw.state & PERF_HES_STOPPED)) { + sparc_pmu_disable_event(cpuc, &event->hw, idx); + event->hw.state |= PERF_HES_STOPPED; + } + + if (!(event->hw.state & PERF_HES_UPTODATE) && (flags & PERF_EF_UPDATE)) { + sparc_perf_event_update(event, &event->hw, idx); + event->hw.state |= PERF_HES_UPTODATE; + } +} + +static void sparc_pmu_del(struct perf_event *event, int _flags) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); - struct hw_perf_event *hwc = &event->hw; unsigned long flags; int i; local_irq_save(flags); - perf_disable(); + perf_pmu_disable(event->pmu); for (i = 0; i < cpuc->n_events; i++) { if (event == cpuc->event[i]) { - int idx = cpuc->current_idx[i]; + /* Absorb the final count and turn off the + * event. + */ + sparc_pmu_stop(event, PERF_EF_UPDATE); /* Shift remaining entries down into * the existing slot. @@ -734,13 +783,6 @@ static void sparc_pmu_disable(struct perf_event *event) cpuc->current_idx[i]; } - /* Absorb the final count and turn off the - * event. - */ - sparc_pmu_disable_event(cpuc, hwc, idx); - barrier(); - sparc_perf_event_update(event, hwc, idx); - perf_event_update_userpage(event); cpuc->n_events--; @@ -748,23 +790,10 @@ static void sparc_pmu_disable(struct perf_event *event) } } - perf_enable(); + perf_pmu_enable(event->pmu); local_irq_restore(flags); } -static int active_event_index(struct cpu_hw_events *cpuc, - struct perf_event *event) -{ - int i; - - for (i = 0; i < cpuc->n_events; i++) { - if (cpuc->event[i] == event) - break; - } - BUG_ON(i == cpuc->n_events); - return cpuc->current_idx[i]; -} - static void sparc_pmu_read(struct perf_event *event) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); @@ -774,15 +803,6 @@ static void sparc_pmu_read(struct perf_event *event) sparc_perf_event_update(event, hwc, idx); } -static void sparc_pmu_unthrottle(struct perf_event *event) -{ - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); - int idx = active_event_index(cpuc, event); - struct hw_perf_event *hwc = &event->hw; - - sparc_pmu_enable_event(cpuc, hwc, idx); -} - static atomic_t active_events = ATOMIC_INIT(0); static DEFINE_MUTEX(pmc_grab_mutex); @@ -877,7 +897,7 @@ static int sparc_check_constraints(struct perf_event **evts, if (!n_ev) return 0; - if (n_ev > perf_max_events) + if (n_ev > MAX_HWEVENTS) return -1; msk0 = perf_event_get_msk(events[0]); @@ -984,23 +1004,27 @@ static int collect_events(struct perf_event *group, int max_count, return n; } -static int sparc_pmu_enable(struct perf_event *event) +static int sparc_pmu_add(struct perf_event *event, int ef_flags) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); int n0, ret = -EAGAIN; unsigned long flags; local_irq_save(flags); - perf_disable(); + perf_pmu_disable(event->pmu); n0 = cpuc->n_events; - if (n0 >= perf_max_events) + if (n0 >= MAX_HWEVENTS) goto out; cpuc->event[n0] = event; cpuc->events[n0] = event->hw.event_base; cpuc->current_idx[n0] = PIC_NO_INDEX; + event->hw.state = PERF_HES_UPTODATE; + if (!(ef_flags & PERF_EF_START)) + event->hw.state |= PERF_HES_STOPPED; + /* * If group events scheduling transaction was started, * skip the schedulability test here, it will be peformed @@ -1020,12 +1044,12 @@ nocheck: ret = 0; out: - perf_enable(); + perf_pmu_enable(event->pmu); local_irq_restore(flags); return ret; } -static int __hw_perf_event_init(struct perf_event *event) +static int sparc_pmu_event_init(struct perf_event *event) { struct perf_event_attr *attr = &event->attr; struct perf_event *evts[MAX_HWEVENTS]; @@ -1038,22 +1062,33 @@ static int __hw_perf_event_init(struct perf_event *event) if (atomic_read(&nmi_active) < 0) return -ENODEV; - pmap = NULL; - if (attr->type == PERF_TYPE_HARDWARE) { + switch (attr->type) { + case PERF_TYPE_HARDWARE: if (attr->config >= sparc_pmu->max_events) return -EINVAL; pmap = sparc_pmu->event_map(attr->config); - } else if (attr->type == PERF_TYPE_HW_CACHE) { + break; + + case PERF_TYPE_HW_CACHE: pmap = sparc_map_cache_event(attr->config); if (IS_ERR(pmap)) return PTR_ERR(pmap); - } else if (attr->type != PERF_TYPE_RAW) - return -EOPNOTSUPP; + break; + + case PERF_TYPE_RAW: + pmap = NULL; + break; + + default: + return -ENOENT; + + } if (pmap) { hwc->event_base = perf_event_encode(pmap); } else { - /* User gives us "(encoding << 16) | pic_mask" for + /* + * User gives us "(encoding << 16) | pic_mask" for * PERF_TYPE_RAW events. */ hwc->event_base = attr->config; @@ -1071,7 +1106,7 @@ static int __hw_perf_event_init(struct perf_event *event) n = 0; if (event->group_leader != event) { n = collect_events(event->group_leader, - perf_max_events - 1, + MAX_HWEVENTS - 1, evts, events, current_idx_dmy); if (n < 0) return -EINVAL; @@ -1107,10 +1142,11 @@ static int __hw_perf_event_init(struct perf_event *event) * Set the flag to make pmu::enable() not perform the * schedulability test, it will be performed at commit time */ -static void sparc_pmu_start_txn(const struct pmu *pmu) +static void sparc_pmu_start_txn(struct pmu *pmu) { struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + perf_pmu_disable(pmu); cpuhw->group_flag |= PERF_EVENT_TXN; } @@ -1119,11 +1155,12 @@ static void sparc_pmu_start_txn(const struct pmu *pmu) * Clear the flag and pmu::enable() will perform the * schedulability test. */ -static void sparc_pmu_cancel_txn(const struct pmu *pmu) +static void sparc_pmu_cancel_txn(struct pmu *pmu) { struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); cpuhw->group_flag &= ~PERF_EVENT_TXN; + perf_pmu_enable(pmu); } /* @@ -1131,7 +1168,7 @@ static void sparc_pmu_cancel_txn(const struct pmu *pmu) * Perform the group schedulability test as a whole * Return 0 if success */ -static int sparc_pmu_commit_txn(const struct pmu *pmu) +static int sparc_pmu_commit_txn(struct pmu *pmu) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); int n; @@ -1147,28 +1184,24 @@ static int sparc_pmu_commit_txn(const struct pmu *pmu) return -EAGAIN; cpuc->group_flag &= ~PERF_EVENT_TXN; + perf_pmu_enable(pmu); return 0; } -static const struct pmu pmu = { - .enable = sparc_pmu_enable, - .disable = sparc_pmu_disable, +static struct pmu pmu = { + .pmu_enable = sparc_pmu_enable, + .pmu_disable = sparc_pmu_disable, + .event_init = sparc_pmu_event_init, + .add = sparc_pmu_add, + .del = sparc_pmu_del, + .start = sparc_pmu_start, + .stop = sparc_pmu_stop, .read = sparc_pmu_read, - .unthrottle = sparc_pmu_unthrottle, .start_txn = sparc_pmu_start_txn, .cancel_txn = sparc_pmu_cancel_txn, .commit_txn = sparc_pmu_commit_txn, }; -const struct pmu *hw_perf_event_init(struct perf_event *event) -{ - int err = __hw_perf_event_init(event); - - if (err) - return ERR_PTR(err); - return &pmu; -} - void perf_event_print_debug(void) { unsigned long flags; @@ -1244,7 +1277,7 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self, continue; if (perf_event_overflow(event, 1, &data, regs)) - sparc_pmu_disable_event(cpuc, hwc, idx); + sparc_pmu_stop(event, 0); } return NOTIFY_STOP; @@ -1285,28 +1318,21 @@ void __init init_hw_perf_events(void) pr_cont("Supported PMU type is '%s'\n", sparc_pmu_type); - /* All sparc64 PMUs currently have 2 events. */ - perf_max_events = 2; - + perf_pmu_register(&pmu); register_die_notifier(&perf_event_nmi_notifier); } -static inline void callchain_store(struct perf_callchain_entry *entry, u64 ip) -{ - if (entry->nr < PERF_MAX_STACK_DEPTH) - entry->ip[entry->nr++] = ip; -} - -static void perf_callchain_kernel(struct pt_regs *regs, - struct perf_callchain_entry *entry) +void perf_callchain_kernel(struct perf_callchain_entry *entry, + struct pt_regs *regs) { unsigned long ksp, fp; #ifdef CONFIG_FUNCTION_GRAPH_TRACER int graph = 0; #endif - callchain_store(entry, PERF_CONTEXT_KERNEL); - callchain_store(entry, regs->tpc); + stack_trace_flush(); + + perf_callchain_store(entry, regs->tpc); ksp = regs->u_regs[UREG_I6]; fp = ksp + STACK_BIAS; @@ -1330,13 +1356,13 @@ static void perf_callchain_kernel(struct pt_regs *regs, pc = sf->callers_pc; fp = (unsigned long)sf->fp + STACK_BIAS; } - callchain_store(entry, pc); + perf_callchain_store(entry, pc); #ifdef CONFIG_FUNCTION_GRAPH_TRACER if ((pc + 8UL) == (unsigned long) &return_to_handler) { int index = current->curr_ret_stack; if (current->ret_stack && index >= graph) { pc = current->ret_stack[index - graph].ret; - callchain_store(entry, pc); + perf_callchain_store(entry, pc); graph++; } } @@ -1344,13 +1370,12 @@ static void perf_callchain_kernel(struct pt_regs *regs, } while (entry->nr < PERF_MAX_STACK_DEPTH); } -static void perf_callchain_user_64(struct pt_regs *regs, - struct perf_callchain_entry *entry) +static void perf_callchain_user_64(struct perf_callchain_entry *entry, + struct pt_regs *regs) { unsigned long ufp; - callchain_store(entry, PERF_CONTEXT_USER); - callchain_store(entry, regs->tpc); + perf_callchain_store(entry, regs->tpc); ufp = regs->u_regs[UREG_I6] + STACK_BIAS; do { @@ -1363,17 +1388,16 @@ static void perf_callchain_user_64(struct pt_regs *regs, pc = sf.callers_pc; ufp = (unsigned long)sf.fp + STACK_BIAS; - callchain_store(entry, pc); + perf_callchain_store(entry, pc); } while (entry->nr < PERF_MAX_STACK_DEPTH); } -static void perf_callchain_user_32(struct pt_regs *regs, - struct perf_callchain_entry *entry) +static void perf_callchain_user_32(struct perf_callchain_entry *entry, + struct pt_regs *regs) { unsigned long ufp; - callchain_store(entry, PERF_CONTEXT_USER); - callchain_store(entry, regs->tpc); + perf_callchain_store(entry, regs->tpc); ufp = regs->u_regs[UREG_I6] & 0xffffffffUL; do { @@ -1386,34 +1410,16 @@ static void perf_callchain_user_32(struct pt_regs *regs, pc = sf.callers_pc; ufp = (unsigned long)sf.fp; - callchain_store(entry, pc); + perf_callchain_store(entry, pc); } while (entry->nr < PERF_MAX_STACK_DEPTH); } -/* Like powerpc we can't get PMU interrupts within the PMU handler, - * so no need for separate NMI and IRQ chains as on x86. - */ -static DEFINE_PER_CPU(struct perf_callchain_entry, callchain); - -struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) +void +perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) { - struct perf_callchain_entry *entry = &__get_cpu_var(callchain); - - entry->nr = 0; - if (!user_mode(regs)) { - stack_trace_flush(); - perf_callchain_kernel(regs, entry); - if (current->mm) - regs = task_pt_regs(current); - else - regs = NULL; - } - if (regs) { - flushw_user(); - if (test_thread_flag(TIF_32BIT)) - perf_callchain_user_32(regs, entry); - else - perf_callchain_user_64(regs, entry); - } - return entry; + flushw_user(); + if (test_thread_flag(TIF_32BIT)) + perf_callchain_user_32(entry, regs); + else + perf_callchain_user_64(entry, regs); } diff --git a/arch/sparc/kernel/prom.h b/arch/sparc/kernel/prom.h index eeb04a7..cf5fe1c 100644 --- a/arch/sparc/kernel/prom.h +++ b/arch/sparc/kernel/prom.h @@ -4,12 +4,6 @@ #include <linux/spinlock.h> #include <asm/prom.h> -extern void * prom_early_alloc(unsigned long size); -extern void irq_trans_init(struct device_node *dp); - -extern unsigned int prom_unique_id; - -extern char *build_path_component(struct device_node *dp); extern void of_console_init(void); extern unsigned int prom_early_allocated; diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c index 1f830da..ed25834 100644 --- a/arch/sparc/kernel/prom_common.c +++ b/arch/sparc/kernel/prom_common.c @@ -20,14 +20,13 @@ #include <linux/mutex.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/of_pdt.h> #include <asm/prom.h> #include <asm/oplib.h> #include <asm/leon.h> #include "prom.h" -void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp); - struct device_node *of_console_device; EXPORT_SYMBOL(of_console_device); @@ -119,192 +118,47 @@ int of_find_in_proplist(const char *list, const char *match, int len) } EXPORT_SYMBOL(of_find_in_proplist); -unsigned int prom_unique_id; - -static struct property * __init build_one_prop(phandle node, char *prev, - char *special_name, - void *special_val, - int special_len) +/* + * SPARC32 and SPARC64's prom_nextprop() do things differently + * here, despite sharing the same interface. SPARC32 doesn't fill in 'buf', + * returning NULL on an error. SPARC64 fills in 'buf', but sets it to an + * empty string upon error. + */ +static int __init handle_nextprop_quirks(char *buf, const char *name) { - static struct property *tmp = NULL; - struct property *p; - const char *name; - - if (tmp) { - p = tmp; - memset(p, 0, sizeof(*p) + 32); - tmp = NULL; - } else { - p = prom_early_alloc(sizeof(struct property) + 32); - p->unique_id = prom_unique_id++; - } - - p->name = (char *) (p + 1); - if (special_name) { - strcpy(p->name, special_name); - p->length = special_len; - p->value = prom_early_alloc(special_len); - memcpy(p->value, special_val, special_len); - } else { - if (prev == NULL) { - name = prom_firstprop(node, p->name); - } else { - name = prom_nextprop(node, prev, p->name); - } + if (!name || strlen(name) == 0) + return -1; - if (!name || strlen(name) == 0) { - tmp = p; - return NULL; - } #ifdef CONFIG_SPARC32 - strcpy(p->name, name); + strcpy(buf, name); #endif - p->length = prom_getproplen(node, p->name); - if (p->length <= 0) { - p->length = 0; - } else { - int len; - - p->value = prom_early_alloc(p->length + 1); - len = prom_getproperty(node, p->name, p->value, - p->length); - if (len <= 0) - p->length = 0; - ((unsigned char *)p->value)[p->length] = '\0'; - } - } - return p; -} - -static struct property * __init build_prop_list(phandle node) -{ - struct property *head, *tail; - - head = tail = build_one_prop(node, NULL, - ".node", &node, sizeof(node)); - - tail->next = build_one_prop(node, NULL, NULL, NULL, 0); - tail = tail->next; - while(tail) { - tail->next = build_one_prop(node, tail->name, - NULL, NULL, 0); - tail = tail->next; - } - - return head; -} - -static char * __init get_one_property(phandle node, const char *name) -{ - char *buf = "<NULL>"; - int len; - - len = prom_getproplen(node, name); - if (len > 0) { - buf = prom_early_alloc(len); - len = prom_getproperty(node, name, buf, len); - } - - return buf; -} - -static struct device_node * __init prom_create_node(phandle node, - struct device_node *parent) -{ - struct device_node *dp; - - if (!node) - return NULL; - - dp = prom_early_alloc(sizeof(*dp)); - dp->unique_id = prom_unique_id++; - dp->parent = parent; - - kref_init(&dp->kref); - - dp->name = get_one_property(node, "name"); - dp->type = get_one_property(node, "device_type"); - dp->phandle = node; - - dp->properties = build_prop_list(node); - - irq_trans_init(dp); - - return dp; -} - -char * __init build_full_name(struct device_node *dp) -{ - int len, ourlen, plen; - char *n; - - plen = strlen(dp->parent->full_name); - ourlen = strlen(dp->path_component_name); - len = ourlen + plen + 2; - - n = prom_early_alloc(len); - strcpy(n, dp->parent->full_name); - if (!of_node_is_root(dp->parent)) { - strcpy(n + plen, "/"); - plen++; - } - strcpy(n + plen, dp->path_component_name); - - return n; + return 0; } -static struct device_node * __init prom_build_tree(struct device_node *parent, - phandle node, - struct device_node ***nextp) +static int __init prom_common_nextprop(phandle node, char *prev, char *buf) { - struct device_node *ret = NULL, *prev_sibling = NULL; - struct device_node *dp; - - while (1) { - dp = prom_create_node(node, parent); - if (!dp) - break; - - if (prev_sibling) - prev_sibling->sibling = dp; - - if (!ret) - ret = dp; - prev_sibling = dp; - - *(*nextp) = dp; - *nextp = &dp->allnext; - - dp->path_component_name = build_path_component(dp); - dp->full_name = build_full_name(dp); - - dp->child = prom_build_tree(dp, prom_getchild(node), nextp); - - if (prom_build_more) - prom_build_more(dp, nextp); - - node = prom_getsibling(node); - } + const char *name; - return ret; + buf[0] = '\0'; + name = prom_nextprop(node, prev, buf); + return handle_nextprop_quirks(buf, name); } unsigned int prom_early_allocated __initdata; +static struct of_pdt_ops prom_sparc_ops __initdata = { + .nextprop = prom_common_nextprop, + .getproplen = prom_getproplen, + .getproperty = prom_getproperty, + .getchild = prom_getchild, + .getsibling = prom_getsibling, +}; + void __init prom_build_devicetree(void) { - struct device_node **nextp; - - allnodes = prom_create_node(prom_root_node, NULL); - allnodes->path_component_name = ""; - allnodes->full_name = "/"; - - nextp = &allnodes->allnext; - allnodes->child = prom_build_tree(allnodes, - prom_getchild(allnodes->phandle), - &nextp); + of_pdt_build_devicetree(prom_root_node, &prom_sparc_ops); of_console_init(); - printk("PROM: Built device tree with %u bytes of memory.\n", - prom_early_allocated); + pr_info("PROM: Built device tree with %u bytes of memory.\n", + prom_early_allocated); } diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index 5f72de6..29bafe0 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c @@ -315,7 +315,7 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_IP_PNP if (!ic_set_manually) { - int chosen = prom_finddevice ("/chosen"); + phandle chosen = prom_finddevice("/chosen"); u32 cl, sv, gw; cl = prom_getintdefault (chosen, "client-ip", 0); diff --git a/arch/sparc/kernel/starfire.c b/arch/sparc/kernel/starfire.c index 060d0f3..a4446c0 100644 --- a/arch/sparc/kernel/starfire.c +++ b/arch/sparc/kernel/starfire.c @@ -23,7 +23,7 @@ int this_is_starfire = 0; void check_if_starfire(void) { - int ssnode = prom_finddevice("/ssp-serial"); + phandle ssnode = prom_finddevice("/ssp-serial"); if (ssnode != 0 && ssnode != -1) this_is_starfire = 1; } diff --git a/arch/sparc/kernel/tadpole.c b/arch/sparc/kernel/tadpole.c index f476a5f..9aba8bd 100644 --- a/arch/sparc/kernel/tadpole.c +++ b/arch/sparc/kernel/tadpole.c @@ -100,7 +100,7 @@ static void swift_clockstop(void) void __init clock_stop_probe(void) { - unsigned int node, clk_nd; + phandle node, clk_nd; char name[20]; prom_getstring(prom_root_node, "name", name, sizeof(name)); |