diff options
author | Daniel Hellstrom <daniel@gaisler.com> | 2011-04-19 19:41:26 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-04-21 18:31:31 -0400 |
commit | 5eb1f4fc167f5adc5f15e722e25eff6713fb3406 (patch) | |
tree | 2e1ffeb506b3d09efc5e16045283430e3e362f63 /arch | |
parent | a481b5d0cb5d1884f16460b4846755518360f1ca (diff) |
sparc32,leon: implement genirq CPU affinity
A simple implementation of CPU affinity, the first CPU in
the affinity CPU mask always takes the IRQ.
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Acked-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sparc/kernel/leon_kernel.c | 64 |
1 files changed, 54 insertions, 10 deletions
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index d8fafeacb496..ab1458454422 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c | |||
@@ -99,25 +99,68 @@ static inline unsigned long get_irqmask(unsigned int irq) | |||
99 | return mask; | 99 | return mask; |
100 | } | 100 | } |
101 | 101 | ||
102 | #ifdef CONFIG_SMP | ||
103 | static int irq_choose_cpu(const struct cpumask *affinity) | ||
104 | { | ||
105 | cpumask_t mask; | ||
106 | |||
107 | cpus_and(mask, cpu_online_map, *affinity); | ||
108 | if (cpus_equal(mask, cpu_online_map) || cpus_empty(mask)) | ||
109 | return 0; | ||
110 | else | ||
111 | return first_cpu(mask); | ||
112 | } | ||
113 | #else | ||
114 | #define irq_choose_cpu(affinity) 0 | ||
115 | #endif | ||
116 | |||
117 | static int leon_set_affinity(struct irq_data *data, const struct cpumask *dest, | ||
118 | bool force) | ||
119 | { | ||
120 | unsigned long mask, oldmask, flags; | ||
121 | int oldcpu, newcpu; | ||
122 | |||
123 | mask = (unsigned long)data->chip_data; | ||
124 | oldcpu = irq_choose_cpu(data->affinity); | ||
125 | newcpu = irq_choose_cpu(dest); | ||
126 | |||
127 | if (oldcpu == newcpu) | ||
128 | goto out; | ||
129 | |||
130 | /* unmask on old CPU first before enabling on the selected CPU */ | ||
131 | spin_lock_irqsave(&leon_irq_lock, flags); | ||
132 | oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(oldcpu)); | ||
133 | LEON3_BYPASS_STORE_PA(LEON_IMASK(oldcpu), (oldmask & ~mask)); | ||
134 | oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(newcpu)); | ||
135 | LEON3_BYPASS_STORE_PA(LEON_IMASK(newcpu), (oldmask | mask)); | ||
136 | spin_unlock_irqrestore(&leon_irq_lock, flags); | ||
137 | out: | ||
138 | return IRQ_SET_MASK_OK; | ||
139 | } | ||
140 | |||
102 | static void leon_unmask_irq(struct irq_data *data) | 141 | static void leon_unmask_irq(struct irq_data *data) |
103 | { | 142 | { |
104 | unsigned long mask, oldmask, flags; | 143 | unsigned long mask, oldmask, flags; |
144 | int cpu; | ||
105 | 145 | ||
106 | mask = (unsigned long)data->chip_data; | 146 | mask = (unsigned long)data->chip_data; |
147 | cpu = irq_choose_cpu(data->affinity); | ||
107 | spin_lock_irqsave(&leon_irq_lock, flags); | 148 | spin_lock_irqsave(&leon_irq_lock, flags); |
108 | oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(0)); | 149 | oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(cpu)); |
109 | LEON3_BYPASS_STORE_PA(LEON_IMASK(0), (oldmask | mask)); | 150 | LEON3_BYPASS_STORE_PA(LEON_IMASK(cpu), (oldmask | mask)); |
110 | spin_unlock_irqrestore(&leon_irq_lock, flags); | 151 | spin_unlock_irqrestore(&leon_irq_lock, flags); |
111 | } | 152 | } |
112 | 153 | ||
113 | static void leon_mask_irq(struct irq_data *data) | 154 | static void leon_mask_irq(struct irq_data *data) |
114 | { | 155 | { |
115 | unsigned long mask, oldmask, flags; | 156 | unsigned long mask, oldmask, flags; |
157 | int cpu; | ||
116 | 158 | ||
117 | mask = (unsigned long)data->chip_data; | 159 | mask = (unsigned long)data->chip_data; |
160 | cpu = irq_choose_cpu(data->affinity); | ||
118 | spin_lock_irqsave(&leon_irq_lock, flags); | 161 | spin_lock_irqsave(&leon_irq_lock, flags); |
119 | oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(0)); | 162 | oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(cpu)); |
120 | LEON3_BYPASS_STORE_PA(LEON_IMASK(0), (oldmask & ~mask)); | 163 | LEON3_BYPASS_STORE_PA(LEON_IMASK(cpu), (oldmask & ~mask)); |
121 | spin_unlock_irqrestore(&leon_irq_lock, flags); | 164 | spin_unlock_irqrestore(&leon_irq_lock, flags); |
122 | } | 165 | } |
123 | 166 | ||
@@ -144,12 +187,13 @@ static void leon_eoi_irq(struct irq_data *data) | |||
144 | } | 187 | } |
145 | 188 | ||
146 | static struct irq_chip leon_irq = { | 189 | static struct irq_chip leon_irq = { |
147 | .name = "leon", | 190 | .name = "leon", |
148 | .irq_startup = leon_startup_irq, | 191 | .irq_startup = leon_startup_irq, |
149 | .irq_shutdown = leon_shutdown_irq, | 192 | .irq_shutdown = leon_shutdown_irq, |
150 | .irq_mask = leon_mask_irq, | 193 | .irq_mask = leon_mask_irq, |
151 | .irq_unmask = leon_unmask_irq, | 194 | .irq_unmask = leon_unmask_irq, |
152 | .irq_eoi = leon_eoi_irq, | 195 | .irq_eoi = leon_eoi_irq, |
196 | .irq_set_affinity = leon_set_affinity, | ||
153 | }; | 197 | }; |
154 | 198 | ||
155 | /* | 199 | /* |