return 0;
}
+extern unsigned long real_hard_smp_processor_id(void);
+
+static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid)
+{
+ unsigned int tid;
+
+ if (this_is_starfire) {
+ tid = starfire_translate(imap, cpuid);
+ tid <<= IMAP_TID_SHIFT;
+ tid &= IMAP_TID_UPA;
+ } else {
+ if (tlb_type == cheetah || tlb_type == cheetah_plus) {
+ unsigned long ver;
+
+ __asm__ ("rdpr %%ver, %0" : "=r" (ver));
+ if ((ver >> 32UL) == __JALAPENO_ID ||
+ (ver >> 32UL) == __SERRANO_ID) {
+ tid = cpuid << IMAP_TID_SHIFT;
+ tid &= IMAP_TID_JBUS;
+ } else {
+ unsigned int a = cpuid & 0x1f;
+ unsigned int n = (cpuid >> 5) & 0x1f;
+
+ tid = ((a << IMAP_AID_SHIFT) |
+ (n << IMAP_NID_SHIFT));
+ tid &= (IMAP_AID_SAFARI |
+ IMAP_NID_SAFARI);;
+ }
+ } else {
+ tid = cpuid << IMAP_TID_SHIFT;
+ tid &= IMAP_TID_UPA;
+ }
+ }
+
+ return tid;
+}
+
/* Now these are always passed a true fully specified sun4u INO. */
void enable_irq(unsigned int irq)
{
struct ino_bucket *bucket = __bucket(irq);
- unsigned long imap;
- unsigned long tid;
+ unsigned long imap, cpuid;
imap = bucket->imap;
if (imap == 0UL)
preempt_disable();
+ /* This gets the physical processor ID, even on uniprocessor,
+ * so we can always program the interrupt target correctly.
+ */
+ cpuid = real_hard_smp_processor_id();
+
if (tlb_type == hypervisor) {
unsigned int ino = __irq_ino(irq);
- int cpu = hard_smp_processor_id();
-
- sun4v_intr_settarget(ino, cpu);
- sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
+ int err;
+
+ err = sun4v_intr_settarget(ino, cpuid);
+ if (err != HV_EOK)
+ printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
+ ino, cpuid, err);
+ err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
+ if (err != HV_EOK)
+ printk("sun4v_intr_setenabled(%x): err(%d)\n",
+ ino, err);
} else {
- if (tlb_type == cheetah || tlb_type == cheetah_plus) {
- unsigned long ver;
-
- __asm__ ("rdpr %%ver, %0" : "=r" (ver));
- if ((ver >> 32) == __JALAPENO_ID ||
- (ver >> 32) == __SERRANO_ID) {
- /* We set it to our JBUS ID. */
- __asm__ __volatile__("ldxa [%%g0] %1, %0"
- : "=r" (tid)
- : "i" (ASI_JBUS_CONFIG));
- tid = ((tid & (0x1fUL<<17)) << 9);
- tid &= IMAP_TID_JBUS;
- } else {
- /* We set it to our Safari AID. */
- __asm__ __volatile__("ldxa [%%g0] %1, %0"
- : "=r" (tid)
- : "i"(ASI_SAFARI_CONFIG));
- tid = ((tid & (0x3ffUL<<17)) << 9);
- tid &= IMAP_AID_SAFARI;
- }
- } else if (this_is_starfire == 0) {
- /* We set it to our UPA MID. */
- __asm__ __volatile__("ldxa [%%g0] %1, %0"
- : "=r" (tid)
- : "i" (ASI_UPA_CONFIG));
- tid = ((tid & UPA_CONFIG_MID) << 9);
- tid &= IMAP_TID_UPA;
- } else {
- tid = (starfire_translate(imap,
- smp_processor_id()) << 26);
- tid &= IMAP_TID_UPA;
- }
+ unsigned int tid = sun4u_compute_tid(imap, cpuid);
/* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product
* of this SYSIO's preconfigured IGN in the SYSIO Control
if (imap != 0UL) {
if (tlb_type == hypervisor) {
unsigned int ino = __irq_ino(irq);
+ int err;
- sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
+ err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
+ if (err != HV_EOK)
+ printk("sun4v_intr_setenabled(%x): "
+ "err(%d)\n", ino, err);
} else {
u32 tmp;
sysino = sun4v_devino_to_sysino(devhandle, devino);
- printk(KERN_INFO "sun4v_irq: Mapping (%x:%x) --> sysino[%lx]\n",
- devhandle, devino, sysino);
-
bucket = &ivector_table[sysino];
/* Catch accidental accesses to these things. IMAP/ICLR handling
* is done by hypervisor calls on sun4v platforms, not by direct
* register accesses.
+ *
+ * But we need to make them look unique for the disable_irq() logic
+ * in free_irq().
*/
- bucket->imap = ~0UL;
- bucket->iclr = ~0UL;
+ bucket->imap = ~0UL - sysino;
+ bucket->iclr = ~0UL - sysino;
bucket->pil = pil;
bucket->flags = flags;
bucket = __bucket(irq);
if (bucket != &pil0_dummy_bucket) {
struct irq_desc *desc = bucket->irq_info;
- unsigned long imap = bucket->imap;
int ent, i;
for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) {
}
if (!desc->action_active_mask) {
+ unsigned long imap = bucket->imap;
+
/* This unique interrupt source is now inactive. */
bucket->flags &= ~IBF_ACTIVE;
if (bp->pil != 0) {
if (tlb_type == hypervisor) {
unsigned int ino = __irq_ino(bp);
+ int err;
- sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
+ err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
+ if (err != HV_EOK)
+ printk("sun4v_intr_setstate(%x): "
+ "err(%d)\n", ino, err);
} else {
upa_writel(ICLR_IDLE, bp->iclr);
- /* Test and add entropy */
- if (random & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
}
+
+ /* Test and add entropy */
+ if (random & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
}
out:
bp->flags &= ~IBF_INPROGRESS;
static int retarget_one_irq(struct irqaction *p, int goal_cpu)
{
struct ino_bucket *bucket = get_ino_in_irqaction(p) + ivector_table;
- unsigned long imap = bucket->imap;
while (!cpu_online(goal_cpu)) {
if (++goal_cpu >= NR_CPUS)
sun4v_intr_settarget(ino, goal_cpu);
sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
} else {
- unsigned int tid;
+ unsigned long imap = bucket->imap;
+ unsigned int tid = sun4u_compute_tid(imap, goal_cpu);
- if (tlb_type == cheetah || tlb_type == cheetah_plus) {
- tid = goal_cpu << 26;
- tid &= IMAP_AID_SAFARI;
- } else if (this_is_starfire == 0) {
- tid = goal_cpu << 26;
- tid &= IMAP_TID_UPA;
- } else {
- tid = (starfire_translate(imap, goal_cpu) << 26);
- tid &= IMAP_TID_UPA;
- }
upa_writel(tid | IMAP_VALID, imap);
}
static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type)
{
- register unsigned long func __asm__("%o5");
- register unsigned long arg0 __asm__("%o0");
- register unsigned long arg1 __asm__("%o1");
- register unsigned long arg2 __asm__("%o2");
-
- func = HV_FAST_CPU_QCONF;
- arg0 = type;
- arg1 = paddr;
- arg2 = 128; /* XXX Implied by Niagara queue offsets. XXX */
- __asm__ __volatile__("ta %8"
- : "=&r" (func), "=&r" (arg0),
- "=&r" (arg1), "=&r" (arg2)
- : "0" (func), "1" (arg0),
- "2" (arg1), "3" (arg2),
- "i" (HV_FAST_TRAP));
-
- if (arg0 != HV_EOK) {
- prom_printf("SUN4V: cpu_qconf(%lu) failed with error %lu\n",
- type, func);
+ unsigned long num_entries = 128;
+ unsigned long status;
+
+ status = sun4v_cpu_qconf(type, paddr, num_entries);
+ if (status != HV_EOK) {
+ prom_printf("SUN4V: sun4v_cpu_qconf(%lu:%lx:%lu) failed, "
+ "err %lu\n", type, paddr, num_entries, status);
prom_halt();
}
}
}
/* Allocate and register the mondo and error queues for this cpu. */
-void __cpuinit sun4v_init_mondo_queues(int use_bootmem)
+void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load)
{
- int cpu = hard_smp_processor_id();
struct trap_per_cpu *tb = &trap_block[cpu];
- alloc_one_mondo(&tb->cpu_mondo_pa, use_bootmem);
- alloc_one_mondo(&tb->dev_mondo_pa, use_bootmem);
- alloc_one_mondo(&tb->resum_mondo_pa, use_bootmem);
- alloc_one_kbuf(&tb->resum_kernel_buf_pa, use_bootmem);
- alloc_one_mondo(&tb->nonresum_mondo_pa, use_bootmem);
- alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, use_bootmem);
+ if (alloc) {
+ alloc_one_mondo(&tb->cpu_mondo_pa, use_bootmem);
+ alloc_one_mondo(&tb->dev_mondo_pa, use_bootmem);
+ alloc_one_mondo(&tb->resum_mondo_pa, use_bootmem);
+ alloc_one_kbuf(&tb->resum_kernel_buf_pa, use_bootmem);
+ alloc_one_mondo(&tb->nonresum_mondo_pa, use_bootmem);
+ alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, use_bootmem);
- init_cpu_send_mondo_info(tb, use_bootmem);
+ init_cpu_send_mondo_info(tb, use_bootmem);
+ }
- sun4v_register_mondo_queues(cpu);
+ if (load) {
+ if (cpu != hard_smp_processor_id()) {
+ prom_printf("SUN4V: init mondo on cpu %d not %d\n",
+ cpu, hard_smp_processor_id());
+ prom_halt();
+ }
+ sun4v_register_mondo_queues(cpu);
+ }
}
/* Only invoked on boot processor. */
memset(&ivector_table[0], 0, sizeof(ivector_table));
if (tlb_type == hypervisor)
- sun4v_init_mondo_queues(1);
+ sun4v_init_mondo_queues(1, hard_smp_processor_id(), 1, 1);
/* We need to clear any IRQ's pending in the soft interrupt
* registers, a spurious one could be left around from the