aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/sn/kernel/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/sn/kernel/irq.c')
-rw-r--r--arch/ia64/sn/kernel/irq.c75
1 files changed, 39 insertions, 36 deletions
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
index 84d276a14ecb..9fc74631ba8a 100644
--- a/arch/ia64/sn/kernel/irq.c
+++ b/arch/ia64/sn/kernel/irq.c
@@ -5,7 +5,7 @@
5 * License. See the file "COPYING" in the main directory of this archive 5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details. 6 * for more details.
7 * 7 *
8 * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. 8 * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
9 */ 9 */
10 10
11#include <linux/irq.h> 11#include <linux/irq.h>
@@ -76,16 +76,14 @@ static void sn_enable_irq(unsigned int irq)
76 76
77static void sn_ack_irq(unsigned int irq) 77static void sn_ack_irq(unsigned int irq)
78{ 78{
79 uint64_t event_occurred, mask = 0; 79 u64 event_occurred, mask = 0;
80 int nasid;
81 80
82 irq = irq & 0xff; 81 irq = irq & 0xff;
83 nasid = get_nasid();
84 event_occurred = 82 event_occurred =
85 HUB_L((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED)); 83 HUB_L((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED));
86 mask = event_occurred & SH_ALL_INT_MASK; 84 mask = event_occurred & SH_ALL_INT_MASK;
87 HUB_S((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS), 85 HUB_S((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS),
88 mask); 86 mask);
89 __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs); 87 __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs);
90 88
91 move_irq(irq); 89 move_irq(irq);
@@ -93,15 +91,12 @@ static void sn_ack_irq(unsigned int irq)
93 91
94static void sn_end_irq(unsigned int irq) 92static void sn_end_irq(unsigned int irq)
95{ 93{
96 int nasid;
97 int ivec; 94 int ivec;
98 uint64_t event_occurred; 95 u64 event_occurred;
99 96
100 ivec = irq & 0xff; 97 ivec = irq & 0xff;
101 if (ivec == SGI_UART_VECTOR) { 98 if (ivec == SGI_UART_VECTOR) {
102 nasid = get_nasid(); 99 event_occurred = HUB_L((u64*)LOCAL_MMR_ADDR (SH_EVENT_OCCURRED));
103 event_occurred = HUB_L((uint64_t *) GLOBAL_MMR_ADDR
104 (nasid, SH_EVENT_OCCURRED));
105 /* If the UART bit is set here, we may have received an 100 /* If the UART bit is set here, we may have received an
106 * interrupt from the UART that the driver missed. To 101 * interrupt from the UART that the driver missed. To
107 * make sure, we IPI ourselves to force us to look again. 102 * make sure, we IPI ourselves to force us to look again.
@@ -132,6 +127,7 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
132 int local_widget, status; 127 int local_widget, status;
133 nasid_t local_nasid; 128 nasid_t local_nasid;
134 struct sn_irq_info *new_irq_info; 129 struct sn_irq_info *new_irq_info;
130 struct sn_pcibus_provider *pci_provider;
135 131
136 new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC); 132 new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
137 if (new_irq_info == NULL) 133 if (new_irq_info == NULL)
@@ -171,8 +167,9 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
171 new_irq_info->irq_cpuid = cpuid; 167 new_irq_info->irq_cpuid = cpuid;
172 register_intr_pda(new_irq_info); 168 register_intr_pda(new_irq_info);
173 169
174 if (IS_PCI_BRIDGE_ASIC(new_irq_info->irq_bridge_type)) 170 pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
175 pcibr_change_devices_irq(new_irq_info); 171 if (pci_provider && pci_provider->target_interrupt)
172 (pci_provider->target_interrupt)(new_irq_info);
176 173
177 spin_lock(&sn_irq_info_lock); 174 spin_lock(&sn_irq_info_lock);
178 list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); 175 list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
@@ -317,6 +314,16 @@ void sn_irq_unfixup(struct pci_dev *pci_dev)
317 pci_dev_put(pci_dev); 314 pci_dev_put(pci_dev);
318} 315}
319 316
317static inline void
318sn_call_force_intr_provider(struct sn_irq_info *sn_irq_info)
319{
320 struct sn_pcibus_provider *pci_provider;
321
322 pci_provider = sn_pci_provider[sn_irq_info->irq_bridge_type];
323 if (pci_provider && pci_provider->force_interrupt)
324 (*pci_provider->force_interrupt)(sn_irq_info);
325}
326
320static void force_interrupt(int irq) 327static void force_interrupt(int irq)
321{ 328{
322 struct sn_irq_info *sn_irq_info; 329 struct sn_irq_info *sn_irq_info;
@@ -325,11 +332,9 @@ static void force_interrupt(int irq)
325 return; 332 return;
326 333
327 rcu_read_lock(); 334 rcu_read_lock();
328 list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[irq], list) { 335 list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[irq], list)
329 if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) && 336 sn_call_force_intr_provider(sn_irq_info);
330 (sn_irq_info->irq_bridge != NULL)) 337
331 pcibr_force_interrupt(sn_irq_info);
332 }
333 rcu_read_unlock(); 338 rcu_read_unlock();
334} 339}
335 340
@@ -351,6 +356,14 @@ static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info)
351 struct pcidev_info *pcidev_info; 356 struct pcidev_info *pcidev_info;
352 struct pcibus_info *pcibus_info; 357 struct pcibus_info *pcibus_info;
353 358
359 /*
360 * Bridge types attached to TIO (anything but PIC) do not need this WAR
361 * since they do not target Shub II interrupt registers. If that
362 * ever changes, this check needs to accomodate.
363 */
364 if (sn_irq_info->irq_bridge_type != PCIIO_ASIC_TYPE_PIC)
365 return;
366
354 pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; 367 pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
355 if (!pcidev_info) 368 if (!pcidev_info)
356 return; 369 return;
@@ -377,16 +390,12 @@ static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info)
377 break; 390 break;
378 } 391 }
379 if (!test_bit(irr_bit, &irr_reg)) { 392 if (!test_bit(irr_bit, &irr_reg)) {
380 if (!test_bit(irq, pda->sn_soft_irr)) { 393 if (!test_bit(irq, pda->sn_in_service_ivecs)) {
381 if (!test_bit(irq, pda->sn_in_service_ivecs)) { 394 regval &= 0xff;
382 regval &= 0xff; 395 if (sn_irq_info->irq_int_bit & regval &
383 if (sn_irq_info->irq_int_bit & regval & 396 sn_irq_info->irq_last_intr) {
384 sn_irq_info->irq_last_intr) { 397 regval &= ~(sn_irq_info->irq_int_bit & regval);
385 regval &= 398 sn_call_force_intr_provider(sn_irq_info);
386 ~(sn_irq_info->
387 irq_int_bit & regval);
388 pcibr_force_interrupt(sn_irq_info);
389 }
390 } 399 }
391 } 400 }
392 } 401 }
@@ -404,13 +413,7 @@ void sn_lb_int_war_check(void)
404 rcu_read_lock(); 413 rcu_read_lock();
405 for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) { 414 for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) {
406 list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[i], list) { 415 list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[i], list) {
407 /* 416 sn_check_intr(i, sn_irq_info);
408 * Only call for PCI bridges that are fully
409 * initialized.
410 */
411 if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
412 (sn_irq_info->irq_bridge != NULL))
413 sn_check_intr(i, sn_irq_info);
414 } 417 }
415 } 418 }
416 rcu_read_unlock(); 419 rcu_read_unlock();