diff options
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/include/asm/netlogic/mips-extns.h | 79 | ||||
-rw-r--r-- | arch/mips/netlogic/common/irq.c | 39 | ||||
-rw-r--r-- | arch/mips/netlogic/common/smp.c | 8 |
3 files changed, 98 insertions, 28 deletions
diff --git a/arch/mips/include/asm/netlogic/mips-extns.h b/arch/mips/include/asm/netlogic/mips-extns.h index 32ba6d95d47c..cc4296595df5 100644 --- a/arch/mips/include/asm/netlogic/mips-extns.h +++ b/arch/mips/include/asm/netlogic/mips-extns.h | |||
@@ -68,6 +68,85 @@ do { \ | |||
68 | __write_64bit_c0_register($9, 7, (val)); \ | 68 | __write_64bit_c0_register($9, 7, (val)); \ |
69 | } while (0) | 69 | } while (0) |
70 | 70 | ||
71 | /* | ||
72 | * Handling the 64 bit EIMR and EIRR registers in 32-bit mode with | ||
73 | * standard functions will be very inefficient. This provides | ||
74 | * optimized functions for the normal operations on the registers. | ||
75 | * | ||
76 | * Call with interrupts disabled. | ||
77 | */ | ||
78 | static inline void ack_c0_eirr(int irq) | ||
79 | { | ||
80 | __asm__ __volatile__( | ||
81 | ".set push\n\t" | ||
82 | ".set mips64\n\t" | ||
83 | ".set noat\n\t" | ||
84 | "li $1, 1\n\t" | ||
85 | "dsllv $1, $1, %0\n\t" | ||
86 | "dmtc0 $1, $9, 6\n\t" | ||
87 | ".set pop" | ||
88 | : : "r" (irq)); | ||
89 | } | ||
90 | |||
91 | static inline void set_c0_eimr(int irq) | ||
92 | { | ||
93 | __asm__ __volatile__( | ||
94 | ".set push\n\t" | ||
95 | ".set mips64\n\t" | ||
96 | ".set noat\n\t" | ||
97 | "li $1, 1\n\t" | ||
98 | "dsllv %0, $1, %0\n\t" | ||
99 | "dmfc0 $1, $9, 7\n\t" | ||
100 | "or $1, %0\n\t" | ||
101 | "dmtc0 $1, $9, 7\n\t" | ||
102 | ".set pop" | ||
103 | : "+r" (irq)); | ||
104 | } | ||
105 | |||
106 | static inline void clear_c0_eimr(int irq) | ||
107 | { | ||
108 | __asm__ __volatile__( | ||
109 | ".set push\n\t" | ||
110 | ".set mips64\n\t" | ||
111 | ".set noat\n\t" | ||
112 | "li $1, 1\n\t" | ||
113 | "dsllv %0, $1, %0\n\t" | ||
114 | "dmfc0 $1, $9, 7\n\t" | ||
115 | "or $1, %0\n\t" | ||
116 | "xor $1, %0\n\t" | ||
117 | "dmtc0 $1, $9, 7\n\t" | ||
118 | ".set pop" | ||
119 | : "+r" (irq)); | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Read c0 eimr and c0 eirr, do AND of the two values, the result is | ||
124 | * the interrupts which are raised and are not masked. | ||
125 | */ | ||
126 | static inline uint64_t read_c0_eirr_and_eimr(void) | ||
127 | { | ||
128 | uint64_t val; | ||
129 | |||
130 | #ifdef CONFIG_64BIT | ||
131 | val = read_c0_eimr() & read_c0_eirr(); | ||
132 | #else | ||
133 | __asm__ __volatile__( | ||
134 | ".set push\n\t" | ||
135 | ".set mips64\n\t" | ||
136 | ".set noat\n\t" | ||
137 | "dmfc0 %M0, $9, 6\n\t" | ||
138 | "dmfc0 %L0, $9, 7\n\t" | ||
139 | "and %M0, %L0\n\t" | ||
140 | "dsll %L0, %M0, 32\n\t" | ||
141 | "dsra %M0, %M0, 32\n\t" | ||
142 | "dsra %L0, %L0, 32\n\t" | ||
143 | ".set pop" | ||
144 | : "=r" (val)); | ||
145 | #endif | ||
146 | |||
147 | return val; | ||
148 | } | ||
149 | |||
71 | static inline int hard_smp_processor_id(void) | 150 | static inline int hard_smp_processor_id(void) |
72 | { | 151 | { |
73 | return __read_32bit_c0_register($15, 1) & 0x3ff; | 152 | return __read_32bit_c0_register($15, 1) & 0x3ff; |
diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index 00dcc7a2bc5a..d42cd1a2a124 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c | |||
@@ -105,21 +105,23 @@ static void xlp_pic_disable(struct irq_data *d) | |||
105 | static void xlp_pic_mask_ack(struct irq_data *d) | 105 | static void xlp_pic_mask_ack(struct irq_data *d) |
106 | { | 106 | { |
107 | struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); | 107 | struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); |
108 | uint64_t mask = 1ull << pd->picirq; | ||
109 | 108 | ||
110 | write_c0_eirr(mask); /* ack by writing EIRR */ | 109 | clear_c0_eimr(pd->picirq); |
110 | ack_c0_eirr(pd->picirq); | ||
111 | } | 111 | } |
112 | 112 | ||
113 | static void xlp_pic_unmask(struct irq_data *d) | 113 | static void xlp_pic_unmask(struct irq_data *d) |
114 | { | 114 | { |
115 | struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); | 115 | struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); |
116 | 116 | ||
117 | if (!pd) | 117 | BUG_ON(!pd); |
118 | return; | ||
119 | 118 | ||
120 | if (pd->extra_ack) | 119 | if (pd->extra_ack) |
121 | pd->extra_ack(d); | 120 | pd->extra_ack(d); |
122 | 121 | ||
122 | /* re-enable the intr on this cpu */ | ||
123 | set_c0_eimr(pd->picirq); | ||
124 | |||
123 | /* Ack is a single write, no need to lock */ | 125 | /* Ack is a single write, no need to lock */ |
124 | nlm_pic_ack(pd->node->picbase, pd->irt); | 126 | nlm_pic_ack(pd->node->picbase, pd->irt); |
125 | } | 127 | } |
@@ -134,32 +136,17 @@ static struct irq_chip xlp_pic = { | |||
134 | 136 | ||
135 | static void cpuintr_disable(struct irq_data *d) | 137 | static void cpuintr_disable(struct irq_data *d) |
136 | { | 138 | { |
137 | uint64_t eimr; | 139 | clear_c0_eimr(d->irq); |
138 | uint64_t mask = 1ull << d->irq; | ||
139 | |||
140 | eimr = read_c0_eimr(); | ||
141 | write_c0_eimr(eimr & ~mask); | ||
142 | } | 140 | } |
143 | 141 | ||
144 | static void cpuintr_enable(struct irq_data *d) | 142 | static void cpuintr_enable(struct irq_data *d) |
145 | { | 143 | { |
146 | uint64_t eimr; | 144 | set_c0_eimr(d->irq); |
147 | uint64_t mask = 1ull << d->irq; | ||
148 | |||
149 | eimr = read_c0_eimr(); | ||
150 | write_c0_eimr(eimr | mask); | ||
151 | } | 145 | } |
152 | 146 | ||
153 | static void cpuintr_ack(struct irq_data *d) | 147 | static void cpuintr_ack(struct irq_data *d) |
154 | { | 148 | { |
155 | uint64_t mask = 1ull << d->irq; | 149 | ack_c0_eirr(d->irq); |
156 | |||
157 | write_c0_eirr(mask); | ||
158 | } | ||
159 | |||
160 | static void cpuintr_nop(struct irq_data *d) | ||
161 | { | ||
162 | WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq); | ||
163 | } | 150 | } |
164 | 151 | ||
165 | /* | 152 | /* |
@@ -170,9 +157,9 @@ struct irq_chip nlm_cpu_intr = { | |||
170 | .name = "XLP-CPU-INTR", | 157 | .name = "XLP-CPU-INTR", |
171 | .irq_enable = cpuintr_enable, | 158 | .irq_enable = cpuintr_enable, |
172 | .irq_disable = cpuintr_disable, | 159 | .irq_disable = cpuintr_disable, |
173 | .irq_mask = cpuintr_nop, | 160 | .irq_mask = cpuintr_disable, |
174 | .irq_ack = cpuintr_nop, | 161 | .irq_ack = cpuintr_ack, |
175 | .irq_eoi = cpuintr_ack, | 162 | .irq_eoi = cpuintr_enable, |
176 | }; | 163 | }; |
177 | 164 | ||
178 | static void __init nlm_init_percpu_irqs(void) | 165 | static void __init nlm_init_percpu_irqs(void) |
@@ -265,7 +252,7 @@ asmlinkage void plat_irq_dispatch(void) | |||
265 | int i, node; | 252 | int i, node; |
266 | 253 | ||
267 | node = nlm_nodeid(); | 254 | node = nlm_nodeid(); |
268 | eirr = read_c0_eirr() & read_c0_eimr(); | 255 | eirr = read_c0_eirr_and_eimr(); |
269 | 256 | ||
270 | i = __ilog2_u64(eirr); | 257 | i = __ilog2_u64(eirr); |
271 | if (i == -1) | 258 | if (i == -1) |
diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c index a080d9ee3cd7..2bb95dcfe20a 100644 --- a/arch/mips/netlogic/common/smp.c +++ b/arch/mips/netlogic/common/smp.c | |||
@@ -84,15 +84,19 @@ void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) | |||
84 | /* IRQ_IPI_SMP_FUNCTION Handler */ | 84 | /* IRQ_IPI_SMP_FUNCTION Handler */ |
85 | void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) | 85 | void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) |
86 | { | 86 | { |
87 | write_c0_eirr(1ull << irq); | 87 | clear_c0_eimr(irq); |
88 | ack_c0_eirr(irq); | ||
88 | smp_call_function_interrupt(); | 89 | smp_call_function_interrupt(); |
90 | set_c0_eimr(irq); | ||
89 | } | 91 | } |
90 | 92 | ||
91 | /* IRQ_IPI_SMP_RESCHEDULE handler */ | 93 | /* IRQ_IPI_SMP_RESCHEDULE handler */ |
92 | void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc) | 94 | void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc) |
93 | { | 95 | { |
94 | write_c0_eirr(1ull << irq); | 96 | clear_c0_eimr(irq); |
97 | ack_c0_eirr(irq); | ||
95 | scheduler_ipi(); | 98 | scheduler_ipi(); |
99 | set_c0_eimr(irq); | ||
96 | } | 100 | } |
97 | 101 | ||
98 | /* | 102 | /* |