diff options
Diffstat (limited to 'arch/sparc/kernel')
47 files changed, 1315 insertions, 1707 deletions
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 6cf591b7e1c..d432fb20358 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -74,7 +74,8 @@ obj-y                     += dma.o  obj-$(CONFIG_PCIC_PCI)    += pcic.o  obj-$(CONFIG_LEON_PCI)    += leon_pci.o -obj-$(CONFIG_GRPCI2)      += leon_pci_grpci2.o +obj-$(CONFIG_SPARC_GRPCI2)+= leon_pci_grpci2.o +obj-$(CONFIG_SPARC_GRPCI1)+= leon_pci_grpci1.o  obj-$(CONFIG_SMP)         += trampoline_$(BITS).o smp_$(BITS).o  obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o leon_smp.o @@ -102,9 +103,6 @@ obj-$(CONFIG_PCI_MSI)        += pci_msi.o  obj-$(CONFIG_COMPAT)         += sys32.o sys_sparc32.o signal32.o -# sparc64 cpufreq -obj-$(CONFIG_US3_FREQ)  += us3_cpufreq.o -obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o  obj-$(CONFIG_US3_MC)    += chmc.o  obj-$(CONFIG_KPROBES)   += kprobes.o diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c index 348fa1aeabc..eefda32b595 100644 --- a/arch/sparc/kernel/apc.c +++ b/arch/sparc/kernel/apc.c @@ -20,6 +20,7 @@  #include <asm/uaccess.h>  #include <asm/auxio.h>  #include <asm/apc.h> +#include <asm/processor.h>  /* Debugging   *  @@ -158,7 +159,7 @@ static int apc_probe(struct platform_device *op)  	/* Assign power management IDLE handler */  	if (!apc_no_idle) -		pm_idle = apc_swift_idle;	 +		sparc_idle = apc_swift_idle;  	printk(KERN_INFO "%s: power management initialized%s\n",   	       APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : ""); diff --git a/arch/sparc/kernel/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c index 68f7e1118e9..961b87f99e6 100644 --- a/arch/sparc/kernel/asm-offsets.c +++ b/arch/sparc/kernel/asm-offsets.c @@ -14,6 +14,8 @@  // #include <linux/mm.h>  #include <linux/kbuild.h> +#include <asm/hibernate.h> +  #ifdef CONFIG_SPARC32  int sparc32_foo(void)  { @@ -24,6 +26,19 @@ int sparc32_foo(void)  #else  int sparc64_foo(void)  { +#ifdef CONFIG_HIBERNATION +	BLANK(); +	OFFSET(SC_REG_FP, saved_context, fp); +	OFFSET(SC_REG_CWP, saved_context, cwp); +	OFFSET(SC_REG_WSTATE, saved_context, wstate); + +	OFFSET(SC_REG_TICK, saved_context, tick); +	OFFSET(SC_REG_PSTATE, saved_context, pstate); + +	OFFSET(SC_REG_G4, saved_context, g4); +	OFFSET(SC_REG_G5, saved_context, g5); +	OFFSET(SC_REG_G6, saved_context, g6); +#endif  	return 0;  }  #endif diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c index a6c94a2bf9d..5c5125895db 100644 --- a/arch/sparc/kernel/cpu.c +++ b/arch/sparc/kernel/cpu.c @@ -493,6 +493,12 @@ static void __init sun4v_cpu_probe(void)  		sparc_pmu_type = "niagara5";  		break; +	case SUN4V_CHIP_SPARC64X: +		sparc_cpu_type = "SPARC64-X"; +		sparc_fpu_type = "SPARC64-X integrated FPU"; +		sparc_pmu_type = "sparc64-x"; +		break; +  	default:  		printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",  		       prom_cpu_compatible); diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 21fd1a8f47d..e2a03004508 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -820,14 +820,6 @@ sys_sparc_pipe:  	 mov	%l5, %o7  	.align	4 -	.globl	sys_sigaltstack -sys_sigaltstack: -	mov	%o7, %l5 -	mov	%fp, %o2 -	call	do_sigaltstack -	 mov	%l5, %o7 - -	.align	4  	.globl	sys_sigstack  sys_sigstack:  	mov	%o7, %l5 diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S index 2feb15c35d9..26b706a1867 100644 --- a/arch/sparc/kernel/head_64.S +++ b/arch/sparc/kernel/head_64.S @@ -134,6 +134,8 @@ prom_niagara_prefix:  	.asciz	"SUNW,UltraSPARC-T"  prom_sparc_prefix:  	.asciz	"SPARC-" +prom_sparc64x_prefix: +	.asciz	"SPARC64-X"  	.align	4  prom_root_compatible:  	.skip	64 @@ -412,7 +414,7 @@ sun4v_chip_type:  	cmp	%g2, 'T'  	be,pt	%xcc, 70f  	 cmp	%g2, 'M' -	bne,pn	%xcc, 4f +	bne,pn	%xcc, 49f  	 nop  70:	ldub	[%g1 + 7], %g2 @@ -425,7 +427,7 @@ sun4v_chip_type:  	cmp	%g2, '5'  	be,pt	%xcc, 5f  	 mov	SUN4V_CHIP_NIAGARA5, %g4 -	ba,pt	%xcc, 4f +	ba,pt	%xcc, 49f  	 nop  91:	sethi	%hi(prom_cpu_compatible), %g1 @@ -439,6 +441,25 @@ sun4v_chip_type:  	 mov	SUN4V_CHIP_NIAGARA2, %g4  4: +	/* Athena */ +	sethi	%hi(prom_cpu_compatible), %g1 +	or	%g1, %lo(prom_cpu_compatible), %g1 +	sethi	%hi(prom_sparc64x_prefix), %g7 +	or	%g7, %lo(prom_sparc64x_prefix), %g7 +	mov	9, %g3 +41:	ldub	[%g7], %g2 +	ldub	[%g1], %g4 +	cmp	%g2, %g4 +	bne,pn	%icc, 49f +	add	%g7, 1, %g7 +	subcc	%g3, 1, %g3 +	bne,pt	%xcc, 41b +	add	%g1, 1, %g1 +	mov	SUN4V_CHIP_SPARC64X, %g4 +	ba,pt	%xcc, 5f +	nop + +49:  	mov	SUN4V_CHIP_UNKNOWN, %g4  5:	sethi	%hi(sun4v_chip_type), %g2  	or	%g2, %lo(sun4v_chip_type), %g2 diff --git a/arch/sparc/kernel/hvtramp.S b/arch/sparc/kernel/hvtramp.S index 9365432904d..605c960b2fa 100644 --- a/arch/sparc/kernel/hvtramp.S +++ b/arch/sparc/kernel/hvtramp.S @@ -128,8 +128,7 @@ hv_cpu_startup:  	call		smp_callin  	 nop -	call		cpu_idle -	 mov		0, %o0 +  	call		cpu_panic  	 nop diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 0f094db918c..2096468de9b 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -693,7 +693,7 @@ static int sparc_io_proc_show(struct seq_file *m, void *v)  static int sparc_io_proc_open(struct inode *inode, struct file *file)  { -	return single_open(file, sparc_io_proc_show, PDE(inode)->data); +	return single_open(file, sparc_io_proc_show, PDE_DATA(inode));  }  static const struct file_operations sparc_io_proc_fops = { diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index 291bb5de9ce..a702d9ab019 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h @@ -48,6 +48,10 @@ extern void sun4m_init_IRQ(void);  extern void sun4m_unmask_profile_irq(void);  extern void sun4m_clear_profile_irq(int cpu); +/* sun4m_smp.c */ +void sun4m_cpu_pre_starting(void *arg); +void sun4m_cpu_pre_online(void *arg); +  /* sun4d_irq.c */  extern spinlock_t sun4d_imsk_lock; @@ -60,6 +64,14 @@ extern int show_sun4d_interrupts(struct seq_file *, void *);  extern void sun4d_distribute_irqs(void);  extern void sun4d_free_irq(unsigned int irq, void *dev_id); +/* sun4d_smp.c */ +void sun4d_cpu_pre_starting(void *arg); +void sun4d_cpu_pre_online(void *arg); + +/* leon_smp.c */ +void leon_cpu_pre_starting(void *arg); +void leon_cpu_pre_online(void *arg); +  /* head_32.S */  extern unsigned int t_nmi[];  extern unsigned int linux_trap_ipi15_sun4d[]; diff --git a/arch/sparc/kernel/kgdb_32.c b/arch/sparc/kernel/kgdb_32.c index 2e424a576a3..dcf210811af 100644 --- a/arch/sparc/kernel/kgdb_32.c +++ b/arch/sparc/kernel/kgdb_32.c @@ -5,6 +5,7 @@  #include <linux/kgdb.h>  #include <linux/kdebug.h> +#include <linux/sched.h>  #include <asm/kdebug.h>  #include <asm/ptrace.h> diff --git a/arch/sparc/kernel/kprobes.c b/arch/sparc/kernel/kprobes.c index a39d1ba5a11..e72212148d2 100644 --- a/arch/sparc/kernel/kprobes.c +++ b/arch/sparc/kernel/kprobes.c @@ -511,7 +511,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)  {  	struct kretprobe_instance *ri = NULL;  	struct hlist_head *head, empty_rp; -	struct hlist_node *node, *tmp; +	struct hlist_node *tmp;  	unsigned long flags, orig_ret_address = 0;  	unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; @@ -531,7 +531,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)  	 *       real return address, and all the rest will point to  	 *       kretprobe_trampoline  	 */ -	hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { +	hlist_for_each_entry_safe(ri, tmp, head, hlist) {  		if (ri->task != current)  			/* another task is sharing our hash bucket */  			continue; @@ -559,7 +559,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)  	kretprobe_hash_unlock(current, &flags);  	preempt_enable_no_resched(); -	hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { +	hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {  		hlist_del(&ri->hlist);  		kfree(ri);  	} diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index 9fcc6b4e93b..54df554b82d 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -953,9 +953,8 @@ static HLIST_HEAD(ldc_channel_list);  static int __ldc_channel_exists(unsigned long id)  {  	struct ldc_channel *lp; -	struct hlist_node *n; -	hlist_for_each_entry(lp, n, &ldc_channel_list, list) { +	hlist_for_each_entry(lp, &ldc_channel_list, list) {  		if (lp->id == id)  			return 1;  	} diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 87f60ee6543..7c0231dabe4 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -213,6 +213,7 @@ unsigned int leon_build_device_irq(unsigned int real_irq,  {  	unsigned int irq;  	unsigned long mask; +	struct irq_desc *desc;  	irq = 0;  	mask = leon_get_irqmask(real_irq); @@ -226,9 +227,12 @@ unsigned int leon_build_device_irq(unsigned int real_irq,  	if (do_ack)  		mask |= LEON_DO_ACK_HW; -	irq_set_chip_and_handler_name(irq, &leon_irq, -				      flow_handler, name); -	irq_set_chip_data(irq, (void *)mask); +	desc = irq_to_desc(irq); +	if (!desc || !desc->handle_irq || desc->handle_irq == handle_bad_irq) { +		irq_set_chip_and_handler_name(irq, &leon_irq, +					      flow_handler, name); +		irq_set_chip_data(irq, (void *)mask); +	}  out:  	return irq; diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c index 852dc843052..88aaaa57bb6 100644 --- a/arch/sparc/kernel/leon_pci.c +++ b/arch/sparc/kernel/leon_pci.c @@ -29,6 +29,8 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)  	pci_add_resource_offset(&resources, &info->io_space,  				info->io_space.start - 0x1000);  	pci_add_resource(&resources, &info->mem_space); +	info->busn.flags = IORESOURCE_BUS; +	pci_add_resource(&resources, &info->busn);  	root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info,  				     &resources); diff --git a/arch/sparc/kernel/leon_pci_grpci1.c b/arch/sparc/kernel/leon_pci_grpci1.c new file mode 100644 index 00000000000..7739a54315e --- /dev/null +++ b/arch/sparc/kernel/leon_pci_grpci1.c @@ -0,0 +1,724 @@ +/* + * leon_pci_grpci1.c: GRPCI1 Host PCI driver + * + * Copyright (C) 2013 Aeroflex Gaisler AB + * + * This GRPCI1 driver does not support PCI interrupts taken from + * GPIO pins. Interrupt generation at PCI parity and system error + * detection is by default turned off since some GRPCI1 cores does + * not support detection. It can be turned on from the bootloader + * using the all_pci_errors property. + * + * Contributors: Daniel Hellstrom <daniel@gaisler.com> + */ + +#include <linux/of_device.h> +#include <linux/export.h> +#include <linux/kernel.h> +#include <linux/of_irq.h> +#include <linux/delay.h> +#include <linux/pci.h> + +#include <asm/leon_pci.h> +#include <asm/sections.h> +#include <asm/vaddrs.h> +#include <asm/leon.h> +#include <asm/io.h> + +#include "irq.h" + +/* Enable/Disable Debugging Configuration Space Access */ +#undef GRPCI1_DEBUG_CFGACCESS + +/* + * GRPCI1 APB Register MAP + */ +struct grpci1_regs { +	unsigned int cfg_stat;		/* 0x00 Configuration / Status */ +	unsigned int bar0;		/* 0x04 BAR0 (RO) */ +	unsigned int page0;		/* 0x08 PAGE0 (RO) */ +	unsigned int bar1;		/* 0x0C BAR1 (RO) */ +	unsigned int page1;		/* 0x10 PAGE1 */ +	unsigned int iomap;		/* 0x14 IO Map */ +	unsigned int stat_cmd;		/* 0x18 PCI Status & Command (RO) */ +	unsigned int irq;		/* 0x1C Interrupt register */ +}; + +#define REGLOAD(a)	(be32_to_cpu(__raw_readl(&(a)))) +#define REGSTORE(a, v)	(__raw_writel(cpu_to_be32(v), &(a))) + +#define PAGE0_BTEN_BIT    0 +#define PAGE0_BTEN        (1 << PAGE0_BTEN_BIT) + +#define CFGSTAT_HOST_BIT  13 +#define CFGSTAT_CTO_BIT   8 +#define CFGSTAT_HOST      (1 << CFGSTAT_HOST_BIT) +#define CFGSTAT_CTO       (1 << CFGSTAT_CTO_BIT) + +#define IRQ_DPE (1 << 9) +#define IRQ_SSE (1 << 8) +#define IRQ_RMA (1 << 7) +#define IRQ_RTA (1 << 6) +#define IRQ_STA (1 << 5) +#define IRQ_DPED (1 << 4) +#define IRQ_INTD (1 << 3) +#define IRQ_INTC (1 << 2) +#define IRQ_INTB (1 << 1) +#define IRQ_INTA (1 << 0) +#define IRQ_DEF_ERRORS (IRQ_RMA | IRQ_RTA | IRQ_STA) +#define IRQ_ALL_ERRORS (IRQ_DPED | IRQ_DEF_ERRORS | IRQ_SSE | IRQ_DPE) +#define IRQ_INTX (IRQ_INTA | IRQ_INTB | IRQ_INTC | IRQ_INTD) +#define IRQ_MASK_BIT 16 + +#define DEF_PCI_ERRORS (PCI_STATUS_SIG_TARGET_ABORT | \ +			PCI_STATUS_REC_TARGET_ABORT | \ +			PCI_STATUS_REC_MASTER_ABORT) +#define ALL_PCI_ERRORS (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY | \ +			PCI_STATUS_SIG_SYSTEM_ERROR | DEF_PCI_ERRORS) + +#define TGT 256 + +struct grpci1_priv { +	struct leon_pci_info	info; /* must be on top of this structure */ +	struct grpci1_regs	*regs;		/* GRPCI register map */ +	struct device		*dev; +	int			pci_err_mask;	/* STATUS register error mask */ +	int			irq;		/* LEON irqctrl GRPCI IRQ */ +	unsigned char		irq_map[4];	/* GRPCI nexus PCI INTX# IRQs */ +	unsigned int		irq_err;	/* GRPCI nexus Virt Error IRQ */ + +	/* AHB PCI Windows */ +	unsigned long		pci_area;	/* MEMORY */ +	unsigned long		pci_area_end; +	unsigned long		pci_io;		/* I/O */ +	unsigned long		pci_conf;	/* CONFIGURATION */ +	unsigned long		pci_conf_end; +	unsigned long		pci_io_va; +}; + +static struct grpci1_priv *grpci1priv; + +static int grpci1_cfg_w32(struct grpci1_priv *priv, unsigned int bus, +				unsigned int devfn, int where, u32 val); + +int grpci1_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ +	struct grpci1_priv *priv = dev->bus->sysdata; +	int irq_group; + +	/* Use default IRQ decoding on PCI BUS0 according slot numbering */ +	irq_group = slot & 0x3; +	pin = ((pin - 1) + irq_group) & 0x3; + +	return priv->irq_map[pin]; +} + +static int grpci1_cfg_r32(struct grpci1_priv *priv, unsigned int bus, +				unsigned int devfn, int where, u32 *val) +{ +	u32 *pci_conf, tmp, cfg; + +	if (where & 0x3) +		return -EINVAL; + +	if (bus == 0) { +		devfn += (0x8 * 6); /* start at AD16=Device0 */ +	} else if (bus == TGT) { +		bus = 0; +		devfn = 0; /* special case: bridge controller itself */ +	} + +	/* Select bus */ +	cfg = REGLOAD(priv->regs->cfg_stat); +	REGSTORE(priv->regs->cfg_stat, (cfg & ~(0xf << 23)) | (bus << 23)); + +	/* do read access */ +	pci_conf = (u32 *) (priv->pci_conf | (devfn << 8) | (where & 0xfc)); +	tmp = LEON3_BYPASS_LOAD_PA(pci_conf); + +	/* check if master abort was received */ +	if (REGLOAD(priv->regs->cfg_stat) & CFGSTAT_CTO) { +		*val = 0xffffffff; +		/* Clear Master abort bit in PCI cfg space (is set) */ +		tmp = REGLOAD(priv->regs->stat_cmd); +		grpci1_cfg_w32(priv, TGT, 0, PCI_COMMAND, tmp); +	} else { +		/* Bus always little endian (unaffected by byte-swapping) */ +		*val = flip_dword(tmp); +	} + +	return 0; +} + +static int grpci1_cfg_r16(struct grpci1_priv *priv, unsigned int bus, +				unsigned int devfn, int where, u32 *val) +{ +	u32 v; +	int ret; + +	if (where & 0x1) +		return -EINVAL; +	ret = grpci1_cfg_r32(priv, bus, devfn, where & ~0x3, &v); +	*val = 0xffff & (v >> (8 * (where & 0x3))); +	return ret; +} + +static int grpci1_cfg_r8(struct grpci1_priv *priv, unsigned int bus, +				unsigned int devfn, int where, u32 *val) +{ +	u32 v; +	int ret; + +	ret = grpci1_cfg_r32(priv, bus, devfn, where & ~0x3, &v); +	*val = 0xff & (v >> (8 * (where & 3))); + +	return ret; +} + +static int grpci1_cfg_w32(struct grpci1_priv *priv, unsigned int bus, +				unsigned int devfn, int where, u32 val) +{ +	unsigned int *pci_conf; +	u32 cfg; + +	if (where & 0x3) +		return -EINVAL; + +	if (bus == 0) { +		devfn += (0x8 * 6); /* start at AD16=Device0 */ +	} else if (bus == TGT) { +		bus = 0; +		devfn = 0; /* special case: bridge controller itself */ +	} + +	/* Select bus */ +	cfg = REGLOAD(priv->regs->cfg_stat); +	REGSTORE(priv->regs->cfg_stat, (cfg & ~(0xf << 23)) | (bus << 23)); + +	pci_conf = (unsigned int *) (priv->pci_conf | +						(devfn << 8) | (where & 0xfc)); +	LEON3_BYPASS_STORE_PA(pci_conf, flip_dword(val)); + +	return 0; +} + +static int grpci1_cfg_w16(struct grpci1_priv *priv, unsigned int bus, +				unsigned int devfn, int where, u32 val) +{ +	int ret; +	u32 v; + +	if (where & 0x1) +		return -EINVAL; +	ret = grpci1_cfg_r32(priv, bus, devfn, where&~3, &v); +	if (ret) +		return ret; +	v = (v & ~(0xffff << (8 * (where & 0x3)))) | +	    ((0xffff & val) << (8 * (where & 0x3))); +	return grpci1_cfg_w32(priv, bus, devfn, where & ~0x3, v); +} + +static int grpci1_cfg_w8(struct grpci1_priv *priv, unsigned int bus, +				unsigned int devfn, int where, u32 val) +{ +	int ret; +	u32 v; + +	ret = grpci1_cfg_r32(priv, bus, devfn, where & ~0x3, &v); +	if (ret != 0) +		return ret; +	v = (v & ~(0xff << (8 * (where & 0x3)))) | +	    ((0xff & val) << (8 * (where & 0x3))); +	return grpci1_cfg_w32(priv, bus, devfn, where & ~0x3, v); +} + +/* Read from Configuration Space. When entering here the PCI layer has taken + * the pci_lock spinlock and IRQ is off. + */ +static int grpci1_read_config(struct pci_bus *bus, unsigned int devfn, +			      int where, int size, u32 *val) +{ +	struct grpci1_priv *priv = grpci1priv; +	unsigned int busno = bus->number; +	int ret; + +	if (PCI_SLOT(devfn) > 15 || busno > 15) { +		*val = ~0; +		return 0; +	} + +	switch (size) { +	case 1: +		ret = grpci1_cfg_r8(priv, busno, devfn, where, val); +		break; +	case 2: +		ret = grpci1_cfg_r16(priv, busno, devfn, where, val); +		break; +	case 4: +		ret = grpci1_cfg_r32(priv, busno, devfn, where, val); +		break; +	default: +		ret = -EINVAL; +		break; +	} + +#ifdef GRPCI1_DEBUG_CFGACCESS +	printk(KERN_INFO +		"grpci1_read_config: [%02x:%02x:%x] ofs=%d val=%x size=%d\n", +		busno, PCI_SLOT(devfn), PCI_FUNC(devfn), where, *val, size); +#endif + +	return ret; +} + +/* Write to Configuration Space. When entering here the PCI layer has taken + * the pci_lock spinlock and IRQ is off. + */ +static int grpci1_write_config(struct pci_bus *bus, unsigned int devfn, +			       int where, int size, u32 val) +{ +	struct grpci1_priv *priv = grpci1priv; +	unsigned int busno = bus->number; + +	if (PCI_SLOT(devfn) > 15 || busno > 15) +		return 0; + +#ifdef GRPCI1_DEBUG_CFGACCESS +	printk(KERN_INFO +		"grpci1_write_config: [%02x:%02x:%x] ofs=%d size=%d val=%x\n", +		busno, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val); +#endif + +	switch (size) { +	default: +		return -EINVAL; +	case 1: +		return grpci1_cfg_w8(priv, busno, devfn, where, val); +	case 2: +		return grpci1_cfg_w16(priv, busno, devfn, where, val); +	case 4: +		return grpci1_cfg_w32(priv, busno, devfn, where, val); +	} +} + +static struct pci_ops grpci1_ops = { +	.read =		grpci1_read_config, +	.write =	grpci1_write_config, +}; + +/* GENIRQ IRQ chip implementation for grpci1 irqmode=0..2. In configuration + * 3 where all PCI Interrupts has a separate IRQ on the system IRQ controller + * this is not needed and the standard IRQ controller can be used. + */ + +static void grpci1_mask_irq(struct irq_data *data) +{ +	u32 irqidx; +	struct grpci1_priv *priv = grpci1priv; + +	irqidx = (u32)data->chip_data - 1; +	if (irqidx > 3) /* only mask PCI interrupts here */ +		return; +	irqidx += IRQ_MASK_BIT; + +	REGSTORE(priv->regs->irq, REGLOAD(priv->regs->irq) & ~(1 << irqidx)); +} + +static void grpci1_unmask_irq(struct irq_data *data) +{ +	u32 irqidx; +	struct grpci1_priv *priv = grpci1priv; + +	irqidx = (u32)data->chip_data - 1; +	if (irqidx > 3) /* only unmask PCI interrupts here */ +		return; +	irqidx += IRQ_MASK_BIT; + +	REGSTORE(priv->regs->irq, REGLOAD(priv->regs->irq) | (1 << irqidx)); +} + +static unsigned int grpci1_startup_irq(struct irq_data *data) +{ +	grpci1_unmask_irq(data); +	return 0; +} + +static void grpci1_shutdown_irq(struct irq_data *data) +{ +	grpci1_mask_irq(data); +} + +static struct irq_chip grpci1_irq = { +	.name		= "grpci1", +	.irq_startup	= grpci1_startup_irq, +	.irq_shutdown	= grpci1_shutdown_irq, +	.irq_mask	= grpci1_mask_irq, +	.irq_unmask	= grpci1_unmask_irq, +}; + +/* Handle one or multiple IRQs from the PCI core */ +static void grpci1_pci_flow_irq(unsigned int irq, struct irq_desc *desc) +{ +	struct grpci1_priv *priv = grpci1priv; +	int i, ack = 0; +	unsigned int irqreg; + +	irqreg = REGLOAD(priv->regs->irq); +	irqreg = (irqreg >> IRQ_MASK_BIT) & irqreg; + +	/* Error Interrupt? */ +	if (irqreg & IRQ_ALL_ERRORS) { +		generic_handle_irq(priv->irq_err); +		ack = 1; +	} + +	/* PCI Interrupt? */ +	if (irqreg & IRQ_INTX) { +		/* Call respective PCI Interrupt handler */ +		for (i = 0; i < 4; i++) { +			if (irqreg & (1 << i)) +				generic_handle_irq(priv->irq_map[i]); +		} +		ack = 1; +	} + +	/* +	 * Call "first level" IRQ chip end-of-irq handler. It will ACK LEON IRQ +	 * Controller, this must be done after IRQ sources have been handled to +	 * avoid double IRQ generation +	 */ +	if (ack) +		desc->irq_data.chip->irq_eoi(&desc->irq_data); +} + +/* Create a virtual IRQ */ +static unsigned int grpci1_build_device_irq(unsigned int irq) +{ +	unsigned int virq = 0, pil; + +	pil = 1 << 8; +	virq = irq_alloc(irq, pil); +	if (virq == 0) +		goto out; + +	irq_set_chip_and_handler_name(virq, &grpci1_irq, handle_simple_irq, +				      "pcilvl"); +	irq_set_chip_data(virq, (void *)irq); + +out: +	return virq; +} + +/* + * Initialize mappings AMBA<->PCI, clear IRQ state, setup PCI interface + * + * Target BARs: + *  BAR0: unused in this implementation + *  BAR1: peripheral DMA to host's memory (size at least 256MByte) + *  BAR2..BAR5: not implemented in hardware + */ +void grpci1_hw_init(struct grpci1_priv *priv) +{ +	u32 ahbadr, bar_sz, data, pciadr; +	struct grpci1_regs *regs = priv->regs; + +	/* set 1:1 mapping between AHB -> PCI memory space */ +	REGSTORE(regs->cfg_stat, priv->pci_area & 0xf0000000); + +	/* map PCI accesses to target BAR1 to Linux kernel memory 1:1 */ +	ahbadr = 0xf0000000 & (u32)__pa(PAGE_ALIGN((unsigned long) &_end)); +	REGSTORE(regs->page1, ahbadr); + +	/* translate I/O accesses to 0, I/O Space always @ PCI low 64Kbytes */ +	REGSTORE(regs->iomap, REGLOAD(regs->iomap) & 0x0000ffff); + +	/* disable and clear pending interrupts */ +	REGSTORE(regs->irq, 0); + +	/* Setup BAR0 outside access range so that it does not conflict with +	 * peripheral DMA. There is no need to set up the PAGE0 register. +	 */ +	grpci1_cfg_w32(priv, TGT, 0, PCI_BASE_ADDRESS_0, 0xffffffff); +	grpci1_cfg_r32(priv, TGT, 0, PCI_BASE_ADDRESS_0, &bar_sz); +	bar_sz = ~bar_sz + 1; +	pciadr = priv->pci_area - bar_sz; +	grpci1_cfg_w32(priv, TGT, 0, PCI_BASE_ADDRESS_0, pciadr); + +	/* +	 * Setup the Host's PCI Target BAR1 for other peripherals to access, +	 * and do DMA to the host's memory. +	 */ +	grpci1_cfg_w32(priv, TGT, 0, PCI_BASE_ADDRESS_1, ahbadr); + +	/* +	 * Setup Latency Timer and cache line size. Default cache line +	 * size will result in poor performance (256 word fetches), 0xff +	 * will set it according to the max size of the PCI FIFO. +	 */ +	grpci1_cfg_w8(priv, TGT, 0, PCI_CACHE_LINE_SIZE, 0xff); +	grpci1_cfg_w8(priv, TGT, 0, PCI_LATENCY_TIMER, 0x40); + +	/* set as bus master, enable pci memory responses, clear status bits */ +	grpci1_cfg_r32(priv, TGT, 0, PCI_COMMAND, &data); +	data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); +	grpci1_cfg_w32(priv, TGT, 0, PCI_COMMAND, data); +} + +static irqreturn_t grpci1_jump_interrupt(int irq, void *arg) +{ +	struct grpci1_priv *priv = arg; +	dev_err(priv->dev, "Jump IRQ happened\n"); +	return IRQ_NONE; +} + +/* Handle GRPCI1 Error Interrupt */ +static irqreturn_t grpci1_err_interrupt(int irq, void *arg) +{ +	struct grpci1_priv *priv = arg; +	u32 status; + +	grpci1_cfg_r16(priv, TGT, 0, PCI_STATUS, &status); +	status &= priv->pci_err_mask; + +	if (status == 0) +		return IRQ_NONE; + +	if (status & PCI_STATUS_PARITY) +		dev_err(priv->dev, "Data Parity Error\n"); + +	if (status & PCI_STATUS_SIG_TARGET_ABORT) +		dev_err(priv->dev, "Signalled Target Abort\n"); + +	if (status & PCI_STATUS_REC_TARGET_ABORT) +		dev_err(priv->dev, "Received Target Abort\n"); + +	if (status & PCI_STATUS_REC_MASTER_ABORT) +		dev_err(priv->dev, "Received Master Abort\n"); + +	if (status & PCI_STATUS_SIG_SYSTEM_ERROR) +		dev_err(priv->dev, "Signalled System Error\n"); + +	if (status & PCI_STATUS_DETECTED_PARITY) +		dev_err(priv->dev, "Parity Error\n"); + +	/* Clear handled INT TYPE IRQs */ +	grpci1_cfg_w16(priv, TGT, 0, PCI_STATUS, status); + +	return IRQ_HANDLED; +} + +static int grpci1_of_probe(struct platform_device *ofdev) +{ +	struct grpci1_regs *regs; +	struct grpci1_priv *priv; +	int err, len; +	const int *tmp; +	u32 cfg, size, err_mask; +	struct resource *res; + +	if (grpci1priv) { +		dev_err(&ofdev->dev, "only one GRPCI1 supported\n"); +		return -ENODEV; +	} + +	if (ofdev->num_resources < 3) { +		dev_err(&ofdev->dev, "not enough APB/AHB resources\n"); +		return -EIO; +	} + +	priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) { +		dev_err(&ofdev->dev, "memory allocation failed\n"); +		return -ENOMEM; +	} +	platform_set_drvdata(ofdev, priv); +	priv->dev = &ofdev->dev; + +	/* find device register base address */ +	res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); +	regs = devm_request_and_ioremap(&ofdev->dev, res); +	if (!regs) { +		dev_err(&ofdev->dev, "io-regs mapping failed\n"); +		return -EADDRNOTAVAIL; +	} + +	/* +	 * check that we're in Host Slot and that we can act as a Host Bridge +	 * and not only as target/peripheral. +	 */ +	cfg = REGLOAD(regs->cfg_stat); +	if ((cfg & CFGSTAT_HOST) == 0) { +		dev_err(&ofdev->dev, "not in host system slot\n"); +		return -EIO; +	} + +	/* check that BAR1 support 256 MByte so that we can map kernel space */ +	REGSTORE(regs->page1, 0xffffffff); +	size = ~REGLOAD(regs->page1) + 1; +	if (size < 0x10000000) { +		dev_err(&ofdev->dev, "BAR1 must be at least 256MByte\n"); +		return -EIO; +	} + +	/* hardware must support little-endian PCI (byte-twisting) */ +	if ((REGLOAD(regs->page0) & PAGE0_BTEN) == 0) { +		dev_err(&ofdev->dev, "byte-twisting is required\n"); +		return -EIO; +	} + +	priv->regs = regs; +	priv->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); +	dev_info(&ofdev->dev, "host found at 0x%p, irq%d\n", regs, priv->irq); + +	/* Find PCI Memory, I/O and Configuration Space Windows */ +	priv->pci_area = ofdev->resource[1].start; +	priv->pci_area_end = ofdev->resource[1].end+1; +	priv->pci_io = ofdev->resource[2].start; +	priv->pci_conf = ofdev->resource[2].start + 0x10000; +	priv->pci_conf_end = priv->pci_conf + 0x10000; +	priv->pci_io_va = (unsigned long)ioremap(priv->pci_io, 0x10000); +	if (!priv->pci_io_va) { +		dev_err(&ofdev->dev, "unable to map PCI I/O area\n"); +		return -EIO; +	} + +	printk(KERN_INFO +		"GRPCI1: MEMORY SPACE [0x%08lx - 0x%08lx]\n" +		"        I/O    SPACE [0x%08lx - 0x%08lx]\n" +		"        CONFIG SPACE [0x%08lx - 0x%08lx]\n", +		priv->pci_area, priv->pci_area_end-1, +		priv->pci_io, priv->pci_conf-1, +		priv->pci_conf, priv->pci_conf_end-1); + +	/* +	 * I/O Space resources in I/O Window mapped into Virtual Adr Space +	 * We never use low 4KB because some devices seem have problems using +	 * address 0. +	 */ +	priv->info.io_space.name = "GRPCI1 PCI I/O Space"; +	priv->info.io_space.start = priv->pci_io_va + 0x1000; +	priv->info.io_space.end = priv->pci_io_va + 0x10000 - 1; +	priv->info.io_space.flags = IORESOURCE_IO; + +	/* +	 * grpci1 has no prefetchable memory, map everything as +	 * non-prefetchable memory +	 */ +	priv->info.mem_space.name = "GRPCI1 PCI MEM Space"; +	priv->info.mem_space.start = priv->pci_area; +	priv->info.mem_space.end = priv->pci_area_end - 1; +	priv->info.mem_space.flags = IORESOURCE_MEM; + +	if (request_resource(&iomem_resource, &priv->info.mem_space) < 0) { +		dev_err(&ofdev->dev, "unable to request PCI memory area\n"); +		err = -ENOMEM; +		goto err1; +	} + +	if (request_resource(&ioport_resource, &priv->info.io_space) < 0) { +		dev_err(&ofdev->dev, "unable to request PCI I/O area\n"); +		err = -ENOMEM; +		goto err2; +	} + +	/* setup maximum supported PCI buses */ +	priv->info.busn.name = "GRPCI1 busn"; +	priv->info.busn.start = 0; +	priv->info.busn.end = 15; + +	grpci1priv = priv; + +	/* Initialize hardware */ +	grpci1_hw_init(priv); + +	/* +	 * Get PCI Interrupt to System IRQ mapping and setup IRQ handling +	 * Error IRQ. All PCI and PCI-Error interrupts are shared using the +	 * same system IRQ. +	 */ +	leon_update_virq_handling(priv->irq, grpci1_pci_flow_irq, "pcilvl", 0); + +	priv->irq_map[0] = grpci1_build_device_irq(1); +	priv->irq_map[1] = grpci1_build_device_irq(2); +	priv->irq_map[2] = grpci1_build_device_irq(3); +	priv->irq_map[3] = grpci1_build_device_irq(4); +	priv->irq_err = grpci1_build_device_irq(5); + +	printk(KERN_INFO "        PCI INTA..D#: IRQ%d, IRQ%d, IRQ%d, IRQ%d\n", +		priv->irq_map[0], priv->irq_map[1], priv->irq_map[2], +		priv->irq_map[3]); + +	/* Enable IRQs on LEON IRQ controller */ +	err = devm_request_irq(&ofdev->dev, priv->irq, grpci1_jump_interrupt, 0, +				"GRPCI1_JUMP", priv); +	if (err) { +		dev_err(&ofdev->dev, "ERR IRQ request failed: %d\n", err); +		goto err3; +	} + +	/* Setup IRQ handler for access errors */ +	err = devm_request_irq(&ofdev->dev, priv->irq_err, +				grpci1_err_interrupt, IRQF_SHARED, "GRPCI1_ERR", +				priv); +	if (err) { +		dev_err(&ofdev->dev, "ERR VIRQ request failed: %d\n", err); +		goto err3; +	} + +	tmp = of_get_property(ofdev->dev.of_node, "all_pci_errors", &len); +	if (tmp && (len == 4)) { +		priv->pci_err_mask = ALL_PCI_ERRORS; +		err_mask = IRQ_ALL_ERRORS << IRQ_MASK_BIT; +	} else { +		priv->pci_err_mask = DEF_PCI_ERRORS; +		err_mask = IRQ_DEF_ERRORS << IRQ_MASK_BIT; +	} + +	/* +	 * Enable Error Interrupts. PCI interrupts are unmasked once request_irq +	 * is called by the PCI Device drivers +	 */ +	REGSTORE(regs->irq, err_mask); + +	/* Init common layer and scan buses */ +	priv->info.ops = &grpci1_ops; +	priv->info.map_irq = grpci1_map_irq; +	leon_pci_init(ofdev, &priv->info); + +	return 0; + +err3: +	release_resource(&priv->info.io_space); +err2: +	release_resource(&priv->info.mem_space); +err1: +	iounmap((void *)priv->pci_io_va); +	grpci1priv = NULL; +	return err; +} + +static struct of_device_id grpci1_of_match[] = { +	{ +	 .name = "GAISLER_PCIFBRG", +	 }, +	{ +	 .name = "01_014", +	 }, +	{}, +}; + +static struct platform_driver grpci1_of_driver = { +	.driver = { +		.name = "grpci1", +		.owner = THIS_MODULE, +		.of_match_table = grpci1_of_match, +	}, +	.probe = grpci1_of_probe, +}; + +static int __init grpci1_init(void) +{ +	return platform_driver_register(&grpci1_of_driver); +} + +subsys_initcall(grpci1_init); diff --git a/arch/sparc/kernel/leon_pci_grpci2.c b/arch/sparc/kernel/leon_pci_grpci2.c index fc4320886a3..5f0402aab7f 100644 --- a/arch/sparc/kernel/leon_pci_grpci2.c +++ b/arch/sparc/kernel/leon_pci_grpci2.c @@ -186,6 +186,8 @@ struct grpci2_cap_first {  #define CAP9_IOMAP_OFS 0x20  #define CAP9_BARSIZE_OFS 0x24 +#define TGT 256 +  struct grpci2_priv {  	struct leon_pci_info	info; /* must be on top of this structure */  	struct grpci2_regs	*regs; @@ -237,8 +239,12 @@ static int grpci2_cfg_r32(struct grpci2_priv *priv, unsigned int bus,  	if (where & 0x3)  		return -EINVAL; -	if (bus == 0 && PCI_SLOT(devfn) != 0) -		devfn += (0x8 * 6); +	if (bus == 0) { +		devfn += (0x8 * 6); /* start at AD16=Device0 */ +	} else if (bus == TGT) { +		bus = 0; +		devfn = 0; /* special case: bridge controller itself */ +	}  	/* Select bus */  	spin_lock_irqsave(&grpci2_dev_lock, flags); @@ -303,8 +309,12 @@ static int grpci2_cfg_w32(struct grpci2_priv *priv, unsigned int bus,  	if (where & 0x3)  		return -EINVAL; -	if (bus == 0 && PCI_SLOT(devfn) != 0) -		devfn += (0x8 * 6); +	if (bus == 0) { +		devfn += (0x8 * 6); /* start at AD16=Device0 */ +	} else if (bus == TGT) { +		bus = 0; +		devfn = 0; /* special case: bridge controller itself */ +	}  	/* Select bus */  	spin_lock_irqsave(&grpci2_dev_lock, flags); @@ -368,7 +378,7 @@ static int grpci2_read_config(struct pci_bus *bus, unsigned int devfn,  	unsigned int busno = bus->number;  	int ret; -	if (PCI_SLOT(devfn) > 15 || (PCI_SLOT(devfn) == 0 && busno == 0)) { +	if (PCI_SLOT(devfn) > 15 || busno > 255) {  		*val = ~0;  		return 0;  	} @@ -406,7 +416,7 @@ static int grpci2_write_config(struct pci_bus *bus, unsigned int devfn,  	struct grpci2_priv *priv = grpci2priv;  	unsigned int busno = bus->number; -	if (PCI_SLOT(devfn) > 15 || (PCI_SLOT(devfn) == 0 && busno == 0)) +	if (PCI_SLOT(devfn) > 15 || busno > 255)  		return 0;  #ifdef GRPCI2_DEBUG_CFGACCESS @@ -578,15 +588,15 @@ void grpci2_hw_init(struct grpci2_priv *priv)  		REGSTORE(regs->ahbmst_map[i], priv->pci_area);  	/* Get the GRPCI2 Host PCI ID */ -	grpci2_cfg_r32(priv, 0, 0, PCI_VENDOR_ID, &priv->pciid); +	grpci2_cfg_r32(priv, TGT, 0, PCI_VENDOR_ID, &priv->pciid);  	/* Get address to first (always defined) capability structure */ -	grpci2_cfg_r8(priv, 0, 0, PCI_CAPABILITY_LIST, &capptr); +	grpci2_cfg_r8(priv, TGT, 0, PCI_CAPABILITY_LIST, &capptr);  	/* Enable/Disable Byte twisting */ -	grpci2_cfg_r32(priv, 0, 0, capptr+CAP9_IOMAP_OFS, &io_map); +	grpci2_cfg_r32(priv, TGT, 0, capptr+CAP9_IOMAP_OFS, &io_map);  	io_map = (io_map & ~0x1) | (priv->bt_enabled ? 1 : 0); -	grpci2_cfg_w32(priv, 0, 0, capptr+CAP9_IOMAP_OFS, io_map); +	grpci2_cfg_w32(priv, TGT, 0, capptr+CAP9_IOMAP_OFS, io_map);  	/* Setup the Host's PCI Target BARs for other peripherals to access,  	 * and do DMA to the host's memory. The target BARs can be sized and @@ -617,17 +627,18 @@ void grpci2_hw_init(struct grpci2_priv *priv)  				pciadr = 0;  			}  		} -		grpci2_cfg_w32(priv, 0, 0, capptr+CAP9_BARSIZE_OFS+i*4, bar_sz); -		grpci2_cfg_w32(priv, 0, 0, PCI_BASE_ADDRESS_0+i*4, pciadr); -		grpci2_cfg_w32(priv, 0, 0, capptr+CAP9_BAR_OFS+i*4, ahbadr); +		grpci2_cfg_w32(priv, TGT, 0, capptr+CAP9_BARSIZE_OFS+i*4, +				bar_sz); +		grpci2_cfg_w32(priv, TGT, 0, PCI_BASE_ADDRESS_0+i*4, pciadr); +		grpci2_cfg_w32(priv, TGT, 0, capptr+CAP9_BAR_OFS+i*4, ahbadr);  		printk(KERN_INFO "        TGT BAR[%d]: 0x%08x (PCI)-> 0x%08x\n",  			i, pciadr, ahbadr);  	}  	/* set as bus master and enable pci memory responses */ -	grpci2_cfg_r32(priv, 0, 0, PCI_COMMAND, &data); +	grpci2_cfg_r32(priv, TGT, 0, PCI_COMMAND, &data);  	data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); -	grpci2_cfg_w32(priv, 0, 0, PCI_COMMAND, data); +	grpci2_cfg_w32(priv, TGT, 0, PCI_COMMAND, data);  	/* Enable Error respone (CPU-TRAP) on illegal memory access. */  	REGSTORE(regs->ctrl, CTRL_ER | CTRL_PE); @@ -788,6 +799,11 @@ static int grpci2_of_probe(struct platform_device *ofdev)  	if (request_resource(&ioport_resource, &priv->info.io_space) < 0)  		goto err4; +	/* setup maximum supported PCI buses */ +	priv->info.busn.name = "GRPCI2 busn"; +	priv->info.busn.start = 0; +	priv->info.busn.end = 255; +  	grpci2_hw_init(priv);  	/* diff --git a/arch/sparc/kernel/leon_pmc.c b/arch/sparc/kernel/leon_pmc.c index 4e174321097..bdf53d9a8d4 100644 --- a/arch/sparc/kernel/leon_pmc.c +++ b/arch/sparc/kernel/leon_pmc.c @@ -9,6 +9,7 @@  #include <asm/leon_amba.h>  #include <asm/cpu_type.h>  #include <asm/leon.h> +#include <asm/processor.h>  /* List of Systems that need fixup instructions around power-down instruction */  unsigned int pmc_leon_fixup_ids[] = { @@ -47,7 +48,7 @@ void pmc_leon_idle_fixup(void)  	 */  	register unsigned int address = (unsigned int)leon3_irqctrl_regs;  	__asm__ __volatile__ ( -		"mov	%%g0, %%asr19\n" +		"wr	%%g0, %%asr19\n"  		"lda	[%0] %1, %%g0\n"  		:  		: "r"(address), "i"(ASI_LEON_BYPASS)); @@ -60,7 +61,7 @@ void pmc_leon_idle_fixup(void)  void pmc_leon_idle(void)  {  	/* For systems without power-down, this will be no-op */ -	__asm__ __volatile__ ("mov	%g0, %asr19\n\t"); +	__asm__ __volatile__ ("wr	%g0, %asr19\n\t");  }  /* Install LEON Power Down function */ @@ -69,9 +70,9 @@ static int __init leon_pmc_install(void)  	if (sparc_cpu_model == sparc_leon) {  		/* Assign power management IDLE handler */  		if (pmc_leon_need_fixup()) -			pm_idle = pmc_leon_idle_fixup; +			sparc_idle = pmc_leon_idle_fixup;  		else -			pm_idle = pmc_leon_idle; +			sparc_idle = pmc_leon_idle;  		printk(KERN_INFO "leon: power management initialized\n");  	} diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c index 0f3fb6d9c8e..6cfc1b09ec2 100644 --- a/arch/sparc/kernel/leon_smp.c +++ b/arch/sparc/kernel/leon_smp.c @@ -69,31 +69,19 @@ static inline unsigned long do_swap(volatile unsigned long *ptr,  	return val;  } -void __cpuinit leon_callin(void) +void __cpuinit leon_cpu_pre_starting(void *arg)  { -	int cpuid = hard_smp_processor_id(); - -	local_ops->cache_all(); -	local_ops->tlb_all();  	leon_configure_cache_smp(); +} -	notify_cpu_starting(cpuid); - -	/* Get our local ticker going. */ -	register_percpu_ce(cpuid); - -	calibrate_delay(); -	smp_store_cpu_info(cpuid); - -	local_ops->cache_all(); -	local_ops->tlb_all(); +void __cpuinit leon_cpu_pre_online(void *arg) +{ +	int cpuid = hard_smp_processor_id(); -	/* -	 * Unblock the master CPU _only_ when the scheduler state -	 * of all secondary CPUs will be up-to-date, so after -	 * the SMP initialization the master will be just allowed -	 * to call the scheduler code. -	 * Allow master to continue. +	/* Allow master to continue. The master will then give us the +	 * go-ahead by setting the smp_commenced_mask and will wait without +	 * timeouts until our setup is completed fully (signified by +	 * our bit being set in the cpu_online_mask).  	 */  	do_swap(&cpu_callin_map[cpuid], 1); @@ -110,9 +98,6 @@ void __cpuinit leon_callin(void)  	while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))  		mb(); - -	local_irq_enable(); -	set_cpu_online(cpuid, true);  }  /* @@ -268,24 +253,15 @@ void __init leon_smp_done(void)  	/* Free unneeded trap tables */  	if (!cpu_present(1)) { -		ClearPageReserved(virt_to_page(&trapbase_cpu1)); -		init_page_count(virt_to_page(&trapbase_cpu1)); -		free_page((unsigned long)&trapbase_cpu1); -		totalram_pages++; +		free_reserved_page(virt_to_page(&trapbase_cpu1));  		num_physpages++;  	}  	if (!cpu_present(2)) { -		ClearPageReserved(virt_to_page(&trapbase_cpu2)); -		init_page_count(virt_to_page(&trapbase_cpu2)); -		free_page((unsigned long)&trapbase_cpu2); -		totalram_pages++; +		free_reserved_page(virt_to_page(&trapbase_cpu2));  		num_physpages++;  	}  	if (!cpu_present(3)) { -		ClearPageReserved(virt_to_page(&trapbase_cpu3)); -		init_page_count(virt_to_page(&trapbase_cpu3)); -		free_page((unsigned long)&trapbase_cpu3); -		totalram_pages++; +		free_reserved_page(virt_to_page(&trapbase_cpu3));  		num_physpages++;  	}  	/* Ok, they are spinning and ready to go. */ diff --git a/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c index dcbb62f6306..8b7297faca7 100644 --- a/arch/sparc/kernel/pmc.c +++ b/arch/sparc/kernel/pmc.c @@ -17,6 +17,7 @@  #include <asm/oplib.h>  #include <asm/uaccess.h>  #include <asm/auxio.h> +#include <asm/processor.h>  /* Debug   * @@ -63,7 +64,7 @@ static int pmc_probe(struct platform_device *op)  #ifndef PMC_NO_IDLE  	/* Assign power management IDLE handler */ -	pm_idle = pmc_swift_idle; +	sparc_idle = pmc_swift_idle;  #endif  	printk(KERN_INFO "%s: power management initialized\n", PMC_DEVNAME); diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index be8e862bada..fdd819dfdac 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -43,8 +43,7 @@   * Power management idle function    * Set in pm platform drivers (apc.c and pmc.c)   */ -void (*pm_idle)(void); -EXPORT_SYMBOL(pm_idle); +void (*sparc_idle)(void);  /*    * Power-off handler instantiation for pm.h compliance @@ -65,23 +64,12 @@ extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);  struct task_struct *last_task_used_math = NULL;  struct thread_info *current_set[NR_CPUS]; -/* - * the idle loop on a Sparc... ;) - */ -void cpu_idle(void) +/* Idle loop support. */ +void arch_cpu_idle(void)  { -	set_thread_flag(TIF_POLLING_NRFLAG); - -	/* endless idle loop with no priority at all */ -	for (;;) { -		while (!need_resched()) { -			if (pm_idle) -				(*pm_idle)(); -			else -				cpu_relax(); -		} -		schedule_preempt_disabled(); -	} +	if (sparc_idle) +		(*sparc_idle)(); +	local_irq_enable();  }  /* XXX cli/sti -> local_irq_xxx here, check this works once SMP is fixed. */ @@ -124,6 +112,8 @@ void show_regs(struct pt_regs *r)  {  	struct reg_window32 *rw = (struct reg_window32 *) r->u_regs[14]; +	show_regs_print_info(KERN_DEFAULT); +          printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx    %s\n",  	       r->psr, r->pc, r->npc, r->y, print_tainted());  	printk("PC: <%pS>\n", (void *) r->pc); @@ -154,11 +144,13 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)  	struct reg_window32 *rw;  	int count = 0; -	if (tsk != NULL) -		task_base = (unsigned long) task_stack_page(tsk); -	else -		task_base = (unsigned long) current_thread_info(); +	if (!tsk) +		tsk = current; +	if (tsk == current && !_ksp) +		__asm__ __volatile__("mov	%%fp, %0" : "=r" (_ksp)); + +	task_base = (unsigned long) task_stack_page(tsk);  	fp = (unsigned long) _ksp;  	do {  		/* Bogus frame pointer? */ @@ -174,17 +166,6 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)  	printk("\n");  } -void dump_stack(void) -{ -	unsigned long *ksp; - -	__asm__ __volatile__("mov	%%fp, %0" -			     : "=r" (ksp)); -	show_stack(current, ksp); -} - -EXPORT_SYMBOL(dump_stack); -  /*   * Note: sparc64 has a pretty intricated thread_saved_pc, check it out.   */ diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index cdb80b2adbe..baebab21549 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -52,20 +52,17 @@  #include "kstack.h" -static void sparc64_yield(int cpu) +/* Idle loop support on sparc64. */ +void arch_cpu_idle(void)  {  	if (tlb_type != hypervisor) {  		touch_nmi_watchdog(); -		return; -	} - -	clear_thread_flag(TIF_POLLING_NRFLAG); -	smp_mb__after_clear_bit(); - -	while (!need_resched() && !cpu_is_offline(cpu)) { +	} else {  		unsigned long pstate; -		/* Disable interrupts. */ +                /* The sun4v sleeping code requires that we have PSTATE.IE cleared over +                 * the cpu sleep hypervisor call. +                 */  		__asm__ __volatile__(  			"rdpr %%pstate, %0\n\t"  			"andn %0, %1, %0\n\t" @@ -73,7 +70,7 @@ static void sparc64_yield(int cpu)  			: "=&r" (pstate)  			: "i" (PSTATE_IE)); -		if (!need_resched() && !cpu_is_offline(cpu)) +		if (!need_resched() && !cpu_is_offline(smp_processor_id()))  			sun4v_cpu_yield();  		/* Re-enable interrupts. */ @@ -84,36 +81,16 @@ static void sparc64_yield(int cpu)  			: "=&r" (pstate)  			: "i" (PSTATE_IE));  	} - -	set_thread_flag(TIF_POLLING_NRFLAG); +	local_irq_enable();  } -/* The idle loop on sparc64. */ -void cpu_idle(void) -{ -	int cpu = smp_processor_id(); - -	set_thread_flag(TIF_POLLING_NRFLAG); - -	while(1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); - -		while (!need_resched() && !cpu_is_offline(cpu)) -			sparc64_yield(cpu); - -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -  #ifdef CONFIG_HOTPLUG_CPU -		if (cpu_is_offline(cpu)) { -			sched_preempt_enable_no_resched(); -			cpu_play_dead(); -		} -#endif -		schedule_preempt_disabled(); -	} +void arch_cpu_idle_dead() +{ +	sched_preempt_enable_no_resched(); +	cpu_play_dead();  } +#endif  #ifdef CONFIG_COMPAT  static void show_regwindow32(struct pt_regs *regs) @@ -186,6 +163,8 @@ static void show_regwindow(struct pt_regs *regs)  void show_regs(struct pt_regs *regs)  { +	show_regs_print_info(KERN_DEFAULT); +  	printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x    %s\n", regs->tstate,  	       regs->tpc, regs->tnpc, regs->y, print_tainted());  	printk("TPC: <%pS>\n", (void *) regs->tpc); @@ -315,7 +294,7 @@ static void sysrq_handle_globreg(int key)  static struct sysrq_key_op sparc_globalreg_op = {  	.handler	= sysrq_handle_globreg, -	.help_msg	= "global-regs(Y)", +	.help_msg	= "global-regs(y)",  	.action_msg	= "Show Global CPU Regs",  }; @@ -385,7 +364,7 @@ static void sysrq_handle_globpmu(int key)  static struct sysrq_key_op sparc_globalpmu_op = {  	.handler	= sysrq_handle_globpmu, -	.help_msg	= "global-pmu(X)", +	.help_msg	= "global-pmu(x)",  	.action_msg	= "Show Global PMU Regs",  }; diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c index 1303021748c..9f20566b077 100644 --- a/arch/sparc/kernel/prom_common.c +++ b/arch/sparc/kernel/prom_common.c @@ -64,7 +64,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len  	err = -ENODEV;  	mutex_lock(&of_set_property_mutex); -	write_lock(&devtree_lock); +	raw_spin_lock(&devtree_lock);  	prevp = &dp->properties;  	while (*prevp) {  		struct property *prop = *prevp; @@ -91,7 +91,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len  		}  		prevp = &(*prevp)->next;  	} -	write_unlock(&devtree_lock); +	raw_spin_unlock(&devtree_lock);  	mutex_unlock(&of_set_property_mutex);  	/* XXX Upate procfs if necessary... */ diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index 0eaf0059aae..88a127b9c69 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c @@ -115,7 +115,7 @@ static void __init process_switch(char c)  			break;  		}  		cheetah_pcache_forced_on = 1; -		add_taint(TAINT_MACHINE_CHECK); +		add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);  		cheetah_enable_pcache();  		break; diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 53e48f721ce..b524f91dd0e 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -61,7 +61,7 @@ struct rt_signal_frame32 {  	compat_sigset_t		mask;  	/* __siginfo_fpu_t * */ u32 fpu_save;  	unsigned int		insns[2]; -	stack_t32		stack; +	compat_stack_t		stack;  	unsigned int		extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */  	/* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */  	siginfo_extra_v8plus_t	v8plus; @@ -230,13 +230,11 @@ segv:  asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)  {  	struct rt_signal_frame32 __user *sf; -	unsigned int psr, pc, npc, u_ss_sp; +	unsigned int psr, pc, npc;  	compat_uptr_t fpu_save;  	compat_uptr_t rwin_save; -	mm_segment_t old_fs;  	sigset_t set;  	compat_sigset_t seta; -	stack_t st;  	int err, i;  	/* Always make any pending restarted system calls return -EINTR */ @@ -295,20 +293,10 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)  	if (!err && fpu_save)  		err |= restore_fpu_state(regs, compat_ptr(fpu_save));  	err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t)); -	err |= __get_user(u_ss_sp, &sf->stack.ss_sp); -	st.ss_sp = compat_ptr(u_ss_sp); -	err |= __get_user(st.ss_flags, &sf->stack.ss_flags); -	err |= __get_user(st.ss_size, &sf->stack.ss_size); +	err |= compat_restore_altstack(&sf->stack);  	if (err)  		goto segv; -	/* It is more difficult to avoid calling this function than to -	   call it and ignore errors.  */ -	old_fs = get_fs(); -	set_fs(KERNEL_DS); -	do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf); -	set_fs(old_fs); -	  	err |= __get_user(rwin_save, &sf->rwin_save);  	if (!err && rwin_save) {  		if (restore_rwin_state(compat_ptr(rwin_save))) @@ -335,7 +323,7 @@ static int invalid_frame_pointer(void __user *fp, int fplen)  	return 0;  } -static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize) +static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)  {  	unsigned long sp; @@ -350,12 +338,7 @@ static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, uns  		return (void __user *) -1L;  	/* This is the X/Open sanctioned signal stack switching.  */ -	if (sa->sa_flags & SA_ONSTACK) { -		if (sas_ss_flags(sp) == 0) -			sp = current->sas_ss_sp + current->sas_ss_size; -	} - -	sp -= framesize; +	sp = sigsp(sp, ksig) - framesize;  	/* Always align the stack frame.  This handles two cases.  First,  	 * sigaltstack need not be mindful of platform specific stack @@ -426,8 +409,8 @@ out_irqs_on:  } -static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, -			 int signo, sigset_t *oldset) +static int setup_frame32(struct ksignal *ksig, struct pt_regs *regs, +			 sigset_t *oldset)  {  	struct signal_frame32 __user *sf;  	int i, err, wsaved; @@ -449,10 +432,12 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,  		sigframe_size += sizeof(__siginfo_rwin_t);  	sf = (struct signal_frame32 __user *) -		get_sigframe(&ka->sa, regs, sigframe_size); +		get_sigframe(ksig, regs, sigframe_size); -	if (invalid_frame_pointer(sf, sigframe_size)) -		goto sigill; +	if (invalid_frame_pointer(sf, sigframe_size)) { +		do_exit(SIGILL); +		return -EINVAL; +	}  	tail = (sf + 1); @@ -526,16 +511,16 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,  		err |= __put_user(rp->ins[7], &sf->ss.callers_pc);  	}	  	if (err) -		goto sigsegv; +		return err;  	/* 3. signal handler back-trampoline and parameters */  	regs->u_regs[UREG_FP] = (unsigned long) sf; -	regs->u_regs[UREG_I0] = signo; +	regs->u_regs[UREG_I0] = ksig->sig;  	regs->u_regs[UREG_I1] = (unsigned long) &sf->info;  	regs->u_regs[UREG_I2] = (unsigned long) &sf->info;  	/* 4. signal handler */ -	regs->tpc = (unsigned long) ka->sa.sa_handler; +	regs->tpc = (unsigned long) ksig->ka.sa.sa_handler;  	regs->tnpc = (regs->tpc + 4);  	if (test_thread_flag(TIF_32BIT)) {  		regs->tpc &= 0xffffffff; @@ -543,8 +528,8 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,  	}  	/* 5. return to kernel instructions */ -	if (ka->ka_restorer) { -		regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; +	if (ksig->ka.ka_restorer) { +		regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;  	} else {  		unsigned long address = ((unsigned long)&(sf->insns[0])); @@ -553,23 +538,14 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,  		err  = __put_user(0x821020d8, &sf->insns[0]); /*mov __NR_sigreturn, %g1*/  		err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/  		if (err) -			goto sigsegv; +			return err;  		flush_signal_insns(address);  	}  	return 0; - -sigill: -	do_exit(SIGILL); -	return -EINVAL; - -sigsegv: -	force_sigsegv(signo, current); -	return -EFAULT;  } -static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, -			    unsigned long signr, sigset_t *oldset, -			    siginfo_t *info) +static int setup_rt_frame32(struct ksignal *ksig, struct pt_regs *regs, +			    sigset_t *oldset)  {  	struct rt_signal_frame32 __user *sf;  	int i, err, wsaved; @@ -591,10 +567,12 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,  		sigframe_size += sizeof(__siginfo_rwin_t);  	sf = (struct rt_signal_frame32 __user *) -		get_sigframe(&ka->sa, regs, sigframe_size); +		get_sigframe(ksig, regs, sigframe_size); -	if (invalid_frame_pointer(sf, sigframe_size)) -		goto sigill; +	if (invalid_frame_pointer(sf, sigframe_size)) { +		do_exit(SIGILL); +		return -EINVAL; +	}  	tail = (sf + 1); @@ -639,12 +617,10 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,  	}  	/* Update the siginfo structure.  */ -	err |= copy_siginfo_to_user32(&sf->info, info); +	err |= copy_siginfo_to_user32(&sf->info, &ksig->info);  	/* Setup sigaltstack */ -	err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); -	err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); -	err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); +	err |= __compat_save_altstack(&sf->stack, regs->u_regs[UREG_FP]);  	switch (_NSIG_WORDS) {  	case 4: seta.sig[7] = (oldset->sig[3] >> 32); @@ -674,16 +650,16 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,  		err |= __put_user(rp->ins[7], &sf->ss.callers_pc);  	}  	if (err) -		goto sigsegv; +		return err;  	/* 3. signal handler back-trampoline and parameters */  	regs->u_regs[UREG_FP] = (unsigned long) sf; -	regs->u_regs[UREG_I0] = signr; +	regs->u_regs[UREG_I0] = ksig->sig;  	regs->u_regs[UREG_I1] = (unsigned long) &sf->info;  	regs->u_regs[UREG_I2] = (unsigned long) &sf->regs;  	/* 4. signal handler */ -	regs->tpc = (unsigned long) ka->sa.sa_handler; +	regs->tpc = (unsigned long) ksig->ka.sa.sa_handler;  	regs->tnpc = (regs->tpc + 4);  	if (test_thread_flag(TIF_32BIT)) {  		regs->tpc &= 0xffffffff; @@ -691,8 +667,8 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,  	}  	/* 5. return to kernel instructions */ -	if (ka->ka_restorer) -		regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; +	if (ksig->ka.ka_restorer) +		regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;  	else {  		unsigned long address = ((unsigned long)&(sf->insns[0])); @@ -704,36 +680,25 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,  		/* t 0x10 */  		err |= __put_user(0x91d02010, &sf->insns[1]);  		if (err) -			goto sigsegv; +			return err;  		flush_signal_insns(address);  	}  	return 0; - -sigill: -	do_exit(SIGILL); -	return -EINVAL; - -sigsegv: -	force_sigsegv(signr, current); -	return -EFAULT;  } -static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, -				  siginfo_t *info, -				  sigset_t *oldset, struct pt_regs *regs) +static inline void handle_signal32(struct ksignal *ksig,  +				  struct pt_regs *regs)  { +	sigset_t *oldset = sigmask_to_save();  	int err; -	if (ka->sa.sa_flags & SA_SIGINFO) -		err = setup_rt_frame32(ka, regs, signr, oldset, info); +	if (ksig->ka.sa.sa_flags & SA_SIGINFO) +		err = setup_rt_frame32(ksig, regs, oldset);  	else -		err = setup_frame32(ka, regs, signr, oldset); - -	if (err) -		return; +		err = setup_frame32(ksig, regs, oldset); -	signal_delivered(signr, info, ka, regs, 0); +	signal_setup_done(err, ksig, 0);  }  static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs, @@ -761,52 +726,43 @@ static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs   * want to handle. Thus you cannot kill init even with a SIGKILL even by   * mistake.   */ -void do_signal32(sigset_t *oldset, struct pt_regs * regs) +void do_signal32(struct pt_regs * regs)  { -	struct k_sigaction ka; -	unsigned long orig_i0; -	int restart_syscall; -	siginfo_t info; -	int signr; -	 -	signr = get_signal_to_deliver(&info, &ka, regs, NULL); +	struct ksignal ksig; +	unsigned long orig_i0 = 0; +	int restart_syscall = 0; +	bool has_handler = get_signal(&ksig); -	restart_syscall = 0; -	orig_i0 = 0;  	if (pt_regs_is_syscall(regs) &&  	    (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {  		restart_syscall = 1;  		orig_i0 = regs->u_regs[UREG_G6];  	} -	if (signr > 0) { +	if (has_handler) {  		if (restart_syscall) -			syscall_restart32(orig_i0, regs, &ka.sa); -		handle_signal32(signr, &ka, &info, oldset, regs); -		return; -	} -	if (restart_syscall && -	    (regs->u_regs[UREG_I0] == ERESTARTNOHAND || -	     regs->u_regs[UREG_I0] == ERESTARTSYS || -	     regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { -		/* replay the system call when we are done */ -		regs->u_regs[UREG_I0] = orig_i0; -		regs->tpc -= 4; -		regs->tnpc -= 4; -		pt_regs_clear_syscall(regs); -	} -	if (restart_syscall && -	    regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { -		regs->u_regs[UREG_G1] = __NR_restart_syscall; -		regs->tpc -= 4; -		regs->tnpc -= 4; -		pt_regs_clear_syscall(regs); +			syscall_restart32(orig_i0, regs, &ksig.ka.sa); +		handle_signal32(&ksig, regs); +	} else { +		if (restart_syscall) { +			switch (regs->u_regs[UREG_I0]) { +			case ERESTARTNOHAND: +	     		case ERESTARTSYS: +			case ERESTARTNOINTR: +				/* replay the system call when we are done */ +				regs->u_regs[UREG_I0] = orig_i0; +				regs->tpc -= 4; +				regs->tnpc -= 4; +				pt_regs_clear_syscall(regs); +			case ERESTART_RESTARTBLOCK: +				regs->u_regs[UREG_G1] = __NR_restart_syscall; +				regs->tpc -= 4; +				regs->tnpc -= 4; +				pt_regs_clear_syscall(regs); +			} +		} +		restore_saved_sigmask();  	} - -	/* If there's no signal to deliver, we just put the saved sigmask -	 * back -	 */ -	restore_saved_sigmask();  }  struct sigstack32 { @@ -856,29 +812,3 @@ asmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp)  out:  	return ret;  } - -asmlinkage long do_sys32_sigaltstack(u32 ussa, u32 uossa, unsigned long sp) -{ -	stack_t uss, uoss; -	u32 u_ss_sp = 0; -	int ret; -	mm_segment_t old_fs; -	stack_t32 __user *uss32 = compat_ptr(ussa); -	stack_t32 __user *uoss32 = compat_ptr(uossa); -	 -	if (ussa && (get_user(u_ss_sp, &uss32->ss_sp) || -		    __get_user(uss.ss_flags, &uss32->ss_flags) || -		    __get_user(uss.ss_size, &uss32->ss_size))) -		return -EFAULT; -	uss.ss_sp = compat_ptr(u_ss_sp); -	old_fs = get_fs(); -	set_fs(KERNEL_DS); -	ret = do_sigaltstack(ussa ? (stack_t __user *) &uss : NULL, -			     uossa ? (stack_t __user *) &uoss : NULL, sp); -	set_fs(old_fs); -	if (!ret && uossa && (put_user(ptr_to_compat(uoss.ss_sp), &uoss32->ss_sp) || -		    __put_user(uoss.ss_flags, &uoss32->ss_flags) || -		    __put_user(uoss.ss_size, &uoss32->ss_size))) -		return -EFAULT; -	return ret; -} diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 68f9c8650af..7d5d8e1f841 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -59,18 +59,6 @@ struct rt_signal_frame {  #define SF_ALIGNEDSZ  (((sizeof(struct signal_frame) + 7) & (~7)))  #define RT_ALIGNEDSZ  (((sizeof(struct rt_signal_frame) + 7) & (~7))) -static int _sigpause_common(old_sigset_t set) -{ -	sigset_t blocked; -	siginitset(&blocked, set); -	return sigsuspend(&blocked); -} - -asmlinkage int sys_sigsuspend(old_sigset_t set) -{ -	return _sigpause_common(set); -} -  asmlinkage void do_sigreturn(struct pt_regs *regs)  {  	struct signal_frame __user *sf; @@ -141,9 +129,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)  	unsigned int psr, pc, npc;  	__siginfo_fpu_t __user *fpu_save;  	__siginfo_rwin_t __user *rwin_save; -	mm_segment_t old_fs;  	sigset_t set; -	stack_t st;  	int err;  	synchronize_user_stack(); @@ -171,8 +157,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)  	if (!err && fpu_save)  		err |= restore_fpu_state(regs, fpu_save);  	err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); -	 -	err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t)); +	err |= restore_altstack(&sf->stack);  	if (err)  		goto segv; @@ -180,14 +165,6 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)  	regs->pc = pc;  	regs->npc = npc; -	/* It is more difficult to avoid calling this function than to -	 * call it and ignore errors. -	 */ -	old_fs = get_fs(); -	set_fs(KERNEL_DS); -	do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf); -	set_fs(old_fs); -  	err |= __get_user(rwin_save, &sf->rwin_save);  	if (!err && rwin_save) {  		if (restore_rwin_state(rwin_save)) @@ -209,7 +186,7 @@ static inline int invalid_frame_pointer(void __user *fp, int fplen)  	return 0;  } -static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize) +static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)  {  	unsigned long sp = regs->u_regs[UREG_FP]; @@ -221,12 +198,7 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re  		return (void __user *) -1L;  	/* This is the X/Open sanctioned signal stack switching.  */ -	if (sa->sa_flags & SA_ONSTACK) { -		if (sas_ss_flags(sp) == 0) -			sp = current->sas_ss_sp + current->sas_ss_size; -	} - -	sp -= framesize; +	sp = sigsp(sp, ksig) - framesize;  	/* Always align the stack frame.  This handles two cases.  First,  	 * sigaltstack need not be mindful of platform specific stack @@ -239,8 +211,8 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re  	return (void __user *) sp;  } -static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs, -		       int signo, sigset_t *oldset) +static int setup_frame(struct ksignal *ksig, struct pt_regs *regs, +		       sigset_t *oldset)  {  	struct signal_frame __user *sf;  	int sigframe_size, err, wsaved; @@ -258,10 +230,12 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,  		sigframe_size += sizeof(__siginfo_rwin_t);  	sf = (struct signal_frame __user *) -		get_sigframe(&ka->sa, regs, sigframe_size); +		get_sigframe(ksig, regs, sigframe_size); -	if (invalid_frame_pointer(sf, sigframe_size)) -		goto sigill_and_return; +	if (invalid_frame_pointer(sf, sigframe_size)) { +		do_exit(SIGILL); +		return -EINVAL; +	}  	tail = sf + 1; @@ -300,21 +274,21 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,  		err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));  	}  	if (err) -		goto sigsegv; +		return err;  	/* 3. signal handler back-trampoline and parameters */  	regs->u_regs[UREG_FP] = (unsigned long) sf; -	regs->u_regs[UREG_I0] = signo; +	regs->u_regs[UREG_I0] = ksig->sig;  	regs->u_regs[UREG_I1] = (unsigned long) &sf->info;  	regs->u_regs[UREG_I2] = (unsigned long) &sf->info;  	/* 4. signal handler */ -	regs->pc = (unsigned long) ka->sa.sa_handler; +	regs->pc = (unsigned long) ksig->ka.sa.sa_handler;  	regs->npc = (regs->pc + 4);  	/* 5. return to kernel instructions */ -	if (ka->ka_restorer) -		regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; +	if (ksig->ka.ka_restorer) +		regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;  	else {  		regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); @@ -324,24 +298,16 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,  		/* t 0x10 */  		err |= __put_user(0x91d02010, &sf->insns[1]);  		if (err) -			goto sigsegv; +			return err;  		/* Flush instruction space. */  		flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));  	}  	return 0; - -sigill_and_return: -	do_exit(SIGILL); -	return -EINVAL; - -sigsegv: -	force_sigsegv(signo, current); -	return -EFAULT;  } -static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, -			  int signo, sigset_t *oldset, siginfo_t *info) +static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, +			  sigset_t *oldset)  {  	struct rt_signal_frame __user *sf;  	int sigframe_size, wsaved; @@ -357,9 +323,11 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  	if (wsaved)  		sigframe_size += sizeof(__siginfo_rwin_t);  	sf = (struct rt_signal_frame __user *) -		get_sigframe(&ka->sa, regs, sigframe_size); -	if (invalid_frame_pointer(sf, sigframe_size)) -		goto sigill; +		get_sigframe(ksig, regs, sigframe_size); +	if (invalid_frame_pointer(sf, sigframe_size)) { +		do_exit(SIGILL); +		return -EINVAL; +	}  	tail = sf + 1;  	err  = __put_user(regs->pc, &sf->regs.pc); @@ -391,9 +359,7 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  	err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));  	/* Setup sigaltstack */ -	err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); -	err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); -	err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); +	err |= __save_altstack(&sf->stack, regs->u_regs[UREG_FP]);  	if (!wsaved) {  		err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], @@ -405,21 +371,21 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  		err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));  	} -	err |= copy_siginfo_to_user(&sf->info, info); +	err |= copy_siginfo_to_user(&sf->info, &ksig->info);  	if (err) -		goto sigsegv; +		return err;  	regs->u_regs[UREG_FP] = (unsigned long) sf; -	regs->u_regs[UREG_I0] = signo; +	regs->u_regs[UREG_I0] = ksig->sig;  	regs->u_regs[UREG_I1] = (unsigned long) &sf->info;  	regs->u_regs[UREG_I2] = (unsigned long) &sf->regs; -	regs->pc = (unsigned long) ka->sa.sa_handler; +	regs->pc = (unsigned long) ksig->ka.sa.sa_handler;  	regs->npc = (regs->pc + 4); -	if (ka->ka_restorer) -		regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; +	if (ksig->ka.ka_restorer) +		regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;  	else {  		regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); @@ -429,38 +395,25 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  		/* t 0x10 */  		err |= __put_user(0x91d02010, &sf->insns[1]);  		if (err) -			goto sigsegv; +			return err;  		/* Flush instruction space. */  		flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));  	}  	return 0; - -sigill: -	do_exit(SIGILL); -	return -EINVAL; - -sigsegv: -	force_sigsegv(signo, current); -	return -EFAULT;  }  static inline void -handle_signal(unsigned long signr, struct k_sigaction *ka, -	      siginfo_t *info, struct pt_regs *regs) +handle_signal(struct ksignal *ksig, struct pt_regs *regs)  {  	sigset_t *oldset = sigmask_to_save();  	int err; -	if (ka->sa.sa_flags & SA_SIGINFO) -		err = setup_rt_frame(ka, regs, signr, oldset, info); +	if (ksig->ka.sa.sa_flags & SA_SIGINFO) +		err = setup_rt_frame(ksig, regs, oldset);  	else -		err = setup_frame(ka, regs, signr, oldset); - -	if (err) -		return; - -	signal_delivered(signr, info, ka, regs, 0); +		err = setup_frame(ksig, regs, oldset); +	signal_setup_done(err, ksig, 0);  }  static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, @@ -490,10 +443,9 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,   */  static void do_signal(struct pt_regs *regs, unsigned long orig_i0)  { -	struct k_sigaction ka; +	struct ksignal ksig;  	int restart_syscall; -	siginfo_t info; -	int signr; +	bool has_handler;  	/* It's a lot of work and synchronization to add a new ptrace  	 * register for GDB to save and restore in order to get @@ -516,7 +468,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)  	if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C))  		regs->u_regs[UREG_G6] = orig_i0; -	signr = get_signal_to_deliver(&info, &ka, regs, NULL); +	has_handler = get_signal(&ksig);  	/* If the debugger messes with the program counter, it clears  	 * the software "in syscall" bit, directing us to not perform @@ -528,35 +480,30 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)  		orig_i0 = regs->u_regs[UREG_G6];  	} - -	if (signr > 0) { +	if (has_handler) {  		if (restart_syscall) -			syscall_restart(orig_i0, regs, &ka.sa); -		handle_signal(signr, &ka, &info, regs); -		return; -	} -	if (restart_syscall && -	    (regs->u_regs[UREG_I0] == ERESTARTNOHAND || -	     regs->u_regs[UREG_I0] == ERESTARTSYS || -	     regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { -		/* replay the system call when we are done */ -		regs->u_regs[UREG_I0] = orig_i0; -		regs->pc -= 4; -		regs->npc -= 4; -		pt_regs_clear_syscall(regs); -	} -	if (restart_syscall && -	    regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { -		regs->u_regs[UREG_G1] = __NR_restart_syscall; -		regs->pc -= 4; -		regs->npc -= 4; -		pt_regs_clear_syscall(regs); +			syscall_restart(orig_i0, regs, &ksig.ka.sa); +		handle_signal(&ksig, regs); +	} else { +		if (restart_syscall) { +			switch (regs->u_regs[UREG_I0]) { +			case ERESTARTNOHAND: +	     		case ERESTARTSYS: +			case ERESTARTNOINTR: +				/* replay the system call when we are done */ +				regs->u_regs[UREG_I0] = orig_i0; +				regs->pc -= 4; +				regs->npc -= 4; +				pt_regs_clear_syscall(regs); +			case ERESTART_RESTARTBLOCK: +				regs->u_regs[UREG_G1] = __NR_restart_syscall; +				regs->pc -= 4; +				regs->npc -= 4; +				pt_regs_clear_syscall(regs); +			} +		} +		restore_saved_sigmask();  	} - -	/* if there's no signal to deliver, we just put the saved sigmask -	 * back -	 */ -	restore_saved_sigmask();  }  void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index 689e1ba6280..35923e8abd8 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -236,23 +236,6 @@ struct rt_signal_frame {  	__siginfo_rwin_t	*rwin_save;  }; -static long _sigpause_common(old_sigset_t set) -{ -	sigset_t blocked; -	siginitset(&blocked, set); -	return sigsuspend(&blocked); -} - -asmlinkage long sys_sigpause(unsigned int set) -{ -	return _sigpause_common(set); -} - -asmlinkage long sys_sigsuspend(old_sigset_t set) -{ -	return _sigpause_common(set); -} -  void do_rt_sigreturn(struct pt_regs *regs)  {  	struct rt_signal_frame __user *sf; @@ -295,7 +278,8 @@ void do_rt_sigreturn(struct pt_regs *regs)  		err |= restore_fpu_state(regs, fpu_save);  	err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); -	if (err || do_sigaltstack(&sf->stack, NULL, (unsigned long)sf) == -EFAULT) +	err |= restore_altstack(&sf->stack); +	if (err)  		goto segv;  	err |= __get_user(rwin_save, &sf->rwin_save); @@ -324,7 +308,7 @@ static int invalid_frame_pointer(void __user *fp)  	return 0;  } -static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize) +static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)  {  	unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS; @@ -336,12 +320,7 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *  		return (void __user *) -1L;  	/* This is the X/Open sanctioned signal stack switching.  */ -	if (ka->sa.sa_flags & SA_ONSTACK) { -		if (sas_ss_flags(sp) == 0) -			sp = current->sas_ss_sp + current->sas_ss_size; -	} - -	sp -= framesize; +	sp = sigsp(sp, ksig) - framesize;  	/* Always align the stack frame.  This handles two cases.  First,  	 * sigaltstack need not be mindful of platform specific stack @@ -355,8 +334,7 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *  }  static inline int -setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, -	       int signo, sigset_t *oldset, siginfo_t *info) +setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)  {  	struct rt_signal_frame __user *sf;  	int wsaved, err, sf_size; @@ -374,10 +352,12 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  	if (wsaved)  		sf_size += sizeof(__siginfo_rwin_t);  	sf = (struct rt_signal_frame __user *) -		get_sigframe(ka, regs, sf_size); +		get_sigframe(ksig, regs, sf_size); -	if (invalid_frame_pointer (sf)) -		goto sigill; +	if (invalid_frame_pointer (sf)) { +		do_exit(SIGILL);	/* won't return, actually */ +		return -EINVAL; +	}  	tail = (sf + 1); @@ -403,11 +383,9 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  	}  	/* Setup sigaltstack */ -	err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); -	err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); -	err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); +	err |= __save_altstack(&sf->stack, regs->u_regs[UREG_FP]); -	err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t)); +	err |= copy_to_user(&sf->mask, sigmask_to_save(), sizeof(sigset_t));  	if (!wsaved) {  		err |= copy_in_user((u64 __user *)sf, @@ -420,18 +398,18 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  		rp = ¤t_thread_info()->reg_window[wsaved - 1];  		err |= copy_to_user(sf, rp, sizeof(struct reg_window));  	} -	if (info) -		err |= copy_siginfo_to_user(&sf->info, info); +	if (ksig->ka.sa.sa_flags & SA_SIGINFO) +		err |= copy_siginfo_to_user(&sf->info, &ksig->info);  	else { -		err |= __put_user(signo, &sf->info.si_signo); +		err |= __put_user(ksig->sig, &sf->info.si_signo);  		err |= __put_user(SI_NOINFO, &sf->info.si_code);  	}  	if (err) -		goto sigsegv; +		return err;  	/* 3. signal handler back-trampoline and parameters */  	regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; -	regs->u_regs[UREG_I0] = signo; +	regs->u_regs[UREG_I0] = ksig->sig;  	regs->u_regs[UREG_I1] = (unsigned long) &sf->info;  	/* The sigcontext is passed in this way because of how it @@ -441,37 +419,15 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  	regs->u_regs[UREG_I2] = (unsigned long) &sf->info;  	/* 5. signal handler */ -	regs->tpc = (unsigned long) ka->sa.sa_handler; +	regs->tpc = (unsigned long) ksig->ka.sa.sa_handler;  	regs->tnpc = (regs->tpc + 4);  	if (test_thread_flag(TIF_32BIT)) {  		regs->tpc &= 0xffffffff;  		regs->tnpc &= 0xffffffff;  	}  	/* 4. return to kernel instructions */ -	regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; +	regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;  	return 0; - -sigill: -	do_exit(SIGILL); -	return -EINVAL; - -sigsegv: -	force_sigsegv(signo, current); -	return -EFAULT; -} - -static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, -				siginfo_t *info, -				sigset_t *oldset, struct pt_regs *regs) -{ -	int err; - -	err = setup_rt_frame(ka, regs, signr, oldset, -			     (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL); -	if (err) -		return; - -	signal_delivered(signr, info, ka, regs, 0);  }  static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, @@ -501,11 +457,9 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,   */  static void do_signal(struct pt_regs *regs, unsigned long orig_i0)  { -	struct k_sigaction ka; +	struct ksignal ksig;  	int restart_syscall; -	sigset_t *oldset = sigmask_to_save(); -	siginfo_t info; -	int signr; +	bool has_handler;  	/* It's a lot of work and synchronization to add a new ptrace  	 * register for GDB to save and restore in order to get @@ -531,13 +485,13 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)  #ifdef CONFIG_COMPAT  	if (test_thread_flag(TIF_32BIT)) { -		extern void do_signal32(sigset_t *, struct pt_regs *); -		do_signal32(oldset, regs); +		extern void do_signal32(struct pt_regs *); +		do_signal32(regs);  		return;  	}  #endif	 -	signr = get_signal_to_deliver(&info, &ka, regs, NULL); +	has_handler = get_signal(&ksig);  	restart_syscall = 0;  	if (pt_regs_is_syscall(regs) && @@ -546,34 +500,30 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)  		orig_i0 = regs->u_regs[UREG_G6];  	} -	if (signr > 0) { +	if (has_handler) {  		if (restart_syscall) -			syscall_restart(orig_i0, regs, &ka.sa); -		handle_signal(signr, &ka, &info, oldset, regs); -		return; -	} -	if (restart_syscall && -	    (regs->u_regs[UREG_I0] == ERESTARTNOHAND || -	     regs->u_regs[UREG_I0] == ERESTARTSYS || -	     regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { -		/* replay the system call when we are done */ -		regs->u_regs[UREG_I0] = orig_i0; -		regs->tpc -= 4; -		regs->tnpc -= 4; -		pt_regs_clear_syscall(regs); -	} -	if (restart_syscall && -	    regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { -		regs->u_regs[UREG_G1] = __NR_restart_syscall; -		regs->tpc -= 4; -		regs->tnpc -= 4; -		pt_regs_clear_syscall(regs); +			syscall_restart(orig_i0, regs, &ksig.ka.sa); +		signal_setup_done(setup_rt_frame(&ksig, regs), &ksig, 0); +	} else { +		if (restart_syscall) { +			switch (regs->u_regs[UREG_I0]) { +			case ERESTARTNOHAND: +	     		case ERESTARTSYS: +			case ERESTARTNOINTR: +				/* replay the system call when we are done */ +				regs->u_regs[UREG_I0] = orig_i0; +				regs->tpc -= 4; +				regs->tnpc -= 4; +				pt_regs_clear_syscall(regs); +			case ERESTART_RESTARTBLOCK: +				regs->u_regs[UREG_G1] = __NR_restart_syscall; +				regs->tpc -= 4; +				regs->tnpc -= 4; +				pt_regs_clear_syscall(regs); +			} +		} +		restore_saved_sigmask();  	} - -	/* If there's no signal to deliver, we just put the saved sigmask -	 * back -	 */ -	restore_saved_sigmask();  }  void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags) diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c index 79db45e5134..e3f2b81c23f 100644 --- a/arch/sparc/kernel/smp_32.c +++ b/arch/sparc/kernel/smp_32.c @@ -20,6 +20,7 @@  #include <linux/seq_file.h>  #include <linux/cache.h>  #include <linux/delay.h> +#include <linux/cpu.h>  #include <asm/ptrace.h>  #include <linux/atomic.h> @@ -32,8 +33,10 @@  #include <asm/cacheflush.h>  #include <asm/tlbflush.h>  #include <asm/cpudata.h> +#include <asm/timer.h>  #include <asm/leon.h> +#include "kernel.h"  #include "irq.h"  volatile unsigned long cpu_callin_map[NR_CPUS] __cpuinitdata = {0,}; @@ -294,6 +297,89 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)  	return ret;  } +void __cpuinit arch_cpu_pre_starting(void *arg) +{ +	local_ops->cache_all(); +	local_ops->tlb_all(); + +	switch(sparc_cpu_model) { +	case sun4m: +		sun4m_cpu_pre_starting(arg); +		break; +	case sun4d: +		sun4d_cpu_pre_starting(arg); +		break; +	case sparc_leon: +		leon_cpu_pre_starting(arg); +		break; +	default: +		BUG(); +	} +} + +void __cpuinit arch_cpu_pre_online(void *arg) +{ +	unsigned int cpuid = hard_smp_processor_id(); + +	register_percpu_ce(cpuid); + +	calibrate_delay(); +	smp_store_cpu_info(cpuid); + +	local_ops->cache_all(); +	local_ops->tlb_all(); + +	switch(sparc_cpu_model) { +	case sun4m: +		sun4m_cpu_pre_online(arg); +		break; +	case sun4d: +		sun4d_cpu_pre_online(arg); +		break; +	case sparc_leon: +		leon_cpu_pre_online(arg); +		break; +	default: +		BUG(); +	} +} + +void __cpuinit sparc_start_secondary(void *arg) +{ +	unsigned int cpu; + +	/* +	 * SMP booting is extremely fragile in some architectures. So run +	 * the cpu initialization code first before anything else. +	 */ +	arch_cpu_pre_starting(arg); + +	preempt_disable(); +	cpu = smp_processor_id(); + +	/* Invoke the CPU_STARTING notifier callbacks */ +	notify_cpu_starting(cpu); + +	arch_cpu_pre_online(arg); + +	/* Set the CPU in the cpu_online_mask */ +	set_cpu_online(cpu, true); + +	/* Enable local interrupts now */ +	local_irq_enable(); + +	wmb(); +	cpu_startup_entry(CPUHP_ONLINE); + +	/* We should never reach here! */ +	BUG(); +} + +void __cpuinit smp_callin(void) +{ +	sparc_start_secondary(NULL); +} +  void smp_bogo(struct seq_file *m)  {  	int i; diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 537eb66abd0..77539eda928 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -127,6 +127,8 @@ void __cpuinit smp_callin(void)  	/* idle thread is expected to have preempt disabled */  	preempt_disable(); + +	cpu_startup_entry(CPUHP_ONLINE);  }  void cpu_panic(void) @@ -849,7 +851,7 @@ void smp_tsb_sync(struct mm_struct *mm)  }  extern unsigned long xcall_flush_tlb_mm; -extern unsigned long xcall_flush_tlb_pending; +extern unsigned long xcall_flush_tlb_page;  extern unsigned long xcall_flush_tlb_kernel_range;  extern unsigned long xcall_fetch_glob_regs;  extern unsigned long xcall_fetch_glob_pmu; @@ -1074,23 +1076,56 @@ local_flush_and_out:  	put_cpu();  } +struct tlb_pending_info { +	unsigned long ctx; +	unsigned long nr; +	unsigned long *vaddrs; +}; + +static void tlb_pending_func(void *info) +{ +	struct tlb_pending_info *t = info; + +	__flush_tlb_pending(t->ctx, t->nr, t->vaddrs); +} +  void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long *vaddrs)  {  	u32 ctx = CTX_HWBITS(mm->context); +	struct tlb_pending_info info;  	int cpu = get_cpu(); +	info.ctx = ctx; +	info.nr = nr; +	info.vaddrs = vaddrs; +  	if (mm == current->mm && atomic_read(&mm->mm_users) == 1)  		cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));  	else -		smp_cross_call_masked(&xcall_flush_tlb_pending, -				      ctx, nr, (unsigned long) vaddrs, -				      mm_cpumask(mm)); +		smp_call_function_many(mm_cpumask(mm), tlb_pending_func, +				       &info, 1);  	__flush_tlb_pending(ctx, nr, vaddrs);  	put_cpu();  } +void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr) +{ +	unsigned long context = CTX_HWBITS(mm->context); +	int cpu = get_cpu(); + +	if (mm == current->mm && atomic_read(&mm->mm_users) == 1) +		cpumask_copy(mm_cpumask(mm), cpumask_of(cpu)); +	else +		smp_cross_call_masked(&xcall_flush_tlb_page, +				      context, vaddr, 0, +				      mm_cpumask(mm)); +	__flush_tlb_page(context, vaddr); + +	put_cpu(); +} +  void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end)  {  	start &= PAGE_MASK; diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index e490ac9327c..f8933be3ca8 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -6,6 +6,7 @@   */  #include <linux/kernel_stat.h> +#include <linux/slab.h>  #include <linux/seq_file.h>  #include <asm/timer.h> diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index ddaea31de58..c9eb82f23d9 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -50,10 +50,9 @@ static inline void show_leds(int cpuid)  			      "i" (ASI_M_CTL));  } -void __cpuinit smp4d_callin(void) +void __cpuinit sun4d_cpu_pre_starting(void *arg)  {  	int cpuid = hard_smp_processor_id(); -	unsigned long flags;  	/* Show we are alive */  	cpu_leds[cpuid] = 0x6; @@ -61,26 +60,20 @@ void __cpuinit smp4d_callin(void)  	/* Enable level15 interrupt, disable level14 interrupt for now */  	cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000); +} -	local_ops->cache_all(); -	local_ops->tlb_all(); +void __cpuinit sun4d_cpu_pre_online(void *arg) +{ +	unsigned long flags; +	int cpuid; -	notify_cpu_starting(cpuid); -	/* -	 * Unblock the master CPU _only_ when the scheduler state +	cpuid = hard_smp_processor_id(); + +	/* Unblock the master CPU _only_ when the scheduler state  	 * of all secondary CPUs will be up-to-date, so after  	 * the SMP initialization the master will be just allowed  	 * to call the scheduler code.  	 */ -	/* Get our local ticker going. */ -	register_percpu_ce(cpuid); - -	calibrate_delay(); -	smp_store_cpu_info(cpuid); -	local_ops->cache_all(); -	local_ops->tlb_all(); - -	/* Allow master to continue. */  	sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1);  	local_ops->cache_all();  	local_ops->tlb_all(); @@ -106,16 +99,12 @@ void __cpuinit smp4d_callin(void)  	local_ops->cache_all();  	local_ops->tlb_all(); -	local_irq_enable();	/* We don't allow PIL 14 yet */ -  	while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))  		barrier();  	spin_lock_irqsave(&sun4d_imsk_lock, flags);  	cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */  	spin_unlock_irqrestore(&sun4d_imsk_lock, flags); -	set_cpu_online(cpuid, true); -  }  /* diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 128af730428..8a65f158153 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -34,30 +34,19 @@ swap_ulong(volatile unsigned long *ptr, unsigned long val)  	return val;  } -void __cpuinit smp4m_callin(void) +void __cpuinit sun4m_cpu_pre_starting(void *arg)  { -	int cpuid = hard_smp_processor_id(); - -	local_ops->cache_all(); -	local_ops->tlb_all(); - -	notify_cpu_starting(cpuid); - -	register_percpu_ce(cpuid); - -	calibrate_delay(); -	smp_store_cpu_info(cpuid); +} -	local_ops->cache_all(); -	local_ops->tlb_all(); +void __cpuinit sun4m_cpu_pre_online(void *arg) +{ +	int cpuid = hard_smp_processor_id(); -	/* -	 * Unblock the master CPU _only_ when the scheduler state -	 * of all secondary CPUs will be up-to-date, so after -	 * the SMP initialization the master will be just allowed -	 * to call the scheduler code. +	/* Allow master to continue. The master will then give us the +	 * go-ahead by setting the smp_commenced_mask and will wait without +	 * timeouts until our setup is completed fully (signified by +	 * our bit being set in the cpu_online_mask).  	 */ -	/* Allow master to continue. */  	swap_ulong(&cpu_callin_map[cpuid], 1);  	/* XXX: What's up with all the flushes? */ @@ -75,10 +64,6 @@ void __cpuinit smp4m_callin(void)  	while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))  		mb(); - -	local_irq_enable(); - -	set_cpu_online(cpuid, true);  }  /* diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S index 8475a474273..f7c72b6efc2 100644 --- a/arch/sparc/kernel/sys32.S +++ b/arch/sparc/kernel/sys32.S @@ -36,108 +36,18 @@ STUB:	sra	REG1, 0, REG1; \  	jmpl	%g1 + %lo(SYSCALL), %g0; \  	sra	REG3, 0, REG3 -#define SIGN4(STUB,SYSCALL,REG1,REG2,REG3,REG4) \ -	.align	32; \ -	.globl	STUB; \ -STUB:	sra	REG1, 0, REG1; \ -	sethi	%hi(SYSCALL), %g1; \ -	sra	REG2, 0, REG2; \ -	sra	REG3, 0, REG3; \ -	jmpl	%g1 + %lo(SYSCALL), %g0; \ -	sra	REG4, 0, REG4 - -SIGN1(sys32_exit, sparc_exit, %o0) -SIGN1(sys32_exit_group, sparc_exit_group, %o0) -SIGN1(sys32_wait4, compat_sys_wait4, %o2) -SIGN1(sys32_creat, sys_creat, %o1) -SIGN1(sys32_mknod, sys_mknod, %o1) -SIGN1(sys32_umount, sys_umount, %o1) -SIGN1(sys32_signal, sys_signal, %o0) -SIGN1(sys32_access, sys_access, %o1) -SIGN1(sys32_msync, sys_msync, %o2) -SIGN2(sys32_reboot, sys_reboot, %o0, %o1) -SIGN1(sys32_setitimer, compat_sys_setitimer, %o0) -SIGN1(sys32_getitimer, compat_sys_getitimer, %o0) -SIGN1(sys32_sethostname, sys_sethostname, %o1) -SIGN1(sys32_swapon, sys_swapon, %o1) -SIGN1(sys32_sigaction, compat_sys_sigaction, %o0) -SIGN1(sys32_rt_sigaction, compat_sys_rt_sigaction, %o0) -SIGN1(sys32_sigprocmask, compat_sys_sigprocmask, %o0) -SIGN1(sys32_rt_sigprocmask, compat_sys_rt_sigprocmask, %o0) -SIGN2(sys32_rt_sigqueueinfo, compat_sys_rt_sigqueueinfo, %o0, %o1) -SIGN1(sys32_getrusage, compat_sys_getrusage, %o0) -SIGN1(sys32_setxattr, sys_setxattr, %o4) -SIGN1(sys32_lsetxattr, sys_lsetxattr, %o4) -SIGN1(sys32_fsetxattr, sys_fsetxattr, %o4) -SIGN1(sys32_fgetxattr, sys_fgetxattr, %o0) -SIGN1(sys32_flistxattr, sys_flistxattr, %o0) -SIGN1(sys32_fremovexattr, sys_fremovexattr, %o0) -SIGN2(sys32_tkill, sys_tkill, %o0, %o1) -SIGN1(sys32_epoll_create, sys_epoll_create, %o0) -SIGN3(sys32_epoll_ctl, sys_epoll_ctl, %o0, %o1, %o2) -SIGN3(sys32_epoll_wait, sys_epoll_wait, %o0, %o2, %o3)  SIGN1(sys32_readahead, compat_sys_readahead, %o0)  SIGN2(sys32_fadvise64, compat_sys_fadvise64, %o0, %o4)  SIGN2(sys32_fadvise64_64, compat_sys_fadvise64_64, %o0, %o5) -SIGN2(sys32_bdflush, sys_bdflush, %o0, %o1) -SIGN1(sys32_mlockall, sys_mlockall, %o0)  SIGN1(sys32_clock_nanosleep, compat_sys_clock_nanosleep, %o1)  SIGN1(sys32_timer_settime, compat_sys_timer_settime, %o1)  SIGN1(sys32_io_submit, compat_sys_io_submit, %o1)  SIGN1(sys32_mq_open, compat_sys_mq_open, %o1)  SIGN1(sys32_select, compat_sys_select, %o0) -SIGN1(sys32_mkdir, sys_mkdir, %o1)  SIGN3(sys32_futex, compat_sys_futex, %o1, %o2, %o5) -SIGN1(sys32_sysfs, compat_sys_sysfs, %o0) -SIGN2(sys32_sendfile, compat_sys_sendfile, %o0, %o1) -SIGN2(sys32_sendfile64, sys_sendfile, %o0, %o1) -SIGN1(sys32_prctl, sys_prctl, %o0) -SIGN1(sys32_sched_rr_get_interval, compat_sys_sched_rr_get_interval, %o0) -SIGN2(sys32_waitpid, sys_waitpid, %o0, %o2) -SIGN1(sys32_getgroups, sys_getgroups, %o0) -SIGN1(sys32_getpgid, sys_getpgid, %o0) -SIGN2(sys32_getpriority, sys_getpriority, %o0, %o1) -SIGN1(sys32_getsid, sys_getsid, %o0) -SIGN2(sys32_kill, sys_kill, %o0, %o1) -SIGN1(sys32_nice, sys_nice, %o0) -SIGN1(sys32_lseek, sys_lseek, %o1) -SIGN2(sys32_open, sparc32_open, %o1, %o2) -SIGN1(sys32_readlink, sys_readlink, %o2) -SIGN1(sys32_sched_get_priority_max, sys_sched_get_priority_max, %o0) -SIGN1(sys32_sched_get_priority_min, sys_sched_get_priority_min, %o0) -SIGN1(sys32_sched_getparam, sys_sched_getparam, %o0) -SIGN1(sys32_sched_getscheduler, sys_sched_getscheduler, %o0) -SIGN1(sys32_sched_setparam, sys_sched_setparam, %o0) -SIGN2(sys32_sched_setscheduler, sys_sched_setscheduler, %o0, %o1) -SIGN1(sys32_getdomainname, sys_getdomainname, %o1) -SIGN1(sys32_setdomainname, sys_setdomainname, %o1) -SIGN1(sys32_setgroups, sys_setgroups, %o0) -SIGN2(sys32_setpgid, sys_setpgid, %o0, %o1) -SIGN3(sys32_setpriority, sys_setpriority, %o0, %o1, %o2) -SIGN1(sys32_ssetmask, sys_ssetmask, %o0) -SIGN2(sys32_syslog, sys_syslog, %o0, %o2) -SIGN1(sys32_umask, sys_umask, %o0) -SIGN3(sys32_tgkill, sys_tgkill, %o0, %o1, %o2) -SIGN1(sys32_sendto, sys_sendto, %o0)  SIGN1(sys32_recvfrom, compat_sys_recvfrom, %o0) -SIGN3(sys32_socket, sys_socket, %o0, %o1, %o2) -SIGN2(sys32_connect, sys_connect, %o0, %o2) -SIGN2(sys32_bind, sys_bind, %o0, %o2) -SIGN2(sys32_listen, sys_listen, %o0, %o1)  SIGN1(sys32_recvmsg, compat_sys_recvmsg, %o0)  SIGN1(sys32_sendmsg, compat_sys_sendmsg, %o0) -SIGN2(sys32_shutdown, sys_shutdown, %o0, %o1) -SIGN3(sys32_socketpair, sys_socketpair, %o0, %o1, %o2) -SIGN1(sys32_getpeername, sys_getpeername, %o0) -SIGN1(sys32_getsockname, sys_getsockname, %o0) -SIGN2(sys32_ioprio_get, sys_ioprio_get, %o0, %o1) -SIGN3(sys32_ioprio_set, sys_ioprio_set, %o0, %o1, %o2) -SIGN2(sys32_splice, sys_splice, %o0, %o2) -SIGN2(sys32_sync_file_range, compat_sync_file_range, %o0, %o5) -SIGN2(sys32_tee, sys_tee, %o0, %o1) -SIGN1(sys32_vmsplice, compat_sys_vmsplice, %o0) -SIGN1(sys32_truncate, sys_truncate, %o1) -SIGN1(sys32_ftruncate, sys_ftruncate, %o1)  	.globl		sys32_mmap2  sys32_mmap2: @@ -329,15 +239,6 @@ do_sys_accept4: /* sys_accept4(int, struct sockaddr *, int *, int) */  	nop  	nop -	.globl		sys32_fanotify_mark -sys32_fanotify_mark: -	sethi		%hi(sys_fanotify_mark), %g1 -	sllx		%o2, 32, %o2 -	or		%o2, %o3, %o2 -	mov		%o4, %o3 -	jmpl		%g1 + %lo(sys_fanotify_mark), %g0 -	 mov		%o5, %o4 -  	.section	__ex_table,"a"  	.align		4  	.word		1b, __retl_efault, 2b, __retl_efault diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c index 4a4cdc633f6..3d0ddbc005f 100644 --- a/arch/sparc/kernel/sys_sparc32.c +++ b/arch/sparc/kernel/sys_sparc32.c @@ -49,71 +49,6 @@  #include <asm/mmu_context.h>  #include <asm/compat_signal.h> -#ifdef CONFIG_SYSVIPC                                                         -asmlinkage long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, u32 fifth) -{ -	int version; - -	version = call >> 16; /* hack for backward compatibility */ -	call &= 0xffff; - -	switch (call) { -	case SEMTIMEDOP: -		if (fifth) -			/* sign extend semid */ -			return compat_sys_semtimedop((int)first, -						     compat_ptr(ptr), second, -						     compat_ptr(fifth)); -		/* else fall through for normal semop() */ -	case SEMOP: -		/* struct sembuf is the same on 32 and 64bit :)) */ -		/* sign extend semid */ -		return sys_semtimedop((int)first, compat_ptr(ptr), second, -				      NULL); -	case SEMGET: -		/* sign extend key, nsems */ -		return sys_semget((int)first, (int)second, third); -	case SEMCTL: -		/* sign extend semid, semnum */ -		return compat_sys_semctl((int)first, (int)second, third, -					 compat_ptr(ptr)); - -	case MSGSND: -		/* sign extend msqid */ -		return compat_sys_msgsnd((int)first, (int)second, third, -					 compat_ptr(ptr)); -	case MSGRCV: -		/* sign extend msqid, msgtyp */ -		return compat_sys_msgrcv((int)first, second, (int)fifth, -					 third, version, compat_ptr(ptr)); -	case MSGGET: -		/* sign extend key */ -		return sys_msgget((int)first, second); -	case MSGCTL: -		/* sign extend msqid */ -		return compat_sys_msgctl((int)first, second, compat_ptr(ptr)); - -	case SHMAT: -		/* sign extend shmid */ -		return compat_sys_shmat((int)first, second, third, version, -					compat_ptr(ptr)); -	case SHMDT: -		return sys_shmdt(compat_ptr(ptr)); -	case SHMGET: -		/* sign extend key_t */ -		return sys_shmget((int)first, second, third); -	case SHMCTL: -		/* sign extend shmid */ -		return compat_sys_shmctl((int)first, second, compat_ptr(ptr)); - -	default: -		return -ENOSYS; -	} - -	return -ENOSYS; -} -#endif -  asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)  {  	if ((int)high < 0) @@ -206,133 +141,19 @@ asmlinkage long compat_sys_fstatat64(unsigned int dfd,  	return cp_compat_stat64(&stat, statbuf);  } -asmlinkage long compat_sys_sysfs(int option, u32 arg1, u32 arg2) -{ -	return sys_sysfs(option, arg1, arg2); -} - -asmlinkage long compat_sys_rt_sigprocmask(int how, -					  compat_sigset_t __user *set, -					  compat_sigset_t __user *oset, -					  compat_size_t sigsetsize) -{ -	sigset_t s; -	compat_sigset_t s32; -	int ret; -	mm_segment_t old_fs = get_fs(); -	 -	if (set) { -		if (copy_from_user (&s32, set, sizeof(compat_sigset_t))) -			return -EFAULT; -		switch (_NSIG_WORDS) { -		case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); -		case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); -		case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); -		case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); -		} -	} -	set_fs (KERNEL_DS); -	ret = sys_rt_sigprocmask(how, -				 set ? (sigset_t __user *) &s : NULL, -				 oset ? (sigset_t __user *) &s : NULL, -				 sigsetsize); -	set_fs (old_fs); -	if (ret) return ret; -	if (oset) { -		switch (_NSIG_WORDS) { -		case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; -		case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; -		case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; -		case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; -		} -		if (copy_to_user (oset, &s32, sizeof(compat_sigset_t))) -			return -EFAULT; -	} -	return 0; -} - -asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set, -				    compat_size_t sigsetsize) +COMPAT_SYSCALL_DEFINE3(sparc_sigaction, int, sig, +			struct compat_old_sigaction __user *,act, +			struct compat_old_sigaction __user *,oact)  { -	sigset_t s; -	compat_sigset_t s32; -	int ret; -	mm_segment_t old_fs = get_fs(); -		 -	set_fs (KERNEL_DS); -	ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize); -	set_fs (old_fs); -	if (!ret) { -		switch (_NSIG_WORDS) { -		case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; -		case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; -		case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; -		case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; -		} -		if (copy_to_user (set, &s32, sizeof(compat_sigset_t))) -			return -EFAULT; -	} -	return ret; -} - -asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig, -					   struct compat_siginfo __user *uinfo) -{ -	siginfo_t info; -	int ret; -	mm_segment_t old_fs = get_fs(); -	 -	if (copy_siginfo_from_user32(&info, uinfo)) -		return -EFAULT; - -	set_fs (KERNEL_DS); -	ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info); -	set_fs (old_fs); -	return ret; -} - -asmlinkage long compat_sys_sigaction(int sig, struct old_sigaction32 __user *act, -				     struct old_sigaction32 __user *oact) -{ -        struct k_sigaction new_ka, old_ka; -        int ret; -  	WARN_ON_ONCE(sig >= 0); -	sig = -sig; - -        if (act) { -		compat_old_sigset_t mask; -		u32 u_handler, u_restorer; -		 -		ret = get_user(u_handler, &act->sa_handler); -		new_ka.sa.sa_handler =  compat_ptr(u_handler); -		ret |= __get_user(u_restorer, &act->sa_restorer); -		new_ka.sa.sa_restorer = compat_ptr(u_restorer); -		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); -		ret |= __get_user(mask, &act->sa_mask); -		if (ret) -			return ret; -		new_ka.ka_restorer = NULL; -		siginitset(&new_ka.sa.sa_mask, mask); -        } - -        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - -	if (!ret && oact) { -		ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler); -		ret |= __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer); -		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); -		ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); -        } - -	return ret; +	return compat_sys_sigaction(-sig, act, oact);  } -asmlinkage long compat_sys_rt_sigaction(int sig, -					struct sigaction32 __user *act, -					struct sigaction32 __user *oact, -					void __user *restorer, -					compat_size_t sigsetsize) +COMPAT_SYSCALL_DEFINE5(rt_sigaction, int, sig, +			struct compat_sigaction __user *,act, +			struct compat_sigaction __user *,oact, +			void __user *,restorer, +			compat_size_t,sigsetsize)  {          struct k_sigaction new_ka, old_ka;          int ret; @@ -349,12 +170,7 @@ asmlinkage long compat_sys_rt_sigaction(int sig,  		ret = get_user(u_handler, &act->sa_handler);  		new_ka.sa.sa_handler =  compat_ptr(u_handler);  		ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t)); -		switch (_NSIG_WORDS) { -		case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32); -		case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32); -		case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32); -		case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32); -		} +		sigset_from_compat(&new_ka.sa.sa_mask, &set32);  		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);  		ret |= __get_user(u_restorer, &act->sa_restorer);  		new_ka.sa.sa_restorer = compat_ptr(u_restorer); @@ -365,12 +181,7 @@ asmlinkage long compat_sys_rt_sigaction(int sig,  	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);  	if (!ret && oact) { -		switch (_NSIG_WORDS) { -		case 4: set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); set32.sig[6] = old_ka.sa.sa_mask.sig[3]; -		case 3: set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); set32.sig[4] = old_ka.sa.sa_mask.sig[2]; -		case 2: set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); set32.sig[2] = old_ka.sa.sa_mask.sig[1]; -		case 1: set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); set32.sig[0] = old_ka.sa.sa_mask.sig[0]; -		} +		sigset_to_compat(&set32, &old_ka.sa.sa_mask);  		ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);  		ret |= __copy_to_user(&oact->sa_mask, &set32, sizeof(compat_sigset_t));  		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); @@ -382,35 +193,6 @@ asmlinkage long compat_sys_rt_sigaction(int sig,          return ret;  } -#ifdef CONFIG_MODULES - -asmlinkage long sys32_init_module(void __user *umod, u32 len, -				  const char __user *uargs) -{ -	return sys_init_module(umod, len, uargs); -} - -asmlinkage long sys32_delete_module(const char __user *name_user, -				    unsigned int flags) -{ -	return sys_delete_module(name_user, flags); -} - -#else /* CONFIG_MODULES */ - -asmlinkage long sys32_init_module(const char __user *name_user, -				  struct module __user *mod_user) -{ -	return -ENOSYS; -} - -asmlinkage long sys32_delete_module(const char __user *name_user) -{ -	return -ENOSYS; -} - -#endif  /* CONFIG_MODULES */ -  asmlinkage compat_ssize_t sys32_pread64(unsigned int fd,  					char __user *ubuf,  					compat_size_t count, @@ -456,25 +238,7 @@ long compat_sys_fadvise64_64(int fd,  				advice);  } -/* This is just a version for 32-bit applications which does - * not force O_LARGEFILE on. - */ - -asmlinkage long sparc32_open(const char __user *filename, -			     int flags, int mode) -{ -	return do_sys_open(AT_FDCWD, filename, flags, mode); -} - -long sys32_lookup_dcookie(unsigned long cookie_high, -			  unsigned long cookie_low, -			  char __user *buf, size_t len) -{ -	return sys_lookup_dcookie((cookie_high << 32) | cookie_low, -				  buf, len); -} - -long compat_sync_file_range(int fd, unsigned long off_high, unsigned long off_low, unsigned long nb_high, unsigned long nb_low, int flags) +long sys32_sync_file_range(unsigned int fd, unsigned long off_high, unsigned long off_low, unsigned long nb_high, unsigned long nb_low, unsigned int flags)  {  	return sys_sync_file_range(fd,  				   (off_high << 32) | off_low, diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index 2da0bdcae52..3a8d1844402 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c @@ -160,49 +160,19 @@ sparc_breakpoint (struct pt_regs *regs)  #endif  } -asmlinkage int -sparc_sigaction (int sig, const struct old_sigaction __user *act, -		 struct old_sigaction __user *oact) +SYSCALL_DEFINE3(sparc_sigaction, int, sig, +		struct old_sigaction __user *,act, +		struct old_sigaction __user *,oact)  { -	struct k_sigaction new_ka, old_ka; -	int ret; -  	WARN_ON_ONCE(sig >= 0); -	sig = -sig; - -	if (act) { -		unsigned long mask; - -		if (!access_ok(VERIFY_READ, act, sizeof(*act)) || -		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) || -		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || -		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) || -		    __get_user(mask, &act->sa_mask)) -			return -EFAULT; -		siginitset(&new_ka.sa.sa_mask, mask); -		new_ka.ka_restorer = NULL; -	} - -	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - -	if (!ret && oact) { -		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || -		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || -		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || -		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || -		    __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) -			return -EFAULT; -	} - -	return ret; +	return sys_sigaction(-sig, act, oact);  } -asmlinkage long -sys_rt_sigaction(int sig, -		 const struct sigaction __user *act, -		 struct sigaction __user *oact, -		 void __user *restorer, -		 size_t sigsetsize) +SYSCALL_DEFINE5(rt_sigaction, int, sig, +		 const struct sigaction __user *, act, +		 struct sigaction __user *, oact, +		 void __user *, restorer, +		 size_t, sigsetsize)  {  	struct k_sigaction new_ka, old_ka;  	int ret; diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 708bc29d36a..2daaaa6eda2 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -353,7 +353,7 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second  		case SEMCTL: {  			err = sys_semctl(first, second,  					 (int)third | IPC_64, -					 (union semun) ptr); +					 (unsigned long) ptr);  			goto out;  		}  		default: @@ -470,10 +470,6 @@ SYSCALL_DEFINE2(64_munmap, unsigned long, addr, size_t, len)  	return vm_munmap(addr, len);  } - -extern unsigned long do_mremap(unsigned long addr, -	unsigned long old_len, unsigned long new_len, -	unsigned long flags, unsigned long new_addr);  SYSCALL_DEFINE5(64_mremap, unsigned long, addr,	unsigned long, old_len,  		unsigned long, new_len, unsigned long, flags, diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S index e0fed7711a9..22a1098961f 100644 --- a/arch/sparc/kernel/syscalls.S +++ b/arch/sparc/kernel/syscalls.S @@ -25,16 +25,10 @@ sys_nis_syscall:  sys_memory_ordering:  	ba,pt	%xcc, sparc_memory_ordering  	 add	%sp, PTREGS_OFF, %o1 -sys_sigaltstack: -	ba,pt	%xcc, do_sigaltstack -	 add	%i6, STACK_BIAS, %o2  #ifdef CONFIG_COMPAT  sys32_sigstack:  	ba,pt	%xcc, do_sys32_sigstack  	 mov	%i6, %o2 -sys32_sigaltstack: -	ba,pt	%xcc, do_sys32_sigaltstack -	 mov	%i6, %o2  #endif  	.align	32  #ifdef CONFIG_COMPAT diff --git a/arch/sparc/kernel/systbls.h b/arch/sparc/kernel/systbls.h index 118759cd734..26e6dd72e92 100644 --- a/arch/sparc/kernel/systbls.h +++ b/arch/sparc/kernel/systbls.h @@ -3,8 +3,8 @@  #include <linux/kernel.h>  #include <linux/types.h> +#include <linux/signal.h>  #include <asm/utrap.h> -#include <asm/signal.h>  extern asmlinkage unsigned long sys_getpagesize(void);  extern asmlinkage long sparc_pipe(struct pt_regs *regs); @@ -36,8 +36,6 @@ extern asmlinkage long sys_rt_sigaction(int sig,  extern asmlinkage void sparc64_set_context(struct pt_regs *regs);  extern asmlinkage void sparc64_get_context(struct pt_regs *regs); -extern asmlinkage long sys_sigpause(unsigned int set); -extern asmlinkage long sys_sigsuspend(old_sigset_t set);  extern void do_rt_sigreturn(struct pt_regs *regs);  #endif /* _SYSTBLS_H */ diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 6ac43c36bbb..7b87171ecf1 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S @@ -55,7 +55,7 @@ sys_call_table:  /*180*/	.long sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_sigpending, sys_ni_syscall  /*185*/	.long sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_newuname  /*190*/	.long sys_init_module, sys_personality, sparc_remap_file_pages, sys_epoll_create, sys_epoll_ctl -/*195*/	.long sys_epoll_wait, sys_ioprio_set, sys_getppid, sparc_sigaction, sys_sgetmask +/*195*/	.long sys_epoll_wait, sys_ioprio_set, sys_getppid, sys_sparc_sigaction, sys_sgetmask  /*200*/	.long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_old_readdir  /*205*/	.long sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_fadvise64  /*210*/	.long sys_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, sys_sysinfo diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 1009ecb9267..6d81597064b 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -18,63 +18,63 @@  	.globl sys_call_table32  sys_call_table32: -/*0*/	.word sys_restart_syscall, sys32_exit, sys_fork, sys_read, sys_write -/*5*/	.word sys32_open, sys_close, sys32_wait4, sys32_creat, sys_link -/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys32_mknod -/*15*/	.word sys_chmod, sys_lchown16, sys_brk, sys_nis_syscall, sys32_lseek +/*0*/	.word sys_restart_syscall, sparc_exit, sys_fork, sys_read, sys_write +/*5*/	.word compat_sys_open, sys_close, compat_sys_wait4, sys_creat, sys_link +/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys_mknod +/*15*/	.word sys_chmod, sys_lchown16, sys_brk, sys_nis_syscall, compat_sys_lseek  /*20*/	.word sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16 -/*25*/	.word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys_pause -/*30*/	.word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice -	.word sys_chown, sys_sync, sys32_kill, compat_sys_newstat, sys32_sendfile +/*25*/	.word compat_sys_vmsplice, compat_sys_ptrace, sys_alarm, compat_sys_sigaltstack, sys_pause +/*30*/	.word compat_sys_utime, sys_lchown, sys_fchown, sys_access, sys_nice +	.word sys_chown, sys_sync, sys_kill, compat_sys_newstat, compat_sys_sendfile  /*40*/	.word compat_sys_newlstat, sys_dup, sys_sparc_pipe, compat_sys_times, sys_getuid -	.word sys32_umount, sys_setgid16, sys_getgid16, sys32_signal, sys_geteuid16 +	.word sys_umount, sys_setgid16, sys_getgid16, sys_signal, sys_geteuid16  /*50*/	.word sys_getegid16, sys_acct, sys_nis_syscall, sys_getgid, compat_sys_ioctl -	.word sys32_reboot, sys32_mmap2, sys_symlink, sys32_readlink, sys32_execve -/*60*/	.word sys32_umask, sys_chroot, compat_sys_newfstat, compat_sys_fstat64, sys_getpagesize -	.word sys32_msync, sys_vfork, sys32_pread64, sys32_pwrite64, sys_geteuid +	.word sys_reboot, sys32_mmap2, sys_symlink, sys_readlink, sys32_execve +/*60*/	.word sys_umask, sys_chroot, compat_sys_newfstat, compat_sys_fstat64, sys_getpagesize +	.word sys_msync, sys_vfork, sys32_pread64, sys32_pwrite64, sys_geteuid  /*70*/	.word sys_getegid, sys_mmap, sys_setreuid, sys_munmap, sys_mprotect  	.word sys_madvise, sys_vhangup, sys32_truncate64, sys_mincore, sys_getgroups16 -/*80*/	.word sys_setgroups16, sys_getpgrp, sys32_setgroups, sys32_setitimer, sys32_ftruncate64 -	.word sys32_swapon, sys32_getitimer, sys_setuid, sys32_sethostname, sys_setgid +/*80*/	.word sys_setgroups16, sys_getpgrp, sys_setgroups, compat_sys_setitimer, sys32_ftruncate64 +	.word sys_swapon, compat_sys_getitimer, sys_setuid, sys_sethostname, sys_setgid  /*90*/	.word sys_dup2, sys_setfsuid, compat_sys_fcntl, sys32_select, sys_setfsgid -	.word sys_fsync, sys32_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*100*/ .word sys32_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending -	.word compat_sys_rt_sigtimedwait, sys32_rt_sigqueueinfo, compat_sys_rt_sigsuspend, sys_setresuid, sys_getresuid +	.word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*100*/ .word sys_getpriority, sys32_rt_sigreturn, compat_sys_rt_sigaction, compat_sys_rt_sigprocmask, compat_sys_rt_sigpending +	.word compat_sys_rt_sigtimedwait, compat_sys_rt_sigqueueinfo, compat_sys_rt_sigsuspend, sys_setresuid, sys_getresuid  /*110*/	.word sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall -	.word sys32_getgroups, compat_sys_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd +	.word sys_getgroups, compat_sys_gettimeofday, compat_sys_getrusage, sys_nis_syscall, sys_getcwd  /*120*/	.word compat_sys_readv, compat_sys_writev, compat_sys_settimeofday, sys_fchown16, sys_fchmod -	.word sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys32_truncate -/*130*/	.word sys32_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall -	.word sys_nis_syscall, sys32_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64 -/*140*/	.word sys32_sendfile64, sys_nis_syscall, sys32_futex, sys_gettid, compat_sys_getrlimit -	.word compat_sys_setrlimit, sys_pivot_root, sys32_prctl, sys_pciconfig_read, sys_pciconfig_write +	.word sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, compat_sys_truncate +/*130*/	.word compat_sys_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall +	.word sys_nis_syscall, sys_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64 +/*140*/	.word sys_sendfile64, sys_nis_syscall, sys32_futex, sys_gettid, compat_sys_getrlimit +	.word compat_sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write  /*150*/	.word sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64  	.word compat_sys_fcntl64, sys_inotify_rm_watch, compat_sys_statfs, compat_sys_fstatfs, sys_oldumount -/*160*/	.word compat_sys_sched_setaffinity, compat_sys_sched_getaffinity, sys32_getdomainname, sys32_setdomainname, sys_nis_syscall -	.word sys_quotactl, sys_set_tid_address, compat_sys_mount, compat_sys_ustat, sys32_setxattr -/*170*/	.word sys32_lsetxattr, sys32_fsetxattr, sys_getxattr, sys_lgetxattr, compat_sys_getdents -	.word sys_setsid, sys_fchdir, sys32_fgetxattr, sys_listxattr, sys_llistxattr -/*180*/	.word sys32_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall -	.word sys32_setpgid, sys32_fremovexattr, sys32_tkill, sys32_exit_group, sys_newuname -/*190*/	.word sys32_init_module, sys_sparc64_personality, sys_remap_file_pages, sys32_epoll_create, sys32_epoll_ctl -	.word sys32_epoll_wait, sys32_ioprio_set, sys_getppid, sys32_sigaction, sys_sgetmask -/*200*/	.word sys32_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir -	.word sys32_readahead, sys32_socketcall, sys32_syslog, sys32_lookup_dcookie, sys32_fadvise64 -/*210*/	.word sys32_fadvise64_64, sys32_tgkill, sys32_waitpid, sys_swapoff, compat_sys_sysinfo -	.word compat_sys_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, compat_sys_adjtimex -/*220*/	.word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid -	.word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid16, sys_setfsgid16 -/*230*/	.word sys32_select, compat_sys_time, sys32_splice, compat_sys_stime, compat_sys_statfs64 -	.word compat_sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys32_mlockall -/*240*/	.word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys32_sched_setscheduler, sys32_sched_getscheduler -	.word sys_sched_yield, sys32_sched_get_priority_max, sys32_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep -/*250*/	.word sys_mremap, compat_sys_sysctl, sys32_getsid, sys_fdatasync, sys_nis_syscall +/*160*/	.word compat_sys_sched_setaffinity, compat_sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall +	.word sys_quotactl, sys_set_tid_address, compat_sys_mount, compat_sys_ustat, sys_setxattr +/*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, compat_sys_getdents +	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr +/*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall +	.word sys_setpgid, sys_fremovexattr, sys_tkill, sparc_exit_group, sys_newuname +/*190*/	.word sys_init_module, sys_sparc64_personality, sys_remap_file_pages, sys_epoll_create, sys_epoll_ctl +	.word sys_epoll_wait, sys_ioprio_set, sys_getppid, compat_sys_sparc_sigaction, sys_sgetmask +/*200*/	.word sys_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir +	.word sys32_readahead, sys32_socketcall, sys_syslog, compat_sys_lookup_dcookie, sys32_fadvise64 +/*210*/	.word sys32_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, compat_sys_sysinfo +	.word compat_sys_ipc, sys32_sigreturn, sys_clone, sys_ioprio_get, compat_sys_adjtimex +/*220*/	.word compat_sys_sigprocmask, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid +	.word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid16, sys_setfsgid16 +/*230*/	.word sys32_select, compat_sys_time, sys_splice, compat_sys_stime, compat_sys_statfs64 +	.word compat_sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall +/*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler +	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, compat_sys_sched_rr_get_interval, compat_sys_nanosleep +/*250*/	.word sys_mremap, compat_sys_sysctl, sys_getsid, sys_fdatasync, sys_nis_syscall  	.word sys32_sync_file_range, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep  /*260*/	.word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun  	.word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy  /*270*/	.word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink  	.word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid -/*280*/	.word sys32_tee, sys_add_key, sys_request_key, compat_sys_keyctl, compat_sys_openat +/*280*/	.word sys_tee, sys_add_key, sys_request_key, compat_sys_keyctl, compat_sys_openat  	.word sys_mkdirat, sys_mknodat, sys_fchownat, compat_sys_futimesat, compat_sys_fstatat64  /*290*/	.word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat  	.word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare @@ -84,7 +84,7 @@ sys_call_table32:  	.word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1  /*320*/	.word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv  	.word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init -/*330*/	.word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime +/*330*/	.word compat_sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime  	.word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev  /*340*/	.word sys_kern_features, sys_kcmp, sys_finit_module diff --git a/arch/sparc/kernel/trampoline_32.S b/arch/sparc/kernel/trampoline_32.S index af27acab448..6cdb08cdabf 100644 --- a/arch/sparc/kernel/trampoline_32.S +++ b/arch/sparc/kernel/trampoline_32.S @@ -79,18 +79,15 @@ cpu3_startup:  	 nop  	/* Start this processor. */ -	call	smp4m_callin +	call	smp_callin  	 nop -	b,a	smp_do_cpu_idle +	b,a	smp_panic  	.text  	.align	4 -smp_do_cpu_idle: -	call	cpu_idle -	 mov	0, %o0 - +smp_panic:  	call	cpu_panic  	 nop @@ -144,10 +141,10 @@ sun4d_cpu_startup:  	 nop  	/* Start this processor. */ -	call	smp4d_callin +	call	smp_callin  	 nop -	b,a	smp_do_cpu_idle +	b,a	smp_panic  	__CPUINIT  	.align	4 @@ -201,7 +198,7 @@ leon_smp_cpu_startup:  	 nop  	/* Start this processor. */ -	call	leon_callin +	call	smp_callin  	 nop -	b,a	smp_do_cpu_idle +	b,a	smp_panic diff --git a/arch/sparc/kernel/trampoline_64.S b/arch/sparc/kernel/trampoline_64.S index da1b781b5e6..2e973a26fbd 100644 --- a/arch/sparc/kernel/trampoline_64.S +++ b/arch/sparc/kernel/trampoline_64.S @@ -407,8 +407,7 @@ after_lock_tlb:  	call		smp_callin  	 nop -	call		cpu_idle -	 mov		0, %o0 +  	call		cpu_panic  	 nop  1:	b,a,pt		%xcc, 1b diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c index a5785ea2a85..662982946a8 100644 --- a/arch/sparc/kernel/traps_32.c +++ b/arch/sparc/kernel/traps_32.c @@ -58,7 +58,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)  	printk("%s(%d): %s [#%d]\n", current->comm, task_pid_nr(current), str, ++die_counter);  	show_regs(regs); -	add_taint(TAINT_DIE); +	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);  	__SAVE; __SAVE; __SAVE; __SAVE;  	__SAVE; __SAVE; __SAVE; __SAVE; diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index e7ecf1507d9..b3f833ab90e 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -2350,13 +2350,6 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)  	} while (++count < 16);  } -void dump_stack(void) -{ -	show_stack(current, NULL); -} - -EXPORT_SYMBOL(dump_stack); -  static inline struct reg_window *kernel_stack_up(struct reg_window *rw)  {  	unsigned long fp = rw->ins[6]; @@ -2383,7 +2376,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)  	notify_die(DIE_OOPS, str, regs, 0, 255, SIGSEGV);  	__asm__ __volatile__("flushw");  	show_regs(regs); -	add_taint(TAINT_DIE); +	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);  	if (regs->tstate & TSTATE_PRIV) {  		struct thread_info *tp = current_thread_info();  		struct reg_window *rw = (struct reg_window *) diff --git a/arch/sparc/kernel/tsb.S b/arch/sparc/kernel/tsb.S index d4bdc7a6237..a313e4a9399 100644 --- a/arch/sparc/kernel/tsb.S +++ b/arch/sparc/kernel/tsb.S @@ -136,12 +136,43 @@ tsb_miss_page_table_walk_sun4v_fastpath:  	 nop  	/* It is a huge page, use huge page TSB entry address we -	 * calculated above. +	 * calculated above.  If the huge page TSB has not been +	 * allocated, setup a trap stack and call hugetlb_setup() +	 * to do so, then return from the trap to replay the TLB +	 * miss. +	 * +	 * This is necessary to handle the case of transparent huge +	 * pages where we don't really have a non-atomic context +	 * in which to allocate the hugepage TSB hash table.  When +	 * the 'mm' faults in the hugepage for the first time, we +	 * thus handle it here.  This also makes sure that we can +	 * allocate the TSB hash table on the correct NUMA node.  	 */  	TRAP_LOAD_TRAP_BLOCK(%g7, %g2) -	ldx		[%g7 + TRAP_PER_CPU_TSB_HUGE_TEMP], %g2 -	cmp		%g2, -1 -	movne		%xcc, %g2, %g1 +	ldx		[%g7 + TRAP_PER_CPU_TSB_HUGE_TEMP], %g1 +	cmp		%g1, -1 +	bne,pt		%xcc, 60f +	 nop + +661:	rdpr		%pstate, %g5 +	wrpr		%g5, PSTATE_AG | PSTATE_MG, %pstate +	.section	.sun4v_2insn_patch, "ax" +	.word		661b +	SET_GL(1) +	nop +	.previous + +	rdpr	%tl, %g3 +	cmp	%g3, 1 +	bne,pn	%xcc, winfix_trampoline +	 nop +	ba,pt	%xcc, etrap +	 rd	%pc, %g7 +	call	hugetlb_setup +	 add	%sp, PTREGS_OFF, %o0 +	ba,pt	%xcc, rtrap +	 nop +  60:  #endif diff --git a/arch/sparc/kernel/us2e_cpufreq.c b/arch/sparc/kernel/us2e_cpufreq.c deleted file mode 100644 index 489fc15f319..00000000000 --- a/arch/sparc/kernel/us2e_cpufreq.c +++ /dev/null @@ -1,413 +0,0 @@ -/* us2e_cpufreq.c: UltraSPARC-IIe cpu frequency support - * - * Copyright (C) 2003 David S. Miller (davem@redhat.com) - * - * Many thanks to Dominik Brodowski for fixing up the cpufreq - * infrastructure in order to make this driver easier to implement. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/cpufreq.h> -#include <linux/threads.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <asm/asi.h> -#include <asm/timer.h> - -static struct cpufreq_driver *cpufreq_us2e_driver; - -struct us2e_freq_percpu_info { -	struct cpufreq_frequency_table table[6]; -}; - -/* Indexed by cpu number. */ -static struct us2e_freq_percpu_info *us2e_freq_table; - -#define HBIRD_MEM_CNTL0_ADDR	0x1fe0000f010UL -#define HBIRD_ESTAR_MODE_ADDR	0x1fe0000f080UL - -/* UltraSPARC-IIe has five dividers: 1, 2, 4, 6, and 8.  These are controlled - * in the ESTAR mode control register. - */ -#define ESTAR_MODE_DIV_1	0x0000000000000000UL -#define ESTAR_MODE_DIV_2	0x0000000000000001UL -#define ESTAR_MODE_DIV_4	0x0000000000000003UL -#define ESTAR_MODE_DIV_6	0x0000000000000002UL -#define ESTAR_MODE_DIV_8	0x0000000000000004UL -#define ESTAR_MODE_DIV_MASK	0x0000000000000007UL - -#define MCTRL0_SREFRESH_ENAB	0x0000000000010000UL -#define MCTRL0_REFR_COUNT_MASK	0x0000000000007f00UL -#define MCTRL0_REFR_COUNT_SHIFT	8 -#define MCTRL0_REFR_INTERVAL	7800 -#define MCTRL0_REFR_CLKS_P_CNT	64 - -static unsigned long read_hbreg(unsigned long addr) -{ -	unsigned long ret; - -	__asm__ __volatile__("ldxa	[%1] %2, %0" -			     : "=&r" (ret) -			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E)); -	return ret; -} - -static void write_hbreg(unsigned long addr, unsigned long val) -{ -	__asm__ __volatile__("stxa	%0, [%1] %2\n\t" -			     "membar	#Sync" -			     : /* no outputs */ -			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E) -			     : "memory"); -	if (addr == HBIRD_ESTAR_MODE_ADDR) { -		/* Need to wait 16 clock cycles for the PLL to lock.  */ -		udelay(1); -	} -} - -static void self_refresh_ctl(int enable) -{ -	unsigned long mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR); - -	if (enable) -		mctrl |= MCTRL0_SREFRESH_ENAB; -	else -		mctrl &= ~MCTRL0_SREFRESH_ENAB; -	write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl); -	(void) read_hbreg(HBIRD_MEM_CNTL0_ADDR); -} - -static void frob_mem_refresh(int cpu_slowing_down, -			     unsigned long clock_tick, -			     unsigned long old_divisor, unsigned long divisor) -{ -	unsigned long old_refr_count, refr_count, mctrl; - -	refr_count  = (clock_tick * MCTRL0_REFR_INTERVAL); -	refr_count /= (MCTRL0_REFR_CLKS_P_CNT * divisor * 1000000000UL); - -	mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR); -	old_refr_count = (mctrl & MCTRL0_REFR_COUNT_MASK) -		>> MCTRL0_REFR_COUNT_SHIFT; - -	mctrl &= ~MCTRL0_REFR_COUNT_MASK; -	mctrl |= refr_count << MCTRL0_REFR_COUNT_SHIFT; -	write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl); -	mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR); - -	if (cpu_slowing_down && !(mctrl & MCTRL0_SREFRESH_ENAB)) { -		unsigned long usecs; - -		/* We have to wait for both refresh counts (old -		 * and new) to go to zero. -		 */ -		usecs = (MCTRL0_REFR_CLKS_P_CNT * -			 (refr_count + old_refr_count) * -			 1000000UL * -			 old_divisor) / clock_tick; -		udelay(usecs + 1UL); -	} -} - -static void us2e_transition(unsigned long estar, unsigned long new_bits, -			    unsigned long clock_tick, -			    unsigned long old_divisor, unsigned long divisor) -{ -	unsigned long flags; - -	local_irq_save(flags); - -	estar &= ~ESTAR_MODE_DIV_MASK; - -	/* This is based upon the state transition diagram in the IIe manual.  */ -	if (old_divisor == 2 && divisor == 1) { -		self_refresh_ctl(0); -		write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits); -		frob_mem_refresh(0, clock_tick, old_divisor, divisor); -	} else if (old_divisor == 1 && divisor == 2) { -		frob_mem_refresh(1, clock_tick, old_divisor, divisor); -		write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits); -		self_refresh_ctl(1); -	} else if (old_divisor == 1 && divisor > 2) { -		us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick, -				1, 2); -		us2e_transition(estar, new_bits, clock_tick, -				2, divisor); -	} else if (old_divisor > 2 && divisor == 1) { -		us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick, -				old_divisor, 2); -		us2e_transition(estar, new_bits, clock_tick, -				2, divisor); -	} else if (old_divisor < divisor) { -		frob_mem_refresh(0, clock_tick, old_divisor, divisor); -		write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits); -	} else if (old_divisor > divisor) { -		write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits); -		frob_mem_refresh(1, clock_tick, old_divisor, divisor); -	} else { -		BUG(); -	} - -	local_irq_restore(flags); -} - -static unsigned long index_to_estar_mode(unsigned int index) -{ -	switch (index) { -	case 0: -		return ESTAR_MODE_DIV_1; - -	case 1: -		return ESTAR_MODE_DIV_2; - -	case 2: -		return ESTAR_MODE_DIV_4; - -	case 3: -		return ESTAR_MODE_DIV_6; - -	case 4: -		return ESTAR_MODE_DIV_8; - -	default: -		BUG(); -	} -} - -static unsigned long index_to_divisor(unsigned int index) -{ -	switch (index) { -	case 0: -		return 1; - -	case 1: -		return 2; - -	case 2: -		return 4; - -	case 3: -		return 6; - -	case 4: -		return 8; - -	default: -		BUG(); -	} -} - -static unsigned long estar_to_divisor(unsigned long estar) -{ -	unsigned long ret; - -	switch (estar & ESTAR_MODE_DIV_MASK) { -	case ESTAR_MODE_DIV_1: -		ret = 1; -		break; -	case ESTAR_MODE_DIV_2: -		ret = 2; -		break; -	case ESTAR_MODE_DIV_4: -		ret = 4; -		break; -	case ESTAR_MODE_DIV_6: -		ret = 6; -		break; -	case ESTAR_MODE_DIV_8: -		ret = 8; -		break; -	default: -		BUG(); -	} - -	return ret; -} - -static unsigned int us2e_freq_get(unsigned int cpu) -{ -	cpumask_t cpus_allowed; -	unsigned long clock_tick, estar; - -	if (!cpu_online(cpu)) -		return 0; - -	cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); -	set_cpus_allowed_ptr(current, cpumask_of(cpu)); - -	clock_tick = sparc64_get_clock_tick(cpu) / 1000; -	estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR); - -	set_cpus_allowed_ptr(current, &cpus_allowed); - -	return clock_tick / estar_to_divisor(estar); -} - -static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index) -{ -	unsigned long new_bits, new_freq; -	unsigned long clock_tick, divisor, old_divisor, estar; -	cpumask_t cpus_allowed; -	struct cpufreq_freqs freqs; - -	if (!cpu_online(cpu)) -		return; - -	cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); -	set_cpus_allowed_ptr(current, cpumask_of(cpu)); - -	new_freq = clock_tick = sparc64_get_clock_tick(cpu) / 1000; -	new_bits = index_to_estar_mode(index); -	divisor = index_to_divisor(index); -	new_freq /= divisor; - -	estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR); - -	old_divisor = estar_to_divisor(estar); - -	freqs.old = clock_tick / old_divisor; -	freqs.new = new_freq; -	freqs.cpu = cpu; -	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - -	if (old_divisor != divisor) -		us2e_transition(estar, new_bits, clock_tick * 1000, -				old_divisor, divisor); - -	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - -	set_cpus_allowed_ptr(current, &cpus_allowed); -} - -static int us2e_freq_target(struct cpufreq_policy *policy, -			  unsigned int target_freq, -			  unsigned int relation) -{ -	unsigned int new_index = 0; - -	if (cpufreq_frequency_table_target(policy, -					   &us2e_freq_table[policy->cpu].table[0], -					   target_freq, relation, &new_index)) -		return -EINVAL; - -	us2e_set_cpu_divider_index(policy->cpu, new_index); - -	return 0; -} - -static int us2e_freq_verify(struct cpufreq_policy *policy) -{ -	return cpufreq_frequency_table_verify(policy, -					      &us2e_freq_table[policy->cpu].table[0]); -} - -static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy) -{ -	unsigned int cpu = policy->cpu; -	unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000; -	struct cpufreq_frequency_table *table = -		&us2e_freq_table[cpu].table[0]; - -	table[0].index = 0; -	table[0].frequency = clock_tick / 1; -	table[1].index = 1; -	table[1].frequency = clock_tick / 2; -	table[2].index = 2; -	table[2].frequency = clock_tick / 4; -	table[2].index = 3; -	table[2].frequency = clock_tick / 6; -	table[2].index = 4; -	table[2].frequency = clock_tick / 8; -	table[2].index = 5; -	table[3].frequency = CPUFREQ_TABLE_END; - -	policy->cpuinfo.transition_latency = 0; -	policy->cur = clock_tick; - -	return cpufreq_frequency_table_cpuinfo(policy, table); -} - -static int us2e_freq_cpu_exit(struct cpufreq_policy *policy) -{ -	if (cpufreq_us2e_driver) -		us2e_set_cpu_divider_index(policy->cpu, 0); - -	return 0; -} - -static int __init us2e_freq_init(void) -{ -	unsigned long manuf, impl, ver; -	int ret; - -	if (tlb_type != spitfire) -		return -ENODEV; - -	__asm__("rdpr %%ver, %0" : "=r" (ver)); -	manuf = ((ver >> 48) & 0xffff); -	impl  = ((ver >> 32) & 0xffff); - -	if (manuf == 0x17 && impl == 0x13) { -		struct cpufreq_driver *driver; - -		ret = -ENOMEM; -		driver = kzalloc(sizeof(struct cpufreq_driver), GFP_KERNEL); -		if (!driver) -			goto err_out; - -		us2e_freq_table = kzalloc( -			(NR_CPUS * sizeof(struct us2e_freq_percpu_info)), -			GFP_KERNEL); -		if (!us2e_freq_table) -			goto err_out; - -		driver->init = us2e_freq_cpu_init; -		driver->verify = us2e_freq_verify; -		driver->target = us2e_freq_target; -		driver->get = us2e_freq_get; -		driver->exit = us2e_freq_cpu_exit; -		driver->owner = THIS_MODULE, -		strcpy(driver->name, "UltraSPARC-IIe"); - -		cpufreq_us2e_driver = driver; -		ret = cpufreq_register_driver(driver); -		if (ret) -			goto err_out; - -		return 0; - -err_out: -		if (driver) { -			kfree(driver); -			cpufreq_us2e_driver = NULL; -		} -		kfree(us2e_freq_table); -		us2e_freq_table = NULL; -		return ret; -	} - -	return -ENODEV; -} - -static void __exit us2e_freq_exit(void) -{ -	if (cpufreq_us2e_driver) { -		cpufreq_unregister_driver(cpufreq_us2e_driver); -		kfree(cpufreq_us2e_driver); -		cpufreq_us2e_driver = NULL; -		kfree(us2e_freq_table); -		us2e_freq_table = NULL; -	} -} - -MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); -MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-IIe"); -MODULE_LICENSE("GPL"); - -module_init(us2e_freq_init); -module_exit(us2e_freq_exit); diff --git a/arch/sparc/kernel/us3_cpufreq.c b/arch/sparc/kernel/us3_cpufreq.c deleted file mode 100644 index eb1624b931d..00000000000 --- a/arch/sparc/kernel/us3_cpufreq.c +++ /dev/null @@ -1,274 +0,0 @@ -/* us3_cpufreq.c: UltraSPARC-III cpu frequency support - * - * Copyright (C) 2003 David S. Miller (davem@redhat.com) - * - * Many thanks to Dominik Brodowski for fixing up the cpufreq - * infrastructure in order to make this driver easier to implement. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/cpufreq.h> -#include <linux/threads.h> -#include <linux/slab.h> -#include <linux/init.h> - -#include <asm/head.h> -#include <asm/timer.h> - -static struct cpufreq_driver *cpufreq_us3_driver; - -struct us3_freq_percpu_info { -	struct cpufreq_frequency_table table[4]; -}; - -/* Indexed by cpu number. */ -static struct us3_freq_percpu_info *us3_freq_table; - -/* UltraSPARC-III has three dividers: 1, 2, and 32.  These are controlled - * in the Safari config register. - */ -#define SAFARI_CFG_DIV_1	0x0000000000000000UL -#define SAFARI_CFG_DIV_2	0x0000000040000000UL -#define SAFARI_CFG_DIV_32	0x0000000080000000UL -#define SAFARI_CFG_DIV_MASK	0x00000000C0000000UL - -static unsigned long read_safari_cfg(void) -{ -	unsigned long ret; - -	__asm__ __volatile__("ldxa	[%%g0] %1, %0" -			     : "=&r" (ret) -			     : "i" (ASI_SAFARI_CONFIG)); -	return ret; -} - -static void write_safari_cfg(unsigned long val) -{ -	__asm__ __volatile__("stxa	%0, [%%g0] %1\n\t" -			     "membar	#Sync" -			     : /* no outputs */ -			     : "r" (val), "i" (ASI_SAFARI_CONFIG) -			     : "memory"); -} - -static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg) -{ -	unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000; -	unsigned long ret; - -	switch (safari_cfg & SAFARI_CFG_DIV_MASK) { -	case SAFARI_CFG_DIV_1: -		ret = clock_tick / 1; -		break; -	case SAFARI_CFG_DIV_2: -		ret = clock_tick / 2; -		break; -	case SAFARI_CFG_DIV_32: -		ret = clock_tick / 32; -		break; -	default: -		BUG(); -	} - -	return ret; -} - -static unsigned int us3_freq_get(unsigned int cpu) -{ -	cpumask_t cpus_allowed; -	unsigned long reg; -	unsigned int ret; - -	if (!cpu_online(cpu)) -		return 0; - -	cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); -	set_cpus_allowed_ptr(current, cpumask_of(cpu)); - -	reg = read_safari_cfg(); -	ret = get_current_freq(cpu, reg); - -	set_cpus_allowed_ptr(current, &cpus_allowed); - -	return ret; -} - -static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) -{ -	unsigned long new_bits, new_freq, reg; -	cpumask_t cpus_allowed; -	struct cpufreq_freqs freqs; - -	if (!cpu_online(cpu)) -		return; - -	cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); -	set_cpus_allowed_ptr(current, cpumask_of(cpu)); - -	new_freq = sparc64_get_clock_tick(cpu) / 1000; -	switch (index) { -	case 0: -		new_bits = SAFARI_CFG_DIV_1; -		new_freq /= 1; -		break; -	case 1: -		new_bits = SAFARI_CFG_DIV_2; -		new_freq /= 2; -		break; -	case 2: -		new_bits = SAFARI_CFG_DIV_32; -		new_freq /= 32; -		break; - -	default: -		BUG(); -	} - -	reg = read_safari_cfg(); - -	freqs.old = get_current_freq(cpu, reg); -	freqs.new = new_freq; -	freqs.cpu = cpu; -	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - -	reg &= ~SAFARI_CFG_DIV_MASK; -	reg |= new_bits; -	write_safari_cfg(reg); - -	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - -	set_cpus_allowed_ptr(current, &cpus_allowed); -} - -static int us3_freq_target(struct cpufreq_policy *policy, -			  unsigned int target_freq, -			  unsigned int relation) -{ -	unsigned int new_index = 0; - -	if (cpufreq_frequency_table_target(policy, -					   &us3_freq_table[policy->cpu].table[0], -					   target_freq, -					   relation, -					   &new_index)) -		return -EINVAL; - -	us3_set_cpu_divider_index(policy->cpu, new_index); - -	return 0; -} - -static int us3_freq_verify(struct cpufreq_policy *policy) -{ -	return cpufreq_frequency_table_verify(policy, -					      &us3_freq_table[policy->cpu].table[0]); -} - -static int __init us3_freq_cpu_init(struct cpufreq_policy *policy) -{ -	unsigned int cpu = policy->cpu; -	unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000; -	struct cpufreq_frequency_table *table = -		&us3_freq_table[cpu].table[0]; - -	table[0].index = 0; -	table[0].frequency = clock_tick / 1; -	table[1].index = 1; -	table[1].frequency = clock_tick / 2; -	table[2].index = 2; -	table[2].frequency = clock_tick / 32; -	table[3].index = 0; -	table[3].frequency = CPUFREQ_TABLE_END; - -	policy->cpuinfo.transition_latency = 0; -	policy->cur = clock_tick; - -	return cpufreq_frequency_table_cpuinfo(policy, table); -} - -static int us3_freq_cpu_exit(struct cpufreq_policy *policy) -{ -	if (cpufreq_us3_driver) -		us3_set_cpu_divider_index(policy->cpu, 0); - -	return 0; -} - -static int __init us3_freq_init(void) -{ -	unsigned long manuf, impl, ver; -	int ret; - -	if (tlb_type != cheetah && tlb_type != cheetah_plus) -		return -ENODEV; - -	__asm__("rdpr %%ver, %0" : "=r" (ver)); -	manuf = ((ver >> 48) & 0xffff); -	impl  = ((ver >> 32) & 0xffff); - -	if (manuf == CHEETAH_MANUF && -	    (impl == CHEETAH_IMPL || -	     impl == CHEETAH_PLUS_IMPL || -	     impl == JAGUAR_IMPL || -	     impl == PANTHER_IMPL)) { -		struct cpufreq_driver *driver; - -		ret = -ENOMEM; -		driver = kzalloc(sizeof(struct cpufreq_driver), GFP_KERNEL); -		if (!driver) -			goto err_out; - -		us3_freq_table = kzalloc( -			(NR_CPUS * sizeof(struct us3_freq_percpu_info)), -			GFP_KERNEL); -		if (!us3_freq_table) -			goto err_out; - -		driver->init = us3_freq_cpu_init; -		driver->verify = us3_freq_verify; -		driver->target = us3_freq_target; -		driver->get = us3_freq_get; -		driver->exit = us3_freq_cpu_exit; -		driver->owner = THIS_MODULE, -		strcpy(driver->name, "UltraSPARC-III"); - -		cpufreq_us3_driver = driver; -		ret = cpufreq_register_driver(driver); -		if (ret) -			goto err_out; - -		return 0; - -err_out: -		if (driver) { -			kfree(driver); -			cpufreq_us3_driver = NULL; -		} -		kfree(us3_freq_table); -		us3_freq_table = NULL; -		return ret; -	} - -	return -ENODEV; -} - -static void __exit us3_freq_exit(void) -{ -	if (cpufreq_us3_driver) { -		cpufreq_unregister_driver(cpufreq_us3_driver); -		kfree(cpufreq_us3_driver); -		cpufreq_us3_driver = NULL; -		kfree(us3_freq_table); -		us3_freq_table = NULL; -	} -} - -MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); -MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-III"); -MODULE_LICENSE("GPL"); - -module_init(us3_freq_init); -module_exit(us3_freq_exit); diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index 3e244f31e56..8647fcc5ca6 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -342,6 +342,7 @@ static void vio_remove(struct mdesc_handle *hp, u64 node)  		printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev));  		device_unregister(dev); +		put_device(dev);  	}  }  |