You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6: (26 commits)
[SPARC64]: Fix UP build.
[SPARC64]: dr-cpu unconfigure support.
[SERIAL]: Fix console write locking in sparc drivers.
[SPARC64]: Give more accurate errors in dr_cpu_configure().
[SPARC64]: Clear cpu_{core,sibling}_map[] in smp_fill_in_sib_core_maps()
[SPARC64]: Fix leak when DR added cpu does not bootup.
[SPARC64]: Add ->set_affinity IRQ handlers.
[SPARC64]: Process dr-cpu events in a kthread instead of workqueue.
[SPARC64]: More sensible udelay implementation.
[SPARC64]: SMP build fixes.
[SPARC64]: mdesc.c needs linux/mm.h
[SPARC64]: Fix build regressions added by dr-cpu changes.
[SPARC64]: Unconditionally register vio_bus_type.
[SPARC64]: Initial LDOM cpu hotplug support.
[SPARC64]: Fix setting of variables in LDOM guest.
[SPARC64]: Fix MD property lifetime bugs.
[SPARC64]: Abstract out mdesc accesses for better MD update handling.
[SPARC64]: Use more mearningful names for IRQ registry.
[SPARC64]: Initial domain-services driver.
[SPARC64]: Export powerd facilities for external entities.
...
This commit is contained in:
@@ -108,6 +108,15 @@ config SECCOMP
|
||||
|
||||
source kernel/Kconfig.hz
|
||||
|
||||
config HOTPLUG_CPU
|
||||
bool "Support for hot-pluggable CPUs"
|
||||
depends on SMP
|
||||
select HOTPLUG
|
||||
---help---
|
||||
Say Y here to experiment with turning CPUs off and on. CPUs
|
||||
can be controlled through /sys/devices/system/cpu/cpu#.
|
||||
Say N if you want to disable CPU hotplug.
|
||||
|
||||
source "init/Kconfig"
|
||||
|
||||
config SYSVIPC_COMPAT
|
||||
@@ -305,6 +314,12 @@ config SUN_IO
|
||||
bool
|
||||
default y
|
||||
|
||||
config SUN_LDOMS
|
||||
bool "Sun Logical Domains support"
|
||||
help
|
||||
Say Y here is you want to support virtual devices via
|
||||
Logical Domains.
|
||||
|
||||
config PCI
|
||||
bool "PCI support"
|
||||
select ARCH_SUPPORTS_MSI
|
||||
|
||||
@@ -18,7 +18,7 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
||||
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
|
||||
pci_psycho.o pci_sabre.o pci_schizo.o \
|
||||
pci_sun4v.o pci_sun4v_asm.o pci_fire.o
|
||||
obj-$(CONFIG_SMP) += smp.o trampoline.o
|
||||
obj-$(CONFIG_SMP) += smp.o trampoline.o hvtramp.o
|
||||
obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o
|
||||
obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
|
||||
obj-$(CONFIG_BINFMT_AOUT32) += binfmt_aout32.o
|
||||
@@ -26,6 +26,7 @@ obj-$(CONFIG_MODULES) += module.o
|
||||
obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o
|
||||
obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o
|
||||
obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o
|
||||
obj-$(CONFIG_AUDIT) += audit.o
|
||||
obj-$(CONFIG_AUDIT)$(CONFIG_SPARC32_COMPAT) += compat_audit.o
|
||||
obj-y += $(obj-yy)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,139 @@
|
||||
/* hvtramp.S: Hypervisor start-cpu trampoline code.
|
||||
*
|
||||
* Copyright (C) 2007 David S. Miller <davem@davemloft.net>
|
||||
*/
|
||||
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/hypervisor.h>
|
||||
#include <asm/scratchpad.h>
|
||||
#include <asm/spitfire.h>
|
||||
#include <asm/hvtramp.h>
|
||||
#include <asm/pstate.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/asi.h>
|
||||
|
||||
.text
|
||||
.align 8
|
||||
.globl hv_cpu_startup, hv_cpu_startup_end
|
||||
|
||||
/* This code executes directly out of the hypervisor
|
||||
* with physical addressing (va==pa). %o0 contains
|
||||
* our client argument which for Linux points to
|
||||
* a descriptor data structure which defines the
|
||||
* MMU entries we need to load up.
|
||||
*
|
||||
* After we set things up we enable the MMU and call
|
||||
* into the kernel.
|
||||
*
|
||||
* First setup basic privileged cpu state.
|
||||
*/
|
||||
hv_cpu_startup:
|
||||
wrpr %g0, 0, %gl
|
||||
wrpr %g0, 15, %pil
|
||||
wrpr %g0, 0, %canrestore
|
||||
wrpr %g0, 0, %otherwin
|
||||
wrpr %g0, 6, %cansave
|
||||
wrpr %g0, 6, %cleanwin
|
||||
wrpr %g0, 0, %cwp
|
||||
wrpr %g0, 0, %wstate
|
||||
wrpr %g0, 0, %tl
|
||||
|
||||
sethi %hi(sparc64_ttable_tl0), %g1
|
||||
wrpr %g1, %tba
|
||||
|
||||
mov %o0, %l0
|
||||
|
||||
lduw [%l0 + HVTRAMP_DESCR_CPU], %g1
|
||||
mov SCRATCHPAD_CPUID, %g2
|
||||
stxa %g1, [%g2] ASI_SCRATCHPAD
|
||||
|
||||
ldx [%l0 + HVTRAMP_DESCR_FAULT_INFO_VA], %g2
|
||||
stxa %g2, [%g0] ASI_SCRATCHPAD
|
||||
|
||||
mov 0, %l1
|
||||
lduw [%l0 + HVTRAMP_DESCR_NUM_MAPPINGS], %l2
|
||||
add %l0, HVTRAMP_DESCR_MAPS, %l3
|
||||
|
||||
1: ldx [%l3 + HVTRAMP_MAPPING_VADDR], %o0
|
||||
clr %o1
|
||||
ldx [%l3 + HVTRAMP_MAPPING_TTE], %o2
|
||||
mov HV_MMU_IMMU | HV_MMU_DMMU, %o3
|
||||
mov HV_FAST_MMU_MAP_PERM_ADDR, %o5
|
||||
ta HV_FAST_TRAP
|
||||
|
||||
brnz,pn %o0, 80f
|
||||
nop
|
||||
|
||||
add %l1, 1, %l1
|
||||
cmp %l1, %l2
|
||||
blt,a,pt %xcc, 1b
|
||||
add %l3, HVTRAMP_MAPPING_SIZE, %l3
|
||||
|
||||
ldx [%l0 + HVTRAMP_DESCR_FAULT_INFO_PA], %o0
|
||||
mov HV_FAST_MMU_FAULT_AREA_CONF, %o5
|
||||
ta HV_FAST_TRAP
|
||||
|
||||
brnz,pn %o0, 80f
|
||||
nop
|
||||
|
||||
wrpr %g0, (PSTATE_PRIV | PSTATE_PEF), %pstate
|
||||
|
||||
ldx [%l0 + HVTRAMP_DESCR_THREAD_REG], %l6
|
||||
|
||||
mov 1, %o0
|
||||
set 1f, %o1
|
||||
mov HV_FAST_MMU_ENABLE, %o5
|
||||
ta HV_FAST_TRAP
|
||||
|
||||
ba,pt %xcc, 80f
|
||||
nop
|
||||
|
||||
1:
|
||||
wr %g0, 0, %fprs
|
||||
wr %g0, ASI_P, %asi
|
||||
|
||||
mov PRIMARY_CONTEXT, %g7
|
||||
stxa %g0, [%g7] ASI_MMU
|
||||
membar #Sync
|
||||
|
||||
mov SECONDARY_CONTEXT, %g7
|
||||
stxa %g0, [%g7] ASI_MMU
|
||||
membar #Sync
|
||||
|
||||
mov %l6, %g6
|
||||
ldx [%g6 + TI_TASK], %g4
|
||||
|
||||
mov 1, %g5
|
||||
sllx %g5, THREAD_SHIFT, %g5
|
||||
sub %g5, (STACKFRAME_SZ + STACK_BIAS), %g5
|
||||
add %g6, %g5, %sp
|
||||
mov 0, %fp
|
||||
|
||||
call init_irqwork_curcpu
|
||||
nop
|
||||
call hard_smp_processor_id
|
||||
nop
|
||||
|
||||
mov %o0, %o1
|
||||
mov 0, %o0
|
||||
mov 0, %o2
|
||||
call sun4v_init_mondo_queues
|
||||
mov 1, %o3
|
||||
|
||||
call init_cur_cpu_trap
|
||||
mov %g6, %o0
|
||||
|
||||
wrpr %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
|
||||
|
||||
call smp_callin
|
||||
nop
|
||||
call cpu_idle
|
||||
mov 0, %o0
|
||||
call cpu_panic
|
||||
nop
|
||||
|
||||
80: ba,pt %xcc, 80b
|
||||
nop
|
||||
|
||||
.align 8
|
||||
hv_cpu_startup_end:
|
||||
@@ -293,6 +293,11 @@ static void sun4u_irq_enable(unsigned int virt_irq)
|
||||
}
|
||||
}
|
||||
|
||||
static void sun4u_set_affinity(unsigned int virt_irq, cpumask_t mask)
|
||||
{
|
||||
sun4u_irq_enable(virt_irq);
|
||||
}
|
||||
|
||||
static void sun4u_irq_disable(unsigned int virt_irq)
|
||||
{
|
||||
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
|
||||
@@ -309,6 +314,10 @@ static void sun4u_irq_disable(unsigned int virt_irq)
|
||||
static void sun4u_irq_end(unsigned int virt_irq)
|
||||
{
|
||||
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
|
||||
struct irq_desc *desc = irq_desc + virt_irq;
|
||||
|
||||
if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
|
||||
return;
|
||||
|
||||
if (likely(data))
|
||||
upa_writeq(ICLR_IDLE, data->iclr);
|
||||
@@ -340,6 +349,24 @@ static void sun4v_irq_enable(unsigned int virt_irq)
|
||||
}
|
||||
}
|
||||
|
||||
static void sun4v_set_affinity(unsigned int virt_irq, cpumask_t mask)
|
||||
{
|
||||
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
|
||||
unsigned int ino = bucket - &ivector_table[0];
|
||||
|
||||
if (likely(bucket)) {
|
||||
unsigned long cpuid;
|
||||
int err;
|
||||
|
||||
cpuid = irq_choose_cpu(virt_irq);
|
||||
|
||||
err = sun4v_intr_settarget(ino, cpuid);
|
||||
if (err != HV_EOK)
|
||||
printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
|
||||
ino, cpuid, err);
|
||||
}
|
||||
}
|
||||
|
||||
static void sun4v_irq_disable(unsigned int virt_irq)
|
||||
{
|
||||
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
|
||||
@@ -373,6 +400,10 @@ static void sun4v_irq_end(unsigned int virt_irq)
|
||||
{
|
||||
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
|
||||
unsigned int ino = bucket - &ivector_table[0];
|
||||
struct irq_desc *desc = irq_desc + virt_irq;
|
||||
|
||||
if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
|
||||
return;
|
||||
|
||||
if (likely(bucket)) {
|
||||
int err;
|
||||
@@ -418,6 +449,28 @@ static void sun4v_virq_enable(unsigned int virt_irq)
|
||||
}
|
||||
}
|
||||
|
||||
static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
|
||||
{
|
||||
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
|
||||
unsigned int ino = bucket - &ivector_table[0];
|
||||
|
||||
if (likely(bucket)) {
|
||||
unsigned long cpuid, dev_handle, dev_ino;
|
||||
int err;
|
||||
|
||||
cpuid = irq_choose_cpu(virt_irq);
|
||||
|
||||
dev_handle = ino & IMAP_IGN;
|
||||
dev_ino = ino & IMAP_INO;
|
||||
|
||||
err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
|
||||
if (err != HV_EOK)
|
||||
printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
|
||||
"err(%d)\n",
|
||||
dev_handle, dev_ino, cpuid, err);
|
||||
}
|
||||
}
|
||||
|
||||
static void sun4v_virq_disable(unsigned int virt_irq)
|
||||
{
|
||||
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
|
||||
@@ -443,6 +496,10 @@ static void sun4v_virq_end(unsigned int virt_irq)
|
||||
{
|
||||
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
|
||||
unsigned int ino = bucket - &ivector_table[0];
|
||||
struct irq_desc *desc = irq_desc + virt_irq;
|
||||
|
||||
if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
|
||||
return;
|
||||
|
||||
if (likely(bucket)) {
|
||||
unsigned long dev_handle, dev_ino;
|
||||
@@ -477,6 +534,7 @@ static struct irq_chip sun4u_irq = {
|
||||
.enable = sun4u_irq_enable,
|
||||
.disable = sun4u_irq_disable,
|
||||
.end = sun4u_irq_end,
|
||||
.set_affinity = sun4u_set_affinity,
|
||||
};
|
||||
|
||||
static struct irq_chip sun4u_irq_ack = {
|
||||
@@ -485,6 +543,7 @@ static struct irq_chip sun4u_irq_ack = {
|
||||
.disable = sun4u_irq_disable,
|
||||
.ack = run_pre_handler,
|
||||
.end = sun4u_irq_end,
|
||||
.set_affinity = sun4u_set_affinity,
|
||||
};
|
||||
|
||||
static struct irq_chip sun4v_irq = {
|
||||
@@ -492,6 +551,7 @@ static struct irq_chip sun4v_irq = {
|
||||
.enable = sun4v_irq_enable,
|
||||
.disable = sun4v_irq_disable,
|
||||
.end = sun4v_irq_end,
|
||||
.set_affinity = sun4v_set_affinity,
|
||||
};
|
||||
|
||||
static struct irq_chip sun4v_irq_ack = {
|
||||
@@ -500,6 +560,7 @@ static struct irq_chip sun4v_irq_ack = {
|
||||
.disable = sun4v_irq_disable,
|
||||
.ack = run_pre_handler,
|
||||
.end = sun4v_irq_end,
|
||||
.set_affinity = sun4v_set_affinity,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
@@ -511,6 +572,7 @@ static struct irq_chip sun4v_msi = {
|
||||
.disable = sun4v_msi_disable,
|
||||
.ack = run_pre_handler,
|
||||
.end = sun4v_irq_end,
|
||||
.set_affinity = sun4v_set_affinity,
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -519,6 +581,7 @@ static struct irq_chip sun4v_virq = {
|
||||
.enable = sun4v_virq_enable,
|
||||
.disable = sun4v_virq_disable,
|
||||
.end = sun4v_virq_end,
|
||||
.set_affinity = sun4v_virt_set_affinity,
|
||||
};
|
||||
|
||||
static struct irq_chip sun4v_virq_ack = {
|
||||
@@ -527,6 +590,7 @@ static struct irq_chip sun4v_virq_ack = {
|
||||
.disable = sun4v_virq_disable,
|
||||
.ack = run_pre_handler,
|
||||
.end = sun4v_virq_end,
|
||||
.set_affinity = sun4v_virt_set_affinity,
|
||||
};
|
||||
|
||||
void irq_install_pre_handler(int virt_irq,
|
||||
@@ -739,6 +803,26 @@ void handler_irq(int irq, struct pt_regs *regs)
|
||||
set_irq_regs(old_regs);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
void fixup_irqs(void)
|
||||
{
|
||||
unsigned int irq;
|
||||
|
||||
for (irq = 0; irq < NR_IRQS; irq++) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&irq_desc[irq].lock, flags);
|
||||
if (irq_desc[irq].action &&
|
||||
!(irq_desc[irq].status & IRQ_PER_CPU)) {
|
||||
if (irq_desc[irq].chip->set_affinity)
|
||||
irq_desc[irq].chip->set_affinity(irq,
|
||||
irq_desc[irq].affinity);
|
||||
}
|
||||
spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct sun5_timer {
|
||||
u64 count0;
|
||||
u64 limit0;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+411
-313
File diff suppressed because it is too large
Load Diff
+31
-23
@@ -1,7 +1,6 @@
|
||||
/* $Id: power.c,v 1.10 2001/12/11 01:57:16 davem Exp $
|
||||
* power.c: Power management driver.
|
||||
/* power.c: Power management driver.
|
||||
*
|
||||
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
|
||||
* Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@@ -19,6 +18,7 @@
|
||||
#include <asm/prom.h>
|
||||
#include <asm/of_device.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/power.h>
|
||||
#include <asm/sstate.h>
|
||||
|
||||
#include <linux/unistd.h>
|
||||
@@ -29,24 +29,26 @@
|
||||
*/
|
||||
int scons_pwroff = 1;
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#include <linux/pci.h>
|
||||
static void __iomem *power_reg;
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
|
||||
static int button_pressed;
|
||||
|
||||
static irqreturn_t power_handler(int irq, void *dev_id)
|
||||
void wake_up_powerd(void)
|
||||
{
|
||||
if (button_pressed == 0) {
|
||||
button_pressed = 1;
|
||||
wake_up(&powerd_wait);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t power_handler(int irq, void *dev_id)
|
||||
{
|
||||
wake_up_powerd();
|
||||
|
||||
/* FIXME: Check registers for status... */
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
extern void machine_halt(void);
|
||||
extern void machine_alt_power_off(void);
|
||||
@@ -56,19 +58,18 @@ void machine_power_off(void)
|
||||
{
|
||||
sstate_poweroff();
|
||||
if (!serial_console || scons_pwroff) {
|
||||
#ifdef CONFIG_PCI
|
||||
if (power_reg) {
|
||||
/* Both register bits seem to have the
|
||||
* same effect, so until I figure out
|
||||
* what the difference is...
|
||||
*/
|
||||
writel(AUXIO_PCIO_CPWR_OFF | AUXIO_PCIO_SPWR_OFF, power_reg);
|
||||
} else
|
||||
#endif /* CONFIG_PCI */
|
||||
} else {
|
||||
if (poweroff_method != NULL) {
|
||||
poweroff_method();
|
||||
/* not reached */
|
||||
}
|
||||
}
|
||||
}
|
||||
machine_halt();
|
||||
}
|
||||
@@ -76,7 +77,6 @@ void machine_power_off(void)
|
||||
void (*pm_power_off)(void) = machine_power_off;
|
||||
EXPORT_SYMBOL(pm_power_off);
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
static int powerd(void *__unused)
|
||||
{
|
||||
static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
|
||||
@@ -86,7 +86,7 @@ static int powerd(void *__unused)
|
||||
daemonize("powerd");
|
||||
|
||||
add_wait_queue(&powerd_wait, &wait);
|
||||
again:
|
||||
|
||||
for (;;) {
|
||||
set_task_state(current, TASK_INTERRUPTIBLE);
|
||||
if (button_pressed)
|
||||
@@ -100,16 +100,28 @@ again:
|
||||
/* Ok, down we go... */
|
||||
button_pressed = 0;
|
||||
if (kernel_execve("/sbin/shutdown", argv, envp) < 0) {
|
||||
printk("powerd: shutdown execution failed\n");
|
||||
add_wait_queue(&powerd_wait, &wait);
|
||||
goto again;
|
||||
printk(KERN_ERR "powerd: shutdown execution failed\n");
|
||||
machine_power_off();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int start_powerd(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = kernel_thread(powerd, NULL, CLONE_FS);
|
||||
if (err < 0)
|
||||
printk(KERN_ERR "power: Failed to start power daemon.\n");
|
||||
else
|
||||
printk(KERN_INFO "power: powerd running.\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
|
||||
{
|
||||
if (irq == PCI_IRQ_NONE)
|
||||
if (irq == 0xffffffff)
|
||||
return 0;
|
||||
if (!of_find_property(dp, "button", NULL))
|
||||
return 0;
|
||||
@@ -130,17 +142,14 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id
|
||||
poweroff_method = machine_halt; /* able to use the standard halt */
|
||||
|
||||
if (has_button_interrupt(irq, op->node)) {
|
||||
if (kernel_thread(powerd, NULL, CLONE_FS) < 0) {
|
||||
printk("Failed to start power daemon.\n");
|
||||
if (start_powerd() < 0)
|
||||
return 0;
|
||||
}
|
||||
printk("powerd running.\n");
|
||||
|
||||
if (request_irq(irq,
|
||||
power_handler, 0, "power", NULL) < 0)
|
||||
printk("power: Error, cannot register IRQ handler.\n");
|
||||
printk(KERN_ERR "power: Cannot setup IRQ handler.\n");
|
||||
} else {
|
||||
printk("not using powerd.\n");
|
||||
printk(KERN_INFO "power: Not using powerd.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -164,4 +173,3 @@ void __init power_init(void)
|
||||
of_register_driver(&power_driver, &of_bus_type);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <linux/compat.h>
|
||||
#include <linux/tick.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/cpu.h>
|
||||
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/uaccess.h>
|
||||
@@ -49,7 +50,7 @@
|
||||
|
||||
/* #define VERBOSE_SHOWREGS */
|
||||
|
||||
static void sparc64_yield(void)
|
||||
static void sparc64_yield(int cpu)
|
||||
{
|
||||
if (tlb_type != hypervisor)
|
||||
return;
|
||||
@@ -57,7 +58,7 @@ static void sparc64_yield(void)
|
||||
clear_thread_flag(TIF_POLLING_NRFLAG);
|
||||
smp_mb__after_clear_bit();
|
||||
|
||||
while (!need_resched()) {
|
||||
while (!need_resched() && !cpu_is_offline(cpu)) {
|
||||
unsigned long pstate;
|
||||
|
||||
/* Disable interrupts. */
|
||||
@@ -68,7 +69,7 @@ static void sparc64_yield(void)
|
||||
: "=&r" (pstate)
|
||||
: "i" (PSTATE_IE));
|
||||
|
||||
if (!need_resched())
|
||||
if (!need_resched() && !cpu_is_offline(cpu))
|
||||
sun4v_cpu_yield();
|
||||
|
||||
/* Re-enable interrupts. */
|
||||
@@ -86,15 +87,25 @@ static void sparc64_yield(void)
|
||||
/* The idle loop on sparc64. */
|
||||
void cpu_idle(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
set_thread_flag(TIF_POLLING_NRFLAG);
|
||||
|
||||
while(1) {
|
||||
tick_nohz_stop_sched_tick();
|
||||
while (!need_resched())
|
||||
sparc64_yield();
|
||||
|
||||
while (!need_resched() && !cpu_is_offline(cpu))
|
||||
sparc64_yield(cpu);
|
||||
|
||||
tick_nohz_restart_sched_tick();
|
||||
|
||||
preempt_enable_no_resched();
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
if (cpu_is_offline(cpu))
|
||||
cpu_play_dead();
|
||||
#endif
|
||||
|
||||
schedule();
|
||||
preempt_disable();
|
||||
}
|
||||
|
||||
@@ -1808,7 +1808,7 @@ static void __init of_fill_in_cpu_data(void)
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
cpu_set(cpuid, cpu_present_map);
|
||||
cpu_set(cpuid, phys_cpu_present_map);
|
||||
cpu_set(cpuid, cpu_possible_map);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -442,7 +442,6 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
|
||||
"D$ parity tl1\t: %u\n"
|
||||
"I$ parity tl1\t: %u\n"
|
||||
#ifndef CONFIG_SMP
|
||||
"Cpu0Bogo\t: %lu.%02lu\n"
|
||||
"Cpu0ClkTck\t: %016lx\n"
|
||||
#endif
|
||||
,
|
||||
@@ -455,10 +454,8 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
|
||||
ncpus_probed,
|
||||
num_online_cpus(),
|
||||
dcache_parity_tl1_occurred,
|
||||
icache_parity_tl1_occurred
|
||||
icache_parity_tl1_occurred,
|
||||
#ifndef CONFIG_SMP
|
||||
, cpu_data(0).udelay_val/(500000/HZ),
|
||||
(cpu_data(0).udelay_val/(5000/HZ)) % 100,
|
||||
cpu_data(0).clock_tick
|
||||
#endif
|
||||
);
|
||||
|
||||
+201
-50
@@ -1,6 +1,6 @@
|
||||
/* smp.c: Sparc64 SMP support.
|
||||
*
|
||||
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
|
||||
* Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/cpudata.h>
|
||||
#include <asm/hvtramp.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irq_regs.h>
|
||||
@@ -41,22 +43,26 @@
|
||||
#include <asm/sections.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/mdesc.h>
|
||||
#include <asm/ldc.h>
|
||||
#include <asm/hypervisor.h>
|
||||
|
||||
extern void calibrate_delay(void);
|
||||
|
||||
int sparc64_multi_core __read_mostly;
|
||||
|
||||
/* Please don't make this stuff initdata!!! --DaveM */
|
||||
unsigned char boot_cpu_id;
|
||||
|
||||
cpumask_t cpu_possible_map __read_mostly = CPU_MASK_NONE;
|
||||
cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE;
|
||||
cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE;
|
||||
cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly =
|
||||
{ [0 ... NR_CPUS-1] = CPU_MASK_NONE };
|
||||
cpumask_t cpu_core_map[NR_CPUS] __read_mostly =
|
||||
{ [0 ... NR_CPUS-1] = CPU_MASK_NONE };
|
||||
|
||||
EXPORT_SYMBOL(cpu_possible_map);
|
||||
EXPORT_SYMBOL(cpu_online_map);
|
||||
EXPORT_SYMBOL(cpu_sibling_map);
|
||||
EXPORT_SYMBOL(cpu_core_map);
|
||||
|
||||
static cpumask_t smp_commenced_mask;
|
||||
static cpumask_t cpu_callout_map;
|
||||
|
||||
void smp_info(struct seq_file *m)
|
||||
{
|
||||
@@ -73,18 +79,17 @@ void smp_bogo(struct seq_file *m)
|
||||
|
||||
for_each_online_cpu(i)
|
||||
seq_printf(m,
|
||||
"Cpu%dBogo\t: %lu.%02lu\n"
|
||||
"Cpu%dClkTck\t: %016lx\n",
|
||||
i, cpu_data(i).udelay_val / (500000/HZ),
|
||||
(cpu_data(i).udelay_val / (5000/HZ)) % 100,
|
||||
i, cpu_data(i).clock_tick);
|
||||
}
|
||||
|
||||
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock);
|
||||
|
||||
extern void setup_sparc64_timer(void);
|
||||
|
||||
static volatile unsigned long callin_flag = 0;
|
||||
|
||||
void __init smp_callin(void)
|
||||
void __devinit smp_callin(void)
|
||||
{
|
||||
int cpuid = hard_smp_processor_id();
|
||||
|
||||
@@ -102,8 +107,6 @@ void __init smp_callin(void)
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
calibrate_delay();
|
||||
cpu_data(cpuid).udelay_val = loops_per_jiffy;
|
||||
callin_flag = 1;
|
||||
__asm__ __volatile__("membar #Sync\n\t"
|
||||
"flush %%g6" : : : "memory");
|
||||
@@ -120,7 +123,9 @@ void __init smp_callin(void)
|
||||
while (!cpu_isset(cpuid, smp_commenced_mask))
|
||||
rmb();
|
||||
|
||||
spin_lock(&call_lock);
|
||||
cpu_set(cpuid, cpu_online_map);
|
||||
spin_unlock(&call_lock);
|
||||
|
||||
/* idle thread is expected to have preempt disabled */
|
||||
preempt_disable();
|
||||
@@ -268,6 +273,67 @@ static void smp_synchronize_one_tick(int cpu)
|
||||
spin_unlock_irqrestore(&itc_sync_lock, flags);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
|
||||
/* XXX Put this in some common place. XXX */
|
||||
static unsigned long kimage_addr_to_ra(void *p)
|
||||
{
|
||||
unsigned long val = (unsigned long) p;
|
||||
|
||||
return kern_base + (val - KERNBASE);
|
||||
}
|
||||
|
||||
static void ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg)
|
||||
{
|
||||
extern unsigned long sparc64_ttable_tl0;
|
||||
extern unsigned long kern_locked_tte_data;
|
||||
extern int bigkernel;
|
||||
struct hvtramp_descr *hdesc;
|
||||
unsigned long trampoline_ra;
|
||||
struct trap_per_cpu *tb;
|
||||
u64 tte_vaddr, tte_data;
|
||||
unsigned long hv_err;
|
||||
|
||||
hdesc = kzalloc(sizeof(*hdesc), GFP_KERNEL);
|
||||
if (!hdesc) {
|
||||
printk(KERN_ERR "ldom_startcpu_cpuid: Cannot allocate "
|
||||
"hvtramp_descr.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hdesc->cpu = cpu;
|
||||
hdesc->num_mappings = (bigkernel ? 2 : 1);
|
||||
|
||||
tb = &trap_block[cpu];
|
||||
tb->hdesc = hdesc;
|
||||
|
||||
hdesc->fault_info_va = (unsigned long) &tb->fault_info;
|
||||
hdesc->fault_info_pa = kimage_addr_to_ra(&tb->fault_info);
|
||||
|
||||
hdesc->thread_reg = thread_reg;
|
||||
|
||||
tte_vaddr = (unsigned long) KERNBASE;
|
||||
tte_data = kern_locked_tte_data;
|
||||
|
||||
hdesc->maps[0].vaddr = tte_vaddr;
|
||||
hdesc->maps[0].tte = tte_data;
|
||||
if (bigkernel) {
|
||||
tte_vaddr += 0x400000;
|
||||
tte_data += 0x400000;
|
||||
hdesc->maps[1].vaddr = tte_vaddr;
|
||||
hdesc->maps[1].tte = tte_data;
|
||||
}
|
||||
|
||||
trampoline_ra = kimage_addr_to_ra(hv_cpu_startup);
|
||||
|
||||
hv_err = sun4v_cpu_start(cpu, trampoline_ra,
|
||||
kimage_addr_to_ra(&sparc64_ttable_tl0),
|
||||
__pa(hdesc));
|
||||
if (hv_err)
|
||||
printk(KERN_ERR "ldom_startcpu_cpuid: sun4v_cpu_start() "
|
||||
"gives error %lu\n", hv_err);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern void sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load);
|
||||
|
||||
extern unsigned long sparc64_cpu_startup;
|
||||
@@ -280,6 +346,7 @@ static struct thread_info *cpu_new_thread = NULL;
|
||||
|
||||
static int __devinit smp_boot_one_cpu(unsigned int cpu)
|
||||
{
|
||||
struct trap_per_cpu *tb = &trap_block[cpu];
|
||||
unsigned long entry =
|
||||
(unsigned long)(&sparc64_cpu_startup);
|
||||
unsigned long cookie =
|
||||
@@ -290,20 +357,25 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
|
||||
p = fork_idle(cpu);
|
||||
callin_flag = 0;
|
||||
cpu_new_thread = task_thread_info(p);
|
||||
cpu_set(cpu, cpu_callout_map);
|
||||
|
||||
if (tlb_type == hypervisor) {
|
||||
/* Alloc the mondo queues, cpu will load them. */
|
||||
sun4v_init_mondo_queues(0, cpu, 1, 0);
|
||||
|
||||
prom_startcpu_cpuid(cpu, entry, cookie);
|
||||
#if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
|
||||
if (ldom_domaining_enabled)
|
||||
ldom_startcpu_cpuid(cpu,
|
||||
(unsigned long) cpu_new_thread);
|
||||
else
|
||||
#endif
|
||||
prom_startcpu_cpuid(cpu, entry, cookie);
|
||||
} else {
|
||||
struct device_node *dp = of_find_node_by_cpuid(cpu);
|
||||
|
||||
prom_startcpu(dp->node, entry, cookie);
|
||||
}
|
||||
|
||||
for (timeout = 0; timeout < 5000000; timeout++) {
|
||||
for (timeout = 0; timeout < 50000; timeout++) {
|
||||
if (callin_flag)
|
||||
break;
|
||||
udelay(100);
|
||||
@@ -313,11 +385,15 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
|
||||
ret = 0;
|
||||
} else {
|
||||
printk("Processor %d is stuck.\n", cpu);
|
||||
cpu_clear(cpu, cpu_callout_map);
|
||||
ret = -ENODEV;
|
||||
}
|
||||
cpu_new_thread = NULL;
|
||||
|
||||
if (tb->hdesc) {
|
||||
kfree(tb->hdesc);
|
||||
tb->hdesc = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -720,7 +796,6 @@ struct call_data_struct {
|
||||
int wait;
|
||||
};
|
||||
|
||||
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock);
|
||||
static struct call_data_struct *call_data;
|
||||
|
||||
extern unsigned long xcall_call_function;
|
||||
@@ -1152,34 +1227,14 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs)
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
void __init smp_tick_init(void)
|
||||
{
|
||||
boot_cpu_id = hard_smp_processor_id();
|
||||
}
|
||||
|
||||
/* /proc/profile writes can call this, don't __init it please. */
|
||||
int setup_profiling_timer(unsigned int multiplier)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Constrain the number of cpus to max_cpus. */
|
||||
void __init smp_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (num_possible_cpus() > max_cpus) {
|
||||
for_each_possible_cpu(i) {
|
||||
if (i != boot_cpu_id) {
|
||||
cpu_clear(i, phys_cpu_present_map);
|
||||
cpu_clear(i, cpu_present_map);
|
||||
if (num_possible_cpus() <= max_cpus)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cpu_data(boot_cpu_id).udelay_val = loops_per_jiffy;
|
||||
}
|
||||
|
||||
void __devinit smp_prepare_boot_cpu(void)
|
||||
@@ -1190,30 +1245,32 @@ void __devinit smp_fill_in_sib_core_maps(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
for_each_present_cpu(i) {
|
||||
unsigned int j;
|
||||
|
||||
cpus_clear(cpu_core_map[i]);
|
||||
if (cpu_data(i).core_id == 0) {
|
||||
cpu_set(i, cpu_core_map[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
for_each_possible_cpu(j) {
|
||||
for_each_present_cpu(j) {
|
||||
if (cpu_data(i).core_id ==
|
||||
cpu_data(j).core_id)
|
||||
cpu_set(j, cpu_core_map[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
for_each_present_cpu(i) {
|
||||
unsigned int j;
|
||||
|
||||
cpus_clear(cpu_sibling_map[i]);
|
||||
if (cpu_data(i).proc_id == -1) {
|
||||
cpu_set(i, cpu_sibling_map[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
for_each_possible_cpu(j) {
|
||||
for_each_present_cpu(j) {
|
||||
if (cpu_data(i).proc_id ==
|
||||
cpu_data(j).proc_id)
|
||||
cpu_set(j, cpu_sibling_map[i]);
|
||||
@@ -1242,18 +1299,112 @@ int __cpuinit __cpu_up(unsigned int cpu)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __init smp_cpus_done(unsigned int max_cpus)
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
void cpu_play_dead(void)
|
||||
{
|
||||
unsigned long bogosum = 0;
|
||||
int cpu = smp_processor_id();
|
||||
unsigned long pstate;
|
||||
|
||||
idle_task_exit();
|
||||
|
||||
if (tlb_type == hypervisor) {
|
||||
struct trap_per_cpu *tb = &trap_block[cpu];
|
||||
|
||||
sun4v_cpu_qconf(HV_CPU_QUEUE_CPU_MONDO,
|
||||
tb->cpu_mondo_pa, 0);
|
||||
sun4v_cpu_qconf(HV_CPU_QUEUE_DEVICE_MONDO,
|
||||
tb->dev_mondo_pa, 0);
|
||||
sun4v_cpu_qconf(HV_CPU_QUEUE_RES_ERROR,
|
||||
tb->resum_mondo_pa, 0);
|
||||
sun4v_cpu_qconf(HV_CPU_QUEUE_NONRES_ERROR,
|
||||
tb->nonresum_mondo_pa, 0);
|
||||
}
|
||||
|
||||
cpu_clear(cpu, smp_commenced_mask);
|
||||
membar_safe("#Sync");
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
__asm__ __volatile__(
|
||||
"rdpr %%pstate, %0\n\t"
|
||||
"wrpr %0, %1, %%pstate"
|
||||
: "=r" (pstate)
|
||||
: "i" (PSTATE_IE));
|
||||
|
||||
while (1)
|
||||
barrier();
|
||||
}
|
||||
|
||||
int __cpu_disable(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
cpuinfo_sparc *c;
|
||||
int i;
|
||||
|
||||
for_each_online_cpu(i)
|
||||
bogosum += cpu_data(i).udelay_val;
|
||||
printk("Total of %ld processors activated "
|
||||
"(%lu.%02lu BogoMIPS).\n",
|
||||
(long) num_online_cpus(),
|
||||
bogosum/(500000/HZ),
|
||||
(bogosum/(5000/HZ))%100);
|
||||
for_each_cpu_mask(i, cpu_core_map[cpu])
|
||||
cpu_clear(cpu, cpu_core_map[i]);
|
||||
cpus_clear(cpu_core_map[cpu]);
|
||||
|
||||
for_each_cpu_mask(i, cpu_sibling_map[cpu])
|
||||
cpu_clear(cpu, cpu_sibling_map[i]);
|
||||
cpus_clear(cpu_sibling_map[cpu]);
|
||||
|
||||
c = &cpu_data(cpu);
|
||||
|
||||
c->core_id = 0;
|
||||
c->proc_id = -1;
|
||||
|
||||
spin_lock(&call_lock);
|
||||
cpu_clear(cpu, cpu_online_map);
|
||||
spin_unlock(&call_lock);
|
||||
|
||||
smp_wmb();
|
||||
|
||||
/* Make sure no interrupts point to this cpu. */
|
||||
fixup_irqs();
|
||||
|
||||
local_irq_enable();
|
||||
mdelay(1);
|
||||
local_irq_disable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __cpu_die(unsigned int cpu)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
smp_rmb();
|
||||
if (!cpu_isset(cpu, smp_commenced_mask))
|
||||
break;
|
||||
msleep(100);
|
||||
}
|
||||
if (cpu_isset(cpu, smp_commenced_mask)) {
|
||||
printk(KERN_ERR "CPU %u didn't die...\n", cpu);
|
||||
} else {
|
||||
#if defined(CONFIG_SUN_LDOMS)
|
||||
unsigned long hv_err;
|
||||
int limit = 100;
|
||||
|
||||
do {
|
||||
hv_err = sun4v_cpu_stop(cpu);
|
||||
if (hv_err == HV_EOK) {
|
||||
cpu_clear(cpu, cpu_present_map);
|
||||
break;
|
||||
}
|
||||
} while (--limit > 0);
|
||||
if (limit <= 0) {
|
||||
printk(KERN_ERR "sun4v_cpu_stop() fails err=%lu\n",
|
||||
hv_err);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void __init smp_cpus_done(unsigned int max_cpus)
|
||||
{
|
||||
}
|
||||
|
||||
void smp_send_reschedule(int cpu)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* $Id: sparc64_ksyms.c,v 1.121 2002/02/09 19:49:31 davem Exp $
|
||||
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
|
||||
/* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
|
||||
*
|
||||
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
|
||||
* Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
|
||||
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
|
||||
* Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
|
||||
*/
|
||||
@@ -28,7 +27,6 @@
|
||||
#include <net/compat.h>
|
||||
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/auxio.h>
|
||||
#include <asm/pgtable.h>
|
||||
@@ -124,10 +122,6 @@ EXPORT_SYMBOL(__write_lock);
|
||||
EXPORT_SYMBOL(__write_unlock);
|
||||
EXPORT_SYMBOL(__write_trylock);
|
||||
|
||||
/* CPU online map and active count. */
|
||||
EXPORT_SYMBOL(cpu_online_map);
|
||||
EXPORT_SYMBOL(phys_cpu_present_map);
|
||||
|
||||
EXPORT_SYMBOL(smp_call_function);
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
@@ -330,12 +324,6 @@ EXPORT_SYMBOL(memset);
|
||||
EXPORT_SYMBOL(memmove);
|
||||
EXPORT_SYMBOL(strncmp);
|
||||
|
||||
/* Delay routines. */
|
||||
EXPORT_SYMBOL(__udelay);
|
||||
EXPORT_SYMBOL(__ndelay);
|
||||
EXPORT_SYMBOL(__const_udelay);
|
||||
EXPORT_SYMBOL(__delay);
|
||||
|
||||
void VISenter(void);
|
||||
/* RAID code needs this */
|
||||
EXPORT_SYMBOL(VISenter);
|
||||
|
||||
@@ -193,7 +193,6 @@ static ssize_t show_##NAME(struct sys_device *dev, char *buf) \
|
||||
}
|
||||
|
||||
SHOW_CPUDATA_ULONG_NAME(clock_tick, clock_tick);
|
||||
SHOW_CPUDATA_ULONG_NAME(udelay_val, udelay_val);
|
||||
SHOW_CPUDATA_UINT_NAME(l1_dcache_size, dcache_size);
|
||||
SHOW_CPUDATA_UINT_NAME(l1_dcache_line_size, dcache_line_size);
|
||||
SHOW_CPUDATA_UINT_NAME(l1_icache_size, icache_size);
|
||||
@@ -203,7 +202,6 @@ SHOW_CPUDATA_UINT_NAME(l2_cache_line_size, ecache_line_size);
|
||||
|
||||
static struct sysdev_attribute cpu_core_attrs[] = {
|
||||
_SYSDEV_ATTR(clock_tick, 0444, show_clock_tick, NULL),
|
||||
_SYSDEV_ATTR(udelay_val, 0444, show_udelay_val, NULL),
|
||||
_SYSDEV_ATTR(l1_dcache_size, 0444, show_l1_dcache_size, NULL),
|
||||
_SYSDEV_ATTR(l1_dcache_line_size, 0444, show_l1_dcache_line_size, NULL),
|
||||
_SYSDEV_ATTR(l1_icache_size, 0444, show_l1_icache_size, NULL),
|
||||
|
||||
@@ -849,9 +849,6 @@ static unsigned long sparc64_init_timers(void)
|
||||
{
|
||||
struct device_node *dp;
|
||||
unsigned long clock;
|
||||
#ifdef CONFIG_SMP
|
||||
extern void smp_tick_init(void);
|
||||
#endif
|
||||
|
||||
dp = of_find_node_by_path("/");
|
||||
if (tlb_type == spitfire) {
|
||||
@@ -874,10 +871,6 @@ static unsigned long sparc64_init_timers(void)
|
||||
clock = of_getintprop_default(dp, "stick-frequency", 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
smp_tick_init();
|
||||
#endif
|
||||
|
||||
return clock;
|
||||
}
|
||||
|
||||
@@ -1038,10 +1031,31 @@ static void __init setup_clockevent_multiplier(unsigned long hz)
|
||||
sparc64_clockevent.mult = mult;
|
||||
}
|
||||
|
||||
static unsigned long tb_ticks_per_usec __read_mostly;
|
||||
|
||||
void __delay(unsigned long loops)
|
||||
{
|
||||
unsigned long bclock, now;
|
||||
|
||||
bclock = tick_ops->get_tick();
|
||||
do {
|
||||
now = tick_ops->get_tick();
|
||||
} while ((now-bclock) < loops);
|
||||
}
|
||||
EXPORT_SYMBOL(__delay);
|
||||
|
||||
void udelay(unsigned long usecs)
|
||||
{
|
||||
__delay(tb_ticks_per_usec * usecs);
|
||||
}
|
||||
EXPORT_SYMBOL(udelay);
|
||||
|
||||
void __init time_init(void)
|
||||
{
|
||||
unsigned long clock = sparc64_init_timers();
|
||||
|
||||
tb_ticks_per_usec = clock / USEC_PER_SEC;
|
||||
|
||||
timer_ticks_per_nsec_quotient =
|
||||
clocksource_hz2mult(clock, SPARC64_NSEC_PER_CYC_SHIFT);
|
||||
|
||||
|
||||
@@ -0,0 +1,395 @@
|
||||
/* vio.c: Virtual I/O channel devices probing infrastructure.
|
||||
*
|
||||
* Copyright (c) 2003-2005 IBM Corp.
|
||||
* Dave Engebretsen engebret@us.ibm.com
|
||||
* Santiago Leon santil@us.ibm.com
|
||||
* Hollis Blanchard <hollisb@us.ibm.com>
|
||||
* Stephen Rothwell
|
||||
*
|
||||
* Adapted to sparc64 by David S. Miller davem@davemloft.net
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/mdesc.h>
|
||||
#include <asm/vio.h>
|
||||
|
||||
static inline int find_in_proplist(const char *list, const char *match,
|
||||
int len)
|
||||
{
|
||||
while (len > 0) {
|
||||
int l;
|
||||
|
||||
if (!strcmp(list, match))
|
||||
return 1;
|
||||
l = strlen(list) + 1;
|
||||
list += l;
|
||||
len -= l;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct vio_device_id *vio_match_device(
|
||||
const struct vio_device_id *matches,
|
||||
const struct vio_dev *dev)
|
||||
{
|
||||
const char *type, *compat;
|
||||
int len;
|
||||
|
||||
type = dev->type;
|
||||
compat = dev->compat;
|
||||
len = dev->compat_len;
|
||||
|
||||
while (matches->type[0] || matches->compat[0]) {
|
||||
int match = 1;
|
||||
if (matches->type[0])
|
||||
match &= !strcmp(matches->type, type);
|
||||
|
||||
if (matches->compat[0]) {
|
||||
match &= len &&
|
||||
find_in_proplist(compat, matches->compat, len);
|
||||
}
|
||||
if (match)
|
||||
return matches;
|
||||
matches++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int vio_bus_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
struct vio_dev *vio_dev = to_vio_dev(dev);
|
||||
struct vio_driver *vio_drv = to_vio_driver(drv);
|
||||
const struct vio_device_id *matches = vio_drv->id_table;
|
||||
|
||||
if (!matches)
|
||||
return 0;
|
||||
|
||||
return vio_match_device(matches, vio_dev) != NULL;
|
||||
}
|
||||
|
||||
static int vio_device_probe(struct device *dev)
|
||||
{
|
||||
struct vio_dev *vdev = to_vio_dev(dev);
|
||||
struct vio_driver *drv = to_vio_driver(dev->driver);
|
||||
const struct vio_device_id *id;
|
||||
int error = -ENODEV;
|
||||
|
||||
if (drv->probe) {
|
||||
id = vio_match_device(drv->id_table, vdev);
|
||||
if (id)
|
||||
error = drv->probe(vdev, id);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int vio_device_remove(struct device *dev)
|
||||
{
|
||||
struct vio_dev *vdev = to_vio_dev(dev);
|
||||
struct vio_driver *drv = to_vio_driver(dev->driver);
|
||||
|
||||
if (drv->remove)
|
||||
return drv->remove(vdev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ssize_t devspec_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct vio_dev *vdev = to_vio_dev(dev);
|
||||
const char *str = "none";
|
||||
|
||||
if (!strcmp(vdev->type, "network"))
|
||||
str = "vnet";
|
||||
else if (!strcmp(vdev->type, "block"))
|
||||
str = "vdisk";
|
||||
|
||||
return sprintf(buf, "%s\n", str);
|
||||
}
|
||||
|
||||
static ssize_t type_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct vio_dev *vdev = to_vio_dev(dev);
|
||||
return sprintf(buf, "%s\n", vdev->type);
|
||||
}
|
||||
|
||||
static struct device_attribute vio_dev_attrs[] = {
|
||||
__ATTR_RO(devspec),
|
||||
__ATTR_RO(type),
|
||||
__ATTR_NULL
|
||||
};
|
||||
|
||||
static struct bus_type vio_bus_type = {
|
||||
.name = "vio",
|
||||
.dev_attrs = vio_dev_attrs,
|
||||
.match = vio_bus_match,
|
||||
.probe = vio_device_probe,
|
||||
.remove = vio_device_remove,
|
||||
};
|
||||
|
||||
int vio_register_driver(struct vio_driver *viodrv)
|
||||
{
|
||||
viodrv->driver.bus = &vio_bus_type;
|
||||
|
||||
return driver_register(&viodrv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL(vio_register_driver);
|
||||
|
||||
void vio_unregister_driver(struct vio_driver *viodrv)
|
||||
{
|
||||
driver_unregister(&viodrv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL(vio_unregister_driver);
|
||||
|
||||
static void __devinit vio_dev_release(struct device *dev)
|
||||
{
|
||||
kfree(to_vio_dev(dev));
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_pciobppath_attr(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct vio_dev *vdev;
|
||||
struct device_node *dp;
|
||||
|
||||
vdev = to_vio_dev(dev);
|
||||
dp = vdev->dp;
|
||||
|
||||
return snprintf (buf, PAGE_SIZE, "%s\n", dp->full_name);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH,
|
||||
show_pciobppath_attr, NULL);
|
||||
|
||||
struct device_node *cdev_node;
|
||||
|
||||
static struct vio_dev *root_vdev;
|
||||
static u64 cdev_cfg_handle;
|
||||
|
||||
static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
|
||||
struct vio_dev *vdev)
|
||||
{
|
||||
u64 a;
|
||||
|
||||
mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
|
||||
const u64 *chan_id;
|
||||
const u64 *irq;
|
||||
u64 target;
|
||||
|
||||
target = mdesc_arc_target(hp, a);
|
||||
|
||||
irq = mdesc_get_property(hp, target, "tx-ino", NULL);
|
||||
if (irq)
|
||||
vdev->tx_irq = sun4v_build_virq(cdev_cfg_handle, *irq);
|
||||
|
||||
irq = mdesc_get_property(hp, target, "rx-ino", NULL);
|
||||
if (irq)
|
||||
vdev->rx_irq = sun4v_build_virq(cdev_cfg_handle, *irq);
|
||||
|
||||
chan_id = mdesc_get_property(hp, target, "id", NULL);
|
||||
if (chan_id)
|
||||
vdev->channel_id = *chan_id;
|
||||
}
|
||||
}
|
||||
|
||||
static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
|
||||
struct device *parent)
|
||||
{
|
||||
const char *type, *compat;
|
||||
struct device_node *dp;
|
||||
struct vio_dev *vdev;
|
||||
int err, tlen, clen;
|
||||
|
||||
type = mdesc_get_property(hp, mp, "device-type", &tlen);
|
||||
if (!type) {
|
||||
type = mdesc_get_property(hp, mp, "name", &tlen);
|
||||
if (!type) {
|
||||
type = mdesc_node_name(hp, mp);
|
||||
tlen = strlen(type) + 1;
|
||||
}
|
||||
}
|
||||
if (tlen > VIO_MAX_TYPE_LEN) {
|
||||
printk(KERN_ERR "VIO: Type string [%s] is too long.\n",
|
||||
type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
compat = mdesc_get_property(hp, mp, "device-type", &clen);
|
||||
if (!compat) {
|
||||
clen = 0;
|
||||
} else if (clen > VIO_MAX_COMPAT_LEN) {
|
||||
printk(KERN_ERR "VIO: Compat len %d for [%s] is too long.\n",
|
||||
clen, type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
|
||||
if (!vdev) {
|
||||
printk(KERN_ERR "VIO: Could not allocate vio_dev\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vdev->mp = mp;
|
||||
memcpy(vdev->type, type, tlen);
|
||||
if (compat)
|
||||
memcpy(vdev->compat, compat, clen);
|
||||
else
|
||||
memset(vdev->compat, 0, sizeof(vdev->compat));
|
||||
vdev->compat_len = clen;
|
||||
|
||||
vdev->channel_id = ~0UL;
|
||||
vdev->tx_irq = ~0;
|
||||
vdev->rx_irq = ~0;
|
||||
|
||||
vio_fill_channel_info(hp, mp, vdev);
|
||||
|
||||
snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%lx", mp);
|
||||
vdev->dev.parent = parent;
|
||||
vdev->dev.bus = &vio_bus_type;
|
||||
vdev->dev.release = vio_dev_release;
|
||||
|
||||
if (parent == NULL) {
|
||||
dp = cdev_node;
|
||||
} else if (to_vio_dev(parent) == root_vdev) {
|
||||
dp = of_get_next_child(cdev_node, NULL);
|
||||
while (dp) {
|
||||
if (!strcmp(dp->type, type))
|
||||
break;
|
||||
|
||||
dp = of_get_next_child(cdev_node, dp);
|
||||
}
|
||||
} else {
|
||||
dp = to_vio_dev(parent)->dp;
|
||||
}
|
||||
vdev->dp = dp;
|
||||
|
||||
err = device_register(&vdev->dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "VIO: Could not register device %s, err=%d\n",
|
||||
vdev->dev.bus_id, err);
|
||||
kfree(vdev);
|
||||
return NULL;
|
||||
}
|
||||
if (vdev->dp)
|
||||
err = sysfs_create_file(&vdev->dev.kobj,
|
||||
&dev_attr_obppath.attr);
|
||||
|
||||
return vdev;
|
||||
}
|
||||
|
||||
static void walk_tree(struct mdesc_handle *hp, u64 n, struct vio_dev *parent)
|
||||
{
|
||||
u64 a;
|
||||
|
||||
mdesc_for_each_arc(a, hp, n, MDESC_ARC_TYPE_FWD) {
|
||||
struct vio_dev *vdev;
|
||||
u64 target;
|
||||
|
||||
target = mdesc_arc_target(hp, a);
|
||||
vdev = vio_create_one(hp, target, &parent->dev);
|
||||
if (vdev)
|
||||
walk_tree(hp, target, vdev);
|
||||
}
|
||||
}
|
||||
|
||||
static void create_devices(struct mdesc_handle *hp, u64 root)
|
||||
{
|
||||
u64 mp;
|
||||
|
||||
root_vdev = vio_create_one(hp, root, NULL);
|
||||
if (!root_vdev) {
|
||||
printk(KERN_ERR "VIO: Coult not create root device.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
walk_tree(hp, root, root_vdev);
|
||||
|
||||
/* Domain services is odd as it doesn't sit underneath the
|
||||
* channel-devices node, so we plug it in manually.
|
||||
*/
|
||||
mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services");
|
||||
if (mp != MDESC_NODE_NULL) {
|
||||
struct vio_dev *parent = vio_create_one(hp, mp,
|
||||
&root_vdev->dev);
|
||||
|
||||
if (parent)
|
||||
walk_tree(hp, mp, parent);
|
||||
}
|
||||
}
|
||||
|
||||
const char *channel_devices_node = "channel-devices";
|
||||
const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
|
||||
const char *cfg_handle_prop = "cfg-handle";
|
||||
|
||||
static int __init vio_init(void)
|
||||
{
|
||||
struct mdesc_handle *hp;
|
||||
const char *compat;
|
||||
const u64 *cfg_handle;
|
||||
int err, len;
|
||||
u64 root;
|
||||
|
||||
err = bus_register(&vio_bus_type);
|
||||
if (err) {
|
||||
printk(KERN_ERR "VIO: Could not register bus type err=%d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
hp = mdesc_grab();
|
||||
if (!hp)
|
||||
return 0;
|
||||
|
||||
root = mdesc_node_by_name(hp, MDESC_NODE_NULL, channel_devices_node);
|
||||
if (root == MDESC_NODE_NULL) {
|
||||
printk(KERN_INFO "VIO: No channel-devices MDESC node.\n");
|
||||
mdesc_release(hp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cdev_node = of_find_node_by_name(NULL, "channel-devices");
|
||||
err = -ENODEV;
|
||||
if (!cdev_node) {
|
||||
printk(KERN_INFO "VIO: No channel-devices OBP node.\n");
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
compat = mdesc_get_property(hp, root, "compatible", &len);
|
||||
if (!compat) {
|
||||
printk(KERN_ERR "VIO: Channel devices lacks compatible "
|
||||
"property\n");
|
||||
goto out_release;
|
||||
}
|
||||
if (!find_in_proplist(compat, channel_devices_compat, len)) {
|
||||
printk(KERN_ERR "VIO: Channel devices node lacks (%s) "
|
||||
"compat entry.\n", channel_devices_compat);
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
cfg_handle = mdesc_get_property(hp, root, cfg_handle_prop, NULL);
|
||||
if (!cfg_handle) {
|
||||
printk(KERN_ERR "VIO: Channel devices lacks %s property\n",
|
||||
cfg_handle_prop);
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
cdev_cfg_handle = *cfg_handle;
|
||||
|
||||
create_devices(hp, root);
|
||||
|
||||
mdesc_release(hp);
|
||||
|
||||
return 0;
|
||||
|
||||
out_release:
|
||||
mdesc_release(hp);
|
||||
return err;
|
||||
}
|
||||
|
||||
postcore_initcall(vio_init);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,6 @@ lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \
|
||||
NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o NGpatch.o \
|
||||
NGpage.o NGbzero.o \
|
||||
copy_in_user.o user_fixup.o memmove.o \
|
||||
mcount.o ipcsum.o rwsem.o xor.o delay.o
|
||||
mcount.o ipcsum.o rwsem.o xor.o
|
||||
|
||||
obj-y += iomap.o
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/* delay.c: Delay loops for sparc64
|
||||
*
|
||||
* Copyright (C) 2004, 2006 David S. Miller <davem@davemloft.net>
|
||||
*
|
||||
* Based heavily upon x86 variant which is:
|
||||
* Copyright (C) 1993 Linus Torvalds
|
||||
* Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <asm/timer.h>
|
||||
|
||||
void __delay(unsigned long loops)
|
||||
{
|
||||
unsigned long bclock, now;
|
||||
|
||||
bclock = tick_ops->get_tick();
|
||||
do {
|
||||
now = tick_ops->get_tick();
|
||||
} while ((now-bclock) < loops);
|
||||
}
|
||||
|
||||
/* We used to multiply by HZ after shifting down by 32 bits
|
||||
* but that runs into problems for higher values of HZ and
|
||||
* slow cpus.
|
||||
*/
|
||||
void __const_udelay(unsigned long n)
|
||||
{
|
||||
n *= 4;
|
||||
|
||||
n *= (cpu_data(raw_smp_processor_id()).udelay_val * (HZ/4));
|
||||
n >>= 32;
|
||||
|
||||
__delay(n + 1);
|
||||
}
|
||||
|
||||
void __udelay(unsigned long n)
|
||||
{
|
||||
__const_udelay(n * 0x10c7UL);
|
||||
}
|
||||
|
||||
|
||||
void __ndelay(unsigned long n)
|
||||
{
|
||||
__const_udelay(n * 0x5UL);
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <asm/openprom.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/ldc.h>
|
||||
|
||||
int prom_service_exists(const char *service_name)
|
||||
{
|
||||
@@ -37,6 +38,10 @@ void prom_sun4v_guest_soft_state(void)
|
||||
/* Reset and reboot the machine with the command 'bcommand'. */
|
||||
void prom_reboot(const char *bcommand)
|
||||
{
|
||||
#ifdef CONFIG_SUN_LDOMS
|
||||
if (ldom_domaining_enabled)
|
||||
ldom_reboot(bcommand);
|
||||
#endif
|
||||
p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) |
|
||||
P1275_INOUT(1, 0), bcommand);
|
||||
}
|
||||
@@ -91,6 +96,10 @@ void prom_cmdline(void)
|
||||
*/
|
||||
void prom_halt(void)
|
||||
{
|
||||
#ifdef CONFIG_SUN_LDOMS
|
||||
if (ldom_domaining_enabled)
|
||||
ldom_power_off();
|
||||
#endif
|
||||
again:
|
||||
p1275_cmd("exit", P1275_INOUT(0, 0));
|
||||
goto again; /* PROM is out to get me -DaveM */
|
||||
@@ -98,6 +107,10 @@ again:
|
||||
|
||||
void prom_halt_power_off(void)
|
||||
{
|
||||
#ifdef CONFIG_SUN_LDOMS
|
||||
if (ldom_domaining_enabled)
|
||||
ldom_power_off();
|
||||
#endif
|
||||
p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0));
|
||||
|
||||
/* if nothing else helps, we just halt */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user