diff options
Diffstat (limited to 'arch/microblaze/kernel')
41 files changed, 1525 insertions, 1859 deletions
diff --git a/arch/microblaze/kernel/.gitignore b/arch/microblaze/kernel/.gitignore new file mode 100644 index 00000000000..c5f676c3c22 --- /dev/null +++ b/arch/microblaze/kernel/.gitignore @@ -0,0 +1 @@ +vmlinux.lds diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile index f0cb5c26c81..08d50cc55e7 100644 --- a/arch/microblaze/kernel/Makefile +++ b/arch/microblaze/kernel/Makefile @@ -7,22 +7,21 @@ ifdef CONFIG_FUNCTION_TRACER  CFLAGS_REMOVE_timer.o = -pg  CFLAGS_REMOVE_intc.o = -pg  CFLAGS_REMOVE_early_printk.o = -pg -CFLAGS_REMOVE_selfmod.o = -pg  CFLAGS_REMOVE_heartbeat.o = -pg  CFLAGS_REMOVE_ftrace.o = -pg +CFLAGS_REMOVE_process.o = -pg  endif  extra-y := head.o vmlinux.lds  obj-y += dma.o exceptions.o \ -	hw_exception_handler.o init_task.o intc.o irq.o \ -	process.o prom.o prom_parse.o ptrace.o \ +	hw_exception_handler.o intc.o irq.o \ +	platform.o process.o prom.o prom_parse.o ptrace.o \  	reset.o setup.o signal.o sys_microblaze.o timer.o traps.o unwind.o  obj-y += cpu/  obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o -obj-$(CONFIG_SELFMOD)		+= selfmod.o  obj-$(CONFIG_HEART_BEAT)	+= heartbeat.o  obj-$(CONFIG_MODULES)		+= microblaze_ksyms.o module.o  obj-$(CONFIG_MMU)		+= misc.o diff --git a/arch/microblaze/kernel/cpu/Makefile b/arch/microblaze/kernel/cpu/Makefile index 59cc7bceaf8..fceed4edea4 100644 --- a/arch/microblaze/kernel/cpu/Makefile +++ b/arch/microblaze/kernel/cpu/Makefile @@ -6,7 +6,7 @@ ifdef CONFIG_FUNCTION_TRACER  CFLAGS_REMOVE_cache.o = -pg  endif -EXTRA_CFLAGS += -DCPU_MAJOR=$(CPU_MAJOR) -DCPU_MINOR=$(CPU_MINOR) \ +ccflags-y := -DCPU_MAJOR=$(CPU_MAJOR) -DCPU_MINOR=$(CPU_MINOR) \  		-DCPU_REV=$(CPU_REV)  obj-y += cache.o cpuinfo.o cpuinfo-pvr-full.o cpuinfo-static.o mb.o pvr.o diff --git a/arch/microblaze/kernel/cpu/cache.c b/arch/microblaze/kernel/cpu/cache.c index 109876e8d64..a6e44410672 100644 --- a/arch/microblaze/kernel/cpu/cache.c +++ b/arch/microblaze/kernel/cpu/cache.c @@ -17,82 +17,70 @@  static inline void __enable_icache_msr(void)  { -	__asm__ __volatile__ ("	msrset	r0, %0;		\ -				nop; "			\ +	__asm__ __volatile__ ("	 msrset	r0, %0;"	\ +				"nop;"			\  			: : "i" (MSR_ICE) : "memory");  }  static inline void __disable_icache_msr(void)  { -	__asm__ __volatile__ ("	msrclr	r0, %0;		\ -				nop; "			\ +	__asm__ __volatile__ ("	 msrclr	r0, %0;"	\ +				"nop;"			\  			: : "i" (MSR_ICE) : "memory");  }  static inline void __enable_dcache_msr(void)  { -	__asm__ __volatile__ ("	msrset	r0, %0;		\ -				nop; "			\ -				:			\ -				: "i" (MSR_DCE)		\ -				: "memory"); +	__asm__ __volatile__ ("	 msrset	r0, %0;"	\ +				"nop;"			\ +			: : "i" (MSR_DCE) : "memory");  }  static inline void __disable_dcache_msr(void)  { -	__asm__ __volatile__ ("	msrclr	r0, %0;		\ -				nop; "			\ -				:			\ -				: "i" (MSR_DCE)		\ -				: "memory"); +	__asm__ __volatile__ ("	 msrclr	r0, %0;"	\ +				"nop; "			\ +			: : "i" (MSR_DCE) : "memory");  }  static inline void __enable_icache_nomsr(void)  { -	__asm__ __volatile__ ("	mfs	r12, rmsr;	\ -				nop;			\ -				ori	r12, r12, %0;	\ -				mts	rmsr, r12;	\ -				nop; "			\ -				:			\ -				: "i" (MSR_ICE)		\ -				: "memory", "r12"); +	__asm__ __volatile__ ("	 mfs	r12, rmsr;"	\ +				"nop;"			\ +				"ori	r12, r12, %0;"	\ +				"mts	rmsr, r12;"	\ +				"nop;"			\ +			: : "i" (MSR_ICE) : "memory", "r12");  }  static inline void __disable_icache_nomsr(void)  { -	__asm__ __volatile__ ("	mfs	r12, rmsr;	\ -				nop;			\ -				andi	r12, r12, ~%0;	\ -				mts	rmsr, r12;	\ -				nop; "			\ -				:			\ -				: "i" (MSR_ICE)		\ -				: "memory", "r12"); +	__asm__ __volatile__ ("	 mfs	r12, rmsr;"	\ +				"nop;"			\ +				"andi	r12, r12, ~%0;"	\ +				"mts	rmsr, r12;"	\ +				"nop;"			\ +			: : "i" (MSR_ICE) : "memory", "r12");  }  static inline void __enable_dcache_nomsr(void)  { -	__asm__ __volatile__ ("	mfs	r12, rmsr;	\ -				nop;			\ -				ori	r12, r12, %0;	\ -				mts	rmsr, r12;	\ -				nop; "			\ -				:			\ -				: "i" (MSR_DCE)		\ -				: "memory", "r12"); +	__asm__ __volatile__ ("	 mfs	r12, rmsr;"	\ +				"nop;"			\ +				"ori	r12, r12, %0;"	\ +				"mts	rmsr, r12;"	\ +				"nop;"			\ +			: : "i" (MSR_DCE) : "memory", "r12");  }  static inline void __disable_dcache_nomsr(void)  { -	__asm__ __volatile__ ("	mfs	r12, rmsr;	\ -				nop;			\ -				andi	r12, r12, ~%0;	\ -				mts	rmsr, r12;	\ -				nop; "			\ -				:			\ -				: "i" (MSR_DCE)		\ -				: "memory", "r12"); +	__asm__ __volatile__ ("	 mfs	r12, rmsr;"	\ +				"nop;"			\ +				"andi	r12, r12, ~%0;"	\ +				"mts	rmsr, r12;"	\ +				"nop;"			\ +			: : "i" (MSR_DCE) : "memory", "r12");  } @@ -106,7 +94,7 @@ do {									\  	int align = ~(cache_line_length - 1);				\  	end = min(start + cache_size, end);				\  	start &= align;							\ -} while (0); +} while (0)  /*   * Helper macro to loop over the specified cache_size/line_length and @@ -118,18 +106,18 @@ do {									\  	int step = -line_length;					\  	WARN_ON(step >= 0);						\  									\ -	__asm__ __volatile__ (" 1:      " #op " %0, r0;			\ -					bgtid   %0, 1b;			\ -					addk    %0, %0, %1;		\ -					" : : "r" (len), "r" (step)	\ +	__asm__ __volatile__ (" 1:      " #op " %0, r0;"		\ +					"bgtid   %0, 1b;"		\ +					"addk    %0, %0, %1;"		\ +					: : "r" (len), "r" (step)	\  					: "memory");			\ -} while (0); +} while (0)  /* Used for wdc.flush/clear which can use rB for offset which is not possible   * to use for simple wdc or wic.   *   * start address is cache aligned - * end address is not aligned, if end is aligned then I have to substract + * end address is not aligned, if end is aligned then I have to subtract   * cacheline length because I can't flush/invalidate the next cacheline.   * If is not, I align it because I will flush/invalidate whole line.   */ @@ -142,28 +130,28 @@ do {									\  	count = end - start;						\  	WARN_ON(count < 0);						\  									\ -	__asm__ __volatile__ (" 1:	" #op "	%0, %1;			\ -					bgtid	%1, 1b;			\ -					addk	%1, %1, %2;		\ -					" : : "r" (start), "r" (count),	\ +	__asm__ __volatile__ (" 1:	" #op "	%0, %1;"		\ +					"bgtid	%1, 1b;"		\ +					"addk	%1, %1, %2;"		\ +					: : "r" (start), "r" (count),	\  					"r" (step) : "memory");		\ -} while (0); +} while (0)  /* It is used only first parameter for OP - for wic, wdc */  #define CACHE_RANGE_LOOP_1(start, end, line_length, op)			\  do {									\ -	int volatile temp;						\ +	int volatile temp = 0;						\  	int align = ~(line_length - 1);					\  	end = ((end & align) == end) ? end - line_length : end & align;	\  	WARN_ON(end - start < 0);					\  									\ -	__asm__ __volatile__ (" 1:	" #op "	%1, r0;			\ -					cmpu	%0, %1, %2;		\ -					bgtid	%0, 1b;			\ -					addk	%1, %1, %3;		\ -				" : : "r" (temp), "r" (start), "r" (end),\ +	__asm__ __volatile__ (" 1:	" #op "	%1, r0;"		\ +					"cmpu	%0, %1, %2;"		\ +					"bgtid	%0, 1b;"		\ +					"addk	%1, %1, %3;"		\ +				: : "r" (temp), "r" (start), "r" (end),	\  					"r" (line_length) : "memory");	\ -} while (0); +} while (0)  #define ASM_LOOP @@ -352,7 +340,7 @@ static void __invalidate_dcache_all_noirq_wt(void)  #endif  	pr_debug("%s\n", __func__);  #ifdef ASM_LOOP -	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc) +	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);  #else  	for (i = 0; i < cpuinfo.dcache_size;  		 i += cpuinfo.dcache_line_length) @@ -361,7 +349,8 @@ static void __invalidate_dcache_all_noirq_wt(void)  #endif  } -/* FIXME It is blindly invalidation as is expected +/* + * FIXME It is blindly invalidation as is expected   * but can't be called on noMMU in microblaze_cache_init below   *   * MS: noMMU kernel won't boot if simple wdc is used @@ -375,7 +364,7 @@ static void __invalidate_dcache_all_wb(void)  	pr_debug("%s\n", __func__);  #ifdef ASM_LOOP  	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, -					wdc) +					wdc);  #else  	for (i = 0; i < cpuinfo.dcache_size;  		 i += cpuinfo.dcache_line_length) @@ -519,7 +508,7 @@ static void __flush_dcache_range_wb(unsigned long start, unsigned long end)  struct scache *mbc;  /* new wb cache model */ -const struct scache wb_msr = { +static const struct scache wb_msr = {  	.ie = __enable_icache_msr,  	.id = __disable_icache_msr,  	.ifl = __flush_icache_all_noirq, @@ -535,7 +524,7 @@ const struct scache wb_msr = {  };  /* There is only difference in ie, id, de, dd functions */ -const struct scache wb_nomsr = { +static const struct scache wb_nomsr = {  	.ie = __enable_icache_nomsr,  	.id = __disable_icache_nomsr,  	.ifl = __flush_icache_all_noirq, @@ -551,7 +540,7 @@ const struct scache wb_nomsr = {  };  /* Old wt cache model with disabling irq and turn off cache */ -const struct scache wt_msr = { +static const struct scache wt_msr = {  	.ie = __enable_icache_msr,  	.id = __disable_icache_msr,  	.ifl = __flush_icache_all_msr_irq, @@ -566,7 +555,7 @@ const struct scache wt_msr = {  	.dinr = __invalidate_dcache_range_msr_irq_wt,  }; -const struct scache wt_nomsr = { +static const struct scache wt_nomsr = {  	.ie = __enable_icache_nomsr,  	.id = __disable_icache_nomsr,  	.ifl = __flush_icache_all_nomsr_irq, @@ -582,7 +571,7 @@ const struct scache wt_nomsr = {  };  /* New wt cache model for newer Microblaze versions */ -const struct scache wt_msr_noirq = { +static const struct scache wt_msr_noirq = {  	.ie = __enable_icache_msr,  	.id = __disable_icache_msr,  	.ifl = __flush_icache_all_noirq, @@ -597,7 +586,7 @@ const struct scache wt_msr_noirq = {  	.dinr = __invalidate_dcache_range_nomsr_wt,  }; -const struct scache wt_nomsr_noirq = { +static const struct scache wt_nomsr_noirq = {  	.ie = __enable_icache_nomsr,  	.id = __disable_icache_nomsr,  	.ifl = __flush_icache_all_noirq, @@ -616,49 +605,48 @@ const struct scache wt_nomsr_noirq = {  #define CPUVER_7_20_A	0x0c  #define CPUVER_7_20_D	0x0f -#define INFO(s)	printk(KERN_INFO "cache: " s "\n"); -  void microblaze_cache_init(void)  {  	if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) {  		if (cpuinfo.dcache_wb) { -			INFO("wb_msr"); +			pr_info("wb_msr\n");  			mbc = (struct scache *)&wb_msr; -			if (cpuinfo.ver_code < CPUVER_7_20_D) { +			if (cpuinfo.ver_code <= CPUVER_7_20_D) {  				/* MS: problem with signal handling - hw bug */ -				INFO("WB won't work properly"); +				pr_info("WB won't work properly\n");  			}  		} else {  			if (cpuinfo.ver_code >= CPUVER_7_20_A) { -				INFO("wt_msr_noirq"); +				pr_info("wt_msr_noirq\n");  				mbc = (struct scache *)&wt_msr_noirq;  			} else { -				INFO("wt_msr"); +				pr_info("wt_msr\n");  				mbc = (struct scache *)&wt_msr;  			}  		}  	} else {  		if (cpuinfo.dcache_wb) { -			INFO("wb_nomsr"); +			pr_info("wb_nomsr\n");  			mbc = (struct scache *)&wb_nomsr; -			if (cpuinfo.ver_code < CPUVER_7_20_D) { +			if (cpuinfo.ver_code <= CPUVER_7_20_D) {  				/* MS: problem with signal handling - hw bug */ -				INFO("WB won't work properly"); +				pr_info("WB won't work properly\n");  			}  		} else {  			if (cpuinfo.ver_code >= CPUVER_7_20_A) { -				INFO("wt_nomsr_noirq"); +				pr_info("wt_nomsr_noirq\n");  				mbc = (struct scache *)&wt_nomsr_noirq;  			} else { -				INFO("wt_nomsr"); +				pr_info("wt_nomsr\n");  				mbc = (struct scache *)&wt_nomsr;  			}  		}  	} -/* FIXME Invalidation is done in U-BOOT - * WT cache: Data is already written to main memory - * WB cache: Discard data on noMMU which caused that kernel doesn't boot - */ +	/* +	 * FIXME Invalidation is done in U-BOOT +	 * WT cache: Data is already written to main memory +	 * WB cache: Discard data on noMMU which caused that kernel doesn't boot +	 */  	/* invalidate_dcache(); */  	enable_dcache(); diff --git a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c index f70a6047f08..93c26cf50de 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c +++ b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c @@ -27,7 +27,7 @@  	early_printk("ERROR: Microblaze " x "-different for PVR and DTS\n");  #else  #define err_printk(x) \ -	printk(KERN_INFO "ERROR: Microblaze " x "-different for PVR and DTS\n"); +	pr_info("ERROR: Microblaze " x "-different for PVR and DTS\n");  #endif  void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu) @@ -38,12 +38,11 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)  	CI(ver_code, VERSION);  	if (!ci->ver_code) { -		printk(KERN_ERR "ERROR: MB has broken PVR regs " -						"-> use DTS setting\n"); +		pr_err("ERROR: MB has broken PVR regs -> use DTS setting\n");  		return;  	} -	temp = PVR_USE_BARREL(pvr) | PVR_USE_MSR_INSTR(pvr) |\ +	temp = PVR_USE_BARREL(pvr) | PVR_USE_MSR_INSTR(pvr) |  		PVR_USE_PCMP_INSTR(pvr) | PVR_USE_DIV(pvr);  	if (ci->use_instr != temp)  		err_printk("BARREL, MSR, PCMP or DIV"); @@ -59,19 +58,20 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)  		err_printk("HW_FPU");  	ci->use_fpu = temp; -	ci->use_exc = PVR_OPCODE_0x0_ILLEGAL(pvr) |\ -			PVR_UNALIGNED_EXCEPTION(pvr) |\ -			PVR_ILL_OPCODE_EXCEPTION(pvr) |\ -			PVR_IOPB_BUS_EXCEPTION(pvr) |\ -			PVR_DOPB_BUS_EXCEPTION(pvr) |\ -			PVR_DIV_ZERO_EXCEPTION(pvr) |\ -			PVR_FPU_EXCEPTION(pvr) |\ +	ci->use_exc = PVR_OPCODE_0x0_ILLEGAL(pvr) | +			PVR_UNALIGNED_EXCEPTION(pvr) | +			PVR_ILL_OPCODE_EXCEPTION(pvr) | +			PVR_IOPB_BUS_EXCEPTION(pvr) | +			PVR_DOPB_BUS_EXCEPTION(pvr) | +			PVR_DIV_ZERO_EXCEPTION(pvr) | +			PVR_FPU_EXCEPTION(pvr) |  			PVR_FSL_EXCEPTION(pvr);  	CI(pvr_user1, USER1);  	CI(pvr_user2, USER2);  	CI(mmu, USE_MMU); +	CI(mmu_privins, MMU_PRIVINS);  	CI(endian, ENDIAN);  	CI(use_icache, USE_ICACHE); @@ -112,7 +112,4 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)  	CI(num_wr_brk, NUMBER_OF_WR_ADDR_BRK);  	CI(fpga_family_code, TARGET_FAMILY); - -	/* take timebase-frequency from DTS */ -	ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency");  } diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c index b16b994ca3d..4854285b26e 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo-static.c +++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c @@ -113,12 +113,11 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)  	ci->num_rd_brk = fcpu(cpu, "xlnx,number-of-rd-addr-brk");  	ci->num_wr_brk = fcpu(cpu, "xlnx,number-of-wr-addr-brk"); -	ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency"); -  	ci->pvr_user1 = fcpu(cpu, "xlnx,pvr-user1");  	ci->pvr_user2 = fcpu(cpu, "xlnx,pvr-user2");  	ci->mmu = fcpu(cpu, "xlnx,use-mmu"); +	ci->mmu_privins = fcpu(cpu, "xlnx,mmu-privileged-instr");  	ci->endian = fcpu(cpu, "xlnx,endianness");  	ci->ver_code = 0; diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c index 87c79fa275c..234acad79b9 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo.c +++ b/arch/microblaze/kernel/cpu/cpuinfo.c @@ -8,6 +8,7 @@   * for more details.   */ +#include <linux/clk.h>  #include <linux/init.h>  #include <asm/cpuinfo.h>  #include <asm/pvr.h> @@ -32,6 +33,16 @@ const struct cpu_ver_key cpu_ver_lookup[] = {  	{"7.30.a", 0x10},  	{"7.30.b", 0x11},  	{"8.00.a", 0x12}, +	{"8.00.b", 0x13}, +	{"8.10.a", 0x14}, +	{"8.20.a", 0x15}, +	{"8.20.b", 0x16}, +	{"8.30.a", 0x17}, +	{"8.40.a", 0x18}, +	{"8.40.b", 0x19}, +	{"8.50.a", 0x1a}, +	{"9.0", 0x1b}, +	{"9.1", 0x1d},  	{NULL, 0},  }; @@ -52,38 +63,62 @@ const struct family_string_key family_string_lookup[] = {  	{"virtex6", 0xe},  	/* FIXME There is no key code defined for spartan2 */  	{"spartan2", 0xf0}, +	{"kintex7", 0x10}, +	{"artix7", 0x11}, +	{"zynq7000", 0x12},  	{NULL, 0},  };  struct cpuinfo cpuinfo; +static struct device_node *cpu;  void __init setup_cpuinfo(void)  { -	struct device_node *cpu = NULL; -  	cpu = (struct device_node *) of_find_node_by_type(NULL, "cpu");  	if (!cpu) -		printk(KERN_ERR "You don't have cpu!!!\n"); +		pr_err("You don't have cpu!!!\n"); -	printk(KERN_INFO "%s: initialising\n", __func__); +	pr_info("%s: initialising\n", __func__);  	switch (cpu_has_pvr()) {  	case 0: -		printk(KERN_WARNING -			"%s: No PVR support. Using static CPU info from FDT\n", +		pr_warn("%s: No PVR support. Using static CPU info from FDT\n",  			__func__);  		set_cpuinfo_static(&cpuinfo, cpu);  		break;  /* FIXME I found weird behavior with MB 7.00.a/b 7.10.a   * please do not use FULL PVR with MMU */  	case 1: -		printk(KERN_INFO "%s: Using full CPU PVR support\n", +		pr_info("%s: Using full CPU PVR support\n",  			__func__);  		set_cpuinfo_static(&cpuinfo, cpu);  		set_cpuinfo_pvr_full(&cpuinfo, cpu);  		break;  	default: -		printk(KERN_WARNING "%s: Unsupported PVR setting\n", __func__); +		pr_warn("%s: Unsupported PVR setting\n", __func__);  		set_cpuinfo_static(&cpuinfo, cpu);  	} + +	if (cpuinfo.mmu_privins) +		pr_warn("%s: Stream instructions enabled" +			" - USERSPACE CAN LOCK THIS KERNEL!\n", __func__); +} + +void __init setup_cpuinfo_clk(void) +{ +	struct clk *clk; + +	clk = of_clk_get(cpu, 0); +	if (IS_ERR(clk)) { +		pr_err("ERROR: CPU CCF input clock not found\n"); +		/* take timebase-frequency from DTS */ +		cpuinfo.cpu_clock_freq = fcpu(cpu, "timebase-frequency"); +	} else { +		cpuinfo.cpu_clock_freq = clk_get_rate(clk); +	} + +	if (!cpuinfo.cpu_clock_freq) { +		pr_err("ERROR: CPU clock frequency not setup\n"); +		BUG(); +	}  } diff --git a/arch/microblaze/kernel/cpu/mb.c b/arch/microblaze/kernel/cpu/mb.c index b4048af0261..7b5dca7ed39 100644 --- a/arch/microblaze/kernel/cpu/mb.c +++ b/arch/microblaze/kernel/cpu/mb.c @@ -97,6 +97,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)  		(cpuinfo.use_exc & PVR2_FPU_EXC_MASK) ? "fpu " : "",  		(cpuinfo.use_exc & PVR2_USE_FSL_EXC) ? "fsl " : ""); +	count += seq_printf(m, +			"Stream-insns:\t%sprivileged\n", +			cpuinfo.mmu_privins ? "un" : ""); +  	if (cpuinfo.use_icache)  		count += seq_printf(m,  				"Icache:\t\t%ukB\tline length:\t%dB\n", @@ -110,10 +114,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)  				"Dcache:\t\t%ukB\tline length:\t%dB\n",  				cpuinfo.dcache_size >> 10,  				cpuinfo.dcache_line_length); +		seq_printf(m, "Dcache-Policy:\t");  		if (cpuinfo.dcache_wb) -			count += seq_printf(m, "\t\twrite-back\n"); +			count += seq_printf(m, "write-back\n");  		else -			count += seq_printf(m, "\t\twrite-through\n"); +			count += seq_printf(m, "write-through\n");  	} else  		count += seq_printf(m, "Dcache:\t\tno\n"); diff --git a/arch/microblaze/kernel/cpu/pvr.c b/arch/microblaze/kernel/cpu/pvr.c index e01afa68273..8d0dc6db48c 100644 --- a/arch/microblaze/kernel/cpu/pvr.c +++ b/arch/microblaze/kernel/cpu/pvr.c @@ -12,7 +12,6 @@  #include <linux/kernel.h>  #include <linux/compiler.h> -#include <asm/system.h>  #include <asm/exceptions.h>  #include <asm/pvr.h> @@ -27,8 +26,8 @@  	register unsigned tmp __asm__("r3");			\  	tmp = 0x0;	/* Prevent warning about unused */	\  	__asm__ __volatile__ (					\ -			"mfs	%0, rpvr" #pvrid ";"	\ -			: "=r" (tmp) : : "memory"); 		\ +			"mfs	%0, rpvr" #pvrid ";"		\ +			: "=r" (tmp) : : "memory");		\  	val = tmp;						\  } @@ -54,7 +53,7 @@ int cpu_has_pvr(void)  	if (!(flags & PVR_MSR_BIT))  		return 0; -	get_single_pvr(0x00, pvr0); +	get_single_pvr(0, pvr0);  	pr_debug("%s: pvr0 is 0x%08x\n", __func__, pvr0);  	if (pvr0 & PVR0_PVR_FULL_MASK) diff --git a/arch/microblaze/kernel/dma.c b/arch/microblaze/kernel/dma.c index 79c74659f20..4633c36c1b3 100644 --- a/arch/microblaze/kernel/dma.c +++ b/arch/microblaze/kernel/dma.c @@ -10,44 +10,14 @@  #include <linux/dma-mapping.h>  #include <linux/gfp.h>  #include <linux/dma-debug.h> -#include <asm/bug.h> -#include <asm/cacheflush.h> - -/* - * Generic direct DMA implementation - * - * This implementation supports a per-device offset that can be applied if - * the address at which memory is visible to devices is not 0. Platform code - * can set archdata.dma_data to an unsigned long holding the offset. By - * default the offset is PCI_DRAM_OFFSET. - */ -static inline void __dma_sync_page(unsigned long paddr, unsigned long offset, -				size_t size, enum dma_data_direction direction) -{ -	switch (direction) { -	case DMA_TO_DEVICE: -		flush_dcache_range(paddr + offset, paddr + offset + size); -		break; -	case DMA_FROM_DEVICE: -		invalidate_dcache_range(paddr + offset, paddr + offset + size); -		break; -	default: -		BUG(); -	} -} - -static unsigned long get_dma_direct_offset(struct device *dev) -{ -	if (likely(dev)) -		return (unsigned long)dev->archdata.dma_data; - -	return PCI_DRAM_OFFSET; /* FIXME Not sure if is correct */ -} +#include <linux/export.h> +#include <linux/bug.h>  #define NOT_COHERENT_CACHE  static void *dma_direct_alloc_coherent(struct device *dev, size_t size, -				dma_addr_t *dma_handle, gfp_t flag) +				       dma_addr_t *dma_handle, gfp_t flag, +				       struct dma_attrs *attrs)  {  #ifdef NOT_COHERENT_CACHE  	return consistent_alloc(flag, size, dma_handle); @@ -64,14 +34,15 @@ static void *dma_direct_alloc_coherent(struct device *dev, size_t size,  		return NULL;  	ret = page_address(page);  	memset(ret, 0, size); -	*dma_handle = virt_to_phys(ret) + get_dma_direct_offset(dev); +	*dma_handle = virt_to_phys(ret);  	return ret;  #endif  }  static void dma_direct_free_coherent(struct device *dev, size_t size, -			      void *vaddr, dma_addr_t dma_handle) +				     void *vaddr, dma_addr_t dma_handle, +				     struct dma_attrs *attrs)  {  #ifdef NOT_COHERENT_CACHE  	consistent_free(size, vaddr); @@ -89,20 +60,14 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,  	/* FIXME this part of code is untested */  	for_each_sg(sgl, sg, nents, i) { -		sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev); -		__dma_sync_page(page_to_phys(sg_page(sg)), sg->offset, +		sg->dma_address = sg_phys(sg); +		__dma_sync(page_to_phys(sg_page(sg)) + sg->offset,  							sg->length, direction);  	}  	return nents;  } -static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg, -				int nents, enum dma_data_direction direction, -				struct dma_attrs *attrs) -{ -} -  static int dma_direct_dma_supported(struct device *dev, u64 mask)  {  	return 1; @@ -115,8 +80,8 @@ static inline dma_addr_t dma_direct_map_page(struct device *dev,  					     enum dma_data_direction direction,  					     struct dma_attrs *attrs)  { -	__dma_sync_page(page_to_phys(page), offset, size, direction); -	return page_to_phys(page) + offset + get_dma_direct_offset(dev); +	__dma_sync(page_to_phys(page) + offset, size, direction); +	return page_to_phys(page) + offset;  }  static inline void dma_direct_unmap_page(struct device *dev, @@ -130,17 +95,76 @@ static inline void dma_direct_unmap_page(struct device *dev,   * phys_to_virt is here because in __dma_sync_page is __virt_to_phys and   * dma_address is physical address   */ -	__dma_sync_page(dma_address, 0 , size, direction); +	__dma_sync(dma_address, size, direction); +} + +static inline void +dma_direct_sync_single_for_cpu(struct device *dev, +			       dma_addr_t dma_handle, size_t size, +			       enum dma_data_direction direction) +{ +	/* +	 * It's pointless to flush the cache as the memory segment +	 * is given to the CPU +	 */ + +	if (direction == DMA_FROM_DEVICE) +		__dma_sync(dma_handle, size, direction); +} + +static inline void +dma_direct_sync_single_for_device(struct device *dev, +				  dma_addr_t dma_handle, size_t size, +				  enum dma_data_direction direction) +{ +	/* +	 * It's pointless to invalidate the cache if the device isn't +	 * supposed to write to the relevant region +	 */ + +	if (direction == DMA_TO_DEVICE) +		__dma_sync(dma_handle, size, direction); +} + +static inline void +dma_direct_sync_sg_for_cpu(struct device *dev, +			   struct scatterlist *sgl, int nents, +			   enum dma_data_direction direction) +{ +	struct scatterlist *sg; +	int i; + +	/* FIXME this part of code is untested */ +	if (direction == DMA_FROM_DEVICE) +		for_each_sg(sgl, sg, nents, i) +			__dma_sync(sg->dma_address, sg->length, direction); +} + +static inline void +dma_direct_sync_sg_for_device(struct device *dev, +			      struct scatterlist *sgl, int nents, +			      enum dma_data_direction direction) +{ +	struct scatterlist *sg; +	int i; + +	/* FIXME this part of code is untested */ +	if (direction == DMA_TO_DEVICE) +		for_each_sg(sgl, sg, nents, i) +			__dma_sync(sg->dma_address, sg->length, direction);  }  struct dma_map_ops dma_direct_ops = { -	.alloc_coherent	= dma_direct_alloc_coherent, -	.free_coherent	= dma_direct_free_coherent, +	.alloc		= dma_direct_alloc_coherent, +	.free		= dma_direct_free_coherent,  	.map_sg		= dma_direct_map_sg, -	.unmap_sg	= dma_direct_unmap_sg,  	.dma_supported	= dma_direct_dma_supported,  	.map_page	= dma_direct_map_page,  	.unmap_page	= dma_direct_unmap_page, +	.sync_single_for_cpu		= dma_direct_sync_single_for_cpu, +	.sync_single_for_device		= dma_direct_sync_single_for_device, +	.sync_sg_for_cpu		= dma_direct_sync_sg_for_cpu, +	.sync_sg_for_device		= dma_direct_sync_sg_for_device,  };  EXPORT_SYMBOL(dma_direct_ops); @@ -149,8 +173,8 @@ EXPORT_SYMBOL(dma_direct_ops);  static int __init dma_init(void)  { -       dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); +	dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); -       return 0; +	return 0;  }  fs_initcall(dma_init); diff --git a/arch/microblaze/kernel/early_printk.c b/arch/microblaze/kernel/early_printk.c index c3616a080eb..365f2d53f1b 100644 --- a/arch/microblaze/kernel/early_printk.c +++ b/arch/microblaze/kernel/early_printk.c @@ -21,7 +21,6 @@  #include <asm/setup.h>  #include <asm/prom.h> -static u32 early_console_initialized;  static u32 base_addr;  #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE @@ -35,7 +34,7 @@ static void early_printk_uartlite_putc(char c)  	 * we'll never timeout on a working UART.  	 */ -	unsigned retries = 10000; +	unsigned retries = 1000000;  	/* read status bit - 0x8 offset */  	while (--retries && (in_be32(base_addr + 8) & (1 << 3)))  		; @@ -50,9 +49,9 @@ static void early_printk_uartlite_write(struct console *unused,  					const char *s, unsigned n)  {  	while (*s && n-- > 0) { -		early_printk_uartlite_putc(*s);  		if (*s == '\n')  			early_printk_uartlite_putc('\r'); +		early_printk_uartlite_putc(*s);  		s++;  	}  } @@ -60,7 +59,7 @@ static void early_printk_uartlite_write(struct console *unused,  static struct console early_serial_uartlite_console = {  	.name = "earlyser",  	.write = early_printk_uartlite_write, -	.flags = CON_PRINTBUFFER, +	.flags = CON_PRINTBUFFER | CON_BOOT,  	.index = -1,  };  #endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */ @@ -94,9 +93,9 @@ static void early_printk_uart16550_write(struct console *unused,  					const char *s, unsigned n)  {  	while (*s && n-- > 0) { -		early_printk_uart16550_putc(*s);  		if (*s == '\n')  			early_printk_uart16550_putc('\r'); +		early_printk_uart16550_putc(*s);  		s++;  	}  } @@ -104,76 +103,82 @@ static void early_printk_uart16550_write(struct console *unused,  static struct console early_serial_uart16550_console = {  	.name = "earlyser",  	.write = early_printk_uart16550_write, -	.flags = CON_PRINTBUFFER, +	.flags = CON_PRINTBUFFER | CON_BOOT,  	.index = -1,  };  #endif /* CONFIG_SERIAL_8250_CONSOLE */ -static struct console *early_console; - -void early_printk(const char *fmt, ...) -{ -	char buf[512]; -	int n; -	va_list ap; - -	if (early_console_initialized) { -		va_start(ap, fmt); -		n = vscnprintf(buf, 512, fmt, ap); -		early_console->write(early_console, buf, n); -		va_end(ap); -	} -} -  int __init setup_early_printk(char *opt)  { -	if (early_console_initialized) +	int version = 0; + +	if (early_console)  		return 1; -#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE -	base_addr = early_uartlite_console(); +	base_addr = of_early_console(&version);  	if (base_addr) { -		early_console_initialized = 1;  #ifdef CONFIG_MMU  		early_console_reg_tlb_alloc(base_addr);  #endif -		early_console = &early_serial_uartlite_console; -		early_printk("early_printk_console is enabled at 0x%08x\n", -							base_addr); - -		/* register_console(early_console); */ - -		return 0; -	} -#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */ - +		switch (version) { +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE +		case UARTLITE: +			pr_info("Early console on uartlite at 0x%08x\n", +								base_addr); +			early_console = &early_serial_uartlite_console; +			break; +#endif  #ifdef CONFIG_SERIAL_8250_CONSOLE -	base_addr = early_uart16550_console(); -	base_addr &= ~3; /* clear register offset */ -	if (base_addr) { -		early_console_initialized = 1; -#ifdef CONFIG_MMU -		early_console_reg_tlb_alloc(base_addr); +		case UART16550: +			pr_info("Early console on uart16650 at 0x%08x\n", +								base_addr); +			early_console = &early_serial_uart16550_console; +			break;  #endif -		early_console = &early_serial_uart16550_console; - -		early_printk("early_printk_console is enabled at 0x%08x\n", -							base_addr); - -		/* register_console(early_console); */ +		default: +			pr_info("Unsupported early console %d\n", +								version); +			return 1; +		} +		register_console(early_console);  		return 0;  	} -#endif /* CONFIG_SERIAL_8250_CONSOLE */ -  	return 1;  } +/* Remap early console to virtual address and do not allocate one TLB + * only for early console because of performance degression */ +void __init remap_early_printk(void) +{ +	if (!early_console) +		return; +	pr_info("early_printk_console remapping from 0x%x to ", base_addr); +	base_addr = (u32) ioremap(base_addr, PAGE_SIZE); +	pr_cont("0x%x\n", base_addr); + +#ifdef CONFIG_MMU +	/* +	 * Early console is on the top of skipped TLB entries +	 * decrease tlb_skip size ensure that hardcoded TLB entry will be +	 * used by generic algorithm +	 * FIXME check if early console mapping is on the top by rereading +	 * TLB entry and compare baseaddr +	 *  mts  rtlbx, (tlb_skip - 1) +	 *  nop +	 *  mfs  rX, rtlblo +	 *  nop +	 *  cmp rX, orig_base_addr +	 */ +	tlb_skip -= 1; +#endif +} +  void __init disable_early_printk(void)  { -	if (!early_console_initialized || !early_console) +	if (!early_console)  		return; -	printk(KERN_WARNING "disabling early console\n"); +	pr_warn("disabling early console\n");  	unregister_console(early_console); -	early_console_initialized = 0; +	early_console = NULL;  } diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S index ca84368570b..7e394fc2c43 100644 --- a/arch/microblaze/kernel/entry-nommu.S +++ b/arch/microblaze/kernel/entry-nommu.S @@ -115,7 +115,7 @@ ENTRY(_interrupt)  	/* restore r31 */  	lwi	r31, r0, PER_CPU(CURRENT_SAVE)  	/* prepare the link register, the argument and jump */ -	la	r15, r0, ret_from_intr - 8 +	addik	r15, r0, ret_from_intr - 8  	addk	r6, r0, r15  	braid	do_IRQ  	add	r5, r0, r1 @@ -124,6 +124,7 @@ ret_from_intr:  	lwi	r11, r1, PT_MODE  	bneid	r11, no_intr_resched +3:  	lwi	r6, r31, TS_THREAD_INFO	/* get thread info */  	lwi	r19, r6, TI_FLAGS	/* get flags in thread info */  				/* do an extra work if any bits are set */ @@ -132,12 +133,13 @@ ret_from_intr:  	beqi	r11, 1f  	bralid	r15, schedule  	nop -1:	andi	r11, r19, _TIF_SIGPENDING +	bri	3b +1:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME  	beqid	r11, no_intr_resched  	addk	r5, r1, r0 -	addk	r7, r0, r0 -	bralid	r15, do_signal +	bralid	r15, do_notify_resume  	addk	r6, r0, r0 +	bri	3b  no_intr_resched:  	/* Disable interrupts, we are now committed to the state restore */ @@ -281,9 +283,10 @@ ENTRY(_user_exception)  	/* Figure out which function to use for this system call. */  	/* Note Microblaze barrel shift is optional, so don't rely on it */  	add	r12, r12, r12			/* convert num -> ptr */ +	addik	r30, r0, 1			/* restarts allowed */  	add	r12, r12, r12  	lwi	r12, r12, sys_call_table	/* Get function pointer */ -	la	r15, r0, ret_to_user-8		/* set return address */ +	addik	r15, r0, ret_to_user-8		/* set return address */  	bra	r12				/* Make the system call. */  	bri	0				/* won't reach here */  1: @@ -292,8 +295,8 @@ ENTRY(_user_exception)  /*   * Debug traps are like a system call, but entered via brki r14, 0x60 - * All we need to do is send the SIGTRAP signal to current, ptrace and do_signal - * will handle the rest + * All we need to do is send the SIGTRAP signal to current, ptrace and + * do_notify_resume will handle the rest   */  ENTRY(_debug_exception)  	swi	r1, r0, PER_CPU(ENTRY_SP)	/* save the current sp */ @@ -370,6 +373,7 @@ ENTRY(_debug_exception)  	bralid	r15, send_sig  	add	r7, r0, r0			/* 3rd param zero */ +	addik	r30, r0, 1			/* restarts allowed ??? */  	/* Restore r3/r4 to work around how ret_to_user works */  	lwi	r3, r1, PT_R3  	lwi	r4, r1, PT_R4 @@ -466,7 +470,6 @@ ENTRY(_switch_to)  ENTRY(ret_from_fork)  	addk	r5, r0, r3 -	addk	r6, r0, r1  	brlid	r15, schedule_tail  	nop  	swi	r31, r1, PT_R31		/* save r31 in user context. */ @@ -475,20 +478,35 @@ ENTRY(ret_from_fork)  	brid	ret_to_user  	nop +ENTRY(ret_from_kernel_thread) +	brlid	r15, schedule_tail +	addk	r5, r0, r3 +	brald	r15, r20 +	addk	r5, r0, r19 +	brid	ret_to_user +	addk	r3, r0, r0 +  work_pending: +	lwi	r11, r1, PT_MODE +	bneid	r11, 2f +3:  	enable_irq -  	andi	r11, r19, _TIF_NEED_RESCHED  	beqi	r11, 1f  	bralid	r15, schedule  	nop -1:	andi	r11, r19, _TIF_SIGPENDING +	bri	4f +1:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME  	beqi	r11, no_work_pending -	addk	r5, r1, r0 -	addik	r7, r0, 1 -	bralid	r15, do_signal -	addk	r6, r0, r0 -	bri	no_work_pending +	addk	r5, r30, r0 +	bralid	r15, do_notify_resume +	addik	r6, r0, 1 +	addk	r30, r0, r0	/* no restarts from now on */ +4: +	disable_irq +	lwi	r6, r31, TS_THREAD_INFO /* get thread info */ +	lwi	r19, r6, TI_FLAGS /* get flags in thread info */ +	bri	3b  ENTRY(ret_to_user)  	disable_irq @@ -502,6 +520,7 @@ ENTRY(ret_to_user)  no_work_pending:  	disable_irq +2:  	/* save r31 */  	swi	r31, r0, PER_CPU(CURRENT_SAVE)  	/* save mode indicator */ @@ -553,26 +572,11 @@ no_work_pending:  	rtid	r14, 0  	nop -sys_vfork: -	brid	microblaze_vfork -	addk	r5, r1, r0 - -sys_clone: -	brid	microblaze_clone -	addk	r7, r1, r0 - -sys_execve: -	brid	microblaze_execve -	addk	r8, r1, r0 -  sys_rt_sigreturn_wrapper: +	addk	r30, r0, r0		/* no restarts for this one */  	brid	sys_rt_sigreturn  	addk	r5, r1, r0 -sys_rt_sigsuspend_wrapper: -	brid	sys_rt_sigsuspend -	addk	r7, r1, r0 -  	/* Interrupt vector table */  	.section	.init.ivt, "ax"  	.org 0x0 diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 819238b8a42..0536bc021cc 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -33,11 +33,14 @@  #undef DEBUG -/* The size of a state save frame. */ -#define STATE_SAVE_SIZE		(PT_SIZE + STATE_SAVE_ARG_SPACE) - -/* The offset of the struct pt_regs in a `state save frame' on the stack. */ -#define PTO	STATE_SAVE_ARG_SPACE /* 24 the space for args */ +#ifdef DEBUG +/* Create space for syscalls counting. */ +.section .data +.global syscall_debug_table +.align 4 +syscall_debug_table: +	.space	(__NR_syscalls * 4) +#endif /* DEBUG */  #define C_ENTRY(name)	.globl name; .align 4; name @@ -172,72 +175,72 @@  1:  #define SAVE_REGS \ -	swi	r2, r1, PTO+PT_R2;	/* Save SDA */			\ -	swi	r3, r1, PTO+PT_R3;					\ -	swi	r4, r1, PTO+PT_R4;					\ -	swi	r5, r1, PTO+PT_R5;					\ -	swi	r6, r1, PTO+PT_R6;					\ -	swi	r7, r1, PTO+PT_R7;					\ -	swi	r8, r1, PTO+PT_R8;					\ -	swi	r9, r1, PTO+PT_R9;					\ -	swi	r10, r1, PTO+PT_R10;					\ -	swi	r11, r1, PTO+PT_R11;	/* save clobbered regs after rval */\ -	swi	r12, r1, PTO+PT_R12;					\ -	swi	r13, r1, PTO+PT_R13;	/* Save SDA2 */			\ -	swi	r14, r1, PTO+PT_PC;	/* PC, before IRQ/trap */	\ -	swi	r15, r1, PTO+PT_R15;	/* Save LP */			\ -	swi	r16, r1, PTO+PT_R16;					\ -	swi	r17, r1, PTO+PT_R17;					\ -	swi	r18, r1, PTO+PT_R18;	/* Save asm scratch reg */	\ -	swi	r19, r1, PTO+PT_R19;					\ -	swi	r20, r1, PTO+PT_R20;					\ -	swi	r21, r1, PTO+PT_R21;					\ -	swi	r22, r1, PTO+PT_R22;					\ -	swi	r23, r1, PTO+PT_R23;					\ -	swi	r24, r1, PTO+PT_R24;					\ -	swi	r25, r1, PTO+PT_R25;					\ -	swi	r26, r1, PTO+PT_R26;					\ -	swi	r27, r1, PTO+PT_R27;					\ -	swi	r28, r1, PTO+PT_R28;					\ -	swi	r29, r1, PTO+PT_R29;					\ -	swi	r30, r1, PTO+PT_R30;					\ -	swi	r31, r1, PTO+PT_R31;	/* Save current task reg */	\ +	swi	r2, r1, PT_R2;	/* Save SDA */			\ +	swi	r3, r1, PT_R3;					\ +	swi	r4, r1, PT_R4;					\ +	swi	r5, r1, PT_R5;					\ +	swi	r6, r1, PT_R6;					\ +	swi	r7, r1, PT_R7;					\ +	swi	r8, r1, PT_R8;					\ +	swi	r9, r1, PT_R9;					\ +	swi	r10, r1, PT_R10;					\ +	swi	r11, r1, PT_R11;	/* save clobbered regs after rval */\ +	swi	r12, r1, PT_R12;					\ +	swi	r13, r1, PT_R13;	/* Save SDA2 */			\ +	swi	r14, r1, PT_PC;	/* PC, before IRQ/trap */	\ +	swi	r15, r1, PT_R15;	/* Save LP */			\ +	swi	r16, r1, PT_R16;					\ +	swi	r17, r1, PT_R17;					\ +	swi	r18, r1, PT_R18;	/* Save asm scratch reg */	\ +	swi	r19, r1, PT_R19;					\ +	swi	r20, r1, PT_R20;					\ +	swi	r21, r1, PT_R21;					\ +	swi	r22, r1, PT_R22;					\ +	swi	r23, r1, PT_R23;					\ +	swi	r24, r1, PT_R24;					\ +	swi	r25, r1, PT_R25;					\ +	swi	r26, r1, PT_R26;					\ +	swi	r27, r1, PT_R27;					\ +	swi	r28, r1, PT_R28;					\ +	swi	r29, r1, PT_R29;					\ +	swi	r30, r1, PT_R30;					\ +	swi	r31, r1, PT_R31;	/* Save current task reg */	\  	mfs	r11, rmsr;		/* save MSR */			\ -	swi	r11, r1, PTO+PT_MSR; +	swi	r11, r1, PT_MSR;  #define RESTORE_REGS \ -	lwi	r11, r1, PTO+PT_MSR;					\ +	lwi	r11, r1, PT_MSR;					\  	mts	rmsr , r11;						\ -	lwi	r2, r1, PTO+PT_R2;	/* restore SDA */		\ -	lwi	r3, r1, PTO+PT_R3;					\ -	lwi	r4, r1, PTO+PT_R4;					\ -	lwi	r5, r1, PTO+PT_R5;					\ -	lwi	r6, r1, PTO+PT_R6;					\ -	lwi	r7, r1, PTO+PT_R7;					\ -	lwi	r8, r1, PTO+PT_R8;					\ -	lwi	r9, r1, PTO+PT_R9;					\ -	lwi	r10, r1, PTO+PT_R10;					\ -	lwi	r11, r1, PTO+PT_R11;	/* restore clobbered regs after rval */\ -	lwi	r12, r1, PTO+PT_R12;					\ -	lwi	r13, r1, PTO+PT_R13;	/* restore SDA2 */		\ -	lwi	r14, r1, PTO+PT_PC;	/* RESTORE_LINK PC, before IRQ/trap */\ -	lwi	r15, r1, PTO+PT_R15;	/* restore LP */		\ -	lwi	r16, r1, PTO+PT_R16;					\ -	lwi	r17, r1, PTO+PT_R17;					\ -	lwi	r18, r1, PTO+PT_R18;	/* restore asm scratch reg */	\ -	lwi	r19, r1, PTO+PT_R19;					\ -	lwi	r20, r1, PTO+PT_R20;					\ -	lwi	r21, r1, PTO+PT_R21;					\ -	lwi	r22, r1, PTO+PT_R22;					\ -	lwi	r23, r1, PTO+PT_R23;					\ -	lwi	r24, r1, PTO+PT_R24;					\ -	lwi	r25, r1, PTO+PT_R25;					\ -	lwi	r26, r1, PTO+PT_R26;					\ -	lwi	r27, r1, PTO+PT_R27;					\ -	lwi	r28, r1, PTO+PT_R28;					\ -	lwi	r29, r1, PTO+PT_R29;					\ -	lwi	r30, r1, PTO+PT_R30;					\ -	lwi	r31, r1, PTO+PT_R31;	/* Restore cur task reg */ +	lwi	r2, r1, PT_R2;	/* restore SDA */		\ +	lwi	r3, r1, PT_R3;					\ +	lwi	r4, r1, PT_R4;					\ +	lwi	r5, r1, PT_R5;					\ +	lwi	r6, r1, PT_R6;					\ +	lwi	r7, r1, PT_R7;					\ +	lwi	r8, r1, PT_R8;					\ +	lwi	r9, r1, PT_R9;					\ +	lwi	r10, r1, PT_R10;					\ +	lwi	r11, r1, PT_R11;	/* restore clobbered regs after rval */\ +	lwi	r12, r1, PT_R12;					\ +	lwi	r13, r1, PT_R13;	/* restore SDA2 */		\ +	lwi	r14, r1, PT_PC;	/* RESTORE_LINK PC, before IRQ/trap */\ +	lwi	r15, r1, PT_R15;	/* restore LP */		\ +	lwi	r16, r1, PT_R16;					\ +	lwi	r17, r1, PT_R17;					\ +	lwi	r18, r1, PT_R18;	/* restore asm scratch reg */	\ +	lwi	r19, r1, PT_R19;					\ +	lwi	r20, r1, PT_R20;					\ +	lwi	r21, r1, PT_R21;					\ +	lwi	r22, r1, PT_R22;					\ +	lwi	r23, r1, PT_R23;					\ +	lwi	r24, r1, PT_R24;					\ +	lwi	r25, r1, PT_R25;					\ +	lwi	r26, r1, PT_R26;					\ +	lwi	r27, r1, PT_R27;					\ +	lwi	r28, r1, PT_R28;					\ +	lwi	r29, r1, PT_R29;					\ +	lwi	r30, r1, PT_R30;					\ +	lwi	r31, r1, PT_R31;	/* Restore cur task reg */  #define SAVE_STATE	\  	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */	\ @@ -250,11 +253,11 @@  	lwi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP));			\  	/* FIXME: I can add these two lines to one */			\  	/* tophys(r1,r1); */						\ -	/* addik	r1, r1, -STATE_SAVE_SIZE; */			\ -	addik	r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; \ +	/* addik	r1, r1, -PT_SIZE; */				\ +	addik	r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \  	SAVE_REGS							\  	brid	2f;							\ -	swi	r1, r1, PTO+PT_MODE; 	 				\ +	swi	r1, r1, PT_MODE; 	 				\  1:	/* User-mode state save.  */					\  	lwi	r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\  	tophys(r1,r1);							\ @@ -262,12 +265,12 @@  	/* MS these three instructions can be added to one */		\  	/* addik	r1, r1, THREAD_SIZE; */				\  	/* tophys(r1,r1); */						\ -	/* addik	r1, r1, -STATE_SAVE_SIZE; */			\ -	addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; \ +	/* addik	r1, r1, -PT_SIZE; */			\ +	addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \  	SAVE_REGS							\  	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));			\ -	swi	r11, r1, PTO+PT_R1; /* Store user SP.  */		\ -	swi	r0, r1, PTO + PT_MODE; /* Was in user-mode.  */		\ +	swi	r11, r1, PT_R1; /* Store user SP.  */		\ +	swi	r0, r1, PT_MODE; /* Was in user-mode.  */		\  	/* MS: I am clearing UMS even in case when I come from kernel space */ \  	clear_ums; 							\  2:	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); @@ -287,27 +290,28 @@   * are masked. This is nice, means we don't have to CLI before state save   */  C_ENTRY(_user_exception): -	addi	r14, r14, 4	/* return address is 4 byte after call */  	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ +	addi	r14, r14, 4	/* return address is 4 byte after call */  	lwi	r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */  	tophys(r1,r1);  	lwi	r1, r1, TS_THREAD_INFO;	/* get stack from task_struct */ -	/* MS these three instructions can be added to one */ -	/* addik	r1, r1, THREAD_SIZE; */ -	/* tophys(r1,r1); */ -	/* addik	r1, r1, -STATE_SAVE_SIZE; */ -	addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; +/* calculate kernel stack pointer from task struct 8k */ +	addik	r1, r1, THREAD_SIZE; +	tophys(r1,r1); + +	addik	r1, r1, -PT_SIZE; /* Make room on the stack.  */  	SAVE_REGS -	swi	r0, r1, PTO + PT_R3 -	swi	r0, r1, PTO + PT_R4 +	swi	r0, r1, PT_R3 +	swi	r0, r1, PT_R4 +	swi	r0, r1, PT_MODE;			/* Was in user-mode. */  	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); -	swi	r11, r1, PTO+PT_R1;		/* Store user SP.  */ +	swi	r11, r1, PT_R1;		/* Store user SP.  */  	clear_ums; -	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); +2:	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));  	/* Save away the syscall number.  */ -	swi	r12, r1, PTO+PT_R0; +	swi	r12, r1, PT_R0;  	tovirt(r1,r1)  /* where the trap should return need -8 to adjust for rtsd r15, 8*/ @@ -326,18 +330,18 @@ C_ENTRY(_user_exception):  	beqi	r11, 4f  	addik	r3, r0, -ENOSYS -	swi	r3, r1, PTO + PT_R3 +	swi	r3, r1, PT_R3  	brlid	r15, do_syscall_trace_enter -	addik	r5, r1, PTO + PT_R0 +	addik	r5, r1, PT_R0  	# do_syscall_trace_enter returns the new syscall nr.  	addk	r12, r0, r3 -	lwi	r5, r1, PTO+PT_R5; -	lwi	r6, r1, PTO+PT_R6; -	lwi	r7, r1, PTO+PT_R7; -	lwi	r8, r1, PTO+PT_R8; -	lwi	r9, r1, PTO+PT_R9; -	lwi	r10, r1, PTO+PT_R10; +	lwi	r5, r1, PT_R5; +	lwi	r6, r1, PT_R6; +	lwi	r7, r1, PT_R7; +	lwi	r8, r1, PT_R8; +	lwi	r9, r1, PT_R9; +	lwi	r10, r1, PT_R10;  4:  /* Jump to the appropriate function for the system call number in r12   * (r12 is not preserved), or return an error if r12 is not valid. @@ -350,12 +354,17 @@ C_ENTRY(_user_exception):  	/* Note Microblaze barrel shift is optional, so don't rely on it */  	add	r12, r12, r12;			/* convert num -> ptr */  	add	r12, r12, r12; +	addi	r30, r0, 1			/* restarts allowed */  #ifdef DEBUG -	/* Trac syscalls and stored them to r0_ram */ -	lwi	r3, r12, 0x400 + r0_ram +	/* Trac syscalls and stored them to syscall_debug_table */ +	/* The first syscall location stores total syscall number */ +	lwi	r3, r0, syscall_debug_table +	addi	r3, r3, 1 +	swi	r3, r0, syscall_debug_table +	lwi	r3, r12, syscall_debug_table  	addi	r3, r3, 1 -	swi	r3, r12, 0x400 + r0_ram +	swi	r3, r12, syscall_debug_table  #endif  	# Find and jump into the syscall handler. @@ -372,9 +381,12 @@ C_ENTRY(_user_exception):  /* Entry point used to return from a syscall/trap */  /* We re-enable BIP bit before state restore */  C_ENTRY(ret_from_trap): -	swi	r3, r1, PTO + PT_R3 -	swi	r4, r1, PTO + PT_R4 +	swi	r3, r1, PT_R3 +	swi	r4, r1, PT_R4 +	lwi	r11, r1, PT_MODE; +/* See if returning to kernel mode, if so, skip resched &c.  */ +	bnei	r11, 2f;  	/* We're returning to user mode, so check for various conditions that  	 * trigger rescheduling. */  	/* FIXME: Restructure all these flag checks. */ @@ -384,56 +396,54 @@ C_ENTRY(ret_from_trap):  	beqi	r11, 1f  	brlid	r15, do_syscall_trace_leave -	addik	r5, r1, PTO + PT_R0 +	addik	r5, r1, PT_R0  1:  	/* We're returning to user mode, so check for various conditions that  	 * trigger rescheduling. */  	/* get thread info from current task */  	lwi	r11, CURRENT_TASK, TS_THREAD_INFO; -	lwi	r11, r11, TI_FLAGS;		/* get flags in thread info */ -	andi	r11, r11, _TIF_NEED_RESCHED; +	lwi	r19, r11, TI_FLAGS;		/* get flags in thread info */ +	andi	r11, r19, _TIF_NEED_RESCHED;  	beqi	r11, 5f;  	bralid	r15, schedule;	/* Call scheduler */  	nop;				/* delay slot */ +	bri	1b  	/* Maybe handle a signal */ -5:	/* get thread info from current task*/ -	lwi	r11, CURRENT_TASK, TS_THREAD_INFO; -	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */ -	andi	r11, r11, _TIF_SIGPENDING; -	beqi	r11, 1f;		/* Signals to handle, handle them */ +5:	 +	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; +	beqi	r11, 4f;		/* Signals to handle, handle them */ -	addik	r5, r1, PTO;		/* Arg 1: struct pt_regs *regs */ -	addi	r7, r0, 1;		/* Arg 3: int in_syscall */ -	bralid	r15, do_signal;	/* Handle any signals */ -	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */ +	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */ +	bralid	r15, do_notify_resume;	/* Handle any signals */ +	add	r6, r30, r0;		/* Arg 2: int in_syscall */ +	add	r30, r0, r0		/* no more restarts */ +	bri	1b  /* Finally, return to user state.  */ -1:	set_bip;			/*  Ints masked for state restore */ +4:	set_bip;			/*  Ints masked for state restore */  	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */  	VM_OFF;  	tophys(r1,r1);  	RESTORE_REGS; -	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */ +	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */  	lwi	r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */ +	bri	6f; + +/* Return to kernel state.  */ +2:	set_bip;			/*  Ints masked for state restore */ +	VM_OFF; +	tophys(r1,r1); +	RESTORE_REGS; +	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */ +	tovirt(r1,r1); +6:  TRAP_return:		/* Make global symbol for debugging */  	rtbd	r14, 0;	/* Instructions to return from an IRQ */  	nop; -/* These syscalls need access to the struct pt_regs on the stack, so we -   implement them in assembly (they're basically all wrappers anyway).  */ - -C_ENTRY(sys_fork_wrapper): -	addi	r5, r0, SIGCHLD			/* Arg 0: flags */ -	lwi	r6, r1, PTO+PT_R1	/* Arg 1: child SP (use parent's) */ -	addik	r7, r1, PTO			/* Arg 2: parent context */ -	add	r8. r0, r0			/* Arg 3: (unused) */ -	add	r9, r0, r0;			/* Arg 4: (unused) */ -	brid	do_fork		/* Do real work (tail-call) */ -	add	r10, r0, r0;			/* Arg 5: (unused) */ -  /* This the initial entry point for a new child thread, with an appropriate     stack in place that makes it look the the child is in the middle of an     syscall.  This function is actually `returned to' from switch_thread @@ -441,31 +451,24 @@ C_ENTRY(sys_fork_wrapper):     saved context).  */  C_ENTRY(ret_from_fork):  	bralid	r15, schedule_tail; /* ...which is schedule_tail's arg */ -	add	r3, r5, r0;	/* switch_thread returns the prev task */ +	add	r5, r3, r0;	/* switch_thread returns the prev task */  				/* ( in the delay slot ) */  	brid	ret_from_trap;	/* Do normal trap return */  	add	r3, r0, r0;	/* Child's fork call should return 0. */ -C_ENTRY(sys_vfork): -	brid	microblaze_vfork	/* Do real work (tail-call) */ -	addik	r5, r1, PTO - -C_ENTRY(sys_clone): -	bnei	r6, 1f;			/* See if child SP arg (arg 1) is 0. */ -	lwi	r6, r1, PTO + PT_R1;	/* If so, use paret's stack ptr */ -1:	addik	r7, r1, PTO;			/* Arg 2: parent context */ -	add	r8, r0, r0;			/* Arg 3: (unused) */ -	add	r9, r0, r0;			/* Arg 4: (unused) */ -	brid	do_fork		/* Do real work (tail-call) */ -	add	r10, r0, r0;			/* Arg 5: (unused) */ - -C_ENTRY(sys_execve): -	brid	microblaze_execve;	/* Do real work (tail-call).*/ -	addik	r8, r1, PTO;		/* add user context as 4th arg */ +C_ENTRY(ret_from_kernel_thread): +	bralid	r15, schedule_tail; /* ...which is schedule_tail's arg */ +	add	r5, r3, r0;	/* switch_thread returns the prev task */ +				/* ( in the delay slot ) */ +	brald	r15, r20	/* fn was left in r20 */ +	addk	r5, r0, r19	/* ... and argument - in r19 */ +	brid	ret_from_trap +	add	r3, r0, r0  C_ENTRY(sys_rt_sigreturn_wrapper): +	addik	r30, r0, 0		/* no restarts */  	brid	sys_rt_sigreturn	/* Do real work */ -	addik	r5, r1, PTO;		/* add user context as 1st arg */ +	addik	r5, r1, 0;		/* add user context as 1st arg */  /*   * HW EXCEPTION rutine start @@ -476,7 +479,7 @@ C_ENTRY(full_exception_trap):  	addik	r17, r17, -4  	SAVE_STATE /* Save registers */  	/* PC, before IRQ/trap - this is one instruction above */ -	swi	r17, r1, PTO+PT_PC; +	swi	r17, r1, PT_PC;  	tovirt(r1,r1)  	/* FIXME this can be store directly in PT_ESR reg.  	 * I tested it but there is a fault */ @@ -486,7 +489,7 @@ C_ENTRY(full_exception_trap):  	mfs	r7, rfsr;		/* save FSR */  	mts	rfsr, r0;	/* Clear sticky fsr */  	rted	r0, full_exception -	addik	r5, r1, PTO		 /* parameter struct pt_regs * regs */ +	addik	r5, r1, 0		 /* parameter struct pt_regs * regs */  /*   * Unaligned data trap. @@ -512,14 +515,14 @@ C_ENTRY(unaligned_data_trap):  	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));  	SAVE_STATE		/* Save registers.*/  	/* PC, before IRQ/trap - this is one instruction above */ -	swi	r17, r1, PTO+PT_PC; +	swi	r17, r1, PT_PC;  	tovirt(r1,r1)  	/* where the trap should return need -8 to adjust for rtsd r15, 8 */  	addik	r15, r0, ret_from_exc-8  	mfs	r3, resr		/* ESR */  	mfs	r4, rear		/* EAR */  	rtbd	r0, _unaligned_data_exception -	addik	r7, r1, PTO		/* parameter struct pt_regs * regs */ +	addik	r7, r1, 0		/* parameter struct pt_regs * regs */  /*   * Page fault traps. @@ -542,49 +545,49 @@ C_ENTRY(unaligned_data_trap):  C_ENTRY(page_fault_data_trap):  	SAVE_STATE		/* Save registers.*/  	/* PC, before IRQ/trap - this is one instruction above */ -	swi	r17, r1, PTO+PT_PC; +	swi	r17, r1, PT_PC;  	tovirt(r1,r1)  	/* where the trap should return need -8 to adjust for rtsd r15, 8 */  	addik	r15, r0, ret_from_exc-8  	mfs	r6, rear		/* parameter unsigned long address */  	mfs	r7, resr		/* parameter unsigned long error_code */  	rted	r0, do_page_fault -	addik	r5, r1, PTO		/* parameter struct pt_regs * regs */ +	addik	r5, r1, 0		/* parameter struct pt_regs * regs */  C_ENTRY(page_fault_instr_trap):  	SAVE_STATE		/* Save registers.*/  	/* PC, before IRQ/trap - this is one instruction above */ -	swi	r17, r1, PTO+PT_PC; +	swi	r17, r1, PT_PC;  	tovirt(r1,r1)  	/* where the trap should return need -8 to adjust for rtsd r15, 8 */  	addik	r15, r0, ret_from_exc-8  	mfs	r6, rear		/* parameter unsigned long address */  	ori	r7, r0, 0		/* parameter unsigned long error_code */  	rted	r0, do_page_fault -	addik	r5, r1, PTO		/* parameter struct pt_regs * regs */ +	addik	r5, r1, 0		/* parameter struct pt_regs * regs */  /* Entry point used to return from an exception.  */  C_ENTRY(ret_from_exc): -	lwi	r11, r1, PTO + PT_MODE; +	lwi	r11, r1, PT_MODE;  	bnei	r11, 2f;		/* See if returning to kernel mode, */  					/* ... if so, skip resched &c.  */  	/* We're returning to user mode, so check for various conditions that  	   trigger rescheduling. */ +1:  	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */ -	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */ -	andi	r11, r11, _TIF_NEED_RESCHED; +	lwi	r19, r11, TI_FLAGS;	/* get flags in thread info */ +	andi	r11, r19, _TIF_NEED_RESCHED;  	beqi	r11, 5f;  /* Call the scheduler before returning from a syscall/trap. */  	bralid	r15, schedule;	/* Call scheduler */  	nop;				/* delay slot */ +	bri	1b  	/* Maybe handle a signal */ -5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */ -	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */ -	andi	r11, r11, _TIF_SIGPENDING; -	beqi	r11, 1f;		/* Signals to handle, handle them */ +5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; +	beqi	r11, 4f;		/* Signals to handle, handle them */  	/*  	 * Handle a signal return; Pending signals should be in r18. @@ -596,20 +599,20 @@ C_ENTRY(ret_from_exc):  	 * traps), but signal handlers may want to examine or change the  	 * complete register state.  Here we save anything not saved by  	 * the normal entry sequence, so that it may be safely restored -	 * (in a possibly modified form) after do_signal returns. */ -	addik	r5, r1, PTO;		/* Arg 1: struct pt_regs *regs */ -	addi	r7, r0, 0;		/* Arg 3: int in_syscall */ -	bralid	r15, do_signal;	/* Handle any signals */ -	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */ +	 * (in a possibly modified form) after do_notify_resume returns. */ +	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */ +	bralid	r15, do_notify_resume;	/* Handle any signals */ +	addi	r6, r0, 0;		/* Arg 2: int in_syscall */ +	bri	1b  /* Finally, return to user state.  */ -1:	set_bip;			/* Ints masked for state restore */ +4:	set_bip;			/* Ints masked for state restore */  	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */  	VM_OFF;  	tophys(r1,r1);  	RESTORE_REGS; -	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */ +	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */  	lwi	r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */  	bri	6f; @@ -618,7 +621,7 @@ C_ENTRY(ret_from_exc):  	VM_OFF;  	tophys(r1,r1);  	RESTORE_REGS; -	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */ +	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */  	tovirt(r1,r1);  6: @@ -651,10 +654,10 @@ C_ENTRY(_interrupt):  	tophys(r1,r1); /* MS: I have in r1 physical address where stack is */  	/* save registers */  /* MS: Make room on the stack -> activation record */ -	addik	r1, r1, -STATE_SAVE_SIZE; +	addik	r1, r1, -PT_SIZE;  	SAVE_REGS  	brid	2f; -	swi	r1, r1, PTO + PT_MODE; /* 0 - user mode, 1 - kernel mode */ +	swi	r1, r1, PT_MODE; /* 0 - user mode, 1 - kernel mode */  1:  /* User-mode state save. */   /* MS: get the saved current */ @@ -664,42 +667,42 @@ C_ENTRY(_interrupt):  	addik	r1, r1, THREAD_SIZE;  	tophys(r1,r1);  	/* save registers */ -	addik	r1, r1, -STATE_SAVE_SIZE; +	addik	r1, r1, -PT_SIZE;  	SAVE_REGS  	/* calculate mode */ -	swi	r0, r1, PTO + PT_MODE; +	swi	r0, r1, PT_MODE;  	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); -	swi	r11, r1, PTO+PT_R1; +	swi	r11, r1, PT_R1;  	clear_ums;  2:  	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));  	tovirt(r1,r1)  	addik	r15, r0, irq_call;  irq_call:rtbd	r0, do_IRQ; -	addik	r5, r1, PTO; +	addik	r5, r1, 0;  /* MS: we are in virtual mode */  ret_from_irq: -	lwi	r11, r1, PTO + PT_MODE; +	lwi	r11, r1, PT_MODE;  	bnei	r11, 2f; +1:  	lwi	r11, CURRENT_TASK, TS_THREAD_INFO; -	lwi	r11, r11, TI_FLAGS; /* MS: get flags from thread info */ -	andi	r11, r11, _TIF_NEED_RESCHED; +	lwi	r19, r11, TI_FLAGS; /* MS: get flags from thread info */ +	andi	r11, r19, _TIF_NEED_RESCHED;  	beqi	r11, 5f  	bralid	r15, schedule;  	nop; /* delay slot */ +	bri	1b      /* Maybe handle a signal */ -5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO; /* MS: get thread info */ -	lwi	r11, r11, TI_FLAGS; /* get flags in thread info */ -	andi	r11, r11, _TIF_SIGPENDING; +5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;  	beqid	r11, no_intr_resched  /* Handle a signal return; Pending signals should be in r18. */ -	addi	r7, r0, 0; /* Arg 3: int in_syscall */ -	addik	r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ -	bralid	r15, do_signal;	/* Handle any signals */ -	add	r6, r0, r0; /* Arg 2: sigset_t *oldset */ +	addik	r5, r1, 0; /* Arg 1: struct pt_regs *regs */ +	bralid	r15, do_notify_resume;	/* Handle any signals */ +	addi	r6, r0, 0; /* Arg 2: int in_syscall */ +	bri	1b  /* Finally, return to user state. */  no_intr_resched: @@ -709,7 +712,7 @@ no_intr_resched:  	VM_OFF;  	tophys(r1,r1);  	RESTORE_REGS -	addik	r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */ +	addik	r1, r1, PT_SIZE /* MS: Clean up stack space. */  	lwi	r1, r1, PT_R1 - PT_SIZE;  	bri	6f;  /* MS: Return to kernel state. */ @@ -737,7 +740,7 @@ restore:  	VM_OFF /* MS: turn off MMU */  	tophys(r1,r1)  	RESTORE_REGS -	addik	r1, r1, STATE_SAVE_SIZE	/* MS: Clean up stack space. */ +	addik	r1, r1, PT_SIZE	/* MS: Clean up stack space. */  	tovirt(r1,r1);  6:  IRQ_return: /* MS: Make global symbol for debugging */ @@ -760,29 +763,29 @@ C_ENTRY(_debug_exception):  	lwi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/  	/* BIP bit is set on entry, no interrupts can occur */ -	addik   r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; +	addik   r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE;  	SAVE_REGS;  	/* save all regs to pt_reg structure */ -	swi	r0, r1, PTO+PT_R0;	/* R0 must be saved too */ -	swi	r14, r1, PTO+PT_R14	/* rewrite saved R14 value */ -	swi	r16, r1, PTO+PT_PC; /* PC and r16 are the same */ +	swi	r0, r1, PT_R0;	/* R0 must be saved too */ +	swi	r14, r1, PT_R14	/* rewrite saved R14 value */ +	swi	r16, r1, PT_PC; /* PC and r16 are the same */  	/* save special purpose registers to pt_regs */  	mfs	r11, rear; -	swi	r11, r1, PTO+PT_EAR; +	swi	r11, r1, PT_EAR;  	mfs	r11, resr; -	swi	r11, r1, PTO+PT_ESR; +	swi	r11, r1, PT_ESR;  	mfs	r11, rfsr; -	swi	r11, r1, PTO+PT_FSR; +	swi	r11, r1, PT_FSR;  	/* stack pointer is in physical address at it is decrease -	 * by STATE_SAVE_SIZE but we need to get correct R1 value */ -	addik   r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + STATE_SAVE_SIZE; -	swi	r11, r1, PTO+PT_R1 +	 * by PT_SIZE but we need to get correct R1 value */ +	addik   r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + PT_SIZE; +	swi	r11, r1, PT_R1  	/* MS: r31 - current pointer isn't changed */  	tovirt(r1,r1)  #ifdef CONFIG_KGDB -	addi	r5, r1, PTO /* pass pt_reg address as the first arg */ -	la	r15, r0, dbtrap_call; /* return address */ +	addi	r5, r1, 0 /* pass pt_reg address as the first arg */ +	addik	r15, r0, dbtrap_call; /* return address */  	rtbd	r0, microblaze_kgdb_break  	nop;  #endif @@ -797,16 +800,16 @@ C_ENTRY(_debug_exception):  	addik	r1, r1, THREAD_SIZE;	/* calculate kernel stack pointer */  	tophys(r1,r1); -	addik	r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */ +	addik	r1, r1, -PT_SIZE; /* Make room on the stack.  */  	SAVE_REGS; -	swi	r16, r1, PTO+PT_PC;	/* Save LP */ -	swi	r0, r1, PTO + PT_MODE; /* Was in user-mode.  */ +	swi	r16, r1, PT_PC;	/* Save LP */ +	swi	r0, r1, PT_MODE; /* Was in user-mode.  */  	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); -	swi	r11, r1, PTO+PT_R1; /* Store user SP.  */ +	swi	r11, r1, PT_R1; /* Store user SP.  */  	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));  	tovirt(r1,r1)  	set_vms; -	addik	r5, r1, PTO; +	addik	r5, r1, 0;  	addik	r15, r0, dbtrap_call;  dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */  	rtbd	r0, sw_exception @@ -814,37 +817,37 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */  	/* MS: The first instruction for the second part of the gdb/kgdb */  	set_bip; /* Ints masked for state restore */ -	lwi	r11, r1, PTO + PT_MODE; +	lwi	r11, r1, PT_MODE;  	bnei	r11, 2f;  /* MS: Return to user space - gdb */ +1:  	/* Get current task ptr into r11 */  	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */ -	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */ -	andi	r11, r11, _TIF_NEED_RESCHED; +	lwi	r19, r11, TI_FLAGS;	/* get flags in thread info */ +	andi	r11, r19, _TIF_NEED_RESCHED;  	beqi	r11, 5f;  	/* Call the scheduler before returning from a syscall/trap. */  	bralid	r15, schedule;	/* Call scheduler */  	nop;				/* delay slot */ +	bri	1b  	/* Maybe handle a signal */ -5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */ -	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */ -	andi	r11, r11, _TIF_SIGPENDING; -	beqi	r11, 1f;		/* Signals to handle, handle them */ +5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; +	beqi	r11, 4f;		/* Signals to handle, handle them */ -	addik	r5, r1, PTO;		/* Arg 1: struct pt_regs *regs */ -	addi  r7, r0, 0;	/* Arg 3: int in_syscall */ -	bralid	r15, do_signal;	/* Handle any signals */ -	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */ +	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */ +	bralid	r15, do_notify_resume;	/* Handle any signals */ +	addi  r6, r0, 0;	/* Arg 2: int in_syscall */ +	bri	1b  /* Finally, return to user state.  */ -1:	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ +4:	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */  	VM_OFF;  	tophys(r1,r1);  	/* MS: Restore all regs */  	RESTORE_REGS -	addik	r1, r1, STATE_SAVE_SIZE	 /* Clean up stack space */ +	addik	r1, r1, PT_SIZE	 /* Clean up stack space */  	lwi	r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */  DBTRAP_return_user: /* MS: Make global symbol for debugging */  	rtbd	r16, 0; /* MS: Instructions to return from a debug trap */ @@ -855,9 +858,9 @@ DBTRAP_return_user: /* MS: Make global symbol for debugging */  	tophys(r1,r1);  	/* MS: Restore all regs */  	RESTORE_REGS -	lwi	r14, r1, PTO+PT_R14; -	lwi	r16, r1, PTO+PT_PC; -	addik	r1, r1, STATE_SAVE_SIZE; /* MS: Clean up stack space */ +	lwi	r14, r1, PT_R14; +	lwi	r16, r1, PT_PC; +	addik	r1, r1, PT_SIZE; /* MS: Clean up stack space */  	tovirt(r1,r1);  DBTRAP_return_kernel: /* MS: Make global symbol for debugging */  	rtbd	r16, 0; /* MS: Instructions to return from a debug trap */ @@ -949,20 +952,22 @@ ENTRY(_switch_to)  	nop  ENTRY(_reset) -	brai	0x70; /* Jump back to FS-boot */ +	brai	0; /* Jump to reset vector */  	/* These are compiled and loaded into high memory, then  	 * copied into place in mach_early_setup */  	.section	.init.ivt, "ax" +#if CONFIG_MANUAL_RESET_VECTOR  	.org	0x0 -	/* this is very important - here is the reset vector */ -	/* in current MMU branch you don't care what is here - it is -	 * used from bootloader site - but this is correct for FS-BOOT */ -	brai	0x70 -	nop +	brai	CONFIG_MANUAL_RESET_VECTOR +#endif +	.org	0x8  	brai	TOPHYS(_user_exception); /* syscall handler */ +	.org	0x10  	brai	TOPHYS(_interrupt);	/* Interrupt handler */ +	.org	0x18  	brai	TOPHYS(_debug_exception);	/* debug trap handler */ +	.org	0x20  	brai	TOPHYS(_hw_exception_handler);	/* HW exception handler */  .section .rodata,"a" diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c index 478f2943ede..42dd12a62ff 100644 --- a/arch/microblaze/kernel/exceptions.c +++ b/arch/microblaze/kernel/exceptions.c @@ -13,11 +13,11 @@   * This file handles the architecture-dependent parts of hardware exceptions   */ +#include <linux/export.h>  #include <linux/kernel.h>  #include <linux/signal.h>  #include <linux/sched.h>  #include <linux/kallsyms.h> -#include <linux/module.h>  #include <asm/exceptions.h>  #include <asm/entry.h>		/* For KM CPU var */ @@ -25,6 +25,7 @@  #include <linux/errno.h>  #include <linux/ptrace.h>  #include <asm/current.h> +#include <asm/cacheflush.h>  #define MICROBLAZE_ILL_OPCODE_EXCEPTION	0x02  #define MICROBLAZE_IBUS_EXCEPTION	0x03 @@ -39,7 +40,7 @@ void die(const char *str, struct pt_regs *fp, long err)  {  	console_verbose();  	spin_lock_irq(&die_lock); -	printk(KERN_WARNING "Oops: %s, sig: %ld\n", str, err); +	pr_warn("Oops: %s, sig: %ld\n", str, err);  	show_regs(fp);  	spin_unlock_irq(&die_lock);  	/* do_exit() should take care of panic'ing from an interrupt @@ -49,18 +50,20 @@ void die(const char *str, struct pt_regs *fp, long err)  }  /* for user application debugging */ -void sw_exception(struct pt_regs *regs) +asmlinkage void sw_exception(struct pt_regs *regs)  {  	_exception(SIGTRAP, regs, TRAP_BRKPT, regs->r16); +	flush_dcache_range(regs->r16, regs->r16 + 0x4); +	flush_icache_range(regs->r16, regs->r16 + 0x4);  }  void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)  {  	siginfo_t info; -	if (kernel_mode(regs)) { +	if (kernel_mode(regs))  		die("Exception in kernel mode", regs, signr); -	} +  	info.si_signo = signr;  	info.si_errno = 0;  	info.si_code = code; @@ -76,8 +79,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,  #endif  #if 0 -	printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x " \ -							"ESR=%08x\n", +	pr_warn("Exception %02x in %s mode, FSR=%08x PC=%08x ESR=%08x\n",  			type, user_mode(regs) ? "user" : "kernel", fsr,  			(unsigned int) regs->pc, (unsigned int) regs->esr);  #endif @@ -89,8 +91,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,  			_exception(SIGILL, regs, ILL_ILLOPC, addr);  			return;  		} -		printk(KERN_WARNING "Illegal opcode exception " \ -							"in kernel mode.\n"); +		pr_warn("Illegal opcode exception in kernel mode.\n");  		die("opcode exception", regs, SIGBUS);  		break;  	case MICROBLAZE_IBUS_EXCEPTION: @@ -99,8 +100,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,  			_exception(SIGBUS, regs, BUS_ADRERR, addr);  			return;  		} -		printk(KERN_WARNING "Instruction bus error exception " \ -							"in kernel mode.\n"); +		pr_warn("Instruction bus error exception in kernel mode.\n");  		die("bus exception", regs, SIGBUS);  		break;  	case MICROBLAZE_DBUS_EXCEPTION: @@ -109,18 +109,16 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,  			_exception(SIGBUS, regs, BUS_ADRERR, addr);  			return;  		} -		printk(KERN_WARNING "Data bus error exception " \ -							"in kernel mode.\n"); +		pr_warn("Data bus error exception in kernel mode.\n");  		die("bus exception", regs, SIGBUS);  		break;  	case MICROBLAZE_DIV_ZERO_EXCEPTION:  		if (user_mode(regs)) {  			pr_debug("Divide by zero exception in user mode\n"); -			_exception(SIGILL, regs, FPE_INTDIV, addr); +			_exception(SIGFPE, regs, FPE_INTDIV, addr);  			return;  		} -		printk(KERN_WARNING "Divide by zero exception " \ -							"in kernel mode.\n"); +		pr_warn("Divide by zero exception in kernel mode.\n");  		die("Divide by zero exception", regs, SIGBUS);  		break;  	case MICROBLAZE_FPU_EXCEPTION: @@ -148,8 +146,8 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,  #endif  	default:  	/* FIXME what to do in unexpected exception */ -		printk(KERN_WARNING "Unexpected exception %02x " -			"PC=%08x in %s mode\n", type, (unsigned int) addr, +		pr_warn("Unexpected exception %02x PC=%08x in %s mode\n", +			type, (unsigned int) addr,  			kernel_mode(regs) ? "kernel" : "user");  	}  	return; diff --git a/arch/microblaze/kernel/ftrace.c b/arch/microblaze/kernel/ftrace.c index 515feb40455..bbcd2533766 100644 --- a/arch/microblaze/kernel/ftrace.c +++ b/arch/microblaze/kernel/ftrace.c @@ -35,22 +35,25 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)  	 * happen. This tool is too much intrusive to  	 * ignore such a protection.  	 */ -	asm volatile("	1:	lwi	%0, %2, 0;		\ -			2:	swi	%3, %2, 0;		\ -				addik	%1, r0, 0;		\ -			3:					\ -				.section .fixup, \"ax\";	\ -			4:	brid	3b;			\ -				addik	%1, r0, 1;		\ -				.previous;			\ -				.section __ex_table,\"a\";	\ -				.word	1b,4b;			\ -				.word	2b,4b;			\ -				.previous;"			\ +	asm volatile("	1:	lwi	%0, %2, 0;"		\ +			"2:	swi	%3, %2, 0;"		\ +			"	addik	%1, r0, 0;"		\ +			"3:"					\ +			"	.section .fixup, \"ax\";"	\ +			"4:	brid	3b;"			\ +			"	addik	%1, r0, 1;"		\ +			"	.previous;"			\ +			"	.section __ex_table,\"a\";"	\ +			"	.word	1b,4b;"			\ +			"	.word	2b,4b;"			\ +			"	.previous;"			\  			: "=&r" (old), "=r" (faulted)  			: "r" (parent), "r" (return_hooker)  	); +	flush_dcache_range((u32)parent, (u32)parent + 4); +	flush_icache_range((u32)parent, (u32)parent + 4); +  	if (unlikely(faulted)) {  		ftrace_graph_stop();  		WARN_ON(1); @@ -78,16 +81,16 @@ static int ftrace_modify_code(unsigned long addr, unsigned int value)  {  	int faulted = 0; -	__asm__ __volatile__("	1:	swi	%2, %1, 0;		\ -					addik	%0, r0, 0;		\ -				2:					\ -					.section .fixup, \"ax\";	\ -				3:	brid	2b;			\ -					addik	%0, r0, 1;		\ -					.previous;			\ -					.section __ex_table,\"a\";	\ -					.word	1b,3b;			\ -					.previous;"			\ +	__asm__ __volatile__("	1:	swi	%2, %1, 0;"		\ +				"	addik	%0, r0, 0;"		\ +				"2:"					\ +				"	.section .fixup, \"ax\";"	\ +				"3:	brid	2b;"			\ +				"	addik	%0, r0, 1;"		\ +				"	.previous;"			\ +				"	.section __ex_table,\"a\";"	\ +				"	.word	1b,3b;"			\ +				"	.previous;"			\  				: "=r" (faulted)  				: "r" (addr), "r" (value)  	); @@ -95,6 +98,9 @@ static int ftrace_modify_code(unsigned long addr, unsigned int value)  	if (unlikely(faulted))  		return -EFAULT; +	flush_dcache_range(addr, addr + 4); +	flush_icache_range(addr, addr + 4); +  	return 0;  } @@ -165,11 +171,8 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)  	return ret;  } -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void)  { -	/* The return code is retured via data */ -	*(unsigned long *)data = 0; -  	return 0;  } @@ -195,8 +198,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func)  	ret += ftrace_modify_code((unsigned long)&ftrace_caller,  				  MICROBLAZE_NOP); -	/* All changes are done - lets do caches consistent */ -	flush_icache();  	return ret;  } @@ -210,7 +211,6 @@ int ftrace_enable_ftrace_graph_caller(void)  	old_jump = *(unsigned int *)ip; /* save jump over instruction */  	ret = ftrace_modify_code(ip, MICROBLAZE_NOP); -	flush_icache();  	pr_debug("%s: Replace instruction: 0x%x\n", __func__, old_jump);  	return ret; @@ -222,7 +222,6 @@ int ftrace_disable_ftrace_graph_caller(void)  	unsigned long ip = (unsigned long)(&ftrace_call_graph);  	ret = ftrace_modify_code(ip, old_jump); -	flush_icache();  	pr_debug("%s\n", __func__);  	return ret; diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S index 42434008209..4655ff342c6 100644 --- a/arch/microblaze/kernel/head.S +++ b/arch/microblaze/kernel/head.S @@ -39,7 +39,7 @@  #include <asm/mmu.h>  #include <asm/processor.h> -.data +.section .data  .global empty_zero_page  .align 12  empty_zero_page: @@ -50,6 +50,11 @@ swapper_pg_dir:  #endif /* CONFIG_MMU */ +.section .rodata +.align 4 +endian_check: +	.word	1 +  	__HEAD  ENTRY(_start)  #if CONFIG_KERNEL_BASE_ADDR == 0 @@ -58,34 +63,43 @@ ENTRY(_start)  real_start:  #endif -	mfs	r1, rmsr -	andi	r1, r1, ~2 -	mts	rmsr, r1 +	mts	rmsr, r0 +/* Disable stack protection from bootloader */ +	mts	rslr, r0 +	addi	r8, r0, 0xFFFFFFFF +	mts	rshr, r8  /* - * Here is checking mechanism which check if Microblaze has msr instructions - * We load msr and compare it with previous r1 value - if is the same, - * msr instructions works if not - cpu don't have them. + * According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc' + * if the msrclr instruction is not enabled. We use this to detect + * if the opcode is available, by issuing msrclr and then testing the result. + * r8 == 0 - msr instructions are implemented + * r8 != 0 - msr instructions are not implemented   */ -	/* r8=0 - I have msr instr, 1 - I don't have them */ -	rsubi	r0, r0, 1	/* set the carry bit */ -	msrclr	r0, 0x4		/* try to clear it */ -	/* read the carry bit, r8 will be '0' if msrclr exists */ -	addik	r8, r0, 0 +	mfs	r1, rmsr +	msrclr	r8, 0 /* clear nothing - just read msr for test */ +	cmpu	r8, r8, r1 /* r1 must contain msr reg content */  /* r7 may point to an FDT, or there may be one linked in.     if it's in r7, we've got to save it away ASAP.     We ensure r7 points to a valid FDT, just in case the bootloader     is broken or non-existent */  	beqi	r7, no_fdt_arg			/* NULL pointer?  don't copy */ -	lw	r11, r0, r7			/* Does r7 point to a */ -	rsubi	r11, r11, OF_DT_HEADER		/* valid FDT? */ +/* Does r7 point to a valid FDT? Load HEADER magic number */ +	/* Run time Big/Little endian platform */ +	/* Save 1 as word and load byte - 0 - BIG, 1 - LITTLE */ +	lbui	r11, r0, TOPHYS(endian_check) +	beqid	r11, big_endian /* DO NOT break delay stop dependency */ +	lw	r11, r0, r7 /* Big endian load in delay slot */ +	lwr	r11, r0, r7 /* Little endian load */ +big_endian: +	rsubi	r11, r11, OF_DT_HEADER	/* Check FDT header */  	beqi	r11, _prepare_copy_fdt  	or	r7, r0, r0		/* clear R7 when not valid DTB */  	bnei	r11, no_fdt_arg			/* No - get out of here */  _prepare_copy_fdt:  	or	r11, r0, r0 /* incremment */  	ori	r4, r0, TOPHYS(_fdt_start) -	ori	r3, r0, (0x4000 - 4) +	ori	r3, r0, (0x8000 - 4)  _copy_fdt:  	lw	r12, r7, r11 /* r12 = r7 + r11 */  	sw	r12, r4, r11 /* addr[r4 + r11] = r12 */ @@ -99,31 +113,35 @@ no_fdt_arg:  #ifndef CONFIG_CMDLINE_BOOL  /*   * handling command line - * copy command line to __init_end. There is space for storing command line. + * copy command line directly to cmd_line placed in data section.   */ -	or	r6, r0, r0		/* incremment */ -	ori	r4, r0, __init_end	/* load address of command line */ +	beqid	r5, skip	/* Skip if NULL pointer */ +	or	r11, r0, r0		/* incremment */ +	ori	r4, r0, cmd_line	/* load address of command line */  	tophys(r4,r4)			/* convert to phys address */  	ori	r3, r0, COMMAND_LINE_SIZE - 1 /* number of loops */  _copy_command_line: -	lbu	r2, r5, r6 /* r2=r5+r6 - r5 contain pointer to command line */ -	sb	r2, r4, r6		/* addr[r4+r6]= r2*/ -	addik	r6, r6, 1		/* increment counting */ +	/* r2=r5+r6 - r5 contain pointer to command line */ +	lbu	r2, r5, r11 +	beqid	r2, skip		/* Skip if no data */ +	sb	r2, r4, r11		/* addr[r4+r6]= r2 */ +	addik	r11, r11, 1		/* increment counting */  	bgtid	r3, _copy_command_line	/* loop for all entries       */ -	addik	r3, r3, -1		/* descrement loop */ +	addik	r3, r3, -1		/* decrement loop */  	addik	r5, r4, 0		/* add new space for command line */  	tovirt(r5,r5) +skip:  #endif /* CONFIG_CMDLINE_BOOL */  #ifdef NOT_COMPILE  /* save bram context */ -	or	r6, r0, r0				/* incremment */ +	or	r11, r0, r0				/* incremment */  	ori	r4, r0, TOPHYS(_bram_load_start)	/* save bram context */  	ori	r3, r0, (LMB_SIZE - 4)  _copy_bram: -	lw	r7, r0, r6		/* r7 = r0 + r6 */ -	sw	r7, r4, r6		/* addr[r4 + r6] = r7*/ -	addik	r6, r6, 4		/* increment counting */ +	lw	r7, r0, r11		/* r7 = r0 + r6 */ +	sw	r7, r4, r11		/* addr[r4 + r6] = r7 */ +	addik	r11, r11, 4		/* increment counting */  	bgtid	r3, _copy_bram		/* loop for all entries */  	addik	r3, r3, -4		/* descrement loop */  #endif @@ -139,6 +157,7 @@ _copy_bram:  _invalidate:  	mts	rtlbx, r3  	mts	rtlbhi, r0			/* flush: ensure V is clear   */ +	mts	rtlblo, r0  	bgtid	r3, _invalidate		/* loop for all entries       */  	addik	r3, r3, -1  	/* sync */ @@ -158,6 +177,53 @@ _invalidate:  	addik	r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */  	tophys(r4,r3)			/* Load the kernel physical address */ +	/* start to do TLB calculation */ +	addik	r12, r0, _end +	rsub	r12, r3, r12 +	addik	r12, r12, CONFIG_LOWMEM_SIZE >> PTE_SHIFT /* that's the pad */ + +	or r9, r0, r0 /* TLB0 = 0 */ +	or r10, r0, r0 /* TLB1 = 0 */ + +	addik	r11, r12, -0x1000000 +	bgei	r11, GT16 /* size is greater than 16MB */ +	addik	r11, r12, -0x0800000 +	bgei	r11, GT8 /* size is greater than 8MB */ +	addik	r11, r12, -0x0400000 +	bgei	r11, GT4 /* size is greater than 4MB */ +	/* size is less than 4MB */ +	addik	r11, r12, -0x0200000 +	bgei	r11, GT2 /* size is greater than 2MB */ +	addik	r9, r0, 0x0100000 /* TLB0 must be 1MB */ +	addik	r11, r12, -0x0100000 +	bgei	r11, GT1 /* size is greater than 1MB */ +	/* TLB1 is 0 which is setup above */ +	bri tlb_end +GT4: /* r11 contains the rest - will be either 1 or 4 */ +	ori r9, r0, 0x400000 /* TLB0 is 4MB */ +	bri TLB1 +GT16: /* TLB0 is 16MB */ +	addik	r9, r0, 0x1000000 /* means TLB0 is 16MB */ +TLB1: +	/* must be used r2 because of subtract if failed */ +	addik	r2, r11, -0x0400000 +	bgei	r2, GT20 /* size is greater than 16MB */ +	/* size is >16MB and <20MB */ +	addik	r11, r11, -0x0100000 +	bgei	r11, GT17 /* size is greater than 17MB */ +	/* kernel is >16MB and < 17MB */ +GT1: +	addik	r10, r0, 0x0100000 /* means TLB1 is 1MB */ +	bri tlb_end +GT2: /* TLB0 is 0 and TLB1 will be 4MB */ +GT17: /* TLB1 is 4MB - kernel size <20MB */ +	addik	r10, r0, 0x0400000 /* means TLB1 is 4MB */ +	bri tlb_end +GT8: /* TLB0 is still zero that's why I can use only TLB1 */ +GT20: /* TLB1 is 16MB - kernel size >20MB */ +	addik	r10, r0, 0x1000000 /* means TLB1 is 16MB */ +tlb_end: +  	/*  	 * Configure and load two entries into TLB slots 0 and 1.  	 * In case we are pinning TLBs, these are reserved in by the @@ -167,29 +233,82 @@ _invalidate:  	andi	r4,r4,0xfffffc00	/* Mask off the real page number */  	ori	r4,r4,(TLB_WR | TLB_EX)	/* Set the write and execute bits */ +	/* +	 * TLB0 is always used - check if is not zero (r9 stores TLB0 value) +	 * if is use TLB1 value and clear it (r10 stores TLB1 value) +	 */ +	bnei	r9, tlb0_not_zero +	add	r9, r10, r0 +	add	r10, r0, r0 +tlb0_not_zero: + +	/* look at the code below */ +	ori	r30, r0, 0x200 +	andi	r29, r9, 0x100000 +	bneid	r29, 1f +	addik	r30, r30, 0x80 +	andi	r29, r9, 0x400000 +	bneid	r29, 1f +	addik	r30, r30, 0x80 +	andi	r29, r9, 0x1000000 +	bneid	r29, 1f +	addik	r30, r30, 0x80 +1:  	andi	r3,r3,0xfffffc00	/* Mask off the effective page number */ -	ori	r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M)) +	ori	r3,r3,(TLB_VALID) +	or	r3, r3, r30 -	mts     rtlbx,r0		/* TLB slow 0 */ +	/* Load tlb_skip size value which is index to first unused TLB entry */ +	lwi	r11, r0, TOPHYS(tlb_skip) +	mts     rtlbx,r11		/* TLB slow 0 */  	mts	rtlblo,r4		/* Load the data portion of the entry */  	mts	rtlbhi,r3		/* Load the tag portion of the entry */ -	addik	r4, r4, 0x01000000	/* Map next 16 M entries */ -	addik	r3, r3, 0x01000000 +	/* Increase tlb_skip size */ +	addik	r11, r11, 1 +	swi	r11, r0, TOPHYS(tlb_skip) + +	/* TLB1 can be zeroes that's why we not setup it */ +	beqi	r10, jump_over2 + +	/* look at the code below */ +	ori	r30, r0, 0x200 +	andi	r29, r10, 0x100000 +	bneid	r29, 1f +	addik	r30, r30, 0x80 +	andi	r29, r10, 0x400000 +	bneid	r29, 1f +	addik	r30, r30, 0x80 +	andi	r29, r10, 0x1000000 +	bneid	r29, 1f +	addik	r30, r30, 0x80 +1: +	addk	r4, r4, r9	/* previous addr + TLB0 size */ +	addk	r3, r3, r9 + +	andi	r3,r3,0xfffffc00	/* Mask off the effective page number */ +	ori	r3,r3,(TLB_VALID) +	or	r3, r3, r30 -	ori	r6,r0,1			/* TLB slot 1 */ -	mts     rtlbx,r6 +	lwi	r11, r0, TOPHYS(tlb_skip) +	mts     rtlbx, r11		/* r11 is used from TLB0 */  	mts	rtlblo,r4		/* Load the data portion of the entry */  	mts	rtlbhi,r3		/* Load the tag portion of the entry */ +	/* Increase tlb_skip size */ +	addik	r11, r11, 1 +	swi	r11, r0, TOPHYS(tlb_skip) + +jump_over2:  	/*  	 * Load a TLB entry for LMB, since we need access to  	 * the exception vectors, using a 4k real==virtual mapping.  	 */ -	ori	r6,r0,3			/* TLB slot 3 */ -	mts     rtlbx,r6 +	/* Use temporary TLB_ID for LMB - clear this temporary mapping later */ +	ori	r11, r0, MICROBLAZE_LMB_TLB_ID +	mts     rtlbx,r11  	ori	r4,r0,(TLB_WR | TLB_EX)  	ori	r3,r0,(TLB_VALID | TLB_PAGESZ(PAGESZ_4K)) @@ -213,26 +332,26 @@ start_here:  #endif /* CONFIG_MMU */  	/* Initialize small data anchors */ -	la	r13, r0, _KERNEL_SDA_BASE_ -	la	r2, r0, _KERNEL_SDA2_BASE_ +	addik	r13, r0, _KERNEL_SDA_BASE_ +	addik	r2, r0, _KERNEL_SDA2_BASE_  	/* Initialize stack pointer */ -	la	r1, r0, init_thread_union + THREAD_SIZE - 4 +	addik	r1, r0, init_thread_union + THREAD_SIZE - 4  	/* Initialize r31 with current task address */ -	la	r31, r0, init_task +	addik	r31, r0, init_task  	/*  	 * Call platform dependent initialize function.  	 * Please see $(ARCH)/mach-$(SUBARCH)/setup.c for  	 * the function.  	 */ -	la	r9, r0, machine_early_init -	brald	r15, r9 +	addik	r11, r0, machine_early_init +	brald	r15, r11  	nop  #ifndef CONFIG_MMU -	la	r15, r0, machine_halt +	addik	r15, r0, machine_halt  	braid	start_kernel  	nop  #else @@ -257,8 +376,7 @@ start_here:  	/* Load up the kernel context */  kernel_load_context: -	# Keep entry 0 and 1 valid. Entry 3 mapped to LMB can go away. -	ori	r5,r0,3 +	ori	r5, r0, MICROBLAZE_LMB_TLB_ID  	mts     rtlbx,r5  	nop  	mts	rtlbhi,r0 diff --git a/arch/microblaze/kernel/heartbeat.c b/arch/microblaze/kernel/heartbeat.c index 154756f3c69..4643e3ab941 100644 --- a/arch/microblaze/kernel/heartbeat.c +++ b/arch/microblaze/kernel/heartbeat.c @@ -17,7 +17,7 @@  static unsigned int base_addr; -void heartbeat(void) +void microblaze_heartbeat(void)  {  	static unsigned int cnt, period, dist; @@ -42,7 +42,7 @@ void heartbeat(void)  	}  } -void setup_heartbeat(void) +void microblaze_setup_heartbeat(void)  {  	struct device_node *gpio = NULL;  	int *prop; @@ -61,7 +61,7 @@ void setup_heartbeat(void)  	if (gpio) {  		base_addr = be32_to_cpup(of_get_property(gpio, "reg", NULL));  		base_addr = (unsigned long) ioremap(base_addr, PAGE_SIZE); -		printk(KERN_NOTICE "Heartbeat GPIO at 0x%x\n", base_addr); +		pr_notice("Heartbeat GPIO at 0x%x\n", base_addr);  		/* GPIO is configured as output */  		prop = (int *) of_get_property(gpio, "xlnx,is-bidir", NULL); diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index 781195438ee..0b11a4469de 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S @@ -75,8 +75,11 @@  #include <asm/mmu.h>  #include <asm/pgtable.h>  #include <asm/signal.h> +#include <asm/registers.h>  #include <asm/asm-offsets.h> +#undef DEBUG +  /* Helpful Macros */  #define NUM_TO_REG(num)		r ## num @@ -91,7 +94,7 @@  		lwi	r6, r1, PT_R6;		\  		lwi	r11, r1, PT_R11;	\  		lwi	r31, r1, PT_R31;	\ -		lwi	r1, r0, TOPHYS(r0_ram + 0); +		lwi	r1, r1, PT_R1;  #endif /* CONFIG_MMU */  #define LWREG_NOP			\ @@ -144,19 +147,14 @@  		or	r3, r0, NUM_TO_REG (regnum);  	/* Shift right instruction depending on available configuration */ -	#if CONFIG_XILINX_MICROBLAZE0_USE_BARREL > 0 -	#define BSRLI(rD, rA, imm)	\ -		bsrli rD, rA, imm -	#elif CONFIG_XILINX_MICROBLAZE0_USE_DIV > 0 -	#define BSRLI(rD, rA, imm)	\ -		ori rD, r0, (1 << imm);	\ -		idivu rD, rD, rA -	#else -	#define BSRLI(rD, rA, imm) BSRLI ## imm (rD, rA) +	#if CONFIG_XILINX_MICROBLAZE0_USE_BARREL == 0  	/* Only the used shift constants defined here - add more if needed */  	#define BSRLI2(rD, rA)				\  		srl rD, rA;		/* << 1 */	\  		srl rD, rD;		/* << 2 */ +	#define BSRLI4(rD, rA)		\ +		BSRLI2(rD, rA);		\ +		BSRLI2(rD, rD)  	#define BSRLI10(rD, rA)				\  		srl rD, rA;		/* << 1 */	\  		srl rD, rD;		/* << 2 */	\ @@ -171,7 +169,33 @@  	#define BSRLI20(rD, rA)		\  		BSRLI10(rD, rA);	\  		BSRLI10(rD, rD) + +	.macro	bsrli, rD, rA, IMM +	.if (\IMM) == 2 +		BSRLI2(\rD, \rA) +	.elseif (\IMM) == 10 +		BSRLI10(\rD, \rA) +	.elseif (\IMM) == 12 +		BSRLI2(\rD, \rA) +		BSRLI10(\rD, \rD) +	.elseif (\IMM) == 14 +		BSRLI4(\rD, \rA) +		BSRLI10(\rD, \rD) +	.elseif (\IMM) == 20 +		BSRLI20(\rD, \rA) +	.elseif (\IMM) == 24 +		BSRLI4(\rD, \rA) +		BSRLI20(\rD, \rD) +	.elseif (\IMM) == 28 +		BSRLI4(\rD, \rA) +		BSRLI4(\rD, \rD) +		BSRLI20(\rD, \rD) +	.else +	.error "BSRLI shift macros \IMM" +	.endif +	.endm  	#endif +  #endif /* CONFIG_MMU */  .extern other_exception_handler /* Defined in exception.c */ @@ -194,8 +218,8 @@   *      -                            W   S   REG   EXC   *   * - * STACK FRAME STRUCTURE (for NO_MMU) - * --------------------------------- + * STACK FRAME STRUCTURE (for CONFIG_MMU=n) + * ----------------------------------------   *   *      +-------------+         + 0   *      |     MSR     | @@ -210,8 +234,8 @@   *      |      .      |   *      |      .      |   * - * NO_MMU kernel use the same r0_ram pointed space - look to vmlinux.lds.S - * which is used for storing register values - old style was, that value were + * MMU kernel uses the same 'pt_pool_space' pointed space + * which is used for storing register values - noMMu style was, that values were   * stored in stack but in case of failure you lost information about register.   * Currently you can see register value in memory in specific place.   * In compare to with previous solution the speed should be the same. @@ -230,8 +254,22 @@   */  /* wrappers to restore state before coming to entry.S */ -  #ifdef CONFIG_MMU +.section .data +.align 4 +pt_pool_space: +	.space	PT_SIZE + +#ifdef DEBUG +/* Create space for exception counting. */ +.section .data +.global exception_debug_table +.align 4 +exception_debug_table: +	/* Look at exception vector table. There is 32 exceptions * word size */ +	.space	(32 * 4) +#endif /* DEBUG */ +  .section .rodata  .align 4  _MB_HW_ExceptionVectorTable: @@ -291,10 +329,10 @@ _hw_exception_handler:  #ifndef CONFIG_MMU  	addik	r1, r1, -(EX_HANDLER_STACK_SIZ); /* Create stack frame */  #else -	swi	r1, r0, TOPHYS(r0_ram + 0); /* GET_SP */ +	swi	r1, r0, TOPHYS(pt_pool_space + PT_R1); /* GET_SP */  	/* Save date to kernel memory. Here is the problem  	 * when you came from user space */ -	ori	r1, r0, TOPHYS(r0_ram + 28); +	ori	r1, r0, TOPHYS(pt_pool_space);  #endif  	swi	r3, r1, PT_R3  	swi	r4, r1, PT_R4 @@ -333,12 +371,12 @@ not_in_delay_slot:  #ifdef DEBUG  /* counting which exception happen */ -	lwi	r5, r0, 0x200 + TOPHYS(r0_ram) +	lwi	r5, r0, TOPHYS(exception_debug_table)  	addi	r5, r5, 1 -	swi	r5, r0, 0x200 + TOPHYS(r0_ram) -	lwi	r5, r6, 0x200 + TOPHYS(r0_ram) +	swi	r5, r0, TOPHYS(exception_debug_table) +	lwi	r5, r6, TOPHYS(exception_debug_table)  	addi	r5, r5, 1 -	swi	r5, r6, 0x200 + TOPHYS(r0_ram) +	swi	r5, r6, TOPHYS(exception_debug_table)  #endif  /* end */  	/* Load the HW Exception vector */ @@ -478,7 +516,7 @@ ex_lw_tail:  	/* Get the destination register number into r5 */  	lbui	r5, r0, TOPHYS(ex_reg_op);  	/* Form load_word jump table offset (lw_table + (8 * regnum)) */ -	la	r6, r0, TOPHYS(lw_table); +	addik	r6, r0, TOPHYS(lw_table);  	addk	r5, r5, r5;  	addk	r5, r5, r5;  	addk	r5, r5, r5; @@ -489,7 +527,7 @@ ex_sw:  	/* Get the destination register number into r5 */  	lbui	r5, r0, TOPHYS(ex_reg_op);  	/* Form store_word jump table offset (sw_table + (8 * regnum)) */ -	la	r6, r0, TOPHYS(sw_table); +	addik	r6, r0, TOPHYS(sw_table);  	add	r5, r5, r5;  	add	r5, r5, r5;  	add	r5, r5, r5; @@ -569,7 +607,7 @@ ex_handler_done:  		 * tried to access a kernel or read-protected page - always  		 * a SEGV). All other faults here must be stores, so no  		 * need to check ESR_S as well. */ -		andi	r4, r4, 0x800		/* ESR_Z - zone protection */ +		andi	r4, r4, ESR_DIZ		/* ESR_Z - zone protection */  		bnei	r4, ex2  		ori	r4, r0, swapper_pg_dir @@ -583,25 +621,25 @@ ex_handler_done:  		 * tried to access a kernel or read-protected page - always  		 * a SEGV). All other faults here must be stores, so no  		 * need to check ESR_S as well. */ -		andi	r4, r4, 0x800		/* ESR_Z */ +		andi	r4, r4, ESR_DIZ		/* ESR_Z */  		bnei	r4, ex2  		/* get current task address */  		addi	r4 ,CURRENT_TASK, TOPHYS(0);  		lwi	r4, r4, TASK_THREAD+PGDIR  	ex4:  		tophys(r4,r4) -		BSRLI(r5,r3,20)		/* Create L1 (pgdir/pmd) address */ -		andi	r5, r5, 0xffc +		/* Create L1 (pgdir/pmd) address */ +		bsrli	r5, r3, PGDIR_SHIFT - 2 +		andi	r5, r5, PAGE_SIZE - 4  /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */  		or	r4, r4, r5  		lwi	r4, r4, 0		/* Get L1 entry */ -		andi	r5, r4, 0xfffff000 /* Extract L2 (pte) base address */ +		andi	r5, r4, PAGE_MASK /* Extract L2 (pte) base address */  		beqi	r5, ex2			/* Bail if no table */  		tophys(r5,r5) -		BSRLI(r6,r3,10)			/* Compute PTE address */ -		andi	r6, r6, 0xffc -		andi	r5, r5, 0xfffff003 +		bsrli	r6, r3, PTE_SHIFT /* Compute PTE address */ +		andi	r6, r6, PAGE_SIZE - 4  		or	r5, r5, r6  		lwi	r4, r5, 0		/* Get Linux PTE */ @@ -620,7 +658,9 @@ ex_handler_done:  		 * Many of these bits are software only. Bits we don't set  		 * here we (properly should) assume have the appropriate value.  		 */ -		andni	r4, r4, 0x0ce2		/* Make sure 20, 21 are zero */ +/* Ignore memory coherent, just LSB on ZSEL is used + EX/WR */ +		andi	r4, r4, PAGE_MASK | TLB_EX | TLB_WR | \ +						TLB_ZSEL(1) | TLB_ATTR_MASK  		ori	r4, r4, _PAGE_HWEXEC	/* make it executable */  		/* find the TLB index that caused the fault. It has to be here*/ @@ -689,18 +729,18 @@ ex_handler_done:  		lwi	r4, r4, TASK_THREAD+PGDIR  	ex6:  		tophys(r4,r4) -		BSRLI(r5,r3,20)		/* Create L1 (pgdir/pmd) address */ -		andi	r5, r5, 0xffc +		/* Create L1 (pgdir/pmd) address */ +		bsrli	r5, r3, PGDIR_SHIFT - 2 +		andi	r5, r5, PAGE_SIZE - 4  /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */  		or	r4, r4, r5  		lwi	r4, r4, 0		/* Get L1 entry */ -		andi	r5, r4, 0xfffff000 /* Extract L2 (pte) base address */ +		andi	r5, r4, PAGE_MASK /* Extract L2 (pte) base address */  		beqi	r5, ex7			/* Bail if no table */  		tophys(r5,r5) -		BSRLI(r6,r3,10)			/* Compute PTE address */ -		andi	r6, r6, 0xffc -		andi	r5, r5, 0xfffff003 +		bsrli	r6, r3, PTE_SHIFT /* Compute PTE address */ +		andi	r6, r6, PAGE_SIZE - 4  		or	r5, r5, r6  		lwi	r4, r5, 0		/* Get Linux PTE */ @@ -719,7 +759,8 @@ ex_handler_done:  		 * here we (properly should) assume have the appropriate value.  		 */  		brid	finish_tlb_load -		andni	r4, r4, 0x0ce2		/* Make sure 20, 21 are zero */ +		andi	r4, r4, PAGE_MASK | TLB_EX | TLB_WR | \ +						TLB_ZSEL(1) | TLB_ATTR_MASK  	ex7:  		/* The bailout. Restore registers to pre-exception conditions  		 * and call the heavyweights to help us out. @@ -759,18 +800,18 @@ ex_handler_done:  		lwi	r4, r4, TASK_THREAD+PGDIR  	ex9:  		tophys(r4,r4) -		BSRLI(r5,r3,20)		/* Create L1 (pgdir/pmd) address */ -		andi	r5, r5, 0xffc +		/* Create L1 (pgdir/pmd) address */ +		bsrli	r5, r3, PGDIR_SHIFT - 2 +		andi	r5, r5, PAGE_SIZE - 4  /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */  		or	r4, r4, r5  		lwi	r4, r4, 0		/* Get L1 entry */ -		andi	r5, r4, 0xfffff000 /* Extract L2 (pte) base address */ +		andi	r5, r4, PAGE_MASK /* Extract L2 (pte) base address */  		beqi	r5, ex10		/* Bail if no table */  		tophys(r5,r5) -		BSRLI(r6,r3,10)			/* Compute PTE address */ -		andi	r6, r6, 0xffc -		andi	r5, r5, 0xfffff003 +		bsrli	r6, r3, PTE_SHIFT /* Compute PTE address */ +		andi	r6, r6, PAGE_SIZE - 4  		or	r5, r5, r6  		lwi	r4, r5, 0		/* Get Linux PTE */ @@ -789,7 +830,8 @@ ex_handler_done:  		 * here we (properly should) assume have the appropriate value.  		 */  		brid	finish_tlb_load -		andni	r4, r4, 0x0ce2		/* Make sure 20, 21 are zero */ +		andi	r4, r4, PAGE_MASK | TLB_EX | TLB_WR | \ +						TLB_ZSEL(1) | TLB_ATTR_MASK  	ex10:  		/* The bailout. Restore registers to pre-exception conditions  		 * and call the heavyweights to help us out. @@ -808,19 +850,26 @@ ex_handler_done:   *	Upon exit, we reload everything and RFI.   * A common place to load the TLB.   */ +.section .data +.align 4 +.global tlb_skip +	tlb_skip: +		.long	MICROBLAZE_TLB_SKIP  	tlb_index: -		.long	1 /* MS: storing last used tlb index */ +		/* MS: storing last used tlb index */ +		.long	MICROBLAZE_TLB_SIZE/2 +.previous  	finish_tlb_load:  		/* MS: load the last used TLB index. */  		lwi	r5, r0, TOPHYS(tlb_index)  		addik	r5, r5, 1 /* MS: inc tlb_index -> use next one */  /* MS: FIXME this is potential fault, because this is mask not count */ -		andi	r5, r5, (MICROBLAZE_TLB_SIZE-1) +		andi	r5, r5, MICROBLAZE_TLB_SIZE - 1  		ori	r6, r0, 1  		cmp	r31, r5, r6  		blti	r31, ex12 -		addik	r5, r6, 1 +		lwi	r5, r0, TOPHYS(tlb_skip)  	ex12:  		/* MS: save back current TLB index */  		swi	r5, r0, TOPHYS(tlb_index) @@ -835,8 +884,14 @@ ex_handler_done:  		 * set of bits. These are size, valid, E, U0, and ensure  		 * bits 20 and 21 are zero.  		 */ -		andi	r3, r3, 0xfffff000 -		ori	r3, r3, 0x0c0 +		andi	r3, r3, PAGE_MASK +#ifdef CONFIG_MICROBLAZE_64K_PAGES +		ori	r3, r3, TLB_VALID | TLB_PAGESZ(PAGESZ_64K) +#elif CONFIG_MICROBLAZE_16K_PAGES +		ori	r3, r3, TLB_VALID | TLB_PAGESZ(PAGESZ_16K) +#else +		ori	r3, r3, TLB_VALID | TLB_PAGESZ(PAGESZ_4K) +#endif  		mts	rtlbhi,	r3		/* Load TLB HI */  		nop @@ -892,7 +947,7 @@ ex_handler_done:  .ent _unaligned_data_exception  _unaligned_data_exception:  	andi	r8, r3, 0x3E0;	/* Mask and extract the register operand */ -	BSRLI(r8,r8,2);		/* r8 >> 2 = register operand * 8 */ +	bsrli   r8, r8, 2;		/* r8 >> 2 = register operand * 8 */  	andi	r6, r3, 0x400;	/* Extract ESR[S] */  	bneid	r6, ex_sw_vm;  	andi	r6, r3, 0x800;	/* Extract ESR[W] - delay slot */ @@ -900,7 +955,7 @@ ex_lw_vm:  	beqid	r6, ex_lhw_vm;  load1:	lbui	r5, r4, 0;	/* Exception address in r4 - delay slot */  /* Load a word, byte-by-byte from destination address and save it in tmp space*/ -	la	r6, r0, ex_tmp_data_loc_0; +	addik	r6, r0, ex_tmp_data_loc_0;  	sbi	r5, r6, 0;  load2:	lbui	r5, r4, 1;  	sbi	r5, r6, 1; @@ -914,7 +969,7 @@ load4:	lbui	r5, r4, 3;  ex_lhw_vm:  	/* Load a half-word, byte-by-byte from destination address and  	 * save it in tmp space */ -	la	r6, r0, ex_tmp_data_loc_0; +	addik	r6, r0, ex_tmp_data_loc_0;  	sbi	r5, r6, 0;  load5:	lbui	r5, r4, 1;  	sbi	r5, r6, 1; @@ -930,7 +985,7 @@ ex_sw_vm:  	addik	r5, r8, sw_table_vm;  	bra	r5;  ex_sw_tail_vm: -	la	r5, r0, ex_tmp_data_loc_0; +	addik	r5, r0, ex_tmp_data_loc_0;  	beqid	r6, ex_shw_vm;  	swi	r3, r5, 0;	/* Get the word - delay slot */  	/* Store the word, byte-by-byte into destination address */ @@ -945,11 +1000,20 @@ store3:	sbi	r3, r4, 2;  store4:	sbi	r3, r4, 3;	/* Delay slot */  ex_shw_vm:  	/* Store the lower half-word, byte-by-byte into destination address */ +#ifdef __MICROBLAZEEL__ +	lbui	r3, r5, 0; +store5:	sbi	r3, r4, 0; +	lbui	r3, r5, 1; +	brid	ret_from_exc; +store6:	sbi	r3, r4, 1;	/* Delay slot */ +#else  	lbui	r3, r5, 2;  store5:	sbi	r3, r4, 0;  	lbui	r3, r5, 3;  	brid	ret_from_exc;  store6:	sbi	r3, r4, 1;	/* Delay slot */ +#endif +  ex_sw_end_vm:			/* Exception handling of store word, ends. */  /* We have to prevent cases that get/put_user macros get unaligned pointer @@ -964,7 +1028,7 @@ ex_unaligned_fixup:  	addik	r7, r0, SIGSEGV  	/* call bad_page_fault for finding aligned fixup, fixup address is saved  	 * in PT_PC which is used as return address from exception */ -	la	r15, r0, ret_from_exc-8 /* setup return address */ +	addik	r15, r0, ret_from_exc-8 /* setup return address */  	brid	bad_page_fault  	nop @@ -1092,23 +1156,23 @@ lw_r10_vm:	R3_TO_LWREG_VM_V	(10);  lw_r11_vm:	R3_TO_LWREG_VM_V	(11);  lw_r12_vm:	R3_TO_LWREG_VM_V	(12);  lw_r13_vm:	R3_TO_LWREG_VM_V	(13); -lw_r14_vm:	R3_TO_LWREG_VM		(14); +lw_r14_vm:	R3_TO_LWREG_VM_V	(14);  lw_r15_vm:	R3_TO_LWREG_VM_V	(15); -lw_r16_vm:	R3_TO_LWREG_VM		(16); +lw_r16_vm:	R3_TO_LWREG_VM_V	(16);  lw_r17_vm:	R3_TO_LWREG_VM_V	(17);  lw_r18_vm:	R3_TO_LWREG_VM_V	(18); -lw_r19_vm:	R3_TO_LWREG_VM		(19); -lw_r20_vm:	R3_TO_LWREG_VM		(20); -lw_r21_vm:	R3_TO_LWREG_VM		(21); -lw_r22_vm:	R3_TO_LWREG_VM		(22); -lw_r23_vm:	R3_TO_LWREG_VM		(23); -lw_r24_vm:	R3_TO_LWREG_VM		(24); -lw_r25_vm:	R3_TO_LWREG_VM		(25); -lw_r26_vm:	R3_TO_LWREG_VM		(26); -lw_r27_vm:	R3_TO_LWREG_VM		(27); -lw_r28_vm:	R3_TO_LWREG_VM		(28); -lw_r29_vm:	R3_TO_LWREG_VM		(29); -lw_r30_vm:	R3_TO_LWREG_VM		(30); +lw_r19_vm:	R3_TO_LWREG_VM_V	(19); +lw_r20_vm:	R3_TO_LWREG_VM_V	(20); +lw_r21_vm:	R3_TO_LWREG_VM_V	(21); +lw_r22_vm:	R3_TO_LWREG_VM_V	(22); +lw_r23_vm:	R3_TO_LWREG_VM_V	(23); +lw_r24_vm:	R3_TO_LWREG_VM_V	(24); +lw_r25_vm:	R3_TO_LWREG_VM_V	(25); +lw_r26_vm:	R3_TO_LWREG_VM_V	(26); +lw_r27_vm:	R3_TO_LWREG_VM_V	(27); +lw_r28_vm:	R3_TO_LWREG_VM_V	(28); +lw_r29_vm:	R3_TO_LWREG_VM_V	(29); +lw_r30_vm:	R3_TO_LWREG_VM_V	(30);  lw_r31_vm:	R3_TO_LWREG_VM_V	(31);  sw_table_vm: @@ -1126,23 +1190,23 @@ sw_r10_vm:	SWREG_TO_R3_VM_V	(10);  sw_r11_vm:	SWREG_TO_R3_VM_V	(11);  sw_r12_vm:	SWREG_TO_R3_VM_V	(12);  sw_r13_vm:	SWREG_TO_R3_VM_V	(13); -sw_r14_vm:	SWREG_TO_R3_VM		(14); +sw_r14_vm:	SWREG_TO_R3_VM_V	(14);  sw_r15_vm:	SWREG_TO_R3_VM_V	(15); -sw_r16_vm:	SWREG_TO_R3_VM		(16); +sw_r16_vm:	SWREG_TO_R3_VM_V	(16);  sw_r17_vm:	SWREG_TO_R3_VM_V	(17);  sw_r18_vm:	SWREG_TO_R3_VM_V	(18); -sw_r19_vm:	SWREG_TO_R3_VM		(19); -sw_r20_vm:	SWREG_TO_R3_VM		(20); -sw_r21_vm:	SWREG_TO_R3_VM		(21); -sw_r22_vm:	SWREG_TO_R3_VM		(22); -sw_r23_vm:	SWREG_TO_R3_VM		(23); -sw_r24_vm:	SWREG_TO_R3_VM		(24); -sw_r25_vm:	SWREG_TO_R3_VM		(25); -sw_r26_vm:	SWREG_TO_R3_VM		(26); -sw_r27_vm:	SWREG_TO_R3_VM		(27); -sw_r28_vm:	SWREG_TO_R3_VM		(28); -sw_r29_vm:	SWREG_TO_R3_VM		(29); -sw_r30_vm:	SWREG_TO_R3_VM		(30); +sw_r19_vm:	SWREG_TO_R3_VM_V	(19); +sw_r20_vm:	SWREG_TO_R3_VM_V	(20); +sw_r21_vm:	SWREG_TO_R3_VM_V	(21); +sw_r22_vm:	SWREG_TO_R3_VM_V	(22); +sw_r23_vm:	SWREG_TO_R3_VM_V	(23); +sw_r24_vm:	SWREG_TO_R3_VM_V	(24); +sw_r25_vm:	SWREG_TO_R3_VM_V	(25); +sw_r26_vm:	SWREG_TO_R3_VM_V	(26); +sw_r27_vm:	SWREG_TO_R3_VM_V	(27); +sw_r28_vm:	SWREG_TO_R3_VM_V	(28); +sw_r29_vm:	SWREG_TO_R3_VM_V	(29); +sw_r30_vm:	SWREG_TO_R3_VM_V	(30);  sw_r31_vm:	SWREG_TO_R3_VM_V	(31);  #endif /* CONFIG_MMU */ diff --git a/arch/microblaze/kernel/init_task.c b/arch/microblaze/kernel/init_task.c deleted file mode 100644 index b5d711f94ff..00000000000 --- a/arch/microblaze/kernel/init_task.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2009 Michal Simek <monstr@monstr.eu> - * Copyright (C) 2009 PetaLogix - * Copyright (C) 2006 Atmark Techno, Inc. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/init_task.h> -#include <linux/fs.h> -#include <linux/mqueue.h> - -#include <asm/pgtable.h> - -static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); - -union thread_union init_thread_union __init_task_data = -	{ INIT_THREAD_INFO(init_task) }; - -struct task_struct init_task = INIT_TASK(init_task); -EXPORT_SYMBOL(init_task); diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c index d61ea33aff7..15c7c12ea0e 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c @@ -1,5 +1,6 @@  /* - * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2007-2013 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2012-2013 Xilinx, Inc.   * Copyright (C) 2007-2009 PetaLogix   * Copyright (C) 2006 Atmark Techno, Inc.   * @@ -8,24 +9,15 @@   * for more details.   */ -#include <linux/init.h> +#include <linux/irqdomain.h>  #include <linux/irq.h> -#include <asm/page.h> +#include <linux/of_address.h>  #include <linux/io.h>  #include <linux/bug.h> -#include <asm/prom.h> -#include <asm/irq.h> +#include "../../drivers/irqchip/irqchip.h" -#ifdef CONFIG_SELFMOD_INTC -#include <asm/selfmod.h> -#define INTC_BASE	BARRIER_BASE_ADDR -#else -static unsigned int intc_baseaddr; -#define INTC_BASE	intc_baseaddr -#endif - -unsigned int nr_irq; +static void __iomem *intc_baseaddr;  /* No one else should require these constants, so define them locally here. */  #define ISR 0x00			/* Interrupt Status Register */ @@ -40,143 +32,166 @@ unsigned int nr_irq;  #define MER_ME (1<<0)  #define MER_HIE (1<<1) -static void intc_enable_or_unmask(unsigned int irq) +static unsigned int (*read_fn)(void __iomem *); +static void (*write_fn)(u32, void __iomem *); + +static void intc_write32(u32 val, void __iomem *addr) +{ +	iowrite32(val, addr); +} + +static unsigned int intc_read32(void __iomem *addr) +{ +	return ioread32(addr); +} + +static void intc_write32_be(u32 val, void __iomem *addr) +{ +	iowrite32be(val, addr); +} + +static unsigned int intc_read32_be(void __iomem *addr)  { -	unsigned long mask = 1 << irq; -	pr_debug("enable_or_unmask: %d\n", irq); -	out_be32(INTC_BASE + SIE, mask); +	return ioread32be(addr); +} + +static void intc_enable_or_unmask(struct irq_data *d) +{ +	unsigned long mask = 1 << d->hwirq; + +	pr_debug("enable_or_unmask: %ld\n", d->hwirq);  	/* ack level irqs because they can't be acked during  	 * ack function since the handle_level_irq function  	 * acks the irq before calling the interrupt handler  	 */ -	if (irq_desc[irq].status & IRQ_LEVEL) -		out_be32(INTC_BASE + IAR, mask); -} +	if (irqd_is_level_type(d)) +		write_fn(mask, intc_baseaddr + IAR); -static void intc_disable_or_mask(unsigned int irq) -{ -	pr_debug("disable: %d\n", irq); -	out_be32(INTC_BASE + CIE, 1 << irq); +	write_fn(mask, intc_baseaddr + SIE);  } -static void intc_ack(unsigned int irq) +static void intc_disable_or_mask(struct irq_data *d)  { -	pr_debug("ack: %d\n", irq); -	out_be32(INTC_BASE + IAR, 1 << irq); +	pr_debug("disable: %ld\n", d->hwirq); +	write_fn(1 << d->hwirq, intc_baseaddr + CIE);  } -static void intc_mask_ack(unsigned int irq) +static void intc_ack(struct irq_data *d)  { -	unsigned long mask = 1 << irq; -	pr_debug("disable_and_ack: %d\n", irq); -	out_be32(INTC_BASE + CIE, mask); -	out_be32(INTC_BASE + IAR, mask); +	pr_debug("ack: %ld\n", d->hwirq); +	write_fn(1 << d->hwirq, intc_baseaddr + IAR);  } -static void intc_end(unsigned int irq) +static void intc_mask_ack(struct irq_data *d)  { -	unsigned long mask = 1 << irq; -	pr_debug("end: %d\n", irq); -	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { -		out_be32(INTC_BASE + SIE, mask); -		/* ack level sensitive intr */ -		if (irq_desc[irq].status & IRQ_LEVEL) -			out_be32(INTC_BASE + IAR, mask); -	} +	unsigned long mask = 1 << d->hwirq; + +	pr_debug("disable_and_ack: %ld\n", d->hwirq); +	write_fn(mask, intc_baseaddr + CIE); +	write_fn(mask, intc_baseaddr + IAR);  }  static struct irq_chip intc_dev = {  	.name = "Xilinx INTC", -	.unmask = intc_enable_or_unmask, -	.mask = intc_disable_or_mask, -	.ack = intc_ack, -	.mask_ack = intc_mask_ack, -	.end = intc_end, +	.irq_unmask = intc_enable_or_unmask, +	.irq_mask = intc_disable_or_mask, +	.irq_ack = intc_ack, +	.irq_mask_ack = intc_mask_ack,  }; -unsigned int get_irq(struct pt_regs *regs) +static struct irq_domain *root_domain; + +unsigned int get_irq(void)  { -	int irq; +	unsigned int hwirq, irq = -1; -	/* -	 * NOTE: This function is the one that needs to be improved in -	 * order to handle multiple interrupt controllers. It currently -	 * is hardcoded to check for interrupts only on the first INTC. -	 */ -	irq = in_be32(INTC_BASE + IVR); -	pr_debug("get_irq: %d\n", irq); +	hwirq = read_fn(intc_baseaddr + IVR); +	if (hwirq != -1U) +		irq = irq_find_mapping(root_domain, hwirq); + +	pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq);  	return irq;  } -void __init init_IRQ(void) +static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) +{ +	u32 intr_mask = (u32)d->host_data; + +	if (intr_mask & (1 << hw)) { +		irq_set_chip_and_handler_name(irq, &intc_dev, +						handle_edge_irq, "edge"); +		irq_clear_status_flags(irq, IRQ_LEVEL); +	} else { +		irq_set_chip_and_handler_name(irq, &intc_dev, +						handle_level_irq, "level"); +		irq_set_status_flags(irq, IRQ_LEVEL); +	} +	return 0; +} + +static const struct irq_domain_ops xintc_irq_domain_ops = { +	.xlate = irq_domain_xlate_onetwocell, +	.map = xintc_map, +}; + +static int __init xilinx_intc_of_init(struct device_node *intc, +					     struct device_node *parent)  { -	u32 i, j, intr_type; -	struct device_node *intc = NULL; -#ifdef CONFIG_SELFMOD_INTC -	unsigned int intc_baseaddr = 0; -	static int arr_func[] = { -				(int)&get_irq, -				(int)&intc_enable_or_unmask, -				(int)&intc_disable_or_mask, -				(int)&intc_mask_ack, -				(int)&intc_ack, -				(int)&intc_end, -				0 -			}; -#endif -	const char * const intc_list[] = { -				"xlnx,xps-intc-1.00.a", -				NULL -			}; - -	for (j = 0; intc_list[j] != NULL; j++) { -		intc = of_find_compatible_node(NULL, NULL, intc_list[j]); -		if (intc) -			break; +	u32 nr_irq, intr_mask; +	int ret; + +	intc_baseaddr = of_iomap(intc, 0); +	BUG_ON(!intc_baseaddr); + +	ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq); +	if (ret < 0) { +		pr_err("%s: unable to read xlnx,num-intr-inputs\n", __func__); +		return -EINVAL; +	} + +	ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &intr_mask); +	if (ret < 0) { +		pr_err("%s: unable to read xlnx,kind-of-intr\n", __func__); +		return -EINVAL;  	} -	BUG_ON(!intc); - -	intc_baseaddr = be32_to_cpup(of_get_property(intc, -								"reg", NULL)); -	intc_baseaddr = (unsigned long) ioremap(intc_baseaddr, PAGE_SIZE); -	nr_irq = be32_to_cpup(of_get_property(intc, -						"xlnx,num-intr-inputs", NULL)); - -	intr_type = -		be32_to_cpup(of_get_property(intc, -						"xlnx,kind-of-intr", NULL)); -	if (intr_type >= (1 << (nr_irq + 1))) -		printk(KERN_INFO " ERROR: Mismatch in kind-of-intr param\n"); - -#ifdef CONFIG_SELFMOD_INTC -	selfmod_function((int *) arr_func, intc_baseaddr); -#endif -	printk(KERN_INFO "%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n", -		intc_list[j], intc_baseaddr, nr_irq, intr_type); + +	if (intr_mask > (u32)((1ULL << nr_irq) - 1)) +		pr_info(" ERROR: Mismatch in kind-of-intr param\n"); + +	pr_info("%s: num_irq=%d, edge=0x%x\n", +		intc->full_name, nr_irq, intr_mask); + +	write_fn = intc_write32; +	read_fn = intc_read32;  	/*  	 * Disable all external interrupts until they are  	 * explicity requested.  	 */ -	out_be32(intc_baseaddr + IER, 0); +	write_fn(0, intc_baseaddr + IER);  	/* Acknowledge any pending interrupts just in case. */ -	out_be32(intc_baseaddr + IAR, 0xffffffff); +	write_fn(0xffffffff, intc_baseaddr + IAR);  	/* Turn on the Master Enable. */ -	out_be32(intc_baseaddr + MER, MER_HIE | MER_ME); - -	for (i = 0; i < nr_irq; ++i) { -		if (intr_type & (0x00000001 << i)) { -			set_irq_chip_and_handler_name(i, &intc_dev, -				handle_edge_irq, intc_dev.name); -			irq_desc[i].status &= ~IRQ_LEVEL; -		} else { -			set_irq_chip_and_handler_name(i, &intc_dev, -				handle_level_irq, intc_dev.name); -			irq_desc[i].status |= IRQ_LEVEL; -		} +	write_fn(MER_HIE | MER_ME, intc_baseaddr + MER); +	if (!(read_fn(intc_baseaddr + MER) & (MER_HIE | MER_ME))) { +		write_fn = intc_write32_be; +		read_fn = intc_read32_be; +		write_fn(MER_HIE | MER_ME, intc_baseaddr + MER);  	} + +	/* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm +	 * lazy and Michal can clean it up to something nicer when he tests +	 * and commits this patch.  ~~gcl */ +	root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops, +							(void *)intr_mask); + +	irq_set_default_host(root_domain); + +	return 0;  } + +IRQCHIP_DECLARE(xilinx_intc, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init); diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c index a9345fb4906..11e24de91aa 100644 --- a/arch/microblaze/kernel/irq.c +++ b/arch/microblaze/kernel/irq.c @@ -17,10 +17,9 @@  #include <linux/seq_file.h>  #include <linux/kernel_stat.h>  #include <linux/irq.h> +#include <linux/irqchip.h>  #include <linux/of_irq.h> -#include <asm/prom.h> -  static u32 concurrent_irq;  void __irq_entry do_IRQ(struct pt_regs *regs) @@ -30,12 +29,12 @@ void __irq_entry do_IRQ(struct pt_regs *regs)  	trace_hardirqs_off();  	irq_enter(); -	irq = get_irq(regs); +	irq = get_irq();  next_irq: -	BUG_ON(irq == -1U); +	BUG_ON(!irq);  	generic_handle_irq(irq); -	irq = get_irq(regs); +	irq = get_irq();  	if (irq != -1U) {  		pr_debug("next irq: %d\n", irq);  		++concurrent_irq; @@ -47,57 +46,8 @@ next_irq:  	trace_hardirqs_on();  } -int show_interrupts(struct seq_file *p, void *v) -{ -	int i = *(loff_t *) v, j; -	struct irqaction *action; -	unsigned long flags; - -	if (i == 0) { -		seq_printf(p, "		"); -		for_each_online_cpu(j) -			seq_printf(p, "CPU%-8d", j); -		seq_putc(p, '\n'); -	} - -	if (i < nr_irq) { -		raw_spin_lock_irqsave(&irq_desc[i].lock, flags); -		action = irq_desc[i].action; -		if (!action) -			goto skip; -		seq_printf(p, "%3d: ", i); -#ifndef CONFIG_SMP -		seq_printf(p, "%10u ", kstat_irqs(i)); -#else -		for_each_online_cpu(j) -			seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); -#endif -		seq_printf(p, " %8s", irq_desc[i].status & -					IRQ_LEVEL ? "level" : "edge"); -		seq_printf(p, " %8s", irq_desc[i].chip->name); -		seq_printf(p, "  %s", action->name); - -		for (action = action->next; action; action = action->next) -			seq_printf(p, ", %s", action->name); - -		seq_putc(p, '\n'); -skip: -		raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); -	} -	return 0; -} - -/* MS: There is no any advance mapping mechanism. We are using simple 32bit -  intc without any cascades or any connection that's why mapping is 1:1 */ -unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq) -{ -	return hwirq; -} -EXPORT_SYMBOL_GPL(irq_create_mapping); - -unsigned int irq_create_of_mapping(struct device_node *controller, -				   const u32 *intspec, unsigned int intsize) +void __init init_IRQ(void)  { -	return intspec[0]; +	/* process the entire interrupt tree in one go */ +	irqchip_init();  } -EXPORT_SYMBOL_GPL(irq_create_of_mapping); diff --git a/arch/microblaze/kernel/mcount.S b/arch/microblaze/kernel/mcount.S index e7eaa7a8cbd..fc1e1322ce4 100644 --- a/arch/microblaze/kernel/mcount.S +++ b/arch/microblaze/kernel/mcount.S @@ -138,7 +138,7 @@ NOALIGN_ENTRY(ftrace_call)  #endif /* CONFIG_DYNAMIC_FTRACE */  /* static normal trace */  	lwi	r6, r1, 120; /* MS: load parent addr */ -	addik	r5, r15, 0; /* MS: load current function addr */ +	addik	r5, r15, -4; /* MS: load current function addr */  	/* MS: here is dependency on previous code */  	brald	r15, r20; /* MS: jump to ftrace handler */  	nop; diff --git a/arch/microblaze/kernel/microblaze_ksyms.c b/arch/microblaze/kernel/microblaze_ksyms.c index 5cb03417400..9f1d02c4c5c 100644 --- a/arch/microblaze/kernel/microblaze_ksyms.c +++ b/arch/microblaze/kernel/microblaze_ksyms.c @@ -7,7 +7,7 @@   * published by the Free Software Foundation.   */ -#include <linux/module.h> +#include <linux/export.h>  #include <linux/string.h>  #include <linux/cryptohash.h>  #include <linux/delay.h> @@ -18,12 +18,9 @@  #include <asm/cacheflush.h>  #include <linux/io.h>  #include <asm/page.h> -#include <asm/system.h>  #include <linux/ftrace.h>  #include <linux/uaccess.h> -extern char *_ebss; -EXPORT_SYMBOL_GPL(_ebss);  #ifdef CONFIG_FUNCTION_TRACER  extern void _mcount(void);  EXPORT_SYMBOL(_mcount); @@ -45,3 +42,14 @@ EXPORT_SYMBOL(empty_zero_page);  #endif  EXPORT_SYMBOL(mbc); + +extern void __divsi3(void); +EXPORT_SYMBOL(__divsi3); +extern void __modsi3(void); +EXPORT_SYMBOL(__modsi3); +extern void __mulsi3(void); +EXPORT_SYMBOL(__mulsi3); +extern void __udivsi3(void); +EXPORT_SYMBOL(__udivsi3); +extern void __umodsi3(void); +EXPORT_SYMBOL(__umodsi3); diff --git a/arch/microblaze/kernel/misc.S b/arch/microblaze/kernel/misc.S index 206da3da361..1dafddeb8a0 100644 --- a/arch/microblaze/kernel/misc.S +++ b/arch/microblaze/kernel/misc.S @@ -29,16 +29,16 @@  .type  _tlbia, @function  .align 4;  _tlbia: -	addik	r12, r0, MICROBLAZE_TLB_SIZE - 1 /* flush all entries (63 - 3) */ +	lwi	r12, r0, tlb_skip;  	/* isync */  _tlbia_1:  	mts	rtlbx, r12  	nop  	mts	rtlbhi, r0 /* flush: ensure V is clear */  	nop -	addik	r11, r12, -2 +	rsubi	r11, r12, MICROBLAZE_TLB_SIZE - 1  	bneid	r11, _tlbia_1 /* loop for all entries */ -	addik	r12, r12, -1 +	addik	r12, r12, 1  	/* sync */  	rtsd	r15, 8  	nop @@ -75,7 +75,7 @@ early_console_reg_tlb_alloc:  	 * Load a TLB entry for the UART, so that microblaze_progress() can use  	 * the UARTs nice and early.  We use a 4k real==virtual mapping.  	 */ -	ori	r4, r0, MICROBLAZE_TLB_SIZE - 1 +	lwi	r4, r0, tlb_skip  	mts	rtlbx, r4 /* TLB slot 63 */  	or	r4,r5,r0 @@ -89,6 +89,11 @@ early_console_reg_tlb_alloc:  	nop  	mts	rtlbhi,r5 /* Load the tag portion of the entry */  	nop + +	lwi	r5, r0, tlb_skip +	addik	r5, r5, 1 +	swi	r5, r0, tlb_skip +  	rtsd	r15, 8  	nop diff --git a/arch/microblaze/kernel/module.c b/arch/microblaze/kernel/module.c index 0e73f660654..182e6be856c 100644 --- a/arch/microblaze/kernel/module.c +++ b/arch/microblaze/kernel/module.c @@ -7,7 +7,7 @@   * published by the Free Software Foundation.   */ -#include <linux/module.h> +#include <linux/export.h>  #include <linux/moduleloader.h>  #include <linux/kernel.h>  #include <linux/elf.h> @@ -18,37 +18,6 @@  #include <asm/pgtable.h>  #include <asm/cacheflush.h> -void *module_alloc(unsigned long size) -{ -	void *ret; -	ret = (size == 0) ? NULL : vmalloc(size); -	pr_debug("module_alloc (%08lx@%08lx)\n", size, (unsigned long int)ret); -	return ret; -} - -void module_free(struct module *module, void *region) -{ -	pr_debug("module_free(%s,%08lx)\n", module->name, -					(unsigned long)region); -	vfree(region); -} - -int module_frob_arch_sections(Elf_Ehdr *hdr, -				Elf_Shdr *sechdrs, -				char *secstrings, -				struct module *mod) -{ -	return 0; -} - -int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, -	unsigned int symindex, unsigned int relsec, struct module *module) -{ -	printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", -		module->name); -	return -ENOEXEC; -} -  int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,  	unsigned int symindex, unsigned int relsec, struct module *module)  { @@ -131,7 +100,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,  			break;  		case R_MICROBLAZE_64_NONE: -			pr_debug("R_MICROBLAZE_NONE\n"); +			pr_debug("R_MICROBLAZE_64_NONE\n");  			break;  		case R_MICROBLAZE_NONE: @@ -139,8 +108,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,  			break;  		default: -			printk(KERN_ERR "module %s: " -				"Unknown relocation: %u\n", +			pr_err("module %s: Unknown relocation: %u\n",  				module->name,  				ELF32_R_TYPE(rela[i].r_info));  			return -ENOEXEC; @@ -155,7 +123,3 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,  	flush_dcache();  	return 0;  } - -void module_arch_cleanup(struct module *mod) -{ -} diff --git a/arch/microblaze/kernel/platform.c b/arch/microblaze/kernel/platform.c new file mode 100644 index 00000000000..b9529caa507 --- /dev/null +++ b/arch/microblaze/kernel/platform.c @@ -0,0 +1,30 @@ +/* + * Copyright 2008 Michal Simek <monstr@monstr.eu> + * + * based on virtex.c file + * + * Copyright 2007 Secret Lab Technologies Ltd. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/init.h> +#include <linux/of_platform.h> +#include <asm/prom.h> +#include <asm/setup.h> + +static struct of_device_id xilinx_of_bus_ids[] __initdata = { +	{ .compatible = "simple-bus", }, +	{ .compatible = "xlnx,compound", }, +	{} +}; + +static int __init microblaze_device_probe(void) +{ +	of_platform_bus_probe(NULL, xilinx_of_bus_ids, NULL); +	of_platform_reset_gpio_probe(); +	return 0; +} +device_initcall(microblaze_device_probe); diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index ba7c4b16ed3..b2dd37196b3 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c @@ -8,158 +8,82 @@   * for more details.   */ -#include <linux/module.h> +#include <linux/cpu.h> +#include <linux/export.h>  #include <linux/sched.h>  #include <linux/pm.h>  #include <linux/tick.h>  #include <linux/bitops.h> -#include <asm/system.h> +#include <linux/ptrace.h>  #include <asm/pgalloc.h> -#include <asm/uaccess.h> /* for USER_DS macros */ +#include <linux/uaccess.h> /* for USER_DS macros */  #include <asm/cacheflush.h>  void show_regs(struct pt_regs *regs)  { -	printk(KERN_INFO " Registers dump: mode=%X\r\n", regs->pt_mode); -	printk(KERN_INFO " r1=%08lX, r2=%08lX, r3=%08lX, r4=%08lX\n", +	show_regs_print_info(KERN_INFO); + +	pr_info(" Registers dump: mode=%X\r\n", regs->pt_mode); +	pr_info(" r1=%08lX, r2=%08lX, r3=%08lX, r4=%08lX\n",  				regs->r1, regs->r2, regs->r3, regs->r4); -	printk(KERN_INFO " r5=%08lX, r6=%08lX, r7=%08lX, r8=%08lX\n", +	pr_info(" r5=%08lX, r6=%08lX, r7=%08lX, r8=%08lX\n",  				regs->r5, regs->r6, regs->r7, regs->r8); -	printk(KERN_INFO " r9=%08lX, r10=%08lX, r11=%08lX, r12=%08lX\n", +	pr_info(" r9=%08lX, r10=%08lX, r11=%08lX, r12=%08lX\n",  				regs->r9, regs->r10, regs->r11, regs->r12); -	printk(KERN_INFO " r13=%08lX, r14=%08lX, r15=%08lX, r16=%08lX\n", +	pr_info(" r13=%08lX, r14=%08lX, r15=%08lX, r16=%08lX\n",  				regs->r13, regs->r14, regs->r15, regs->r16); -	printk(KERN_INFO " r17=%08lX, r18=%08lX, r19=%08lX, r20=%08lX\n", +	pr_info(" r17=%08lX, r18=%08lX, r19=%08lX, r20=%08lX\n",  				regs->r17, regs->r18, regs->r19, regs->r20); -	printk(KERN_INFO " r21=%08lX, r22=%08lX, r23=%08lX, r24=%08lX\n", +	pr_info(" r21=%08lX, r22=%08lX, r23=%08lX, r24=%08lX\n",  				regs->r21, regs->r22, regs->r23, regs->r24); -	printk(KERN_INFO " r25=%08lX, r26=%08lX, r27=%08lX, r28=%08lX\n", +	pr_info(" r25=%08lX, r26=%08lX, r27=%08lX, r28=%08lX\n",  				regs->r25, regs->r26, regs->r27, regs->r28); -	printk(KERN_INFO " r29=%08lX, r30=%08lX, r31=%08lX, rPC=%08lX\n", +	pr_info(" r29=%08lX, r30=%08lX, r31=%08lX, rPC=%08lX\n",  				regs->r29, regs->r30, regs->r31, regs->pc); -	printk(KERN_INFO " msr=%08lX, ear=%08lX, esr=%08lX, fsr=%08lX\n", +	pr_info(" msr=%08lX, ear=%08lX, esr=%08lX, fsr=%08lX\n",  				regs->msr, regs->ear, regs->esr, regs->fsr);  } -void (*pm_idle)(void);  void (*pm_power_off)(void) = NULL;  EXPORT_SYMBOL(pm_power_off); -static int hlt_counter = 1; - -void disable_hlt(void) -{ -	hlt_counter++; -} -EXPORT_SYMBOL(disable_hlt); - -void enable_hlt(void) -{ -	hlt_counter--; -} -EXPORT_SYMBOL(enable_hlt); - -static int __init nohlt_setup(char *__unused) -{ -	hlt_counter = 1; -	return 1; -} -__setup("nohlt", nohlt_setup); - -static int __init hlt_setup(char *__unused) -{ -	hlt_counter = 0; -	return 1; -} -__setup("hlt", hlt_setup); - -void default_idle(void) -{ -	if (likely(hlt_counter)) { -		local_irq_disable(); -		stop_critical_timings(); -		cpu_relax(); -		start_critical_timings(); -		local_irq_enable(); -	} else { -		clear_thread_flag(TIF_POLLING_NRFLAG); -		smp_mb__after_clear_bit(); -		local_irq_disable(); -		while (!need_resched()) -			cpu_sleep(); -		local_irq_enable(); -		set_thread_flag(TIF_POLLING_NRFLAG); -	} -} - -void cpu_idle(void) -{ -	set_thread_flag(TIF_POLLING_NRFLAG); - -	/* endless idle loop with no priority at all */ -	while (1) { -		void (*idle)(void) = pm_idle; - -		if (!idle) -			idle = default_idle; - -		tick_nohz_stop_sched_tick(1); -		while (!need_resched()) -			idle(); -		tick_nohz_restart_sched_tick(); - -		preempt_enable_no_resched(); -		schedule(); -		preempt_disable(); -		check_pgt_cache(); -	} -} -  void flush_thread(void)  {  }  int copy_thread(unsigned long clone_flags, unsigned long usp, -		unsigned long unused, -		struct task_struct *p, struct pt_regs *regs) +		unsigned long arg, struct task_struct *p)  {  	struct pt_regs *childregs = task_pt_regs(p);  	struct thread_info *ti = task_thread_info(p); -	*childregs = *regs; -	if (user_mode(regs)) +	if (unlikely(p->flags & PF_KTHREAD)) { +		/* if we're creating a new kernel thread then just zeroing all +		 * the registers. That's OK for a brand new thread.*/ +		memset(childregs, 0, sizeof(struct pt_regs)); +		memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); +		ti->cpu_context.r1  = (unsigned long)childregs; +		ti->cpu_context.r20 = (unsigned long)usp; /* fn */ +		ti->cpu_context.r19 = (unsigned long)arg; +		childregs->pt_mode = 1; +		local_save_flags(childregs->msr); +#ifdef CONFIG_MMU +		ti->cpu_context.msr = childregs->msr & ~MSR_IE; +#endif +		ti->cpu_context.r15 = (unsigned long)ret_from_kernel_thread - 8; +		return 0; +	} +	*childregs = *current_pt_regs(); +	if (usp)  		childregs->r1 = usp; -	else -		childregs->r1 = ((unsigned long) ti) + THREAD_SIZE; -#ifndef CONFIG_MMU  	memset(&ti->cpu_context, 0, sizeof(struct cpu_context));  	ti->cpu_context.r1 = (unsigned long)childregs; +#ifndef CONFIG_MMU  	ti->cpu_context.msr = (unsigned long)childregs->msr;  #else +	childregs->msr |= MSR_UMS; -	/* if creating a kernel thread then update the current reg (we don't -	 * want to use the parent's value when restoring by POP_STATE) */ -	if (kernel_mode(regs)) -		/* save new current on stack to use POP_STATE */ -		childregs->CURRENT_TASK = (unsigned long)p; -	/* if returning to user then use the parent's value of this register */ - -	/* if we're creating a new kernel thread then just zeroing all -	 * the registers. That's OK for a brand new thread.*/ -	/* Pls. note that some of them will be restored in POP_STATE */ -	if (kernel_mode(regs)) -		memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); -	/* if this thread is created for fork/vfork/clone, then we want to -	 * restore all the parent's context */ -	/* in addition to the registers which will be restored by POP_STATE */ -	else { -		ti->cpu_context = *(struct cpu_context *)regs; -		childregs->msr |= MSR_UMS; -	} - -	/* FIXME STATE_SAVE_PT_OFFSET; */ -	ti->cpu_context.r1  = (unsigned long)childregs - STATE_SAVE_ARG_SPACE;  	/* we should consider the fact that childregs is a copy of the parent  	 * regs which were saved immediately after entering the kernel state  	 * before enabling VM. This MSR will be restored in switch_to and @@ -170,7 +94,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,  	 * excepting for VM and UMS  	 * don't touch UMS , CARRY and cache bits  	 * right now MSR is a copy of parent one */ -	childregs->msr |= MSR_BIP;  	childregs->msr &= ~MSR_EIP;  	childregs->msr |= MSR_IE;  	childregs->msr &= ~MSR_VM; @@ -179,11 +102,16 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,  	ti->cpu_context.msr = (childregs->msr|MSR_VM);  	ti->cpu_context.msr &= ~MSR_UMS; /* switch_to to kernel mode */ +	ti->cpu_context.msr &= ~MSR_IE;  #endif  	ti->cpu_context.r15 = (unsigned long)ret_from_fork - 8; +	/* +	 *  r21 is the thread reg, r10 is 6th arg to clone +	 *  which contains TLS area +	 */  	if (clone_flags & CLONE_SETTLS) -		; +		childregs->r21 = childregs->r10;  	return 0;  } @@ -205,29 +133,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk)  }  #endif -static void kernel_thread_helper(int (*fn)(void *), void *arg) -{ -	fn(arg); -	do_exit(-1); -} - -int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) -{ -	struct pt_regs regs; - -	memset(®s, 0, sizeof(regs)); -	/* store them in non-volatile registers */ -	regs.r5 = (unsigned long)fn; -	regs.r6 = (unsigned long)arg; -	local_save_flags(regs.msr); -	regs.pc = (unsigned long)kernel_thread_helper; -	regs.pt_mode = 1; - -	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, -			®s, 0, NULL, NULL); -} -EXPORT_SYMBOL_GPL(kernel_thread); -  unsigned long get_wchan(struct task_struct *p)  {  /* TBD (used by procfs) */ @@ -237,12 +142,12 @@ unsigned long get_wchan(struct task_struct *p)  /* Set up a thread for executing a new program */  void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)  { -	set_fs(USER_DS);  	regs->pc = pc;  	regs->r1 = usp;  	regs->pt_mode = 0;  #ifdef CONFIG_MMU  	regs->msr |= MSR_UMS; +	regs->msr &= ~MSR_VM;  #endif  } @@ -256,3 +161,8 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)  	return 0; /* MicroBlaze has no separate FPU registers */  }  #endif /* CONFIG_MMU */ + +void arch_cpu_idle(void) +{ +       local_irq_enable(); +} diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index a105301e2b7..68f099960eb 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -14,6 +14,7 @@   */  #include <stdarg.h> +#include <linux/export.h>  #include <linux/kernel.h>  #include <linux/string.h>  #include <linux/init.h> @@ -25,99 +26,75 @@  #include <linux/delay.h>  #include <linux/initrd.h>  #include <linux/bitops.h> -#include <linux/module.h>  #include <linux/kexec.h>  #include <linux/debugfs.h>  #include <linux/irq.h>  #include <linux/memblock.h> +#include <linux/of_fdt.h>  #include <asm/prom.h>  #include <asm/page.h>  #include <asm/processor.h>  #include <asm/irq.h>  #include <linux/io.h> -#include <asm/system.h>  #include <asm/mmu.h>  #include <asm/pgtable.h>  #include <asm/sections.h>  #include <asm/pci-bridge.h> -void __init early_init_dt_add_memory_arch(u64 base, u64 size) -{ -	memblock_add(base, size); -} - -u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align) -{ -	return memblock_alloc(size, align); -} -  #ifdef CONFIG_EARLY_PRINTK -/* MS this is Microblaze specifig function */ -static int __init early_init_dt_scan_serial(unsigned long node, -				const char *uname, int depth, void *data) -{ -	unsigned long l; -	char *p; -	int *addr; - -	pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); - -/* find all serial nodes */ -	if (strncmp(uname, "serial", 6) != 0) -		return 0; - -	early_init_dt_check_for_initrd(node); +static const char *stdout; -/* find compatible node with uartlite */ -	p = of_get_flat_dt_prop(node, "compatible", &l); -	if ((strncmp(p, "xlnx,xps-uartlite", 17) != 0) && -			(strncmp(p, "xlnx,opb-uartlite", 17) != 0) && -			(strncmp(p, "xlnx,axi-uartlite", 17) != 0)) -		return 0; - -	addr = of_get_flat_dt_prop(node, "reg", &l); -	return be32_to_cpup(addr); /* return address */ -} - -/* this function is looking for early uartlite console - Microblaze specific */ -int __init early_uartlite_console(void) -{ -	return of_scan_flat_dt(early_init_dt_scan_serial, NULL); -} - -/* MS this is Microblaze specifig function */ -static int __init early_init_dt_scan_serial_full(unsigned long node, +static int __init early_init_dt_scan_chosen_serial(unsigned long node,  				const char *uname, int depth, void *data)  { -	unsigned long l; -	char *p; -	unsigned int addr; - -	pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); - -/* find all serial nodes */ -	if (strncmp(uname, "serial", 6) != 0) -		return 0; - -	early_init_dt_check_for_initrd(node); - -/* find compatible node with uartlite */ -	p = of_get_flat_dt_prop(node, "compatible", &l); - -	if ((strncmp(p, "xlnx,xps-uart16550", 18) != 0) && -		(strncmp(p, "xlnx,axi-uart16550", 18) != 0)) -		return 0; - -	addr = *(u32 *)of_get_flat_dt_prop(node, "reg", &l); -	addr += *(u32 *)of_get_flat_dt_prop(node, "reg-offset", &l); -	return be32_to_cpu(addr); /* return address */ +	int l; +	const char *p; + +	pr_debug("%s: depth: %d, uname: %s\n", __func__, depth, uname); + +	if (depth == 1 && (strcmp(uname, "chosen") == 0 || +				strcmp(uname, "chosen@0") == 0)) { +		p = of_get_flat_dt_prop(node, "linux,stdout-path", &l); +		if (p != NULL && l > 0) +			stdout = p; /* store pointer to stdout-path */ +	} + +	if (stdout && strstr(stdout, uname)) { +		p = of_get_flat_dt_prop(node, "compatible", &l); +		pr_debug("Compatible string: %s\n", p); + +		if ((strncmp(p, "xlnx,xps-uart16550", 18) == 0) || +			(strncmp(p, "xlnx,axi-uart16550", 18) == 0)) { +			unsigned int addr; + +			*(u32 *)data = UART16550; + +			addr = *(u32 *)of_get_flat_dt_prop(node, "reg", &l); +			addr += *(u32 *)of_get_flat_dt_prop(node, +							"reg-offset", &l); +			/* clear register offset */ +			return be32_to_cpu(addr) & ~3; +		} +		if ((strncmp(p, "xlnx,xps-uartlite", 17) == 0) || +				(strncmp(p, "xlnx,opb-uartlite", 17) == 0) || +				(strncmp(p, "xlnx,axi-uartlite", 17) == 0) || +				(strncmp(p, "xlnx,mdm", 8) == 0)) { +			const unsigned int *addrp; + +			*(u32 *)data = UARTLITE; + +			addrp = of_get_flat_dt_prop(node, "reg", &l); +			return be32_to_cpup(addrp); /* return address */ +		} +	} +	return 0;  } -/* this function is looking for early uartlite console - Microblaze specific */ -int __init early_uart16550_console(void) +/* this function is looking for early console - Microblaze specific */ +int __init of_early_console(void *version)  { -	return of_scan_flat_dt(early_init_dt_scan_serial_full, NULL); +	return of_scan_flat_dt(early_init_dt_scan_chosen_serial, version);  }  #endif @@ -125,68 +102,15 @@ void __init early_init_devtree(void *params)  {  	pr_debug(" -> early_init_devtree(%p)\n", params); -	/* Setup flat device-tree pointer */ -	initial_boot_params = params; - -	/* Retrieve various informations from the /chosen node of the -	 * device-tree, including the platform type, initrd location and -	 * size, TCE reserve, and more ... -	 */ -	of_scan_flat_dt(early_init_dt_scan_chosen, NULL); +	early_init_dt_scan(params); +	if (!strlen(boot_command_line)) +		strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); -	/* Scan memory nodes and rebuild MEMBLOCKs */ -	memblock_init(); -	of_scan_flat_dt(early_init_dt_scan_root, NULL); -	of_scan_flat_dt(early_init_dt_scan_memory, NULL); - -	/* Save command line for /proc/cmdline and then parse parameters */ -	strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE);  	parse_early_param(); -	memblock_analyze(); +	memblock_allow_resize();  	pr_debug("Phys. mem: %lx\n", (unsigned long) memblock_phys_mem_size());  	pr_debug(" <- early_init_devtree()\n");  } - -#ifdef CONFIG_BLK_DEV_INITRD -void __init early_init_dt_setup_initrd_arch(unsigned long start, -		unsigned long end) -{ -	initrd_start = (unsigned long)__va(start); -	initrd_end = (unsigned long)__va(end); -	initrd_below_start_ok = 1; -} -#endif - -/******* - * - * New implementation of the OF "find" APIs, return a refcounted - * object, call of_node_put() when done.  The device tree and list - * are protected by a rw_lock. - * - * Note that property management will need some locking as well, - * this isn't dealt with yet. - * - *******/ - -#if defined(CONFIG_DEBUG_FS) && defined(DEBUG) -static struct debugfs_blob_wrapper flat_dt_blob; - -static int __init export_flat_device_tree(void) -{ -	struct dentry *d; - -	flat_dt_blob.data = initial_boot_params; -	flat_dt_blob.size = initial_boot_params->totalsize; - -	d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR, -				of_debugfs_root, &flat_dt_blob); -	if (!d) -		return 1; - -	return 0; -} -device_initcall(export_flat_device_tree); -#endif diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c index 99d9b61cccb..068762f55fd 100644 --- a/arch/microblaze/kernel/prom_parse.c +++ b/arch/microblaze/kernel/prom_parse.c @@ -1,89 +1,12 @@  #undef DEBUG +#include <linux/export.h>  #include <linux/kernel.h>  #include <linux/string.h> -#include <linux/pci_regs.h> -#include <linux/module.h>  #include <linux/ioport.h>  #include <linux/etherdevice.h>  #include <linux/of_address.h>  #include <asm/prom.h> -#include <asm/pci-bridge.h> - -#ifdef CONFIG_PCI -int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) -{ -	struct device_node *dn, *ppnode; -	struct pci_dev *ppdev; -	u32 lspec; -	u32 laddr[3]; -	u8 pin; -	int rc; - -	/* Check if we have a device node, if yes, fallback to standard OF -	 * parsing -	 */ -	dn = pci_device_to_OF_node(pdev); -	if (dn) -		return of_irq_map_one(dn, 0, out_irq); - -	/* Ok, we don't, time to have fun. Let's start by building up an -	 * interrupt spec.  we assume #interrupt-cells is 1, which is standard -	 * for PCI. If you do different, then don't use that routine. -	 */ -	rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); -	if (rc != 0) -		return rc; -	/* No pin, exit */ -	if (pin == 0) -		return -ENODEV; - -	/* Now we walk up the PCI tree */ -	lspec = pin; -	for (;;) { -		/* Get the pci_dev of our parent */ -		ppdev = pdev->bus->self; - -		/* Ouch, it's a host bridge... */ -		if (ppdev == NULL) { -			struct pci_controller *host; -			host = pci_bus_to_host(pdev->bus); -			ppnode = host ? host->dn : NULL; -			/* No node for host bridge ? give up */ -			if (ppnode == NULL) -				return -EINVAL; -		} else -			/* We found a P2P bridge, check if it has a node */ -			ppnode = pci_device_to_OF_node(ppdev); - -		/* Ok, we have found a parent with a device-node, hand over to -		 * the OF parsing code. -		 * We build a unit address from the linux device to be used for -		 * resolution. Note that we use the linux bus number which may -		 * not match your firmware bus numbering. -		 * Fortunately, in most cases, interrupt-map-mask doesn't -		 * include the bus number as part of the matching. -		 * You should still be careful about that though if you intend -		 * to rely on this function (you ship  a firmware that doesn't -		 * create device nodes for all PCI devices). -		 */ -		if (ppnode) -			break; - -		/* We can only get here if we hit a P2P bridge with no node, -		 * let's do standard swizzling and try again -		 */ -		lspec = pci_swizzle_interrupt_pin(pdev, lspec); -		pdev = ppdev; -	} - -	laddr[0] = (pdev->bus->number << 16) -		| (pdev->devfn << 8); -	laddr[1]  = laddr[2] = 0; -	return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq); -} -EXPORT_SYMBOL_GPL(of_irq_map_pci); -#endif /* CONFIG_PCI */  void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,  		unsigned long *busno, unsigned long *phys, unsigned long *size) @@ -110,41 +33,3 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,  	cells = prop ? *(u32 *)prop : of_n_size_cells(dn);  	*size = of_read_number(dma_window, cells);  } - -/** - * Search the device tree for the best MAC address to use.  'mac-address' is - * checked first, because that is supposed to contain to "most recent" MAC - * address. If that isn't set, then 'local-mac-address' is checked next, - * because that is the default address.  If that isn't set, then the obsolete - * 'address' is checked, just in case we're using an old device tree. - * - * Note that the 'address' property is supposed to contain a virtual address of - * the register set, but some DTS files have redefined that property to be the - * MAC address. - * - * All-zero MAC addresses are rejected, because those could be properties that - * exist in the device tree, but were not set by U-Boot.  For example, the - * DTS could define 'mac-address' and 'local-mac-address', with zero MAC - * addresses.  Some older U-Boots only initialized 'local-mac-address'.  In - * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists - * but is all zeros. -*/ -const void *of_get_mac_address(struct device_node *np) -{ -	struct property *pp; - -	pp = of_find_property(np, "mac-address", NULL); -	if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) -		return pp->value; - -	pp = of_find_property(np, "local-mac-address", NULL); -	if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) -		return pp->value; - -	pp = of_find_property(np, "address", NULL); -	if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) -		return pp->value; - -	return NULL; -} -EXPORT_SYMBOL(of_get_mac_address); diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c index 05ac8cc975d..39cf50841f6 100644 --- a/arch/microblaze/kernel/ptrace.c +++ b/arch/microblaze/kernel/ptrace.c @@ -39,7 +39,8 @@  #include <linux/uaccess.h>  #include <asm/asm-offsets.h>  #include <asm/cacheflush.h> -#include <asm/io.h> +#include <asm/syscall.h> +#include <linux/io.h>  /* Returns the address where the register at REG_OFFS in P is stashed away. */  static microblaze_reg_t *reg_save_addr(unsigned reg_offs, @@ -123,7 +124,7 @@ long arch_ptrace(struct task_struct *child, long request,  			rval = -EIO;  		if (rval == 0 && request == PTRACE_PEEKUSR) -			rval = put_user(val, (unsigned long *)data); +			rval = put_user(val, (unsigned long __user *)data);  		break;  	default:  		rval = ptrace_request(child, request, addr, data); @@ -135,7 +136,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)  {  	long ret = 0; -	secure_computing(regs->r12); +	secure_computing_strict(regs->r12);  	if (test_thread_flag(TIF_SYSCALL_TRACE) &&  	    tracehook_report_syscall_entry(regs)) @@ -146,10 +147,8 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)  		 */  		ret = -1L; -	if (unlikely(current->audit_context)) -		audit_syscall_entry(EM_XILINX_MICROBLAZE, regs->r12, -				    regs->r5, regs->r6, -				    regs->r7, regs->r8); +	audit_syscall_entry(EM_MICROBLAZE, regs->r12, regs->r5, regs->r6, +			    regs->r7, regs->r8);  	return ret ?: regs->r12;  } @@ -158,37 +157,13 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)  {  	int step; -	if (unlikely(current->audit_context)) -		audit_syscall_exit(AUDITSC_RESULT(regs->r3), regs->r3); +	audit_syscall_exit(regs);  	step = test_thread_flag(TIF_SINGLESTEP);  	if (step || test_thread_flag(TIF_SYSCALL_TRACE))  		tracehook_report_syscall_exit(regs, step);  } -#if 0 -static asmlinkage void syscall_trace(void) -{ -	if (!test_thread_flag(TIF_SYSCALL_TRACE)) -		return; -	if (!(current->ptrace & PT_PTRACED)) -		return; -	/* The 0x80 provides a way for the tracing parent to distinguish -	 between a syscall stop and SIGTRAP delivery */ -	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) -				? 0x80 : 0)); -	/* -	 * this isn't the same as continuing with a signal, but it will do -	 * for normal use. strace only continues with a signal if the -	 * stopping signal is not SIGTRAP. -brl -	 */ -	if (current->exit_code) { -		send_sig(current->exit_code, current, 1); -		current->exit_code = 0; -	} -} -#endif -  void ptrace_disable(struct task_struct *child)  {  	/* nothing to do */ diff --git a/arch/microblaze/kernel/reset.c b/arch/microblaze/kernel/reset.c index bd8ccab5cef..fbe58c6554a 100644 --- a/arch/microblaze/kernel/reset.c +++ b/arch/microblaze/kernel/reset.c @@ -19,59 +19,21 @@  static int handle; /* reset pin handle */  static unsigned int reset_val; -static int of_reset_gpio_handle(void) -{ -	int ret; /* variable which stored handle reset gpio pin */ -	struct device_node *root; /* root node */ -	struct device_node *gpio; /* gpio node */ -	struct gpio_chip *gc; -	u32 flags; -	const void *gpio_spec; - -	/* find out root node */ -	root = of_find_node_by_path("/"); - -	/* give me handle for gpio node to be possible allocate pin */ -	ret = of_parse_phandles_with_args(root, "hard-reset-gpios", -				"#gpio-cells", 0, &gpio, &gpio_spec); -	if (ret) { -		pr_debug("%s: can't parse gpios property\n", __func__); -		goto err0; -	} - -	gc = of_node_to_gpiochip(gpio); -	if (!gc) { -		pr_debug("%s: gpio controller %s isn't registered\n", -			 root->full_name, gpio->full_name); -		ret = -ENODEV; -		goto err1; -	} - -	ret = gc->of_xlate(gc, root, gpio_spec, &flags); -	if (ret < 0) -		goto err1; - -	ret += gc->base; -err1: -	of_node_put(gpio); -err0: -	pr_debug("%s exited with status %d\n", __func__, ret); -	return ret; -} -  void of_platform_reset_gpio_probe(void)  {  	int ret; -	handle = of_reset_gpio_handle(); +	handle = of_get_named_gpio(of_find_node_by_path("/"), +				   "hard-reset-gpios", 0);  	if (!gpio_is_valid(handle)) { -		printk(KERN_INFO "Skipping unavailable RESET gpio %d (%s)\n", +		pr_info("Skipping unavailable RESET gpio %d (%s)\n",  				handle, "reset"); +		return;  	}  	ret = gpio_request(handle, "reset");  	if (ret < 0) { -		printk(KERN_INFO "GPIO pin is already allocated\n"); +		pr_info("GPIO pin is already allocated\n");  		return;  	} @@ -88,7 +50,7 @@ void of_platform_reset_gpio_probe(void)  	/* Setup output direction */  	gpio_set_value(handle, 0); -	printk(KERN_INFO "RESET: Registered gpio device: %d, current val: %d\n", +	pr_info("RESET: Registered gpio device: %d, current val: %d\n",  							handle, reset_val);  	return;  err: @@ -99,10 +61,17 @@ err:  static void gpio_system_reset(void)  { -	gpio_set_value(handle, 1 - reset_val); +	if (gpio_is_valid(handle)) +		gpio_set_value(handle, 1 - reset_val); +	else +		pr_notice("Reset GPIO unavailable - halting!\n");  }  #else -#define gpio_system_reset() do {} while (0) +static void gpio_system_reset(void) +{ +	pr_notice("No reset GPIO present - halting!\n"); +} +  void of_platform_reset_gpio_probe(void)  {  	return; @@ -111,30 +80,29 @@ void of_platform_reset_gpio_probe(void)  void machine_restart(char *cmd)  { -	printk(KERN_NOTICE "Machine restart...\n"); +	pr_notice("Machine restart...\n");  	gpio_system_reset(); -	dump_stack();  	while (1)  		;  }  void machine_shutdown(void)  { -	printk(KERN_NOTICE "Machine shutdown...\n"); +	pr_notice("Machine shutdown...\n");  	while (1)  		;  }  void machine_halt(void)  { -	printk(KERN_NOTICE "Machine halt...\n"); +	pr_notice("Machine halt...\n");  	while (1)  		;  }  void machine_power_off(void)  { -	printk(KERN_NOTICE "Machine power off...\n"); +	pr_notice("Machine power off...\n");  	while (1)  		;  } diff --git a/arch/microblaze/kernel/selfmod.c b/arch/microblaze/kernel/selfmod.c deleted file mode 100644 index 89508bdc9f3..00000000000 --- a/arch/microblaze/kernel/selfmod.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> - * Copyright (C) 2009 PetaLogix - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include <linux/interrupt.h> -#include <asm/selfmod.h> - -#undef DEBUG - -#if __GNUC__ > 3 -#error GCC 4 unsupported SELFMOD. Please disable SELFMOD from menuconfig. -#endif - -#define OPCODE_IMM		0xB0000000 -#define OPCODE_LWI		0xE8000000 -#define OPCODE_LWI_MASK		0xEC000000 -#define OPCODE_RTSD		0xB60F0008 /* return from func: rtsd r15, 8 */ -#define OPCODE_ADDIK		0x30000000 -#define OPCODE_ADDIK_MASK	0xFC000000 - -#define IMM_BASE	(OPCODE_IMM | (BARRIER_BASE_ADDR >> 16)) -#define LWI_BASE	(OPCODE_LWI | (BARRIER_BASE_ADDR & 0x0000ff00)) -#define LWI_BASE_MASK	(OPCODE_LWI_MASK | (BARRIER_BASE_ADDR & 0x0000ff00)) -#define ADDIK_BASE	(OPCODE_ADDIK | (BARRIER_BASE_ADDR & 0x0000ff00)) -#define ADDIK_BASE_MASK	(OPCODE_ADDIK_MASK | (BARRIER_BASE_ADDR & 0x0000ff00)) - -#define MODIFY_INSTR {						\ -	pr_debug("%s: curr instr, (%d):0x%x, next(%d):0x%x\n",		\ -		__func__, i, addr[i], i + 1, addr[i + 1]);		\ -	addr[i] = OPCODE_IMM + (base >> 16);				\ -	/* keep instruction opcode and add only last 16bits */		\ -	addr[i + 1] = (addr[i + 1] & 0xffff00ff) + (base & 0xffff);	\ -	__invalidate_icache(addr[i]);					\ -	__invalidate_icache(addr[i + 1]);				\ -	pr_debug("%s: hack instr, (%d):0x%x, next(%d):0x%x\n",		\ -		__func__, i, addr[i], i + 1, addr[i + 1]); } - -/* NOTE - * self-modified part of code for improvement of interrupt controller - * save instruction in interrupt rutine - */ -void selfmod_function(const int *arr_fce, const unsigned int base) -{ -	unsigned int flags, i, j, *addr = NULL; - -	local_irq_save(flags); -	__disable_icache(); - -	/* zero terminated array */ -	for (j = 0; arr_fce[j] != 0; j++) { -		/* get start address of function */ -		addr = (unsigned int *) arr_fce[j]; -		pr_debug("%s: func(%d) at 0x%x\n", -					__func__, j, (unsigned int) addr); -		for (i = 0; ; i++) { -			pr_debug("%s: instruction code at %d: 0x%x\n", -						__func__, i, addr[i]); -			if (addr[i] == IMM_BASE) { -				/* detecting of lwi (0xE8) or swi (0xF8) instr -				 * I can detect both opcode with one mask */ -				if ((addr[i + 1] & LWI_BASE_MASK) == LWI_BASE) { -					MODIFY_INSTR; -				} else /* detection addik for ack */ -				if ((addr[i + 1] & ADDIK_BASE_MASK) == -								ADDIK_BASE) { -					MODIFY_INSTR; -				} -			} else if (addr[i] == OPCODE_RTSD) { -				/* return from function means end of function */ -				pr_debug("%s: end of array %d\n", __func__, i); -				break; -			} -		} -	} -	local_irq_restore(flags); -} /* end of self-modified code */ diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index bb1558e4b28..ab5b488e1fd 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -9,12 +9,15 @@   */  #include <linux/init.h> +#include <linux/clk-provider.h> +#include <linux/clocksource.h>  #include <linux/string.h>  #include <linux/seq_file.h>  #include <linux/cpu.h>  #include <linux/initrd.h>  #include <linux/console.h>  #include <linux/debugfs.h> +#include <linux/of_fdt.h>  #include <asm/setup.h>  #include <asm/sections.h> @@ -30,7 +33,6 @@  #include <asm/entry.h>  #include <asm/cpuinfo.h> -#include <asm/system.h>  #include <asm/prom.h>  #include <asm/pgtable.h> @@ -41,37 +43,37 @@ DEFINE_PER_CPU(unsigned int, R11_SAVE);	/* Temp variable for entry */  DEFINE_PER_CPU(unsigned int, CURRENT_SAVE);	/* Saved current pointer */  unsigned int boot_cpuid; -char cmd_line[COMMAND_LINE_SIZE]; +/* + * Placed cmd_line to .data section because can be initialized from + * ASM code. Default position is BSS section which is cleared + * in machine_early_init(). + */ +char cmd_line[COMMAND_LINE_SIZE] __attribute__ ((section(".data")));  void __init setup_arch(char **cmdline_p)  { -	*cmdline_p = cmd_line; +	*cmdline_p = boot_command_line;  	console_verbose();  	unflatten_device_tree(); -	/* NOTE I think that this function is not necessary to call */ -	/* irq_early_init(); */  	setup_cpuinfo();  	microblaze_cache_init();  	setup_memory(); -	xilinx_pci_init(); - -#if defined(CONFIG_SELFMOD_INTC) || defined(CONFIG_SELFMOD_TIMER) -	printk(KERN_NOTICE "Self modified code enable\n"); +#ifdef CONFIG_EARLY_PRINTK +	/* remap early console to virtual address */ +	remap_early_printk();  #endif -#ifdef CONFIG_VT -#if defined(CONFIG_XILINX_CONSOLE) -	conswitchp = &xil_con; -#elif defined(CONFIG_DUMMY_CONSOLE) +	xilinx_pci_init(); + +#if defined(CONFIG_DUMMY_CONSOLE)  	conswitchp = &dummy_con;  #endif -#endif  }  #ifdef CONFIG_MTD_UCLINUX @@ -92,10 +94,14 @@ inline unsigned get_romfs_len(unsigned *addr)  }  #endif	/* CONFIG_MTD_UCLINUX_EBSS */ +unsigned long kernel_tlb; +  void __init machine_early_init(const char *cmdline, unsigned int ram, -		unsigned int fdt, unsigned int msr) +		unsigned int fdt, unsigned int msr, unsigned int tlb0, +		unsigned int tlb1)  { -	unsigned long *src, *dst = (unsigned long *)0x0; +	unsigned long *src, *dst; +	unsigned int offset = 0;  	/* If CONFIG_MTD_UCLINUX is defined, assume ROMFS is at the  	 * end of kernel. There are two position which we want to check. @@ -115,7 +121,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,  	/* Move ROMFS out of BSS before clearing it */  	if (romfs_size > 0) { -		memmove(&_ebss, (int *)romfs_base, romfs_size); +		memmove(&__bss_stop, (int *)romfs_base, romfs_size);  		klimit += romfs_size;  	}  #endif @@ -124,51 +130,59 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,  	memset(__bss_start, 0, __bss_stop-__bss_start);  	memset(_ssbss, 0, _esbss-_ssbss); -	/* Copy command line passed from bootloader */ -#ifndef CONFIG_CMDLINE_BOOL -	if (cmdline && cmdline[0] != '\0') -		strlcpy(cmd_line, cmdline, COMMAND_LINE_SIZE); -#endif -  	lockdep_init();  /* initialize device tree for usage in early_printk */ -	early_init_devtree((void *)_fdt_start); +	early_init_devtree(_fdt_start);  #ifdef CONFIG_EARLY_PRINTK  	setup_early_printk(NULL);  #endif -	eprintk("Ramdisk addr 0x%08x, ", ram); +	/* setup kernel_tlb after BSS cleaning +	 * Maybe worth to move to asm code */ +	kernel_tlb = tlb0 + tlb1; +	/* printk("TLB1 0x%08x, TLB0 0x%08x, tlb 0x%x\n", tlb0, +							tlb1, kernel_tlb); */ + +	pr_info("Ramdisk addr 0x%08x, ", ram);  	if (fdt) -		eprintk("FDT at 0x%08x\n", fdt); +		pr_info("FDT at 0x%08x\n", fdt);  	else -		eprintk("Compiled-in FDT at 0x%08x\n", -					(unsigned int)_fdt_start); +		pr_info("Compiled-in FDT at %p\n", _fdt_start);  #ifdef CONFIG_MTD_UCLINUX -	eprintk("Found romfs @ 0x%08x (0x%08x)\n", +	pr_info("Found romfs @ 0x%08x (0x%08x)\n",  			romfs_base, romfs_size); -	eprintk("#### klimit %p ####\n", old_klimit); +	pr_info("#### klimit %p ####\n", old_klimit);  	BUG_ON(romfs_size < 0); /* What else can we do? */ -	eprintk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n", -			romfs_size, romfs_base, (unsigned)&_ebss); +	pr_info("Moved 0x%08x bytes from 0x%08x to 0x%08x\n", +			romfs_size, romfs_base, (unsigned)&__bss_stop); -	eprintk("New klimit: 0x%08x\n", (unsigned)klimit); +	pr_info("New klimit: 0x%08x\n", (unsigned)klimit);  #endif  #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR -	if (msr) -		eprintk("!!!Your kernel has setup MSR instruction but " -				"CPU don't have it %d\n", msr); +	if (msr) { +		pr_info("!!!Your kernel has setup MSR instruction but "); +		pr_cont("CPU don't have it %x\n", msr); +	}  #else -	if (!msr) -		eprintk("!!!Your kernel not setup MSR instruction but " -				"CPU have it %d\n", msr); +	if (!msr) { +		pr_info("!!!Your kernel not setup MSR instruction but "); +		pr_cont("CPU have it %x\n", msr); +	}  #endif -	for (src = __ivt_start; src < __ivt_end; src++, dst++) +	/* Do not copy reset vectors. offset = 0x2 means skip the first +	 * two instructions. dst is pointer to MB vectors which are placed +	 * in block ram. If you want to copy reset vector setup offset to 0x0 */ +#if !CONFIG_MANUAL_RESET_VECTOR +	offset = 0x2; +#endif +	dst = (unsigned long *) (offset * sizeof(u32)); +	for (src = __ivt_start + offset; src < __ivt_end; src++, dst++)  		*dst = *src;  	/* Initialize global data */ @@ -176,6 +190,13 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,  	per_cpu(CURRENT_SAVE, 0) = (unsigned long)current;  } +void __init time_init(void) +{ +	of_clk_init(NULL); +	setup_cpuinfo_clk(); +	clocksource_of_init(); +} +  #ifdef CONFIG_DEBUG_FS  struct dentry *of_debugfs_root; @@ -186,32 +207,21 @@ static int microblaze_debugfs_init(void)  	return of_debugfs_root == NULL;  }  arch_initcall(microblaze_debugfs_init); -#endif -static int dflt_bus_notify(struct notifier_block *nb, -				unsigned long action, void *data) +# ifdef CONFIG_MMU +static int __init debugfs_tlb(void)  { -	struct device *dev = data; +	struct dentry *d; -	/* We are only intereted in device addition */ -	if (action != BUS_NOTIFY_ADD_DEVICE) -		return 0; +	if (!of_debugfs_root) +		return -ENODEV; -	set_dma_ops(dev, &dma_direct_ops); - -	return NOTIFY_DONE; -} - -static struct notifier_block dflt_plat_bus_notifier = { -	.notifier_call = dflt_bus_notify, -	.priority = INT_MAX, -}; - -static int __init setup_bus_notifier(void) -{ -	bus_register_notifier(&platform_bus_type, &dflt_plat_bus_notifier); +	d = debugfs_create_u32("tlb_skip", S_IRUGO, of_debugfs_root, &tlb_skip); +	if (!d) +		return -ENOMEM;  	return 0;  } - -arch_initcall(setup_bus_notifier); +device_initcall(debugfs_tlb); +# endif +#endif diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index d8d3bb396cd..49a07a4d76d 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -31,6 +31,7 @@  #include <linux/personality.h>  #include <linux/percpu.h>  #include <linux/linkage.h> +#include <linux/tracehook.h>  #include <asm/entry.h>  #include <asm/ucontext.h>  #include <linux/uaccess.h> @@ -40,17 +41,6 @@  #include <asm/cacheflush.h>  #include <asm/syscalls.h> -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - -asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall); - -asmlinkage long -sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, -		struct pt_regs *regs) -{ -	return do_sigaltstack(uss, uoss, regs->r1); -} -  /*   * Do a signal return; undo the signal stack.   */ @@ -93,29 +83,26 @@ static int restore_sigcontext(struct pt_regs *regs,  asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)  {  	struct rt_sigframe __user *frame = -		(struct rt_sigframe __user *)(regs->r1 + STATE_SAVE_ARG_SPACE); +		(struct rt_sigframe __user *)(regs->r1);  	sigset_t set;  	int rval; +	/* Always make any pending restarted system calls return -EINTR */ +	current_thread_info()->restart_block.fn = do_no_restart_syscall; +  	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))  		goto badframe;  	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))  		goto badframe; -	sigdelsetmask(&set, ~_BLOCKABLE); -	spin_lock_irq(¤t->sighand->siglock); -	current->blocked = set; -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); +	set_current_blocked(&set);  	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval))  		goto badframe; -	/* It is more difficult to avoid calling this function than to -	 call it and ignore errors. */ -	if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->r1)) +	if (restore_altstack(&frame->uc.uc_stack))  		goto badframe;  	return rval; @@ -169,7 +156,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)  	return (void __user *)((sp - frame_size) & -8UL);  } -static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, +static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  			sigset_t *set, struct pt_regs *regs)  {  	struct rt_sigframe __user *frame; @@ -197,12 +184,8 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	/* Create the ucontext. */  	err |= __put_user(0, &frame->uc.uc_flags); -	err |= __put_user(0, &frame->uc.uc_link); -	err |= __put_user((void *)current->sas_ss_sp, -			&frame->uc.uc_stack.ss_sp); -	err |= __put_user(sas_ss_flags(regs->r1), -			&frame->uc.uc_stack.ss_flags); -	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); +	err |= __put_user(NULL, &frame->uc.uc_link); +	err |= __save_altstack(&frame->uc.uc_stack, regs->r1);  	err |= setup_sigcontext(&frame->uc.uc_mcontext,  			regs, set->sig[0]);  	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); @@ -233,7 +216,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  		/* MS: I need add offset in page */  		address += ((unsigned long)frame->tramp) & ~PAGE_MASK;  		/* MS address is virtual */ -		address = virt_to_phys(address); +		address = __virt_to_phys(address);  		invalidate_icache_range(address, address + 8);  		flush_dcache_range(address, address + 8);  	} @@ -247,7 +230,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  		goto give_sigsegv;  	/* Set up registers for signal handler */ -	regs->r1 = (unsigned long) frame - STATE_SAVE_ARG_SPACE; +	regs->r1 = (unsigned long) frame;  	/* Signal handler args: */  	regs->r5 = signal; /* arg 0: signum */ @@ -258,21 +241,16 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	set_fs(USER_DS); -	/* the tracer may want to single-step inside the handler */ -	if (test_thread_flag(TIF_SINGLESTEP)) -		ptrace_notify(SIGTRAP); -  #ifdef DEBUG_SIG -	printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n", +	pr_info("SIG deliver (%s:%d): sp=%p pc=%08lx\n",  		current->comm, current->pid, frame, regs->pc);  #endif -	return; +	return 0;  give_sigsegv: -	if (sig == SIGSEGV) -		ka->sa.sa_handler = SIG_DFL; -	force_sig(SIGSEGV, current); +	force_sigsegv(sig, current); +	return -EFAULT;  }  /* Handle restarting system calls */ @@ -295,15 +273,7 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)  	case -ERESTARTNOINTR:  do_restart:  		/* offset of 4 bytes to re-execute trap (brki) instruction */ -#ifndef CONFIG_MMU  		regs->pc -= 4; -#else -		/* offset of 8 bytes required = 4 for rtbd -		   offset, plus 4 for size of -			"brki r14,8" -		   instruction. */ -		regs->pc -= 8; -#endif  		break;  	}  } @@ -312,28 +282,24 @@ do_restart:   * OK, we're invoking a handler   */ -static int +static void  handle_signal(unsigned long sig, struct k_sigaction *ka, -		siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) +		siginfo_t *info, struct pt_regs *regs)  { +	sigset_t *oldset = sigmask_to_save(); +	int ret; +  	/* Set up the stack frame */  	if (ka->sa.sa_flags & SA_SIGINFO) -		setup_rt_frame(sig, ka, info, oldset, regs); +		ret = setup_rt_frame(sig, ka, info, oldset, regs);  	else -		setup_rt_frame(sig, ka, NULL, oldset, regs); - -	if (ka->sa.sa_flags & SA_ONESHOT) -		ka->sa.sa_handler = SIG_DFL; - -	if (!(ka->sa.sa_flags & SA_NODEFER)) { -		spin_lock_irq(¤t->sighand->siglock); -		sigorsets(¤t->blocked, -				¤t->blocked, &ka->sa.sa_mask); -		sigaddset(¤t->blocked, sig); -		recalc_sigpending(); -		spin_unlock_irq(¤t->sighand->siglock); -	} -	return 1; +		ret = setup_rt_frame(sig, ka, NULL, oldset, regs); + +	if (ret) +		return; + +	signal_delivered(sig, info, ka, regs, +			test_thread_flag(TIF_SINGLESTEP));  }  /* @@ -345,46 +311,24 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,   * the kernel can handle, and then we build all the user-level signal handling   * stack-frames in one go after that.   */ -int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall) +static void do_signal(struct pt_regs *regs, int in_syscall)  {  	siginfo_t info;  	int signr;  	struct k_sigaction ka;  #ifdef DEBUG_SIG -	printk(KERN_INFO "do signal: %p %p %d\n", regs, oldset, in_syscall); -	printk(KERN_INFO "do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1, +	pr_info("do signal: %p %d\n", regs, in_syscall); +	pr_info("do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1,  			regs->r12, current_thread_info()->flags);  #endif -	/* -	 * We want the common case to go fast, which -	 * is why we may in certain cases get here from -	 * kernel mode. Just return without doing anything -	 * if so. -	 */ -	if (kernel_mode(regs)) -		return 1; - -	if (current_thread_info()->status & TS_RESTORE_SIGMASK) -		oldset = ¤t->saved_sigmask; -	else -		oldset = ¤t->blocked;  	signr = get_signal_to_deliver(&info, &ka, regs, NULL);  	if (signr > 0) {  		/* Whee! Actually deliver the signal. */  		if (in_syscall)  			handle_restart(regs, &ka, 1); -		if (handle_signal(signr, &ka, &info, oldset, regs)) { -			/* -			 * A signal was successfully delivered; the saved -			 * sigmask will have been stored in the signal frame, -			 * and will be restored by sigreturn, so we can simply -			 * clear the TS_RESTORE_SIGMASK flag. -			 */ -			current_thread_info()->status &= -			    ~TS_RESTORE_SIGMASK; -		} -		return 1; +		handle_signal(signr, &ka, &info, regs); +		return;  	}  	if (in_syscall) @@ -394,11 +338,14 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)  	 * If there's no signal to deliver, we just put the saved sigmask  	 * back.  	 */ -	if (current_thread_info()->status & TS_RESTORE_SIGMASK) { -		current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -		sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); -	} +	restore_saved_sigmask(); +} -	/* Did we come from a system call? */ -	return 0; +asmlinkage void do_notify_resume(struct pt_regs *regs, int in_syscall) +{ +	if (test_thread_flag(TIF_SIGPENDING)) +		do_signal(regs, in_syscall); + +	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) +		tracehook_notify_resume(regs);  } diff --git a/arch/microblaze/kernel/stacktrace.c b/arch/microblaze/kernel/stacktrace.c index 84bc6686102..b4debe283a7 100644 --- a/arch/microblaze/kernel/stacktrace.c +++ b/arch/microblaze/kernel/stacktrace.c @@ -9,11 +9,11 @@   * for more details.   */ +#include <linux/export.h>  #include <linux/sched.h>  #include <linux/stacktrace.h>  #include <linux/thread_info.h>  #include <linux/ptrace.h> -#include <linux/module.h>  #include <asm/unwind.h>  void save_stack_trace(struct stack_trace *trace) diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c index 2250fe9d269..f1e1f666ddd 100644 --- a/arch/microblaze/kernel/sys_microblaze.c +++ b/arch/microblaze/kernel/sys_microblaze.c @@ -13,6 +13,7 @@   */  #include <linux/errno.h> +#include <linux/export.h>  #include <linux/mm.h>  #include <linux/smp.h>  #include <linux/syscalls.h> @@ -24,50 +25,17 @@  #include <linux/sys.h>  #include <linux/ipc.h>  #include <linux/file.h> -#include <linux/module.h>  #include <linux/err.h>  #include <linux/fs.h>  #include <linux/semaphore.h>  #include <linux/uaccess.h>  #include <linux/unistd.h>  #include <linux/slab.h> -  #include <asm/syscalls.h> -asmlinkage long microblaze_vfork(struct pt_regs *regs) -{ -	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->r1, -						regs, 0, NULL, NULL); -} - -asmlinkage long microblaze_clone(int flags, unsigned long stack, struct pt_regs *regs) -{ -	if (!stack) -		stack = regs->r1; -	return do_fork(flags, stack, regs, 0, NULL, NULL); -} - -asmlinkage long microblaze_execve(const char __user *filenamei, -				  const char __user *const __user *argv, -				  const char __user *const __user *envp, -				  struct pt_regs *regs) -{ -	int error; -	char *filename; - -	filename = getname(filenamei); -	error = PTR_ERR(filename); -	if (IS_ERR(filename)) -		goto out; -	error = do_execve(filename, argv, envp, regs); -	putname(filename); -out: -	return error; -} - -asmlinkage long sys_mmap(unsigned long addr, unsigned long len, -			unsigned long prot, unsigned long flags, -			unsigned long fd, off_t pgoff) +SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, +		unsigned long, prot, unsigned long, flags, unsigned long, fd, +		off_t, pgoff)  {  	if (pgoff & ~PAGE_MASK)  		return -EINVAL; @@ -75,23 +43,13 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len,  	return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT);  } -/* - * Do a system call from kernel instead of calling sys_execve so we - * end up with proper pt_regs. - */ -int kernel_execve(const char *filename, -		  const char *const argv[], -		  const char *const envp[]) +SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, +		unsigned long, prot, unsigned long, flags, unsigned long, fd, +		unsigned long, pgoff)  { -	register const char *__a __asm__("r5") = filename; -	register const void *__b __asm__("r6") = argv; -	register const void *__c __asm__("r7") = envp; -	register unsigned long __syscall __asm__("r12") = __NR_execve; -	register unsigned long __ret __asm__("r3"); -	__asm__ __volatile__ ("brki r14, 0x8" -			: "=r" (__ret), "=r" (__syscall) -			: "1" (__syscall), "r" (__a), "r" (__b), "r" (__c) -			: "r4", "r8", "r9", -			"r10", "r11", "r14", "cc", "memory"); -	return __ret; +	if (pgoff & (~PAGE_MASK >> 12)) +		return -EINVAL; + +	return sys_mmap_pgoff(addr, len, prot, flags, fd, +			      pgoff >> (PAGE_SHIFT - 12));  } diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S index e88a930fd1e..329dfbad810 100644 --- a/arch/microblaze/kernel/syscall_table.S +++ b/arch/microblaze/kernel/syscall_table.S @@ -2,11 +2,7 @@ ENTRY(sys_call_table)  	.long sys_restart_syscall	/* 0 - old "setup()" system call,  					 * used for restarting */  	.long sys_exit -#ifdef CONFIG_MMU -	.long sys_fork_wrapper -#else -	.long sys_ni_syscall -#endif +	.long sys_fork  	.long sys_read  	.long sys_write  	.long sys_open			/* 5 */ @@ -173,7 +169,7 @@ ENTRY(sys_call_table)  	.long sys_ni_syscall		/* sys_vm86 */  	.long sys_ni_syscall		/* Old sys_query_module */  	.long sys_poll -	.long sys_nfsservctl +	.long sys_ni_syscall		/* old nfsservctl */  	.long sys_setresgid		/* 170 */  	.long sys_getresgid  	.long sys_prctl @@ -196,7 +192,7 @@ ENTRY(sys_call_table)  	.long sys_ni_syscall		/* reserved for streams2 */  	.long sys_vfork		/* 190 */  	.long sys_getrlimit -	.long sys_mmap_pgoff		/* mmap2 */ +	.long sys_mmap2  	.long sys_truncate64  	.long sys_ftruncate64  	.long sys_stat64		/* 195 */ @@ -312,7 +308,7 @@ ENTRY(sys_call_table)  	.long sys_readlinkat		/* 305 */  	.long sys_fchmodat  	.long sys_faccessat -	.long sys_ni_syscall /* pselect6 */ +	.long sys_pselect6  	.long sys_ppoll  	.long sys_unshare		/* 310 */  	.long sys_set_robust_list @@ -367,11 +363,23 @@ ENTRY(sys_call_table)  	.long sys_sendmsg		/* 360 */  	.long sys_recvmsg  	.long sys_accept4 -	.long sys_ni_syscall -	.long sys_ni_syscall +	.long sys_preadv +	.long sys_pwritev  	.long sys_rt_tgsigqueueinfo	/* 365 */  	.long sys_perf_event_open  	.long sys_recvmmsg  	.long sys_fanotify_init  	.long sys_fanotify_mark  	.long sys_prlimit64	/* 370 */ +	.long sys_name_to_handle_at +	.long sys_open_by_handle_at +	.long sys_clock_adjtime +	.long sys_syncfs +	.long sys_setns			/* 375 */ +	.long sys_sendmmsg +	.long sys_process_vm_readv +	.long sys_process_vm_writev +	.long sys_kcmp +	.long sys_finit_module +	.long sys_sched_setattr +	.long sys_sched_getattr diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index a5aa33db1df..dd96f0e4bfa 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -1,5 +1,6 @@  /* - * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2007-2013 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2012-2013 Xilinx, Inc.   * Copyright (C) 2007-2009 PetaLogix   * Copyright (C) 2006 Atmark Techno, Inc.   * @@ -8,38 +9,20 @@   * for more details.   */ -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/param.h>  #include <linux/interrupt.h> -#include <linux/profile.h> -#include <linux/irq.h>  #include <linux/delay.h>  #include <linux/sched.h> -#include <linux/spinlock.h> -#include <linux/err.h> +#include <linux/sched_clock.h>  #include <linux/clk.h> -#include <linux/clocksource.h>  #include <linux/clockchips.h> -#include <linux/io.h> -#include <linux/bug.h> +#include <linux/of_address.h> +#include <linux/of_irq.h>  #include <asm/cpuinfo.h> -#include <asm/setup.h> -#include <asm/prom.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <linux/cnt32_to_63.h> - -#ifdef CONFIG_SELFMOD_TIMER -#include <asm/selfmod.h> -#define TIMER_BASE	BARRIER_BASE_ADDR -#else -static unsigned int timer_baseaddr; -#define TIMER_BASE	timer_baseaddr -#endif -unsigned int freq_div_hz; -unsigned int timer_clock_freq; +static void __iomem *timer_baseaddr; + +static unsigned int freq_div_hz; +static unsigned int timer_clock_freq;  #define TCSR0	(0x00)  #define TLR0	(0x04) @@ -60,26 +43,51 @@ unsigned int timer_clock_freq;  #define TCSR_PWMA	(1<<9)  #define TCSR_ENALL	(1<<10) -static inline void microblaze_timer0_stop(void) +static unsigned int (*read_fn)(void __iomem *); +static void (*write_fn)(u32, void __iomem *); + +static void timer_write32(u32 val, void __iomem *addr) +{ +	iowrite32(val, addr); +} + +static unsigned int timer_read32(void __iomem *addr) +{ +	return ioread32(addr); +} + +static void timer_write32_be(u32 val, void __iomem *addr) +{ +	iowrite32be(val, addr); +} + +static unsigned int timer_read32_be(void __iomem *addr) +{ +	return ioread32be(addr); +} + +static inline void xilinx_timer0_stop(void)  { -	out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0) & ~TCSR_ENT); +	write_fn(read_fn(timer_baseaddr + TCSR0) & ~TCSR_ENT, +		 timer_baseaddr + TCSR0);  } -static inline void microblaze_timer0_start_periodic(unsigned long load_val) +static inline void xilinx_timer0_start_periodic(unsigned long load_val)  {  	if (!load_val)  		load_val = 1; -	out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */ +	/* loading value to timer reg */ +	write_fn(load_val, timer_baseaddr + TLR0);  	/* load the initial value */ -	out_be32(TIMER_BASE + TCSR0, TCSR_LOAD); +	write_fn(TCSR_LOAD, timer_baseaddr + TCSR0);  	/* see timer data sheet for detail  	 * !ENALL - don't enable 'em all  	 * !PWMA - disable pwm  	 * TINT - clear interrupt status  	 * ENT- enable timer itself -	 * EINT - enable interrupt +	 * ENIT - enable interrupt  	 * !LOAD - clear the bit to let go  	 * ARHT - auto reload  	 * !CAPT - no external trigger @@ -87,74 +95,75 @@ static inline void microblaze_timer0_start_periodic(unsigned long load_val)  	 * UDT - set the timer as down counter  	 * !MDT0 - generate mode  	 */ -	out_be32(TIMER_BASE + TCSR0, -			TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT); +	write_fn(TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT, +		 timer_baseaddr + TCSR0);  } -static inline void microblaze_timer0_start_oneshot(unsigned long load_val) +static inline void xilinx_timer0_start_oneshot(unsigned long load_val)  {  	if (!load_val)  		load_val = 1; -	out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */ +	/* loading value to timer reg */ +	write_fn(load_val, timer_baseaddr + TLR0);  	/* load the initial value */ -	out_be32(TIMER_BASE + TCSR0, TCSR_LOAD); +	write_fn(TCSR_LOAD, timer_baseaddr + TCSR0); -	out_be32(TIMER_BASE + TCSR0, -			TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT); +	write_fn(TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT, +		 timer_baseaddr + TCSR0);  } -static int microblaze_timer_set_next_event(unsigned long delta, +static int xilinx_timer_set_next_event(unsigned long delta,  					struct clock_event_device *dev)  {  	pr_debug("%s: next event, delta %x\n", __func__, (u32)delta); -	microblaze_timer0_start_oneshot(delta); +	xilinx_timer0_start_oneshot(delta);  	return 0;  } -static void microblaze_timer_set_mode(enum clock_event_mode mode, +static void xilinx_timer_set_mode(enum clock_event_mode mode,  				struct clock_event_device *evt)  {  	switch (mode) {  	case CLOCK_EVT_MODE_PERIODIC: -		printk(KERN_INFO "%s: periodic\n", __func__); -		microblaze_timer0_start_periodic(freq_div_hz); +		pr_info("%s: periodic\n", __func__); +		xilinx_timer0_start_periodic(freq_div_hz);  		break;  	case CLOCK_EVT_MODE_ONESHOT: -		printk(KERN_INFO "%s: oneshot\n", __func__); +		pr_info("%s: oneshot\n", __func__);  		break;  	case CLOCK_EVT_MODE_UNUSED: -		printk(KERN_INFO "%s: unused\n", __func__); +		pr_info("%s: unused\n", __func__);  		break;  	case CLOCK_EVT_MODE_SHUTDOWN: -		printk(KERN_INFO "%s: shutdown\n", __func__); -		microblaze_timer0_stop(); +		pr_info("%s: shutdown\n", __func__); +		xilinx_timer0_stop();  		break;  	case CLOCK_EVT_MODE_RESUME: -		printk(KERN_INFO "%s: resume\n", __func__); +		pr_info("%s: resume\n", __func__);  		break;  	}  } -static struct clock_event_device clockevent_microblaze_timer = { -	.name		= "microblaze_clockevent", +static struct clock_event_device clockevent_xilinx_timer = { +	.name		= "xilinx_clockevent",  	.features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,  	.shift		= 8,  	.rating		= 300, -	.set_next_event	= microblaze_timer_set_next_event, -	.set_mode	= microblaze_timer_set_mode, +	.set_next_event	= xilinx_timer_set_next_event, +	.set_mode	= xilinx_timer_set_mode,  };  static inline void timer_ack(void)  { -	out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0)); +	write_fn(read_fn(timer_baseaddr + TCSR0), timer_baseaddr + TCSR0);  }  static irqreturn_t timer_interrupt(int irq, void *dev_id)  { -	struct clock_event_device *evt = &clockevent_microblaze_timer; +	struct clock_event_device *evt = &clockevent_xilinx_timer;  #ifdef CONFIG_HEART_BEAT -	heartbeat(); +	microblaze_heartbeat();  #endif  	timer_ack();  	evt->event_handler(evt); @@ -163,157 +172,147 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)  static struct irqaction timer_irqaction = {  	.handler = timer_interrupt, -	.flags = IRQF_DISABLED | IRQF_TIMER, +	.flags = IRQF_TIMER,  	.name = "timer", -	.dev_id = &clockevent_microblaze_timer, +	.dev_id = &clockevent_xilinx_timer,  }; -static __init void microblaze_clockevent_init(void) +static __init void xilinx_clockevent_init(void)  { -	clockevent_microblaze_timer.mult = +	clockevent_xilinx_timer.mult =  		div_sc(timer_clock_freq, NSEC_PER_SEC, -				clockevent_microblaze_timer.shift); -	clockevent_microblaze_timer.max_delta_ns = -		clockevent_delta2ns((u32)~0, &clockevent_microblaze_timer); -	clockevent_microblaze_timer.min_delta_ns = -		clockevent_delta2ns(1, &clockevent_microblaze_timer); -	clockevent_microblaze_timer.cpumask = cpumask_of(0); -	clockevents_register_device(&clockevent_microblaze_timer); +				clockevent_xilinx_timer.shift); +	clockevent_xilinx_timer.max_delta_ns = +		clockevent_delta2ns((u32)~0, &clockevent_xilinx_timer); +	clockevent_xilinx_timer.min_delta_ns = +		clockevent_delta2ns(1, &clockevent_xilinx_timer); +	clockevent_xilinx_timer.cpumask = cpumask_of(0); +	clockevents_register_device(&clockevent_xilinx_timer);  } -static cycle_t microblaze_read(struct clocksource *cs) +static u64 xilinx_clock_read(void) +{ +	return read_fn(timer_baseaddr + TCR1); +} + +static cycle_t xilinx_read(struct clocksource *cs)  {  	/* reading actual value of timer 1 */ -	return (cycle_t) (in_be32(TIMER_BASE + TCR1)); +	return (cycle_t)xilinx_clock_read();  } -static struct timecounter microblaze_tc = { +static struct timecounter xilinx_tc = {  	.cc = NULL,  }; -static cycle_t microblaze_cc_read(const struct cyclecounter *cc) +static cycle_t xilinx_cc_read(const struct cyclecounter *cc)  { -	return microblaze_read(NULL); +	return xilinx_read(NULL);  } -static struct cyclecounter microblaze_cc = { -	.read = microblaze_cc_read, +static struct cyclecounter xilinx_cc = { +	.read = xilinx_cc_read,  	.mask = CLOCKSOURCE_MASK(32),  	.shift = 8,  }; -int __init init_microblaze_timecounter(void) +static int __init init_xilinx_timecounter(void)  { -	microblaze_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC, -				microblaze_cc.shift); +	xilinx_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC, +				xilinx_cc.shift); -	timecounter_init(µblaze_tc, µblaze_cc, sched_clock()); +	timecounter_init(&xilinx_tc, &xilinx_cc, sched_clock());  	return 0;  }  static struct clocksource clocksource_microblaze = { -	.name		= "microblaze_clocksource", +	.name		= "xilinx_clocksource",  	.rating		= 300, -	.read		= microblaze_read, +	.read		= xilinx_read,  	.mask		= CLOCKSOURCE_MASK(32), -	.shift		= 8, /* I can shift it */  	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,  }; -static int __init microblaze_clocksource_init(void) +static int __init xilinx_clocksource_init(void)  { -	clocksource_microblaze.mult = -			clocksource_hz2mult(timer_clock_freq, -						clocksource_microblaze.shift); -	if (clocksource_register(&clocksource_microblaze)) +	if (clocksource_register_hz(&clocksource_microblaze, timer_clock_freq))  		panic("failed to register clocksource");  	/* stop timer1 */ -	out_be32(TIMER_BASE + TCSR1, in_be32(TIMER_BASE + TCSR1) & ~TCSR_ENT); +	write_fn(read_fn(timer_baseaddr + TCSR1) & ~TCSR_ENT, +		 timer_baseaddr + TCSR1);  	/* start timer1 - up counting without interrupt */ -	out_be32(TIMER_BASE + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT); +	write_fn(TCSR_TINT|TCSR_ENT|TCSR_ARHT, timer_baseaddr + TCSR1);  	/* register timecounter - for ftrace support */ -	init_microblaze_timecounter(); +	init_xilinx_timecounter();  	return 0;  } -/* - * We have to protect accesses before timer initialization - * and return 0 for sched_clock function below. - */ -static int timer_initialized; - -void __init time_init(void) +static void __init xilinx_timer_init(struct device_node *timer)  { -	u32 irq, i = 0; +	struct clk *clk; +	static int initialized; +	u32 irq;  	u32 timer_num = 1; -	struct device_node *timer = NULL; -	const void *prop; -#ifdef CONFIG_SELFMOD_TIMER -	unsigned int timer_baseaddr = 0; -	int arr_func[] = { -				(int)µblaze_read, -				(int)&timer_interrupt, -				(int)µblaze_clocksource_init, -				(int)µblaze_timer_set_mode, -				(int)µblaze_timer_set_next_event, -				0 -			}; -#endif -	const char * const timer_list[] = { -		"xlnx,xps-timer-1.00.a", -		NULL -	}; - -	for (i = 0; timer_list[i] != NULL; i++) { -		timer = of_find_compatible_node(NULL, NULL, timer_list[i]); -		if (timer) -			break; + +	if (initialized) +		return; + +	initialized = 1; + +	timer_baseaddr = of_iomap(timer, 0); +	if (!timer_baseaddr) { +		pr_err("ERROR: invalid timer base address\n"); +		BUG();  	} -	BUG_ON(!timer); -	timer_baseaddr = be32_to_cpup(of_get_property(timer, "reg", NULL)); -	timer_baseaddr = (unsigned long) ioremap(timer_baseaddr, PAGE_SIZE); -	irq = be32_to_cpup(of_get_property(timer, "interrupts", NULL)); -	timer_num = be32_to_cpup(of_get_property(timer, -						"xlnx,one-timer-only", NULL)); +	write_fn = timer_write32; +	read_fn = timer_read32; + +	write_fn(TCSR_MDT, timer_baseaddr + TCSR0); +	if (!(read_fn(timer_baseaddr + TCSR0) & TCSR_MDT)) { +		write_fn = timer_write32_be; +		read_fn = timer_read32_be; +	} + +	irq = irq_of_parse_and_map(timer, 0); + +	of_property_read_u32(timer, "xlnx,one-timer-only", &timer_num);  	if (timer_num) { -		eprintk(KERN_EMERG "Please enable two timers in HW\n"); +		pr_emerg("Please enable two timers in HW\n");  		BUG();  	} -#ifdef CONFIG_SELFMOD_TIMER -	selfmod_function((int *) arr_func, timer_baseaddr); -#endif -	printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n", -		timer_list[i], timer_baseaddr, irq); - -	/* If there is clock-frequency property than use it */ -	prop = of_get_property(timer, "clock-frequency", NULL); -	if (prop) -		timer_clock_freq = be32_to_cpup(prop); -	else +	pr_info("%s: irq=%d\n", timer->full_name, irq); + +	clk = of_clk_get(timer, 0); +	if (IS_ERR(clk)) { +		pr_err("ERROR: timer CCF input clock not found\n"); +		/* If there is clock-frequency property than use it */ +		of_property_read_u32(timer, "clock-frequency", +				    &timer_clock_freq); +	} else { +		timer_clock_freq = clk_get_rate(clk); +	} + +	if (!timer_clock_freq) { +		pr_err("ERROR: Using CPU clock frequency\n");  		timer_clock_freq = cpuinfo.cpu_clock_freq; +	}  	freq_div_hz = timer_clock_freq / HZ;  	setup_irq(irq, &timer_irqaction);  #ifdef CONFIG_HEART_BEAT -	setup_heartbeat(); +	microblaze_setup_heartbeat();  #endif -	microblaze_clocksource_init(); -	microblaze_clockevent_init(); -	timer_initialized = 1; -} +	xilinx_clocksource_init(); +	xilinx_clockevent_init(); -unsigned long long notrace sched_clock(void) -{ -	if (timer_initialized) { -		struct clocksource *cs = &clocksource_microblaze; -		cycle_t cyc = cnt32_to_63(cs->read(NULL)); -		return clocksource_cyc2ns(cyc, cs->mult, cs->shift); -	} -	return 0; +	sched_clock_register(xilinx_clock_read, 32, timer_clock_freq);  } + +CLOCKSOURCE_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a", +		       xilinx_timer_init); diff --git a/arch/microblaze/kernel/traps.c b/arch/microblaze/kernel/traps.c index ba034d421ec..cb619533a19 100644 --- a/arch/microblaze/kernel/traps.c +++ b/arch/microblaze/kernel/traps.c @@ -8,14 +8,13 @@   * for more details.   */ +#include <linux/export.h>  #include <linux/kernel.h>  #include <linux/kallsyms.h> -#include <linux/module.h>  #include <linux/sched.h>  #include <linux/debug_locks.h>  #include <asm/exceptions.h> -#include <asm/system.h>  #include <asm/unwind.h>  void trap_init(void) @@ -27,7 +26,7 @@ static unsigned long kstack_depth_to_print;	/* 0 == entire stack */  static int __init kstack_setup(char *s)  { -	return !strict_strtoul(s, 0, &kstack_depth_to_print); +	return !kstrtoul(s, 0, &kstack_depth_to_print);  }  __setup("kstack=", kstack_setup); @@ -67,9 +66,7 @@ void show_stack(struct task_struct *task, unsigned long *sp)  	}  	print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4, (void *)fp,  		       words_to_show << 2, 0); -	printk(KERN_INFO "\n\n"); - -	pr_info("Call Trace:\n"); +	pr_info("\n\nCall Trace:\n");  	microblaze_unwind(task, NULL);  	pr_info("\n"); @@ -78,9 +75,3 @@ void show_stack(struct task_struct *task, unsigned long *sp)  	debug_show_held_locks(task);  } - -void dump_stack(void) -{ -	show_stack(NULL, NULL); -} -EXPORT_SYMBOL(dump_stack); diff --git a/arch/microblaze/kernel/unwind.c b/arch/microblaze/kernel/unwind.c index fefac5c3358..1f7b8d44966 100644 --- a/arch/microblaze/kernel/unwind.c +++ b/arch/microblaze/kernel/unwind.c @@ -13,17 +13,18 @@   */  /* #define DEBUG 1 */ +#include <linux/export.h>  #include <linux/kallsyms.h>  #include <linux/kernel.h>  #include <linux/sched.h>  #include <linux/stacktrace.h>  #include <linux/types.h>  #include <linux/errno.h> -#include <linux/module.h>  #include <linux/io.h>  #include <asm/sections.h>  #include <asm/exceptions.h>  #include <asm/unwind.h> +#include <asm/switch_to.h>  struct stack_trace; @@ -183,7 +184,7 @@ static inline void unwind_trap(struct task_struct *task, unsigned long pc,   * @trace : Where to store stack backtrace (PC values).   *	    NULL == print backtrace to kernel log   */ -void microblaze_unwind_inner(struct task_struct *task, +static void microblaze_unwind_inner(struct task_struct *task,  			     unsigned long pc, unsigned long fp,  			     unsigned long leaf_return,  			     struct stack_trace *trace) diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S index 96a88c31fe4..be9488d6973 100644 --- a/arch/microblaze/kernel/vmlinux.lds.S +++ b/arch/microblaze/kernel/vmlinux.lds.S @@ -44,13 +44,14 @@ SECTIONS {  	__fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET) {  		_fdt_start = . ;		/* place for fdt blob */  		*(__fdt_blob) ;			/* Any link-placed DTB */ -	        . = _fdt_start + 0x4000;	/* Pad up to 16kbyte */ +	        . = _fdt_start + 0x8000;	/* Pad up to 32kbyte */  		_fdt_end = . ;  	}  	. = ALIGN(16);  	RODATA  	EXCEPTION_TABLE(16) +	NOTES  	/*  	 * sdata2 section can go anywhere, but must be word aligned @@ -70,11 +71,6 @@ SECTIONS {  	RW_DATA_SECTION(32, PAGE_SIZE, THREAD_SIZE)  	_edata = . ; -	/* Reserve some low RAM for r0 based memory references */ -	. = ALIGN(0x4) ; -	r0_ram = . ; -	. = . +  PAGE_SIZE;	/* a page should be enough */ -  	/* Under the microblaze ABI, .sdata and .sbss must be contiguous */  	. = ALIGN(8);  	.sdata : AT(ADDR(.sdata) - LOAD_OFFSET) { @@ -123,20 +119,10 @@ SECTIONS {  	__init_end_before_initramfs = .; -	.init.ramfs ALIGN(PAGE_SIZE) : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { -		__initramfs_start = .; -		*(.init.ramfs) -		__initramfs_end = .; -		. = ALIGN(4); -		LONG(0); -/* - * FIXME this can break initramfs for MMU. - * Pad init.ramfs up to page boundary, - * so that __init_end == __bss_start. This will make image.elf - * consistent with the image.bin - */ -		/* . = ALIGN(PAGE_SIZE); */ +	.init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { +		INIT_RAM_FS  	} +  	__init_end = .;  	.bss ALIGN (PAGE_SIZE) : AT(ADDR(.bss) - LOAD_OFFSET) { @@ -146,7 +132,6 @@ SECTIONS {  			*(COMMON)  		. = ALIGN (4) ;  		__bss_stop = . ; -		_ebss = . ;  	}  	. = ALIGN(PAGE_SIZE);  	_end = .;  | 
