Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 113143
b: refs/heads/master
c: 69c010b
h: refs/heads/master
i:
  113141: 4f749c6
  113139: 9b29dcc
  113135: e02a35e
v: v3
  • Loading branch information
David S. Miller committed Sep 20, 2008
1 parent 76454b6 commit c01f83d
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 130 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 2e57572a50a4de41c6cbc879a4866a312d4cd316
refs/heads/master: 69c010b24560be5ca7667e94a352183e60ed205e
40 changes: 20 additions & 20 deletions trunk/arch/sparc/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -272,17 +272,18 @@ smp4m_ticker:
*/
maybe_smp4m_msg:
GET_PROCESSOR4M_ID(o3)
set sun4m_interrupts, %l5
ld [%l5], %o5
sethi %hi(sun4m_irq_percpu), %l5
sll %o3, 2, %o3
or %l5, %lo(sun4m_irq_percpu), %o5
sethi %hi(0x40000000), %o2
sll %o3, 12, %o3
ld [%o5 + %o3], %o1
andcc %o1, %o2, %g0
ld [%o1 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending
andcc %o3, %o2, %g0
be,a smp4m_ticker
cmp %l7, 14
st %o2, [%o5 + 0x4]
st %o2, [%o1 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x40000000
WRITE_PAUSE
ld [%o5], %g0
ld [%o1 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending
WRITE_PAUSE
or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr
Expand All @@ -300,16 +301,16 @@ linux_trap_ipi15_sun4m:
SAVE_ALL
sethi %hi(0x80000000), %o2
GET_PROCESSOR4M_ID(o0)
set sun4m_interrupts, %l5
ld [%l5], %o5
sll %o0, 12, %o0
add %o5, %o0, %o5
ld [%o5], %o3
sethi %hi(sun4m_irq_percpu), %l5
or %l5, %lo(sun4m_irq_percpu), %o5
sll %o0, 2, %o0
ld [%o5 + %o0], %o5
ld [%o5 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending
andcc %o3, %o2, %g0
be 1f ! Must be an NMI async memory error
st %o2, [%o5 + 4]
st %o2, [%o5 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x80000000
WRITE_PAUSE
ld [%o5], %g0
ld [%o5 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending
WRITE_PAUSE
or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr
Expand All @@ -323,12 +324,11 @@ linux_trap_ipi15_sun4m:
1:
/* NMI async memory error handling. */
sethi %hi(0x80000000), %l4
sethi %hi(0x4000), %o3
sub %o5, %o0, %o5
add %o5, %o3, %l5
st %l4, [%l5 + 0xc]
sethi %hi(sun4m_irq_global), %o5
ld [%o5 + %lo(sun4m_irq_global)], %l5
st %l4, [%l5 + 0x0c] ! sun4m_irq_global->mask_set=0x80000000
WRITE_PAUSE
ld [%l5], %g0
ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
WRITE_PAUSE
or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr
Expand All @@ -337,9 +337,9 @@ linux_trap_ipi15_sun4m:
WRITE_PAUSE
call sun4m_nmi
nop
st %l4, [%l5 + 0x8]
st %l4, [%l5 + 0x08] ! sun4m_irq_global->mask_clear=0x80000000
WRITE_PAUSE
ld [%l5], %g0
ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
WRITE_PAUSE
RESTORE_ALL

Expand Down
163 changes: 54 additions & 109 deletions trunk/arch/sparc/kernel/sun4m_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,53 +41,25 @@

#include "irq.h"

/* On the sun4m, just like the timers, we have both per-cpu and master
* interrupt registers.
*/

/* These registers are used for sending/receiving irqs from/to
* different cpu's.
*/
struct sun4m_intreg_percpu {
unsigned int tbt; /* Interrupts still pending for this cpu. */

/* These next two registers are WRITE-ONLY and are only
* "on bit" sensitive, "off bits" written have NO affect.
*/
unsigned int clear; /* Clear this cpus irqs here. */
unsigned int set; /* Set this cpus irqs here. */
unsigned char space[PAGE_SIZE - 12];
struct sun4m_irq_percpu {
u32 pending;
u32 clear;
u32 set;
};

/*
* djhr
* Actually the clear and set fields in this struct are misleading..
* according to the SLAVIO manual (and the same applies for the SEC)
* the clear field clears bits in the mask which will ENABLE that IRQ
* the set field sets bits in the mask to DISABLE the IRQ.
*
* Also the undirected_xx address in the SLAVIO is defined as
* RESERVED and write only..
*
* DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
* sun4m machines, for MP the layout makes more sense.
*/
struct sun4m_intregs {
struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
unsigned int tbt; /* IRQ's that are still pending. */
unsigned int irqs; /* Master IRQ bits. */

/* Again, like the above, two these registers are WRITE-ONLY. */
unsigned int clear; /* Clear master IRQ's by setting bits here. */
unsigned int set; /* Set master IRQ's by setting bits here. */

/* This register is both READ and WRITE. */
unsigned int undirected_target; /* Which cpu gets undirected irqs. */
struct sun4m_irq_global {
u32 pending;
u32 mask;
u32 mask_clear;
u32 mask_set;
u32 interrupt_target;
};

static unsigned long dummy;
/* Code in entry.S needs to get at these register mappings. */
struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
struct sun4m_irq_global __iomem *sun4m_irq_global;

struct sun4m_intregs *sun4m_interrupts;
static unsigned long dummy;
unsigned long *irq_rcvreg = &dummy;

/* Dave Redman (djhr@tadpole.co.uk)
Expand Down Expand Up @@ -182,9 +154,9 @@ static void sun4m_disable_irq(unsigned int irq_nr)
mask = sun4m_get_irqmask(irq_nr);
local_irq_save(flags);
if (irq_nr > 15)
sun4m_interrupts->set = mask;
sbus_writel(mask, &sun4m_irq_global->mask_set);
else
sun4m_interrupts->cpu_intregs[cpu].set = mask;
sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
local_irq_restore(flags);
}

Expand All @@ -201,13 +173,13 @@ static void sun4m_enable_irq(unsigned int irq_nr)
mask = sun4m_get_irqmask(irq_nr);
local_irq_save(flags);
if (irq_nr > 15)
sun4m_interrupts->clear = mask;
sbus_writel(mask, &sun4m_irq_global->mask_clear);
else
sun4m_interrupts->cpu_intregs[cpu].clear = mask;
sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
local_irq_restore(flags);
} else {
local_irq_save(flags);
sun4m_interrupts->clear = SUN4M_INT_FLOPPY;
sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
local_irq_restore(flags);
}
}
Expand Down Expand Up @@ -236,34 +208,30 @@ static unsigned long cpu_pil_to_imask[16] = {
*/
static void sun4m_disable_pil_irq(unsigned int pil)
{
sun4m_interrupts->set = cpu_pil_to_imask[pil];
sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set);
}

static void sun4m_enable_pil_irq(unsigned int pil)
{
sun4m_interrupts->clear = cpu_pil_to_imask[pil];
sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear);
}

#ifdef CONFIG_SMP
static void sun4m_send_ipi(int cpu, int level)
{
unsigned long mask;

mask = sun4m_get_irqmask(level);
sun4m_interrupts->cpu_intregs[cpu].set = mask;
unsigned long mask = sun4m_get_irqmask(level);
sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
}

static void sun4m_clear_ipi(int cpu, int level)
{
unsigned long mask;

mask = sun4m_get_irqmask(level);
sun4m_interrupts->cpu_intregs[cpu].clear = mask;
unsigned long mask = sun4m_get_irqmask(level);
sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
}

static void sun4m_set_udt(int cpu)
{
sun4m_interrupts->undirected_target = cpu;
sbus_writel(cpu, &sun4m_irq_global->interrupt_target);
}
#endif

Expand Down Expand Up @@ -347,7 +315,7 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
for (i = 0; i < num_cpu_timers; i++)
sbus_writel(0, &timers_percpu[i]->l14_limit);
if (num_cpu_timers == 4)
sbus_writel(SUN4M_INT_E14, &sun4m_interrupts->set);
sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set);

#ifdef CONFIG_SMP
{
Expand All @@ -372,62 +340,38 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)

void __init sun4m_init_IRQ(void)
{
int ie_node,i;
struct linux_prom_registers int_regs[PROMREG_MAX];
int num_regs;
struct resource r;
int mid;

local_irq_disable();
if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
(ie_node = prom_getchild (ie_node)) == 0 ||
(ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
prom_printf("Cannot find /obio/interrupt node\n");
prom_halt();
struct device_node *dp = of_find_node_by_name(NULL, "interrupt");
int len, i, mid, num_cpu_iregs;
const u32 *addr;

if (!dp) {
printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n");
return;
}
num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
sizeof(int_regs));
num_regs = (num_regs/sizeof(struct linux_prom_registers));

/* Apply the obio ranges to these registers. */
prom_apply_obio_ranges(int_regs, num_regs);

int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
int_regs[4].which_io = int_regs[num_regs-1].which_io;
for(ie_node = 1; ie_node < 4; ie_node++) {
int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;

addr = of_get_property(dp, "address", &len);
if (!addr) {
printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
return;
}

memset((char *)&r, 0, sizeof(struct resource));
/* Map the interrupt registers for all possible cpus. */
r.flags = int_regs[0].which_io;
r.start = int_regs[0].phys_addr;
sun4m_interrupts = (struct sun4m_intregs *) of_ioremap(&r, 0,
PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu");
num_cpu_iregs = (len / sizeof(u32)) - 1;
for (i = 0; i < num_cpu_iregs; i++) {
sun4m_irq_percpu[i] = (void __iomem *)
(unsigned long) addr[i];
}
sun4m_irq_global = (void __iomem *)
(unsigned long) addr[num_cpu_iregs];

/* Map the system interrupt control registers. */
r.flags = int_regs[4].which_io;
r.start = int_regs[4].phys_addr;
of_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
local_irq_disable();

sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set);
for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff;

if (!cpu_find_by_instance(1, NULL, NULL)) {
/* system wide interrupts go to cpu 0, this should always
* be safe because it is guaranteed to be fitted or OBP doesn't
* come up
*
* Not sure, but writing here on SLAVIO systems may puke
* so I don't do it unless there is more than 1 cpu.
*/
irq_rcvreg = (unsigned long *)
&sun4m_interrupts->undirected_target;
sun4m_interrupts->undirected_target = 0;
sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);

if (num_cpu_iregs == 4) {
irq_rcvreg = (unsigned long *) &sun4m_irq_global->interrupt_target;
sbus_writel(0, &sun4m_irq_global->interrupt_target);
}
BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
Expand All @@ -442,5 +386,6 @@ void __init sun4m_init_IRQ(void)
BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
#endif

/* Cannot enable interrupts until OBP ticker is disabled. */
}

0 comments on commit c01f83d

Please sign in to comment.