powerpc: use end_IRQ for iseries irqs
[powerpc.git] / arch / powerpc / platforms / iseries / irq.c
1 /*
2  * This module supports the iSeries PCI bus interrupt handling
3  * Copyright (C) 20yy  <Robert L Holtorf> <IBM Corp>
4  * Copyright (C) 2004-2005 IBM Corporation
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the:
18  * Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330,
20  * Boston, MA  02111-1307  USA
21  *
22  * Change Activity:
23  *   Created, December 13, 2000 by Wayne Holm
24  * End Change Activity
25  */
26 #include <linux/config.h>
27 #include <linux/pci.h>
28 #include <linux/init.h>
29 #include <linux/threads.h>
30 #include <linux/smp.h>
31 #include <linux/param.h>
32 #include <linux/string.h>
33 #include <linux/bootmem.h>
34 #include <linux/ide.h>
35 #include <linux/irq.h>
36 #include <linux/spinlock.h>
37
38 #include <asm/iseries/hv_types.h>
39 #include <asm/iseries/hv_lp_event.h>
40 #include <asm/iseries/hv_call_xm.h>
41
42 #include "irq.h"
43 #include "call_pci.h"
44
45 enum pci_event_type {
46         pe_bus_created          = 0,    /* PHB has been created */
47         pe_bus_error            = 1,    /* PHB has failed */
48         pe_bus_failed           = 2,    /* Msg to Secondary, Primary failed bus */
49         pe_node_failed          = 4,    /* Multi-adapter bridge has failed */
50         pe_node_recovered       = 5,    /* Multi-adapter bridge has recovered */
51         pe_bus_recovered        = 12,   /* PHB has been recovered */
52         pe_unquiese_bus         = 18,   /* Secondary bus unqiescing */
53         pe_bridge_error         = 21,   /* Bridge Error */
54         pe_slot_interrupt       = 22    /* Slot interrupt */
55 };
56
57 struct pci_event {
58         struct HvLpEvent event;
59         union {
60                 u64 __align;            /* Align on an 8-byte boundary */
61                 struct {
62                         u32             fisr;
63                         HvBusNumber     bus_number;
64                         HvSubBusNumber  sub_bus_number;
65                         HvAgentId       dev_id;
66                 } slot;
67                 struct {
68                         HvBusNumber     bus_number;
69                         HvSubBusNumber  sub_bus_number;
70                 } bus;
71                 struct {
72                         HvBusNumber     bus_number;
73                         HvSubBusNumber  sub_bus_number;
74                         HvAgentId       dev_id;
75                 } node;
76         } data;
77 };
78
79 static void int_received(struct pci_event *event, struct pt_regs *regs)
80 {
81         int irq;
82 #ifdef CONFIG_IRQSTACKS
83         struct thread_info *curtp, *irqtp;
84 #endif
85
86         switch (event->event.xSubtype) {
87         case pe_slot_interrupt:
88                 irq = event->event.xCorrelationToken;
89                 /* Dispatch the interrupt handlers for this irq */
90 #ifdef CONFIG_IRQSTACKS
91                 /* Switch to the irq stack to handle this */
92                 curtp = current_thread_info();
93                 irqtp = hardirq_ctx[smp_processor_id()];
94                 if (curtp != irqtp) {
95                         irqtp->task = curtp->task;
96                         irqtp->flags = 0;
97                         call___do_IRQ(irq, regs, irqtp);
98                         irqtp->task = NULL;
99                         if (irqtp->flags)
100                                 set_bits(irqtp->flags, &curtp->flags);
101                 } else
102 #endif
103                         __do_IRQ(irq, regs);
104                 break;
105                 /* Ignore error recovery events for now */
106         case pe_bus_created:
107                 printk(KERN_INFO "int_received: system bus %d created\n",
108                         event->data.bus.bus_number);
109                 break;
110         case pe_bus_error:
111         case pe_bus_failed:
112                 printk(KERN_INFO "int_received: system bus %d failed\n",
113                         event->data.bus.bus_number);
114                 break;
115         case pe_bus_recovered:
116         case pe_unquiese_bus:
117                 printk(KERN_INFO "int_received: system bus %d recovered\n",
118                         event->data.bus.bus_number);
119                 break;
120         case pe_node_failed:
121         case pe_bridge_error:
122                 printk(KERN_INFO
123                         "int_received: multi-adapter bridge %d/%d/%d failed\n",
124                         event->data.node.bus_number,
125                         event->data.node.sub_bus_number,
126                         event->data.node.dev_id);
127                 break;
128         case pe_node_recovered:
129                 printk(KERN_INFO
130                         "int_received: multi-adapter bridge %d/%d/%d recovered\n",
131                         event->data.node.bus_number,
132                         event->data.node.sub_bus_number,
133                         event->data.node.dev_id);
134                 break;
135         default:
136                 printk(KERN_ERR
137                         "int_received: unrecognized event subtype 0x%x\n",
138                         event->event.xSubtype);
139                 break;
140         }
141 }
142
143 static void pci_event_handler(struct HvLpEvent *event, struct pt_regs *regs)
144 {
145         if (event && (event->xType == HvLpEvent_Type_PciIo)) {
146                 switch (event->xFlags.xFunction) {
147                 case HvLpEvent_Function_Int:
148                         int_received((struct pci_event *)event, regs);
149                         break;
150                 case HvLpEvent_Function_Ack:
151                         printk(KERN_ERR
152                                 "pci_event_handler: unexpected ack received\n");
153                         break;
154                 default:
155                         printk(KERN_ERR
156                                 "pci_event_handler: unexpected event function %d\n",
157                                 (int)event->xFlags.xFunction);
158                         break;
159                 }
160         } else if (event)
161                 printk(KERN_ERR
162                         "pci_event_handler: Unrecognized PCI event type 0x%x\n",
163                         (int)event->xType);
164         else
165                 printk(KERN_ERR "pci_event_handler: NULL event received\n");
166 }
167
168 /*
169  * This is called by init_IRQ.  set in ppc_md.init_IRQ by iSeries_setup.c
170  * It must be called before the bus walk.
171  */
172 void __init iSeries_init_IRQ(void)
173 {
174         /* Register PCI event handler and open an event path */
175         int ret;
176
177         ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
178                         &pci_event_handler);
179         if (ret == 0) {
180                 ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
181                 if (ret != 0)
182                         printk(KERN_ERR "iseries_init_IRQ: open event path "
183                                         "failed with rc 0x%x\n", ret);
184         } else
185                 printk(KERN_ERR "iseries_init_IRQ: register handler "
186                                 "failed with rc 0x%x\n", ret);
187 }
188
189 #define REAL_IRQ_TO_SUBBUS(irq) (((irq) >> 14) & 0xff)
190 #define REAL_IRQ_TO_BUS(irq)    ((((irq) >> 6) & 0xff) + 1)
191 #define REAL_IRQ_TO_IDSEL(irq)  ((((irq) >> 3) & 7) + 1)
192 #define REAL_IRQ_TO_FUNC(irq)   ((irq) & 7)
193
194 /*
195  * This will be called by device drivers (via enable_IRQ)
196  * to enable INTA in the bridge interrupt status register.
197  */
198 static void iseries_enable_IRQ(unsigned int irq)
199 {
200         u32 bus, dev_id, function, mask;
201         const u32 sub_bus = 0;
202         unsigned int rirq = virt_irq_to_real_map[irq];
203
204         /* The IRQ has already been locked by the caller */
205         bus = REAL_IRQ_TO_BUS(rirq);
206         function = REAL_IRQ_TO_FUNC(rirq);
207         dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
208
209         /* Unmask secondary INTA */
210         mask = 0x80000000;
211         HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask);
212 }
213
214 /* This is called by iseries_activate_IRQs */
215 static unsigned int iseries_startup_IRQ(unsigned int irq)
216 {
217         u32 bus, dev_id, function, mask;
218         const u32 sub_bus = 0;
219         unsigned int rirq = virt_irq_to_real_map[irq];
220
221         bus = REAL_IRQ_TO_BUS(rirq);
222         function = REAL_IRQ_TO_FUNC(rirq);
223         dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
224
225         /* Link the IRQ number to the bridge */
226         HvCallXm_connectBusUnit(bus, sub_bus, dev_id, irq);
227
228         /* Unmask bridge interrupts in the FISR */
229         mask = 0x01010000 << function;
230         HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask);
231         iseries_enable_IRQ(irq);
232         return 0;
233 }
234
235 /*
236  * This is called out of iSeries_fixup to activate interrupt
237  * generation for usable slots
238  */
239 void __init iSeries_activate_IRQs()
240 {
241         int irq;
242         unsigned long flags;
243
244         for_each_irq (irq) {
245                 irq_desc_t *desc = get_irq_desc(irq);
246
247                 if (desc && desc->handler && desc->handler->startup) {
248                         spin_lock_irqsave(&desc->lock, flags);
249                         desc->handler->startup(irq);
250                         spin_unlock_irqrestore(&desc->lock, flags);
251                 }
252         }
253 }
254
255 /*  this is not called anywhere currently */
256 static void iseries_shutdown_IRQ(unsigned int irq)
257 {
258         u32 bus, dev_id, function, mask;
259         const u32 sub_bus = 0;
260         unsigned int rirq = virt_irq_to_real_map[irq];
261
262         /* irq should be locked by the caller */
263         bus = REAL_IRQ_TO_BUS(rirq);
264         function = REAL_IRQ_TO_FUNC(rirq);
265         dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
266
267         /* Invalidate the IRQ number in the bridge */
268         HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0);
269
270         /* Mask bridge interrupts in the FISR */
271         mask = 0x01010000 << function;
272         HvCallPci_maskFisr(bus, sub_bus, dev_id, mask);
273 }
274
275 /*
276  * This will be called by device drivers (via disable_IRQ)
277  * to disable INTA in the bridge interrupt status register.
278  */
279 static void iseries_disable_IRQ(unsigned int irq)
280 {
281         u32 bus, dev_id, function, mask;
282         const u32 sub_bus = 0;
283         unsigned int rirq = virt_irq_to_real_map[irq];
284
285         /* The IRQ has already been locked by the caller */
286         bus = REAL_IRQ_TO_BUS(rirq);
287         function = REAL_IRQ_TO_FUNC(rirq);
288         dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
289
290         /* Mask secondary INTA   */
291         mask = 0x80000000;
292         HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask);
293 }
294
295 static void iseries_end_IRQ(unsigned int irq)
296 {
297         unsigned int rirq = virt_irq_to_real_map[irq];
298
299         HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq),
300                 (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
301 }
302
303 static hw_irq_controller iSeries_IRQ_handler = {
304         .typename = "iSeries irq controller",
305         .startup = iseries_startup_IRQ,
306         .shutdown = iseries_shutdown_IRQ,
307         .enable = iseries_enable_IRQ,
308         .disable = iseries_disable_IRQ,
309         .end = iseries_end_IRQ
310 };
311
312 /*
313  * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot
314  * It calculates the irq value for the slot.
315  * Note that sub_bus is always 0 (at the moment at least).
316  */
317 int __init iSeries_allocate_IRQ(HvBusNumber bus,
318                 HvSubBusNumber sub_bus, HvAgentId dev_id)
319 {
320         int virtirq;
321         unsigned int realirq;
322         u8 idsel = (dev_id >> 4);
323         u8 function = dev_id & 7;
324
325         realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
326                 + function;
327         virtirq = virt_irq_create_mapping(realirq);
328
329         irq_desc[virtirq].handler = &iSeries_IRQ_handler;
330         return virtirq;
331 }