X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fia64%2Fsn%2Fkernel%2Firq.c;fp=arch%2Fia64%2Fsn%2Fkernel%2Firq.c;h=c373113d073a5f23a18fa051239b66f37f516243;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=7bb6ad188ba39855f1516465e4fee89f5b4ef145;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index 7bb6ad188..c373113d0 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c @@ -26,11 +26,11 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info); int sn_force_interrupt_flag = 1; extern int sn_ioif_inited; -struct list_head **sn_irq_lh; -static DEFINE_SPINLOCK(sn_irq_info_lock); /* non-IRQ lock */ +static struct list_head **sn_irq_lh; +static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */ -u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, - struct sn_irq_info *sn_irq_info, +static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, + u64 sn_irq_info, int req_irq, nasid_t req_nasid, int req_slice) { @@ -40,13 +40,12 @@ u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT, (u64) SAL_INTR_ALLOC, (u64) local_nasid, - (u64) local_widget, __pa(sn_irq_info), (u64) req_irq, + (u64) local_widget, (u64) sn_irq_info, (u64) req_irq, (u64) req_nasid, (u64) req_slice); - return ret_stuff.status; } -void sn_intr_free(nasid_t local_nasid, int local_widget, +static inline void sn_intr_free(nasid_t local_nasid, int local_widget, struct sn_irq_info *sn_irq_info) { struct ia64_sal_retval ret_stuff; @@ -113,91 +112,73 @@ static void sn_end_irq(unsigned int irq) static void sn_irq_info_free(struct rcu_head *head); -struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info, - nasid_t nasid, int slice) +static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask) { - int vector; - int cpuphys; - 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; + struct sn_irq_info *sn_irq_info, *sn_irq_info_safe; + int cpuid, cpuphys; - memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info)); + cpuid = first_cpu(mask); + cpuphys = cpu_physical_id(cpuid); - bridge = (u64) new_irq_info->irq_bridge; - if (!bridge) { - kfree(new_irq_info); - return NULL; /* irq is not a device interrupt */ - } + 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); + local_nasid = NASID_GET(bridge); - if (local_nasid & 1) - local_widget = TIO_SWIN_WIDGETNUM(bridge); - else - local_widget = SWIN_WIDGETNUM(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); - /* Update kernels new_irq_info with new target info */ - unregister_intr_pda(new_irq_info); + /* 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, - new_irq_info, vector, - nasid, slice); + /* 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); - return NULL; - } + /* SAL call failed */ + if (status) { + kfree(new_irq_info); + break; + } - cpuphys = nasid_slice_to_cpuid(nasid, slice); - new_irq_info->irq_cpuid = cpuphys; - register_intr_pda(new_irq_info); + new_irq_info->irq_cpuid = cpuid; + register_intr_pda(new_irq_info); - pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type]; + 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); - /* - * 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); + 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((vector & 0xff), cpuphys, 0); + set_irq_affinity_info((irq & 0xff), cpuphys, 0); #endif - - return new_irq_info; -} - -static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask) -{ - struct sn_irq_info *sn_irq_info, *sn_irq_info_safe; - nasid_t nasid; - int slice; - - nasid = cpuid_to_nasid(first_cpu(mask)); - slice = cpuid_to_slice(first_cpu(mask)); - - list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe, - sn_irq_lh[irq], list) - (void)sn_retarget_vector(sn_irq_info, nasid, slice); + } } struct hw_interrupt_type irq_type_sn = { @@ -221,12 +202,9 @@ void sn_irq_init(void) int i; irq_desc_t *base_desc = irq_desc; - ia64_first_device_vector = IA64_SN2_FIRST_DEVICE_VECTOR; - ia64_last_device_vector = IA64_SN2_LAST_DEVICE_VECTOR; - for (i = 0; i < NR_IRQS; i++) { - if (base_desc[i].chip == &no_irq_type) { - base_desc[i].chip = &irq_type_sn; + if (base_desc[i].handler == &no_irq_type) { + base_desc[i].handler = &irq_type_sn; } } } @@ -307,7 +285,6 @@ void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info) /* link it into the sn_irq[irq] list */ spin_lock(&sn_irq_info_lock); list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]); - reserve_irq_vector(sn_irq_info->irq_irq); spin_unlock(&sn_irq_info_lock); register_intr_pda(sn_irq_info); @@ -333,11 +310,8 @@ void sn_irq_unfixup(struct pci_dev *pci_dev) spin_lock(&sn_irq_info_lock); list_del_rcu(&sn_irq_info->list); spin_unlock(&sn_irq_info_lock); - if (list_empty(sn_irq_lh[sn_irq_info->irq_irq])) - free_irq_vector(sn_irq_info->irq_irq); call_rcu(&sn_irq_info->rcu, sn_irq_info_free); pci_dev_put(pci_dev); - } static inline void @@ -376,6 +350,9 @@ static void force_interrupt(int irq) static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info) { u64 regval; + int irr_reg_num; + int irr_bit; + u64 irr_reg; struct pcidev_info *pcidev_info; struct pcibus_info *pcibus_info; @@ -396,7 +373,23 @@ static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info) pdi_pcibus_info; regval = pcireg_intr_status_get(pcibus_info); - if (!ia64_get_irr(irq_to_vector(irq))) { + irr_reg_num = irq_to_vector(irq) / 64; + irr_bit = irq_to_vector(irq) % 64; + switch (irr_reg_num) { + case 0: + irr_reg = ia64_getreg(_IA64_REG_CR_IRR0); + break; + case 1: + irr_reg = ia64_getreg(_IA64_REG_CR_IRR1); + break; + case 2: + irr_reg = ia64_getreg(_IA64_REG_CR_IRR2); + break; + case 3: + irr_reg = ia64_getreg(_IA64_REG_CR_IRR3); + break; + } + if (!test_bit(irr_bit, &irr_reg)) { if (!test_bit(irq, pda->sn_in_service_ivecs)) { regval &= 0xff; if (sn_irq_info->irq_int_bit & regval &