Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 68633
b: refs/heads/master
c: 42d5f99
h: refs/heads/master
i:
  68631: f1024d0
v: v3
  • Loading branch information
David S. Miller committed Oct 14, 2007
1 parent 2a6d3db commit d1704e1
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 34 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: f14356de1c9eef6cd7ca9679457d8f5f2411f617
refs/heads/master: 42d5f99b1d801b87c45c87d7392f610d5aef351b
122 changes: 91 additions & 31 deletions trunk/arch/sparc64/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <asm/auxio.h>
#include <asm/head.h>
#include <asm/hypervisor.h>
#include <asm/cacheflush.h>

/* UPA nodes send interrupt packet to UltraSparc with first data reg
* value low 5 (7 on Starfire) bits holding the IRQ identifier being
Expand All @@ -56,17 +57,71 @@
* of the vectored interrupt trap handler(s) in entry.S and sun4v_ivec.S
*/
struct ino_bucket {
/*0x00*/unsigned long irq_chain_pa;
/*0x00*/unsigned long __irq_chain_pa;

/* Virtual interrupt number assigned to this INO. */
/*0x08*/unsigned int virt_irq;
/*0x08*/unsigned int __virt_irq;
/*0x0c*/unsigned int __pad;
};

#define NUM_IVECS (IMAP_INR + 1)
struct ino_bucket *ivector_table;
unsigned long ivector_table_pa;

/* On several sun4u processors, it is illegal to mix bypass and
* non-bypass accesses. Therefore we access all INO buckets
* using bypass accesses only.
*/
static unsigned long bucket_get_chain_pa(unsigned long bucket_pa)
{
unsigned long ret;

__asm__ __volatile__("ldxa [%1] %2, %0"
: "=&r" (ret)
: "r" (bucket_pa +
offsetof(struct ino_bucket,
__irq_chain_pa)),
"i" (ASI_PHYS_USE_EC));

return ret;
}

static void bucket_clear_chain_pa(unsigned long bucket_pa)
{
__asm__ __volatile__("stxa %%g0, [%0] %1"
: /* no outputs */
: "r" (bucket_pa +
offsetof(struct ino_bucket,
__irq_chain_pa)),
"i" (ASI_PHYS_USE_EC));
}

static unsigned int bucket_get_virt_irq(unsigned long bucket_pa)
{
unsigned int ret;

__asm__ __volatile__("lduwa [%1] %2, %0"
: "=&r" (ret)
: "r" (bucket_pa +
offsetof(struct ino_bucket,
__virt_irq)),
"i" (ASI_PHYS_USE_EC));

return ret;
}

static void bucket_set_virt_irq(unsigned long bucket_pa,
unsigned int virt_irq)
{
__asm__ __volatile__("stwa %0, [%1] %2"
: /* no outputs */
: "r" (virt_irq),
"r" (bucket_pa +
offsetof(struct ino_bucket,
__virt_irq)),
"i" (ASI_PHYS_USE_EC));
}

#define __irq_ino(irq) \
(((struct ino_bucket *)(irq)) - &ivector_table[0])
#define __bucket(irq) ((struct ino_bucket *)(irq))
Expand Down Expand Up @@ -569,18 +624,21 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
{
struct ino_bucket *bucket;
struct irq_handler_data *data;
unsigned int virt_irq;
int ino;

BUG_ON(tlb_type == hypervisor);

ino = (upa_readq(imap) & (IMAP_IGN | IMAP_INO)) + inofixup;
bucket = &ivector_table[ino];
if (!bucket->virt_irq) {
bucket->virt_irq = virt_irq_alloc(__irq(bucket));
set_irq_chip(bucket->virt_irq, &sun4u_irq);
virt_irq = bucket_get_virt_irq(__pa(bucket));
if (!virt_irq) {
virt_irq = virt_irq_alloc(__irq(bucket));
bucket_set_virt_irq(__pa(bucket), virt_irq);
set_irq_chip(virt_irq, &sun4u_irq);
}

data = get_irq_chip_data(bucket->virt_irq);
data = get_irq_chip_data(virt_irq);
if (unlikely(data))
goto out;

Expand All @@ -589,30 +647,33 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
prom_halt();
}
set_irq_chip_data(bucket->virt_irq, data);
set_irq_chip_data(virt_irq, data);

data->imap = imap;
data->iclr = iclr;

out:
return bucket->virt_irq;
return virt_irq;
}

static unsigned int sun4v_build_common(unsigned long sysino,
struct irq_chip *chip)
{
struct ino_bucket *bucket;
struct irq_handler_data *data;
unsigned int virt_irq;

BUG_ON(tlb_type != hypervisor);

bucket = &ivector_table[sysino];
if (!bucket->virt_irq) {
bucket->virt_irq = virt_irq_alloc(__irq(bucket));
set_irq_chip(bucket->virt_irq, chip);
virt_irq = bucket_get_virt_irq(__pa(bucket));
if (!virt_irq) {
virt_irq = virt_irq_alloc(__irq(bucket));
bucket_set_virt_irq(__pa(bucket), virt_irq);
set_irq_chip(virt_irq, chip);
}

data = get_irq_chip_data(bucket->virt_irq);
data = get_irq_chip_data(virt_irq);
if (unlikely(data))
goto out;

Expand All @@ -621,7 +682,7 @@ static unsigned int sun4v_build_common(unsigned long sysino,
prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
prom_halt();
}
set_irq_chip_data(bucket->virt_irq, data);
set_irq_chip_data(virt_irq, data);

/* Catch accidental accesses to these things. IMAP/ICLR handling
* is done by hypervisor calls on sun4v platforms, not by direct
Expand All @@ -631,7 +692,7 @@ static unsigned int sun4v_build_common(unsigned long sysino,
data->iclr = ~0UL;

out:
return bucket->virt_irq;
return virt_irq;
}

unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
Expand All @@ -646,19 +707,24 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
struct irq_handler_data *data;
struct ino_bucket *bucket;
unsigned long hv_err, cookie;
unsigned int virt_irq;

bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC);
if (unlikely(!bucket))
return 0;
__flush_dcache_range((unsigned long) bucket,
((unsigned long) bucket +
sizeof(struct ino_bucket)));

bucket->virt_irq = virt_irq_alloc(__irq(bucket));
set_irq_chip(bucket->virt_irq, &sun4v_virq);
virt_irq = virt_irq_alloc(__irq(bucket));
bucket_set_virt_irq(__pa(bucket), virt_irq);
set_irq_chip(virt_irq, &sun4v_virq);

data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
if (unlikely(!data))
return 0;

set_irq_chip_data(bucket->virt_irq, data);
set_irq_chip_data(virt_irq, data);

/* Catch accidental accesses to these things. IMAP/ICLR handling
* is done by hypervisor calls on sun4v platforms, not by direct
Expand All @@ -675,10 +741,10 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
prom_halt();
}

virt_to_real_irq_table[bucket->virt_irq].dev_handle = devhandle;
virt_to_real_irq_table[bucket->virt_irq].dev_ino = devino;
virt_to_real_irq_table[virt_irq].dev_handle = devhandle;
virt_to_real_irq_table[virt_irq].dev_ino = devino;

return bucket->virt_irq;
return virt_irq;
}

void ack_bad_irq(unsigned int virt_irq)
Expand Down Expand Up @@ -718,17 +784,9 @@ void handler_irq(int irq, struct pt_regs *regs)
unsigned long next_pa;
unsigned int virt_irq;

__asm__ __volatile__("ldxa [%2] %4, %0\n\t"
"lduwa [%3] %4, %1\n\t"
"stxa %%g0, [%2] %4"
: "=&r" (next_pa), "=&r" (virt_irq)
: "r" (bucket_pa +
offsetof(struct ino_bucket,
irq_chain_pa)),
"r" (bucket_pa +
offsetof(struct ino_bucket,
virt_irq)),
"i" (ASI_PHYS_USE_EC));
next_pa = bucket_get_chain_pa(bucket_pa);
virt_irq = bucket_get_virt_irq(bucket_pa);
bucket_clear_chain_pa(bucket_pa);

__do_IRQ(virt_irq);

Expand Down Expand Up @@ -957,6 +1015,8 @@ void __init init_IRQ(void)
prom_printf("Fatal error, cannot allocate ivector_table\n");
prom_halt();
}
__flush_dcache_range((unsigned long) ivector_table,
((unsigned long) ivector_table) + size);

ivector_table_pa = __pa(ivector_table);

Expand Down
2 changes: 0 additions & 2 deletions trunk/arch/sparc64/mm/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,6 @@ void prom_world(int enter)
__asm__ __volatile__("flushw");
}

#ifdef DCACHE_ALIASING_POSSIBLE
void __flush_dcache_range(unsigned long start, unsigned long end)
{
unsigned long va;
Expand All @@ -655,7 +654,6 @@ void __flush_dcache_range(unsigned long start, unsigned long end)
"i" (ASI_DCACHE_INVALIDATE));
}
}
#endif /* DCACHE_ALIASING_POSSIBLE */

/* get_new_mmu_context() uses "cache + 1". */
DEFINE_SPINLOCK(ctx_alloc_lock);
Expand Down

0 comments on commit d1704e1

Please sign in to comment.