void __init xics_init(void) { int rc = -1; /* Fist locate ICP */ if (firmware_has_feature(FW_FEATURE_LPAR)) rc = icp_hv_init(); if (rc < 0) rc = icp_native_init(); if (rc < 0) { pr_warning("XICS: Cannot find a Presentation Controller !\n"); return; } /* Copy get_irq callback over to ppc_md */ ppc_md.get_irq = icp_ops->get_irq; /* Patch up IPI chip EOI */ xics_ipi_chip.irq_eoi = icp_ops->eoi; /* Now locate ICS */ rc = ics_rtas_init(); if (rc < 0) rc = ics_opal_init(); if (rc < 0) pr_warning("XICS: Cannot find a Source Controller !\n"); /* Initialize common bits */ xics_get_server_size(); xics_update_irq_servers(); xics_init_host(); xics_setup_cpu(); }
void __init xics_init(void) { int rc = -1; if (firmware_has_feature(FW_FEATURE_LPAR)) rc = icp_hv_init(); if (rc < 0) rc = icp_native_init(); if (rc < 0) { pr_warning("XICS: Cannot find a Presentation Controller !\n"); return; } ppc_md.get_irq = icp_ops->get_irq; xics_ipi_chip.irq_eoi = icp_ops->eoi; rc = ics_rtas_init(); if (rc < 0) rc = ics_opal_init(); if (rc < 0) pr_warning("XICS: Cannot find a Source Controller !\n"); xics_get_server_size(); xics_update_irq_servers(); xics_init_host(); xics_setup_cpu(); }
/* Interrupts are disabled. */ void xics_migrate_irqs_away(void) { int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id(); unsigned int irq, virq; /* If we used to be the default server, move to the new "boot_cpuid" */ if (hw_cpu == xics_default_server) xics_update_irq_servers(); /* Reject any interrupt that was queued to us... */ icp_ops->set_priority(0); /* Remove ourselves from the global interrupt queue */ xics_set_cpu_giq(xics_default_distrib_server, 0); /* Allow IPIs again... */ icp_ops->set_priority(DEFAULT_PRIORITY); for_each_irq(virq) { struct irq_desc *desc; struct irq_chip *chip; long server; unsigned long flags; struct ics *ics; /* We can't set affinity on ISA interrupts */ if (virq < NUM_ISA_INTERRUPTS) continue; desc = irq_to_desc(virq); /* We only need to migrate enabled IRQS */ if (!desc || !desc->action) continue; if (desc->irq_data.domain != xics_host) continue; irq = desc->irq_data.hwirq; /* We need to get IPIs still. */ if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) continue; chip = irq_desc_get_chip(desc); if (!chip || !chip->irq_set_affinity) continue; raw_spin_lock_irqsave(&desc->lock, flags); /* Locate interrupt server */ server = -1; ics = irq_get_chip_data(virq); if (ics) server = ics->get_server(ics, irq); if (server < 0) { printk(KERN_ERR "%s: Can't find server for irq %d\n", __func__, irq); goto unlock; } /* We only support delivery to all cpus or to one cpu. * The irq has to be migrated only in the single cpu * case. */ if (server != hw_cpu) goto unlock; /* This is expected during cpu offline. */ if (cpu_online(cpu)) pr_warning("IRQ %u affinity broken off cpu %u\n", virq, cpu); /* Reset affinity to all cpus */ raw_spin_unlock_irqrestore(&desc->lock, flags); irq_set_affinity(virq, cpu_all_mask); continue; unlock: raw_spin_unlock_irqrestore(&desc->lock, flags); } }
void xics_migrate_irqs_away(void) { int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id(); unsigned int irq, virq; struct irq_desc *desc; if (hw_cpu == xics_default_server) xics_update_irq_servers(); icp_ops->set_priority(0); xics_set_cpu_giq(xics_default_distrib_server, 0); icp_ops->set_priority(DEFAULT_PRIORITY); for_each_irq_desc(virq, desc) { struct irq_chip *chip; long server; unsigned long flags; struct ics *ics; if (virq < NUM_ISA_INTERRUPTS) continue; if (!desc->action) continue; if (desc->irq_data.domain != xics_host) continue; irq = desc->irq_data.hwirq; if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) continue; chip = irq_desc_get_chip(desc); if (!chip || !chip->irq_set_affinity) continue; raw_spin_lock_irqsave(&desc->lock, flags); server = -1; ics = irq_get_chip_data(virq); if (ics) server = ics->get_server(ics, irq); if (server < 0) { printk(KERN_ERR "%s: Can't find server for irq %d\n", __func__, irq); goto unlock; } if (server != hw_cpu) goto unlock; if (cpu_online(cpu)) pr_warning("IRQ %u affinity broken off cpu %u\n", virq, cpu); raw_spin_unlock_irqrestore(&desc->lock, flags); irq_set_affinity(virq, cpu_all_mask); continue; unlock: raw_spin_unlock_irqrestore(&desc->lock, flags); } }