Commit b9e763cd authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc

Pull sparc fixes from David Miller:
 "Various sparc bug fixes, in particular:

  1) TSB hashes have to be flushed before TLB on sparc64, from Dave
     Kleikamp.

  2) LEON timer interrupts can get stuck, from Andreas Larsson.

  3) Sparc64 needs to handle lack of address-congruence devicetree
     property, from Bob Picco"

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc:
  sparc: tsb must be flushed before tlb
  sparc,leon: Convert to use devm_ioremap_resource
  sparc64 address-congruence property
  sparc32, leon: Enable interrupts before going idle to avoid getting stuck
  sparc32, leon: Remove separate "ticker" timer for SMP
  sparc: kernel: using strlcpy() instead of strcpy()
  arch: sparc: prom: looping issue, need additional length check in the outside looping
  sparc: remove inline marking of EXPORT_SYMBOL functions
  sparc: Switch to asm-generic/linkage.h
parents aa4927b9 23a01138
...@@ -6,6 +6,7 @@ generic-y += cputime.h ...@@ -6,6 +6,7 @@ generic-y += cputime.h
generic-y += div64.h generic-y += div64.h
generic-y += emergency-restart.h generic-y += emergency-restart.h
generic-y += exec.h generic-y += exec.h
generic-y += linkage.h
generic-y += local64.h generic-y += local64.h
generic-y += mutex.h generic-y += mutex.h
generic-y += irq_regs.h generic-y += irq_regs.h
......
...@@ -135,7 +135,7 @@ static inline int sparc_leon3_cpuid(void) ...@@ -135,7 +135,7 @@ static inline int sparc_leon3_cpuid(void)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
# define LEON3_IRQ_IPI_DEFAULT 13 # define LEON3_IRQ_IPI_DEFAULT 13
# define LEON3_IRQ_TICKER (leon3_ticker_irq) # define LEON3_IRQ_TICKER (leon3_gptimer_irq)
# define LEON3_IRQ_CROSS_CALL 15 # define LEON3_IRQ_CROSS_CALL 15
#endif #endif
......
...@@ -47,6 +47,7 @@ struct amba_prom_registers { ...@@ -47,6 +47,7 @@ struct amba_prom_registers {
#define LEON3_GPTIMER_LD 4 #define LEON3_GPTIMER_LD 4
#define LEON3_GPTIMER_IRQEN 8 #define LEON3_GPTIMER_IRQEN 8
#define LEON3_GPTIMER_SEPIRQ 8 #define LEON3_GPTIMER_SEPIRQ 8
#define LEON3_GPTIMER_TIMERS 0x7
#define LEON23_REG_TIMER_CONTROL_EN 0x00000001 /* 1 = enable counting */ #define LEON23_REG_TIMER_CONTROL_EN 0x00000001 /* 1 = enable counting */
/* 0 = hold scalar and counter */ /* 0 = hold scalar and counter */
......
#ifndef __ASM_LINKAGE_H
#define __ASM_LINKAGE_H
/* Nothing to see here... */
#endif
...@@ -843,7 +843,8 @@ void ldom_reboot(const char *boot_command) ...@@ -843,7 +843,8 @@ void ldom_reboot(const char *boot_command)
unsigned long len; unsigned long len;
strcpy(full_boot_str, "boot "); strcpy(full_boot_str, "boot ");
strcpy(full_boot_str + strlen("boot "), boot_command); strlcpy(full_boot_str + strlen("boot "), boot_command,
sizeof(full_boot_str + strlen("boot ")));
len = strlen(full_boot_str); len = strlen(full_boot_str);
if (reboot_data_supported) { if (reboot_data_supported) {
......
...@@ -38,7 +38,6 @@ static DEFINE_SPINLOCK(leon_irq_lock); ...@@ -38,7 +38,6 @@ static DEFINE_SPINLOCK(leon_irq_lock);
unsigned long leon3_gptimer_irq; /* interrupt controller irq number */ unsigned long leon3_gptimer_irq; /* interrupt controller irq number */
unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */ unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */
int leon3_ticker_irq; /* Timer ticker IRQ */
unsigned int sparc_leon_eirq; unsigned int sparc_leon_eirq;
#define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu]) #define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu])
#define LEON_IACK (&leon3_irqctrl_regs->iclear) #define LEON_IACK (&leon3_irqctrl_regs->iclear)
...@@ -278,6 +277,9 @@ irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused) ...@@ -278,6 +277,9 @@ irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused)
leon_clear_profile_irq(cpu); leon_clear_profile_irq(cpu);
if (cpu == boot_cpu_id)
timer_interrupt(irq, NULL);
ce = &per_cpu(sparc32_clockevent, cpu); ce = &per_cpu(sparc32_clockevent, cpu);
irq_enter(); irq_enter();
...@@ -299,6 +301,7 @@ void __init leon_init_timers(void) ...@@ -299,6 +301,7 @@ void __init leon_init_timers(void)
int icsel; int icsel;
int ampopts; int ampopts;
int err; int err;
u32 config;
sparc_config.get_cycles_offset = leon_cycles_offset; sparc_config.get_cycles_offset = leon_cycles_offset;
sparc_config.cs_period = 1000000 / HZ; sparc_config.cs_period = 1000000 / HZ;
...@@ -377,23 +380,6 @@ void __init leon_init_timers(void) ...@@ -377,23 +380,6 @@ void __init leon_init_timers(void)
LEON3_BYPASS_STORE_PA( LEON3_BYPASS_STORE_PA(
&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0); &leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0);
#ifdef CONFIG_SMP
leon3_ticker_irq = leon3_gptimer_irq + 1 + leon3_gptimer_idx;
if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) &
(1<<LEON3_GPTIMER_SEPIRQ))) {
printk(KERN_ERR "timer not configured with separate irqs\n");
BUG();
}
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].val,
0);
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld,
(((1000000/HZ) - 1)));
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl,
0);
#endif
/* /*
* The IRQ controller may (if implemented) consist of multiple * The IRQ controller may (if implemented) consist of multiple
* IRQ controllers, each mapped on a 4Kb boundary. * IRQ controllers, each mapped on a 4Kb boundary.
...@@ -416,13 +402,6 @@ void __init leon_init_timers(void) ...@@ -416,13 +402,6 @@ void __init leon_init_timers(void)
if (eirq != 0) if (eirq != 0)
leon_eirq_setup(eirq); leon_eirq_setup(eirq);
irq = _leon_build_device_irq(NULL, leon3_gptimer_irq+leon3_gptimer_idx);
err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
if (err) {
printk(KERN_ERR "unable to attach timer IRQ%d\n", irq);
prom_halt();
}
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
{ {
unsigned long flags; unsigned long flags;
...@@ -439,30 +418,31 @@ void __init leon_init_timers(void) ...@@ -439,30 +418,31 @@ void __init leon_init_timers(void)
} }
#endif #endif
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, config = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config);
LEON3_GPTIMER_EN | if (config & (1 << LEON3_GPTIMER_SEPIRQ))
LEON3_GPTIMER_RL | leon3_gptimer_irq += leon3_gptimer_idx;
LEON3_GPTIMER_LD | else if ((config & LEON3_GPTIMER_TIMERS) > 1)
LEON3_GPTIMER_IRQEN); pr_warn("GPTIMER uses shared irqs, using other timers of the same core will fail.\n");
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* Install per-cpu IRQ handler for broadcasted ticker */ /* Install per-cpu IRQ handler for broadcasted ticker */
irq = leon_build_device_irq(leon3_ticker_irq, handle_percpu_irq, irq = leon_build_device_irq(leon3_gptimer_irq, handle_percpu_irq,
"per-cpu", 0); "per-cpu", 0);
err = request_irq(irq, leon_percpu_timer_ce_interrupt, err = request_irq(irq, leon_percpu_timer_ce_interrupt,
IRQF_PERCPU | IRQF_TIMER, "ticker", IRQF_PERCPU | IRQF_TIMER, "timer", NULL);
NULL); #else
irq = _leon_build_device_irq(NULL, leon3_gptimer_irq);
err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
#endif
if (err) { if (err) {
printk(KERN_ERR "unable to attach ticker IRQ%d\n", irq); pr_err("Unable to attach timer IRQ%d\n", irq);
prom_halt(); prom_halt();
} }
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl,
LEON3_GPTIMER_EN | LEON3_GPTIMER_EN |
LEON3_GPTIMER_RL | LEON3_GPTIMER_RL |
LEON3_GPTIMER_LD | LEON3_GPTIMER_LD |
LEON3_GPTIMER_IRQEN); LEON3_GPTIMER_IRQEN);
#endif
return; return;
bad: bad:
printk(KERN_ERR "No Timer/irqctrl found\n"); printk(KERN_ERR "No Timer/irqctrl found\n");
......
...@@ -536,11 +536,9 @@ static int grpci1_of_probe(struct platform_device *ofdev) ...@@ -536,11 +536,9 @@ static int grpci1_of_probe(struct platform_device *ofdev)
/* find device register base address */ /* find device register base address */
res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
regs = devm_request_and_ioremap(&ofdev->dev, res); regs = devm_ioremap_resource(&ofdev->dev, res);
if (!regs) { if (IS_ERR(regs))
dev_err(&ofdev->dev, "io-regs mapping failed\n"); return PTR_ERR(regs);
return -EADDRNOTAVAIL;
}
/* /*
* check that we're in Host Slot and that we can act as a Host Bridge * check that we're in Host Slot and that we can act as a Host Bridge
......
...@@ -47,6 +47,10 @@ void pmc_leon_idle_fixup(void) ...@@ -47,6 +47,10 @@ void pmc_leon_idle_fixup(void)
* MMU does not get a TLB miss here by using the MMU BYPASS ASI. * MMU does not get a TLB miss here by using the MMU BYPASS ASI.
*/ */
register unsigned int address = (unsigned int)leon3_irqctrl_regs; register unsigned int address = (unsigned int)leon3_irqctrl_regs;
/* Interrupts need to be enabled to not hang the CPU */
local_irq_enable();
__asm__ __volatile__ ( __asm__ __volatile__ (
"wr %%g0, %%asr19\n" "wr %%g0, %%asr19\n"
"lda [%0] %1, %%g0\n" "lda [%0] %1, %%g0\n"
...@@ -60,6 +64,9 @@ void pmc_leon_idle_fixup(void) ...@@ -60,6 +64,9 @@ void pmc_leon_idle_fixup(void)
*/ */
void pmc_leon_idle(void) void pmc_leon_idle(void)
{ {
/* Interrupts need to be enabled to not hang the CPU */
local_irq_enable();
/* For systems without power-down, this will be no-op */ /* For systems without power-down, this will be no-op */
__asm__ __volatile__ ("wr %g0, %asr19\n\t"); __asm__ __volatile__ ("wr %g0, %asr19\n\t");
} }
......
...@@ -304,7 +304,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -304,7 +304,7 @@ void __init setup_arch(char **cmdline_p)
/* Initialize PROM console and command line. */ /* Initialize PROM console and command line. */
*cmdline_p = prom_getbootargs(); *cmdline_p = prom_getbootargs();
strcpy(boot_command_line, *cmdline_p); strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE);
parse_early_param(); parse_early_param();
boot_flags_init(*cmdline_p); boot_flags_init(*cmdline_p);
......
...@@ -555,7 +555,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -555,7 +555,7 @@ void __init setup_arch(char **cmdline_p)
{ {
/* Initialize PROM console and command line. */ /* Initialize PROM console and command line. */
*cmdline_p = prom_getbootargs(); *cmdline_p = prom_getbootargs();
strcpy(boot_command_line, *cmdline_p); strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE);
parse_early_param(); parse_early_param();
boot_flags_init(*cmdline_p); boot_flags_init(*cmdline_p);
......
...@@ -1098,7 +1098,14 @@ static int __init grab_mblocks(struct mdesc_handle *md) ...@@ -1098,7 +1098,14 @@ static int __init grab_mblocks(struct mdesc_handle *md)
m->size = *val; m->size = *val;
val = mdesc_get_property(md, node, val = mdesc_get_property(md, node,
"address-congruence-offset", NULL); "address-congruence-offset", NULL);
m->offset = *val;
/* The address-congruence-offset property is optional.
* Explicity zero it be identifty this.
*/
if (val)
m->offset = *val;
else
m->offset = 0UL;
numadbg("MBLOCK[%d]: base[%llx] size[%llx] offset[%llx]\n", numadbg("MBLOCK[%d]: base[%llx] size[%llx] offset[%llx]\n",
count - 1, m->base, m->size, m->offset); count - 1, m->base, m->size, m->offset);
......
...@@ -85,8 +85,8 @@ static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr, ...@@ -85,8 +85,8 @@ static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr,
} }
if (!tb->active) { if (!tb->active) {
global_flush_tlb_page(mm, vaddr);
flush_tsb_user_page(mm, vaddr); flush_tsb_user_page(mm, vaddr);
global_flush_tlb_page(mm, vaddr);
goto out; goto out;
} }
......
...@@ -23,23 +23,25 @@ prom_getbootargs(void) ...@@ -23,23 +23,25 @@ prom_getbootargs(void)
return barg_buf; return barg_buf;
} }
switch(prom_vers) { switch (prom_vers) {
case PROM_V0: case PROM_V0:
cp = barg_buf; cp = barg_buf;
/* Start from 1 and go over fd(0,0,0)kernel */ /* Start from 1 and go over fd(0,0,0)kernel */
for(iter = 1; iter < 8; iter++) { for (iter = 1; iter < 8; iter++) {
arg = (*(romvec->pv_v0bootargs))->argv[iter]; arg = (*(romvec->pv_v0bootargs))->argv[iter];
if (arg == NULL) if (arg == NULL)
break; break;
while(*arg != 0) { while (*arg != 0) {
/* Leave place for space and null. */ /* Leave place for space and null. */
if(cp >= barg_buf + BARG_LEN-2){ if (cp >= barg_buf + BARG_LEN - 2)
/* We might issue a warning here. */ /* We might issue a warning here. */
break; break;
}
*cp++ = *arg++; *cp++ = *arg++;
} }
*cp++ = ' '; *cp++ = ' ';
if (cp >= barg_buf + BARG_LEN - 1)
/* We might issue a warning here. */
break;
} }
*cp = 0; *cp = 0;
break; break;
......
...@@ -39,7 +39,7 @@ inline phandle __prom_getchild(phandle node) ...@@ -39,7 +39,7 @@ inline phandle __prom_getchild(phandle node)
return prom_node_to_node("child", node); return prom_node_to_node("child", node);
} }
inline phandle prom_getchild(phandle node) phandle prom_getchild(phandle node)
{ {
phandle cnode; phandle cnode;
...@@ -72,7 +72,7 @@ inline phandle __prom_getsibling(phandle node) ...@@ -72,7 +72,7 @@ inline phandle __prom_getsibling(phandle node)
return prom_node_to_node(prom_peer_name, node); return prom_node_to_node(prom_peer_name, node);
} }
inline phandle prom_getsibling(phandle node) phandle prom_getsibling(phandle node)
{ {
phandle sibnode; phandle sibnode;
...@@ -89,7 +89,7 @@ EXPORT_SYMBOL(prom_getsibling); ...@@ -89,7 +89,7 @@ EXPORT_SYMBOL(prom_getsibling);
/* Return the length in bytes of property 'prop' at node 'node'. /* Return the length in bytes of property 'prop' at node 'node'.
* Return -1 on error. * Return -1 on error.
*/ */
inline int prom_getproplen(phandle node, const char *prop) int prom_getproplen(phandle node, const char *prop)
{ {
unsigned long args[6]; unsigned long args[6];
...@@ -113,8 +113,8 @@ EXPORT_SYMBOL(prom_getproplen); ...@@ -113,8 +113,8 @@ EXPORT_SYMBOL(prom_getproplen);
* 'buffer' which has a size of 'bufsize'. If the acquisition * 'buffer' which has a size of 'bufsize'. If the acquisition
* was successful the length will be returned, else -1 is returned. * was successful the length will be returned, else -1 is returned.
*/ */
inline int prom_getproperty(phandle node, const char *prop, int prom_getproperty(phandle node, const char *prop,
char *buffer, int bufsize) char *buffer, int bufsize)
{ {
unsigned long args[8]; unsigned long args[8];
int plen; int plen;
...@@ -141,7 +141,7 @@ EXPORT_SYMBOL(prom_getproperty); ...@@ -141,7 +141,7 @@ EXPORT_SYMBOL(prom_getproperty);
/* Acquire an integer property and return its value. Returns -1 /* Acquire an integer property and return its value. Returns -1
* on failure. * on failure.
*/ */
inline int prom_getint(phandle node, const char *prop) int prom_getint(phandle node, const char *prop)
{ {
int intprop; int intprop;
...@@ -235,7 +235,7 @@ static const char *prom_nextprop_name = "nextprop"; ...@@ -235,7 +235,7 @@ static const char *prom_nextprop_name = "nextprop";
/* Return the first property type for node 'node'. /* Return the first property type for node 'node'.
* buffer should be at least 32B in length * buffer should be at least 32B in length
*/ */
inline char *prom_firstprop(phandle node, char *buffer) char *prom_firstprop(phandle node, char *buffer)
{ {
unsigned long args[7]; unsigned long args[7];
...@@ -261,7 +261,7 @@ EXPORT_SYMBOL(prom_firstprop); ...@@ -261,7 +261,7 @@ EXPORT_SYMBOL(prom_firstprop);
* at node 'node' . Returns NULL string if no more * at node 'node' . Returns NULL string if no more
* property types for this node. * property types for this node.
*/ */
inline char *prom_nextprop(phandle node, const char *oprop, char *buffer) char *prom_nextprop(phandle node, const char *oprop, char *buffer)
{ {
unsigned long args[7]; unsigned long args[7];
char buf[32]; char buf[32];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment