~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/skiboot/core/interrupts.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2013-2014 IBM Corp.
 
2
 *
 
3
 * Licensed under the Apache License, Version 2.0 (the "License");
 
4
 * you may not use this file except in compliance with the License.
 
5
 * You may obtain a copy of the License at
 
6
 *
 
7
 *      http://www.apache.org/licenses/LICENSE-2.0
 
8
 *
 
9
 * Unless required by applicable law or agreed to in writing, software
 
10
 * distributed under the License is distributed on an "AS IS" BASIS,
 
11
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 
12
 * implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
#include <skiboot.h>
 
18
#include <chip.h>
 
19
#include <cpu.h>
 
20
#include <fsp.h>
 
21
#include <interrupts.h>
 
22
#include <opal.h>
 
23
#include <io.h>
 
24
#include <cec.h>
 
25
#include <device.h>
 
26
#include <ccan/str/str.h>
 
27
#include <timer.h>
 
28
 
 
29
/* ICP registers */
 
30
#define ICP_XIRR                0x4     /* 32-bit access */
 
31
#define ICP_CPPR                0x4     /* 8-bit access */
 
32
#define ICP_MFRR                0xc     /* 8-bit access */
 
33
 
 
34
static LIST_HEAD(irq_sources);
 
35
static struct lock irq_lock = LOCK_UNLOCKED;
 
36
 
 
37
void __register_irq_source(struct irq_source *is)
 
38
{
 
39
        struct irq_source *is1;
 
40
 
 
41
        prlog(PR_DEBUG, "IRQ: Registering %04x..%04x ops @%p (data %p)\n",
 
42
              is->start, is->end - 1, is->ops, is->data);
 
43
 
 
44
        lock(&irq_lock);
 
45
        list_for_each(&irq_sources, is1, link) {
 
46
                if (is->end > is1->start && is->start < is1->end) {
 
47
                        prerror("register IRQ source overlap !\n");
 
48
                        prerror("  new: %x..%x old: %x..%x\n",
 
49
                                is->start, is->end - 1,
 
50
                                is1->start, is1->end - 1);
 
51
                        assert(0);
 
52
                }
 
53
        }
 
54
        list_add_tail(&irq_sources, &is->link);
 
55
        unlock(&irq_lock);
 
56
}
 
57
 
 
58
void register_irq_source(const struct irq_source_ops *ops, void *data,
 
59
                         uint32_t start, uint32_t count)
 
60
{
 
61
        struct irq_source *is;
 
62
 
 
63
        is = zalloc(sizeof(struct irq_source));
 
64
        assert(is);
 
65
        is->start = start;
 
66
        is->end = start + count;
 
67
        is->ops = ops;
 
68
        is->data = data;
 
69
 
 
70
        __register_irq_source(is);
 
71
}
 
72
 
 
73
void unregister_irq_source(uint32_t start, uint32_t count)
 
74
{
 
75
        struct irq_source *is;
 
76
 
 
77
        lock(&irq_lock);
 
78
        list_for_each(&irq_sources, is, link) {
 
79
                if (start >= is->start && start < is->end) {
 
80
                        if (start != is->start ||
 
81
                            count != (is->end - is->start)) {
 
82
                                prerror("unregister IRQ source mismatch !\n");
 
83
                                prerror("start:%x, count: %x match: %x..%x\n",
 
84
                                        start, count, is->start, is->end);
 
85
                                assert(0);
 
86
                        }
 
87
                        list_del(&is->link);
 
88
                        unlock(&irq_lock);
 
89
                        /* XXX Add synchronize / RCU */
 
90
                        free(is);
 
91
                        return;
 
92
                }
 
93
        }
 
94
        unlock(&irq_lock);
 
95
        prerror("unregister IRQ source not found !\n");
 
96
        prerror("start:%x, count: %x\n", start, count);
 
97
        assert(0);
 
98
}
 
99
 
 
100
static struct irq_source *irq_find_source(uint32_t isn)
 
101
{
 
102
        struct irq_source *is;
 
103
 
 
104
        lock(&irq_lock);
 
105
        list_for_each(&irq_sources, is, link) {
 
106
                if (isn >= is->start && isn < is->end) {
 
107
                        unlock(&irq_lock);
 
108
                        return is;
 
109
                }
 
110
        }
 
111
        unlock(&irq_lock);
 
112
 
 
113
        return NULL;
 
114
}
 
115
 
 
116
void adjust_irq_source(struct irq_source *is, uint32_t new_count)
 
117
{
 
118
        struct irq_source *is1;
 
119
        uint32_t new_end = is->start + new_count;
 
120
 
 
121
        prlog(PR_DEBUG, "IRQ: Adjusting %04x..%04x to %04x..%04x\n",
 
122
              is->start, is->end - 1, is->start, new_end - 1);
 
123
 
 
124
        lock(&irq_lock);
 
125
        list_for_each(&irq_sources, is1, link) {
 
126
                if (is1 == is)
 
127
                        continue;
 
128
                if (new_end > is1->start && is->start < is1->end) {
 
129
                        prerror("adjust IRQ source overlap !\n");
 
130
                        prerror("  new: %x..%x old: %x..%x\n",
 
131
                                is->start, new_end - 1,
 
132
                                is1->start, is1->end - 1);
 
133
                        assert(0);
 
134
                }
 
135
        }
 
136
        is->end = new_end;
 
137
        unlock(&irq_lock);
 
138
}
 
139
 
 
140
/*
 
141
 * This takes a 6-bit chip id and returns a 20 bit value representing
 
142
 * the PSI interrupt. This includes all the fields above, ie, is a
 
143
 * global interrupt number.
 
144
 *
 
145
 * For P8, this returns the base of the 8-interrupts block for PSI
 
146
 */
 
147
uint32_t get_psi_interrupt(uint32_t chip_id)
 
148
{
 
149
        uint32_t irq;
 
150
 
 
151
        switch(proc_gen) {
 
152
        case proc_gen_p7:
 
153
                /* Get the chip ID into position, it already has
 
154
                 * the T bit so all we need is room for the GX
 
155
                 * bit, 9 bit BUID and 4 bit level
 
156
                 */
 
157
                irq  = chip_id << (1 + 9 + 4);
 
158
 
 
159
                /* Add in the BUID */
 
160
                irq |= P7_PSI_IRQ_BUID << 4;
 
161
                break;
 
162
        case proc_gen_p8:
 
163
                irq = p8_chip_irq_block_base(chip_id, P8_IRQ_BLOCK_MISC);
 
164
                irq += P8_IRQ_MISC_PSI_BASE;
 
165
                break;
 
166
        default:
 
167
                assert(false);
 
168
        };
 
169
 
 
170
        return irq;
 
171
}
 
172
 
 
173
 
 
174
struct dt_node *add_ics_node(void)
 
175
{
 
176
        struct dt_node *ics = dt_new_addr(dt_root, "interrupt-controller", 0);
 
177
        if (!ics)
 
178
                return NULL;
 
179
 
 
180
        dt_add_property_cells(ics, "reg", 0, 0, 0, 0);
 
181
        dt_add_property_strings(ics, "compatible", "IBM,ppc-xics",
 
182
                                "IBM,opal-xics");
 
183
        dt_add_property_cells(ics, "#address-cells", 0);
 
184
        dt_add_property_cells(ics, "#interrupt-cells", 2);
 
185
        dt_add_property_string(ics, "device_type",
 
186
                               "PowerPC-Interrupt-Source-Controller");
 
187
        dt_add_property(ics, "interrupt-controller", NULL, 0);
 
188
 
 
189
        return ics;
 
190
}
 
191
 
 
192
uint32_t get_ics_phandle(void)
 
193
{
 
194
        struct dt_node *i;
 
195
 
 
196
        for (i = dt_first(dt_root); i; i = dt_next(dt_root, i)) {
 
197
                if (streq(i->name, "interrupt-controller@0")) {
 
198
                        return i->phandle;
 
199
                }
 
200
        }
 
201
        abort();
 
202
}
 
203
 
 
204
void add_opal_interrupts(void)
 
205
{
 
206
        struct irq_source *is;
 
207
        unsigned int i, count = 0;
 
208
        uint32_t *irqs = NULL, isn;
 
209
 
 
210
        lock(&irq_lock);
 
211
        list_for_each(&irq_sources, is, link) {
 
212
                /*
 
213
                 * Add a source to opal-interrupts if it has an
 
214
                 * ->interrupt callback
 
215
                 */
 
216
                if (!is->ops->interrupt)
 
217
                        continue;
 
218
                for (isn = is->start; isn < is->end; isn++) {
 
219
                        i = count++;
 
220
                        irqs = realloc(irqs, 4 * count);
 
221
                        irqs[i] = isn;
 
222
                }
 
223
        }
 
224
        unlock(&irq_lock);
 
225
 
 
226
        /* The opal-interrupts property has one cell per interrupt,
 
227
         * it is not a standard interrupt property.
 
228
         *
 
229
         * Note: Even if empty, create it, otherwise some bogus error
 
230
         * handling in Linux can cause problems.
 
231
         */
 
232
        dt_add_property(opal_node, "opal-interrupts", irqs, count * 4);
 
233
 
 
234
        free(irqs);
 
235
}
 
236
 
 
237
/*
 
238
 * This is called at init time (and one fast reboot) to sanitize the
 
239
 * ICP. We set our priority to 0 to mask all interrupts and make sure
 
240
 * no IPI is on the way.
 
241
 */
 
242
void reset_cpu_icp(void)
 
243
{
 
244
        void *icp = this_cpu()->icp_regs;
 
245
 
 
246
        if (!icp)
 
247
                return;
 
248
 
 
249
        /* Clear pending IPIs */
 
250
        out_8(icp + ICP_MFRR, 0xff);
 
251
 
 
252
        /* Set priority to max, ignore all incoming interrupts, EOI IPIs */
 
253
        out_be32(icp + ICP_XIRR, 2);
 
254
}
 
255
 
 
256
/* Used by the PSI code to send an EOI during reset. This will also
 
257
 * set the CPPR to 0 which should already be the case anyway
 
258
 */
 
259
void icp_send_eoi(uint32_t interrupt)
 
260
{
 
261
        void *icp = this_cpu()->icp_regs;
 
262
 
 
263
        if (!icp)
 
264
                return;
 
265
 
 
266
        /* Set priority to max, ignore all incoming interrupts */
 
267
        out_be32(icp + ICP_XIRR, interrupt & 0xffffff);
 
268
}
 
269
 
 
270
/* This is called before winkle, we clear pending IPIs and set our priority
 
271
 * to 1 to mask all but the IPI
 
272
 */
 
273
void icp_prep_for_rvwinkle(void)
 
274
{
 
275
        void *icp = this_cpu()->icp_regs;
 
276
 
 
277
        if (!icp)
 
278
                return;
 
279
 
 
280
        /* Clear pending IPIs */
 
281
        out_8(icp + ICP_MFRR, 0xff);
 
282
 
 
283
        /* Set priority to 1, ignore all incoming interrupts, EOI IPIs */
 
284
        out_be32(icp + ICP_XIRR, 0x01000002);
 
285
}
 
286
 
 
287
/* This is called to wakeup somebody from winkle */
 
288
void icp_kick_cpu(struct cpu_thread *cpu)
 
289
{
 
290
        void *icp = cpu->icp_regs;
 
291
 
 
292
        if (!icp)
 
293
                return;
 
294
 
 
295
        /* Send high priority IPI */
 
296
        out_8(icp + ICP_MFRR, 0);
 
297
}
 
298
 
 
299
/* Returns the number of chip ID bits used for interrupt numbers */
 
300
static uint32_t p8_chip_id_bits(uint32_t chip)
 
301
{
 
302
        struct proc_chip *proc_chip = get_chip(chip);
 
303
 
 
304
        assert(proc_chip);
 
305
        switch (proc_chip->type) {
 
306
        case PROC_CHIP_P8_MURANO:
 
307
        case PROC_CHIP_P8_VENICE:
 
308
                return 6;
 
309
                break;
 
310
 
 
311
        case PROC_CHIP_P8_NAPLES:
 
312
                return 5;
 
313
                break;
 
314
 
 
315
        default:
 
316
                /* This shouldn't be called on non-P8 based systems */
 
317
                assert(0);
 
318
                return 0;
 
319
                break;
 
320
        }
 
321
}
 
322
 
 
323
/* The chip id mask is the upper p8_chip_id_bits of the irq number */
 
324
static uint32_t chip_id_mask(uint32_t chip)
 
325
{
 
326
        uint32_t chip_id_bits = p8_chip_id_bits(chip);
 
327
        uint32_t chip_id_mask;
 
328
 
 
329
        chip_id_mask = ((1 << chip_id_bits) - 1);
 
330
        chip_id_mask <<= P8_IRQ_BITS - chip_id_bits;
 
331
        return chip_id_mask;
 
332
}
 
333
 
 
334
/* The block mask is what remains of the 19 bit irq number after
 
335
 * removing the upper 5 or 6 bits for the chip# and the lower 11 bits
 
336
 * for the number of bits per block. */
 
337
static uint32_t block_mask(uint32_t chip)
 
338
{
 
339
        uint32_t chip_id_bits = p8_chip_id_bits(chip);
 
340
        uint32_t irq_block_mask;
 
341
 
 
342
        irq_block_mask = P8_IRQ_BITS - chip_id_bits - P8_IVE_BITS;
 
343
        irq_block_mask = ((1 << irq_block_mask) - 1) << P8_IVE_BITS;
 
344
        return irq_block_mask;
 
345
}
 
346
 
 
347
uint32_t p8_chip_irq_block_base(uint32_t chip, uint32_t block)
 
348
{
 
349
        uint32_t irq;
 
350
 
 
351
        assert(chip < (1 << p8_chip_id_bits(chip)));
 
352
        irq = SETFIELD(chip_id_mask(chip), 0, chip);
 
353
        irq = SETFIELD(block_mask(chip), irq, block);
 
354
 
 
355
        return irq;
 
356
}
 
357
 
 
358
uint32_t p8_chip_irq_phb_base(uint32_t chip, uint32_t phb)
 
359
{
 
360
        assert(chip < (1 << p8_chip_id_bits(chip)));
 
361
 
 
362
        return p8_chip_irq_block_base(chip, phb + P8_IRQ_BLOCK_PHB_BASE);
 
363
}
 
364
 
 
365
uint32_t p8_irq_to_chip(uint32_t irq)
 
366
{
 
367
        /* This assumes we only have one type of cpu in a system,
 
368
         * which should be ok. */
 
369
        return GETFIELD(chip_id_mask(this_cpu()->chip_id), irq);
 
370
}
 
371
 
 
372
uint32_t p8_irq_to_block(uint32_t irq)
 
373
{
 
374
        return GETFIELD(block_mask(this_cpu()->chip_id), irq);
 
375
}
 
376
 
 
377
uint32_t p8_irq_to_phb(uint32_t irq)
 
378
{
 
379
        return p8_irq_to_block(irq) - P8_IRQ_BLOCK_PHB_BASE;
 
380
}
 
381
 
 
382
bool irq_source_eoi(uint32_t isn)
 
383
{
 
384
        struct irq_source *is = irq_find_source(isn);
 
385
 
 
386
        if (!is || !is->ops->eoi)
 
387
                return false;
 
388
 
 
389
        is->ops->eoi(is, isn);
 
390
        return true;
 
391
}
 
392
 
 
393
static int64_t opal_set_xive(uint32_t isn, uint16_t server, uint8_t priority)
 
394
{
 
395
        struct irq_source *is = irq_find_source(isn);
 
396
 
 
397
        if (!is || !is->ops->set_xive)
 
398
                return OPAL_PARAMETER;
 
399
 
 
400
        return is->ops->set_xive(is, isn, server, priority);
 
401
}
 
402
opal_call(OPAL_SET_XIVE, opal_set_xive, 3);
 
403
 
 
404
static int64_t opal_get_xive(uint32_t isn, uint16_t *server, uint8_t *priority)
 
405
{
 
406
        struct irq_source *is = irq_find_source(isn);
 
407
 
 
408
        if (!is || !is->ops->get_xive)
 
409
                return OPAL_PARAMETER;
 
410
 
 
411
        return is->ops->get_xive(is, isn, server, priority);
 
412
}
 
413
opal_call(OPAL_GET_XIVE, opal_get_xive, 3);
 
414
 
 
415
static int64_t opal_handle_interrupt(uint32_t isn, __be64 *outstanding_event_mask)
 
416
{
 
417
        struct irq_source *is = irq_find_source(isn);
 
418
        int64_t rc = OPAL_SUCCESS;
 
419
 
 
420
        /* No source ? return */
 
421
        if (!is || !is->ops->interrupt) {
 
422
                rc = OPAL_PARAMETER;
 
423
                goto bail;
 
424
        }
 
425
 
 
426
        /* Run it */
 
427
        is->ops->interrupt(is, isn);
 
428
 
 
429
        /* Check timers if SLW timer isn't working */
 
430
        if (!slw_timer_ok())
 
431
                check_timers(true);
 
432
 
 
433
        /* Update output events */
 
434
 bail:
 
435
        if (outstanding_event_mask)
 
436
                *outstanding_event_mask = cpu_to_be64(opal_pending_events);
 
437
 
 
438
        return rc;
 
439
}
 
440
opal_call(OPAL_HANDLE_INTERRUPT, opal_handle_interrupt, 2);
 
441
 
 
442
void init_interrupts(void)
 
443
{
 
444
        struct dt_node *icp;
 
445
        const struct dt_property *sranges;
 
446
        struct cpu_thread *cpu;
 
447
        u32 base, count, i;
 
448
        u64 addr, size;
 
449
 
 
450
        dt_for_each_compatible(dt_root, icp, "ibm,ppc-xicp") {
 
451
                sranges = dt_require_property(icp,
 
452
                                              "ibm,interrupt-server-ranges",
 
453
                                              -1);
 
454
                base = dt_get_number(sranges->prop, 1);
 
455
                count = dt_get_number(sranges->prop + 4, 1);
 
456
                for (i = 0; i < count; i++) {
 
457
                        addr = dt_get_address(icp, i, &size);
 
458
                        cpu = find_cpu_by_server(base + i);
 
459
                        if (cpu)
 
460
                                cpu->icp_regs = (void *)addr;
 
461
                }
 
462
        }
 
463
}
 
464
 
 
465