static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask) { struct sn_irq_info *sn_irq_info, *sn_irq_info_safe; int cpuid, cpuphys; cpuid = first_cpu(mask); cpuphys = cpu_physical_id(cpuid); list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe, sn_irq_lh[irq], list) { u64 bridge; int local_widget, status; nasid_t local_nasid; struct sn_irq_info *new_irq_info; struct sn_pcibus_provider *pci_provider; new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC); if (new_irq_info == NULL) break; memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info)); bridge = (u64) new_irq_info->irq_bridge; if (!bridge) { kfree(new_irq_info); break; /* irq is not a device interrupt */ } local_nasid = NASID_GET(bridge); if (local_nasid & 1) local_widget = TIO_SWIN_WIDGETNUM(bridge); else local_widget = SWIN_WIDGETNUM(bridge); /* Free the old PROM new_irq_info structure */ sn_intr_free(local_nasid, local_widget, new_irq_info); /* Update kernels new_irq_info with new target info */ unregister_intr_pda(new_irq_info); /* allocate a new PROM new_irq_info struct */ status = sn_intr_alloc(local_nasid, local_widget, __pa(new_irq_info), irq, cpuid_to_nasid(cpuid), cpuid_to_slice(cpuid)); /* SAL call failed */ if (status) { kfree(new_irq_info); break; } new_irq_info->irq_cpuid = cpuid; register_intr_pda(new_irq_info); pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type]; if (pci_provider && pci_provider->target_interrupt) (pci_provider->target_interrupt)(new_irq_info); spin_lock(&sn_irq_info_lock); list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); spin_unlock(&sn_irq_info_lock); call_rcu(&sn_irq_info->rcu, sn_irq_info_free); #ifdef CONFIG_SMP set_irq_affinity_info((irq & 0xff), cpuphys, 0); #endif }
struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info, nasid_t nasid, int slice) { int vector; int cpuid; #ifdef CONFIG_SMP int cpuphys; #endif int64_t bridge; int local_widget, status; nasid_t local_nasid; struct sn_irq_info *new_irq_info; struct sn_pcibus_provider *pci_provider; new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC); if (new_irq_info == NULL) return NULL; memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info)); bridge = (u64) new_irq_info->irq_bridge; if (!bridge) { kfree(new_irq_info); return NULL; /* irq is not a device interrupt */ } local_nasid = NASID_GET(bridge); if (local_nasid & 1) local_widget = TIO_SWIN_WIDGETNUM(bridge); else local_widget = SWIN_WIDGETNUM(bridge); vector = sn_irq_info->irq_irq; /* Free the old PROM new_irq_info structure */ sn_intr_free(local_nasid, local_widget, new_irq_info); unregister_intr_pda(new_irq_info); /* allocate a new PROM new_irq_info struct */ status = sn_intr_alloc(local_nasid, local_widget, new_irq_info, vector, nasid, slice); /* SAL call failed */ if (status) { kfree(new_irq_info); return NULL; } /* Update kernels new_irq_info with new target info */ cpuid = nasid_slice_to_cpuid(new_irq_info->irq_nasid, new_irq_info->irq_slice); new_irq_info->irq_cpuid = cpuid; register_intr_pda(new_irq_info); pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type]; /* * If this represents a line interrupt, target it. If it's * an msi (irq_int_bit < 0), it's already targeted. */ if (new_irq_info->irq_int_bit >= 0 && pci_provider && pci_provider->target_interrupt) (pci_provider->target_interrupt)(new_irq_info); spin_lock(&sn_irq_info_lock); list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); spin_unlock(&sn_irq_info_lock); call_rcu(&sn_irq_info->rcu, sn_irq_info_free); #ifdef CONFIG_SMP cpuphys = cpu_physical_id(cpuid); set_irq_affinity_info((vector & 0xff), cpuphys, 0); #endif return new_irq_info; }