aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/uv/uv_irq.h15
-rw-r--r--arch/x86/kernel/apic/io_apic.c49
-rw-r--r--arch/x86/kernel/uv_irq.c128
-rw-r--r--drivers/misc/sgi-xp/xpc_uv.c5
4 files changed, 180 insertions, 17 deletions
diff --git a/arch/x86/include/asm/uv/uv_irq.h b/arch/x86/include/asm/uv/uv_irq.h
index 9613c8c0b647..5397e1290952 100644
--- a/arch/x86/include/asm/uv/uv_irq.h
+++ b/arch/x86/include/asm/uv/uv_irq.h
@@ -25,12 +25,21 @@ struct uv_IO_APIC_route_entry {
25 dest : 32; 25 dest : 32;
26}; 26};
27 27
28enum {
29 UV_AFFINITY_ALL,
30 UV_AFFINITY_NODE,
31 UV_AFFINITY_CPU
32};
33
28extern struct irq_chip uv_irq_chip; 34extern struct irq_chip uv_irq_chip;
29 35
30extern int arch_enable_uv_irq(char *, unsigned int, int, int, unsigned long); 36extern int
37arch_enable_uv_irq(char *, unsigned int, int, int, unsigned long, int);
31extern void arch_disable_uv_irq(int, unsigned long); 38extern void arch_disable_uv_irq(int, unsigned long);
39extern int uv_set_irq_affinity(unsigned int, const struct cpumask *);
32 40
33extern int uv_setup_irq(char *, int, int, unsigned long); 41extern int uv_irq_2_mmr_info(int, unsigned long *, int *);
34extern void uv_teardown_irq(unsigned int, int, unsigned long); 42extern int uv_setup_irq(char *, int, int, unsigned long, int);
43extern void uv_teardown_irq(unsigned int);
35 44
36#endif /* _ASM_X86_UV_UV_IRQ_H */ 45#endif /* _ASM_X86_UV_UV_IRQ_H */
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 8c718c93d079..bb52e7f6e953 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -3731,9 +3731,10 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
3731 * on the specified blade to allow the sending of MSIs to the specified CPU. 3731 * on the specified blade to allow the sending of MSIs to the specified CPU.
3732 */ 3732 */
3733int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade, 3733int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
3734 unsigned long mmr_offset) 3734 unsigned long mmr_offset, int restrict)
3735{ 3735{
3736 const struct cpumask *eligible_cpu = cpumask_of(cpu); 3736 const struct cpumask *eligible_cpu = cpumask_of(cpu);
3737 struct irq_desc *desc = irq_to_desc(irq);
3737 struct irq_cfg *cfg; 3738 struct irq_cfg *cfg;
3738 int mmr_pnode; 3739 int mmr_pnode;
3739 unsigned long mmr_value; 3740 unsigned long mmr_value;
@@ -3749,6 +3750,11 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
3749 if (err != 0) 3750 if (err != 0)
3750 return err; 3751 return err;
3751 3752
3753 if (restrict == UV_AFFINITY_CPU)
3754 desc->status |= IRQ_NO_BALANCING;
3755 else
3756 desc->status |= IRQ_MOVE_PCNTXT;
3757
3752 spin_lock_irqsave(&vector_lock, flags); 3758 spin_lock_irqsave(&vector_lock, flags);
3753 set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq, 3759 set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
3754 irq_name); 3760 irq_name);
@@ -3777,11 +3783,10 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
3777 * Disable the specified MMR located on the specified blade so that MSIs are 3783 * Disable the specified MMR located on the specified blade so that MSIs are
3778 * longer allowed to be sent. 3784 * longer allowed to be sent.
3779 */ 3785 */
3780void arch_disable_uv_irq(int mmr_blade, unsigned long mmr_offset) 3786void arch_disable_uv_irq(int mmr_pnode, unsigned long mmr_offset)
3781{ 3787{
3782 unsigned long mmr_value; 3788 unsigned long mmr_value;
3783 struct uv_IO_APIC_route_entry *entry; 3789 struct uv_IO_APIC_route_entry *entry;
3784 int mmr_pnode;
3785 3790
3786 BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long)); 3791 BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
3787 3792
@@ -3789,9 +3794,45 @@ void arch_disable_uv_irq(int mmr_blade, unsigned long mmr_offset)
3789 entry = (struct uv_IO_APIC_route_entry *)&mmr_value; 3794 entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
3790 entry->mask = 1; 3795 entry->mask = 1;
3791 3796
3792 mmr_pnode = uv_blade_to_pnode(mmr_blade);
3793 uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value); 3797 uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
3794} 3798}
3799
3800int uv_set_irq_affinity(unsigned int irq, const struct cpumask *mask)
3801{
3802 struct irq_desc *desc = irq_to_desc(irq);
3803 struct irq_cfg *cfg = desc->chip_data;
3804 unsigned int dest;
3805 unsigned long mmr_value;
3806 struct uv_IO_APIC_route_entry *entry;
3807 unsigned long mmr_offset;
3808 unsigned mmr_pnode;
3809
3810 dest = set_desc_affinity(desc, mask);
3811 if (dest == BAD_APICID)
3812 return -1;
3813
3814 mmr_value = 0;
3815 entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
3816
3817 entry->vector = cfg->vector;
3818 entry->delivery_mode = apic->irq_delivery_mode;
3819 entry->dest_mode = apic->irq_dest_mode;
3820 entry->polarity = 0;
3821 entry->trigger = 0;
3822 entry->mask = 0;
3823 entry->dest = dest;
3824
3825 /* Get previously stored MMR and pnode of hub sourcing interrupts */
3826 if (uv_irq_2_mmr_info(irq, &mmr_offset, &mmr_pnode))
3827 return -1;
3828
3829 uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
3830
3831 if (cfg->move_in_progress)
3832 send_cleanup_vector(cfg);
3833
3834 return 0;
3835}
3795#endif /* CONFIG_X86_64 */ 3836#endif /* CONFIG_X86_64 */
3796 3837
3797int __init io_apic_get_redir_entries (int ioapic) 3838int __init io_apic_get_redir_entries (int ioapic)
diff --git a/arch/x86/kernel/uv_irq.c b/arch/x86/kernel/uv_irq.c
index aeef529917e4..9a83775ab0f3 100644
--- a/arch/x86/kernel/uv_irq.c
+++ b/arch/x86/kernel/uv_irq.c
@@ -9,10 +9,22 @@
9 */ 9 */
10 10
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/rbtree.h>
12#include <linux/irq.h> 13#include <linux/irq.h>
13 14
14#include <asm/apic.h> 15#include <asm/apic.h>
15#include <asm/uv/uv_irq.h> 16#include <asm/uv/uv_irq.h>
17#include <asm/uv/uv_hub.h>
18
19/* MMR offset and pnode of hub sourcing interrupts for a given irq */
20struct uv_irq_2_mmr_pnode{
21 struct rb_node list;
22 unsigned long offset;
23 int pnode;
24 int irq;
25};
26static spinlock_t uv_irq_lock;
27static struct rb_root uv_irq_root;
16 28
17static void uv_noop(unsigned int irq) 29static void uv_noop(unsigned int irq)
18{ 30{
@@ -39,25 +51,106 @@ struct irq_chip uv_irq_chip = {
39 .unmask = uv_noop, 51 .unmask = uv_noop,
40 .eoi = uv_ack_apic, 52 .eoi = uv_ack_apic,
41 .end = uv_noop, 53 .end = uv_noop,
54 .set_affinity = uv_set_irq_affinity,
42}; 55};
43 56
44/* 57/*
58 * Add offset and pnode information of the hub sourcing interrupts to the
59 * rb tree for a specific irq.
60 */
61static int uv_set_irq_2_mmr_info(int irq, unsigned long offset, unsigned blade)
62{
63 struct rb_node **link = &uv_irq_root.rb_node;
64 struct rb_node *parent = NULL;
65 struct uv_irq_2_mmr_pnode *n;
66 struct uv_irq_2_mmr_pnode *e;
67 unsigned long irqflags;
68
69 n = kmalloc_node(sizeof(struct uv_irq_2_mmr_pnode), GFP_KERNEL,
70 uv_blade_to_memory_nid(blade));
71 if (!n)
72 return -ENOMEM;
73
74 n->irq = irq;
75 n->offset = offset;
76 n->pnode = uv_blade_to_pnode(blade);
77 spin_lock_irqsave(&uv_irq_lock, irqflags);
78 /* Find the right place in the rbtree: */
79 while (*link) {
80 parent = *link;
81 e = rb_entry(parent, struct uv_irq_2_mmr_pnode, list);
82
83 if (unlikely(irq == e->irq)) {
84 /* irq entry exists */
85 e->pnode = uv_blade_to_pnode(blade);
86 e->offset = offset;
87 spin_unlock_irqrestore(&uv_irq_lock, irqflags);
88 kfree(n);
89 return 0;
90 }
91
92 if (irq < e->irq)
93 link = &(*link)->rb_left;
94 else
95 link = &(*link)->rb_right;
96 }
97
98 /* Insert the node into the rbtree. */
99 rb_link_node(&n->list, parent, link);
100 rb_insert_color(&n->list, &uv_irq_root);
101
102 spin_unlock_irqrestore(&uv_irq_lock, irqflags);
103 return 0;
104}
105
106/* Retrieve offset and pnode information from the rb tree for a specific irq */
107int uv_irq_2_mmr_info(int irq, unsigned long *offset, int *pnode)
108{
109 struct uv_irq_2_mmr_pnode *e;
110 struct rb_node *n;
111 unsigned long irqflags;
112
113 spin_lock_irqsave(&uv_irq_lock, irqflags);
114 n = uv_irq_root.rb_node;
115 while (n) {
116 e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
117
118 if (e->irq == irq) {
119 *offset = e->offset;
120 *pnode = e->pnode;
121 spin_unlock_irqrestore(&uv_irq_lock, irqflags);
122 return 0;
123 }
124
125 if (irq < e->irq)
126 n = n->rb_left;
127 else
128 n = n->rb_right;
129 }
130 spin_unlock_irqrestore(&uv_irq_lock, irqflags);
131 return -1;
132}
133
134/*
45 * Set up a mapping of an available irq and vector, and enable the specified 135 * Set up a mapping of an available irq and vector, and enable the specified
46 * MMR that defines the MSI that is to be sent to the specified CPU when an 136 * MMR that defines the MSI that is to be sent to the specified CPU when an
47 * interrupt is raised. 137 * interrupt is raised.
48 */ 138 */
49int uv_setup_irq(char *irq_name, int cpu, int mmr_blade, 139int uv_setup_irq(char *irq_name, int cpu, int mmr_blade,
50 unsigned long mmr_offset) 140 unsigned long mmr_offset, int restrict)
51{ 141{
52 int irq; 142 int irq, ret;
53 int ret; 143
144 irq = create_irq_nr(NR_IRQS_LEGACY, uv_blade_to_memory_nid(mmr_blade));
54 145
55 irq = create_irq();
56 if (irq <= 0) 146 if (irq <= 0)
57 return -EBUSY; 147 return -EBUSY;
58 148
59 ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset); 149 ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset,
60 if (ret != irq) 150 restrict);
151 if (ret == irq)
152 uv_set_irq_2_mmr_info(irq, mmr_offset, mmr_blade);
153 else
61 destroy_irq(irq); 154 destroy_irq(irq);
62 155
63 return ret; 156 return ret;
@@ -71,9 +164,28 @@ EXPORT_SYMBOL_GPL(uv_setup_irq);
71 * 164 *
72 * Set mmr_blade and mmr_offset to what was passed in on uv_setup_irq(). 165 * Set mmr_blade and mmr_offset to what was passed in on uv_setup_irq().
73 */ 166 */
74void uv_teardown_irq(unsigned int irq, int mmr_blade, unsigned long mmr_offset) 167void uv_teardown_irq(unsigned int irq)
75{ 168{
76 arch_disable_uv_irq(mmr_blade, mmr_offset); 169 struct uv_irq_2_mmr_pnode *e;
170 struct rb_node *n;
171 unsigned long irqflags;
172
173 spin_lock_irqsave(&uv_irq_lock, irqflags);
174 n = uv_irq_root.rb_node;
175 while (n) {
176 e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
177 if (e->irq == irq) {
178 arch_disable_uv_irq(e->pnode, e->offset);
179 rb_erase(n, &uv_irq_root);
180 kfree(e);
181 break;
182 }
183 if (irq < e->irq)
184 n = n->rb_left;
185 else
186 n = n->rb_right;
187 }
188 spin_unlock_irqrestore(&uv_irq_lock, irqflags);
77 destroy_irq(irq); 189 destroy_irq(irq);
78} 190}
79EXPORT_SYMBOL_GPL(uv_teardown_irq); 191EXPORT_SYMBOL_GPL(uv_teardown_irq);
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c
index c76677afda1b..b5bbe59f9c57 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -106,7 +106,8 @@ xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name)
106 int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); 106 int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
107 107
108#if defined CONFIG_X86_64 108#if defined CONFIG_X86_64
109 mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset); 109 mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset,
110 UV_AFFINITY_CPU);
110 if (mq->irq < 0) { 111 if (mq->irq < 0) {
111 dev_err(xpc_part, "uv_setup_irq() returned error=%d\n", 112 dev_err(xpc_part, "uv_setup_irq() returned error=%d\n",
112 -mq->irq); 113 -mq->irq);
@@ -136,7 +137,7 @@ static void
136xpc_release_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq) 137xpc_release_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq)
137{ 138{
138#if defined CONFIG_X86_64 139#if defined CONFIG_X86_64
139 uv_teardown_irq(mq->irq, mq->mmr_blade, mq->mmr_offset); 140 uv_teardown_irq(mq->irq);
140 141
141#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV 142#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
142 int mmr_pnode; 143 int mmr_pnode;