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

« back to all changes in this revision

Viewing changes to roms/skiboot/hw/prd.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 2014-2015 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
 * imitations under the License.
 
15
 */
 
16
 
 
17
#include <skiboot.h>
 
18
#include <opal.h>
 
19
#include <lock.h>
 
20
#include <xscom.h>
 
21
#include <chip.h>
 
22
#include <opal-msg.h>
 
23
#include <fsp.h>
 
24
#include <mem_region.h>
 
25
 
 
26
enum events {
 
27
        EVENT_ATTN      = 1 << 0,
 
28
        EVENT_OCC_ERROR = 1 << 1,
 
29
        EVENT_OCC_RESET = 1 << 2,
 
30
};
 
31
 
 
32
static uint8_t events[MAX_CHIPS];
 
33
static uint64_t ipoll_status[MAX_CHIPS];
 
34
static struct opal_prd_msg prd_msg;
 
35
static bool prd_msg_inuse, prd_active;
 
36
struct dt_node *prd_node;
 
37
 
 
38
/* Locking:
 
39
 *
 
40
 * The events lock serialises access to the events, ipoll_status,
 
41
 * prd_msg_inuse, and prd_active variables.
 
42
 *
 
43
 * The ipoll_lock protects against concurrent updates to the ipoll registers.
 
44
 *
 
45
 * The ipoll_lock may be acquired with events_lock held. This order must
 
46
 * be preserved.
 
47
 */
 
48
static struct lock events_lock = LOCK_UNLOCKED;
 
49
static struct lock ipoll_lock = LOCK_UNLOCKED;
 
50
 
 
51
/* PRD registers */
 
52
#define PRD_IPOLL_REG_MASK      0x01020013
 
53
#define PRD_IPOLL_REG_STATUS    0x01020014
 
54
#define PRD_IPOLL_XSTOP         PPC_BIT(0) /* Xstop for host/core/millicode */
 
55
#define PRD_IPOLL_RECOV         PPC_BIT(1) /* Recoverable */
 
56
#define PRD_IPOLL_SPEC_ATTN     PPC_BIT(2) /* Special attention */
 
57
#define PRD_IPOLL_HOST_ATTN     PPC_BIT(3) /* Host attention */
 
58
#define PRD_IPOLL_MASK          PPC_BITMASK(0, 3)
 
59
 
 
60
static int queue_prd_msg_hbrt(struct opal_prd_msg *msg,
 
61
                void (*consumed)(void *data))
 
62
{
 
63
        uint64_t *buf;
 
64
 
 
65
        BUILD_ASSERT(sizeof(*msg) / sizeof(uint64_t) == 4);
 
66
 
 
67
        buf = (uint64_t *)msg;
 
68
 
 
69
        return _opal_queue_msg(OPAL_MSG_PRD, msg, consumed, 4, buf);
 
70
}
 
71
 
 
72
static int queue_prd_msg_nop(struct opal_prd_msg *msg,
 
73
                void (*consumed)(void *data))
 
74
{
 
75
        (void)msg;
 
76
        (void)consumed;
 
77
        return OPAL_UNSUPPORTED;
 
78
}
 
79
 
 
80
static int (*queue_prd_msg)(struct opal_prd_msg *msg,
 
81
                void (*consumed)(void *data)) = queue_prd_msg_nop;
 
82
 
 
83
static void send_next_pending_event(void);
 
84
 
 
85
static void prd_msg_consumed(void *data)
 
86
{
 
87
        struct opal_prd_msg *msg = data;
 
88
        uint32_t proc;
 
89
        uint8_t event = 0;
 
90
 
 
91
        lock(&events_lock);
 
92
        switch (msg->hdr.type) {
 
93
        case OPAL_PRD_MSG_TYPE_ATTN:
 
94
                proc = msg->attn.proc;
 
95
 
 
96
                /* If other ipoll events have been received in the time
 
97
                 * between prd_msg creation and consumption, we'll need to
 
98
                 * raise a separate ATTN message for those. So, we only
 
99
                 * clear the event if we don't have any further ipoll_status
 
100
                 * bits.
 
101
                 */
 
102
                ipoll_status[proc] &= ~msg->attn.ipoll_status;
 
103
                if (!ipoll_status[proc])
 
104
                        event = EVENT_ATTN;
 
105
 
 
106
                break;
 
107
        case OPAL_PRD_MSG_TYPE_OCC_ERROR:
 
108
                proc = msg->occ_error.chip;
 
109
                event = EVENT_OCC_ERROR;
 
110
                break;
 
111
        case OPAL_PRD_MSG_TYPE_OCC_RESET:
 
112
                proc = msg->occ_reset.chip;
 
113
                event = EVENT_OCC_RESET;
 
114
                break;
 
115
        default:
 
116
                prlog(PR_ERR, "PRD: invalid msg consumed, type: 0x%x\n",
 
117
                                msg->hdr.type);
 
118
        }
 
119
 
 
120
        if (event)
 
121
                events[proc] &= ~event;
 
122
        prd_msg_inuse = false;
 
123
        send_next_pending_event();
 
124
        unlock(&events_lock);
 
125
}
 
126
 
 
127
static int populate_ipoll_msg(struct opal_prd_msg *msg, uint32_t proc)
 
128
{
 
129
        uint64_t ipoll_mask;
 
130
        int rc;
 
131
 
 
132
        lock(&ipoll_lock);
 
133
        rc = xscom_read(proc, PRD_IPOLL_REG_MASK, &ipoll_mask);
 
134
        unlock(&ipoll_lock);
 
135
 
 
136
        if (rc) {
 
137
                prlog(PR_ERR, "PRD: Unable to read ipoll status (chip %d)!\n",
 
138
                                proc);
 
139
                return -1;
 
140
        }
 
141
 
 
142
        msg->attn.proc = proc;
 
143
        msg->attn.ipoll_status = ipoll_status[proc];
 
144
        msg->attn.ipoll_mask = ipoll_mask;
 
145
        return 0;
 
146
}
 
147
 
 
148
static void send_next_pending_event(void)
 
149
{
 
150
        struct proc_chip *chip;
 
151
        uint32_t proc;
 
152
        uint8_t event;
 
153
 
 
154
        assert(!prd_msg_inuse);
 
155
 
 
156
        if (!prd_active)
 
157
                return;
 
158
 
 
159
        event = 0;
 
160
 
 
161
        for_each_chip(chip) {
 
162
                proc = chip->id;
 
163
                if (events[proc]) {
 
164
                        event = events[proc];
 
165
                        break;
 
166
                }
 
167
        }
 
168
 
 
169
        if (!event)
 
170
                return;
 
171
 
 
172
        prd_msg_inuse = true;
 
173
        prd_msg.token = 0;
 
174
        prd_msg.hdr.size = sizeof(prd_msg);
 
175
 
 
176
        if (event & EVENT_ATTN) {
 
177
                prd_msg.hdr.type = OPAL_PRD_MSG_TYPE_ATTN;
 
178
                populate_ipoll_msg(&prd_msg, proc);
 
179
        } else if (event & EVENT_OCC_ERROR) {
 
180
                prd_msg.hdr.type = OPAL_PRD_MSG_TYPE_OCC_ERROR;
 
181
                prd_msg.occ_error.chip = proc;
 
182
        } else if (event & EVENT_OCC_RESET) {
 
183
                prd_msg.hdr.type = OPAL_PRD_MSG_TYPE_OCC_RESET;
 
184
                prd_msg.occ_reset.chip = proc;
 
185
                occ_msg_queue_occ_reset();
 
186
        }
 
187
 
 
188
        queue_prd_msg(&prd_msg, prd_msg_consumed);
 
189
}
 
190
 
 
191
static void __prd_event(uint32_t proc, uint8_t event)
 
192
{
 
193
        events[proc] |= event;
 
194
        if (!prd_msg_inuse)
 
195
                send_next_pending_event();
 
196
}
 
197
 
 
198
static void prd_event(uint32_t proc, uint8_t event)
 
199
{
 
200
        lock(&events_lock);
 
201
        __prd_event(proc, event);
 
202
        unlock(&events_lock);
 
203
}
 
204
 
 
205
static int __ipoll_update_mask(uint32_t proc, bool set, uint64_t bits)
 
206
{
 
207
        uint64_t mask;
 
208
        int rc;
 
209
 
 
210
        rc = xscom_read(proc, PRD_IPOLL_REG_MASK, &mask);
 
211
        if (rc)
 
212
                return rc;
 
213
 
 
214
        if (set)
 
215
                mask |= bits;
 
216
        else
 
217
                mask &= ~bits;
 
218
 
 
219
        return xscom_write(proc, PRD_IPOLL_REG_MASK, mask);
 
220
}
 
221
 
 
222
static int ipoll_record_and_mask_pending(uint32_t proc)
 
223
{
 
224
        uint64_t status;
 
225
        int rc;
 
226
 
 
227
        lock(&ipoll_lock);
 
228
        rc = xscom_read(proc, PRD_IPOLL_REG_STATUS, &status);
 
229
        status &= PRD_IPOLL_MASK;
 
230
        if (!rc)
 
231
                __ipoll_update_mask(proc, true, status);
 
232
        unlock(&ipoll_lock);
 
233
 
 
234
        if (!rc)
 
235
                ipoll_status[proc] |= status;
 
236
 
 
237
        return rc;
 
238
}
 
239
 
 
240
/* Entry point for interrupts */
 
241
void prd_psi_interrupt(uint32_t proc)
 
242
{
 
243
        int rc;
 
244
 
 
245
        lock(&events_lock);
 
246
 
 
247
        rc = ipoll_record_and_mask_pending(proc);
 
248
        if (rc)
 
249
                prlog(PR_ERR, "PRD: Failed to update IPOLL mask\n");
 
250
 
 
251
        __prd_event(proc, EVENT_ATTN);
 
252
 
 
253
        unlock(&events_lock);
 
254
}
 
255
 
 
256
void prd_tmgt_interrupt(uint32_t proc)
 
257
{
 
258
        prd_event(proc, EVENT_OCC_ERROR);
 
259
}
 
260
 
 
261
void prd_occ_reset(uint32_t proc)
 
262
{
 
263
        prd_event(proc, EVENT_OCC_RESET);
 
264
}
 
265
 
 
266
/* incoming message handlers */
 
267
static int prd_msg_handle_attn_ack(struct opal_prd_msg *msg)
 
268
{
 
269
        int rc;
 
270
 
 
271
        lock(&ipoll_lock);
 
272
        rc = __ipoll_update_mask(msg->attn_ack.proc, false,
 
273
                        msg->attn_ack.ipoll_ack & PRD_IPOLL_MASK);
 
274
        unlock(&ipoll_lock);
 
275
 
 
276
        if (rc)
 
277
                prlog(PR_ERR, "PRD: Unable to unmask ipoll!\n");
 
278
 
 
279
        return rc;
 
280
}
 
281
 
 
282
static int prd_msg_handle_init(struct opal_prd_msg *msg)
 
283
{
 
284
        struct proc_chip *chip;
 
285
 
 
286
        lock(&ipoll_lock);
 
287
        for_each_chip(chip) {
 
288
                __ipoll_update_mask(chip->id, false,
 
289
                        msg->init.ipoll & PRD_IPOLL_MASK);
 
290
        }
 
291
        unlock(&ipoll_lock);
 
292
 
 
293
        /* we're transitioning from inactive to active; send any pending tmgt
 
294
         * interrupts */
 
295
        lock(&events_lock);
 
296
        prd_active = true;
 
297
        if (!prd_msg_inuse)
 
298
                send_next_pending_event();
 
299
        unlock(&events_lock);
 
300
 
 
301
        return OPAL_SUCCESS;
 
302
}
 
303
 
 
304
static int prd_msg_handle_fini(void)
 
305
{
 
306
        struct proc_chip *chip;
 
307
 
 
308
        lock(&events_lock);
 
309
        prd_active = false;
 
310
        unlock(&events_lock);
 
311
 
 
312
        lock(&ipoll_lock);
 
313
        for_each_chip(chip) {
 
314
                __ipoll_update_mask(chip->id, true, PRD_IPOLL_MASK);
 
315
        }
 
316
        unlock(&ipoll_lock);
 
317
 
 
318
        return OPAL_SUCCESS;
 
319
}
 
320
 
 
321
/* Entry from the host above */
 
322
static int64_t opal_prd_msg(struct opal_prd_msg *msg)
 
323
{
 
324
        int rc;
 
325
 
 
326
        /* fini is a little special: the kernel (which may not have the entire
 
327
         * opal_prd_msg definition) can send a FINI message, so we don't check
 
328
         * the full size */
 
329
        if (msg->hdr.size >= sizeof(struct opal_prd_msg_header) &&
 
330
                        msg->hdr.type == OPAL_PRD_MSG_TYPE_FINI)
 
331
                return prd_msg_handle_fini();
 
332
 
 
333
        if (msg->hdr.size != sizeof(*msg))
 
334
                return OPAL_PARAMETER;
 
335
 
 
336
        switch (msg->hdr.type) {
 
337
        case OPAL_PRD_MSG_TYPE_INIT:
 
338
                rc = prd_msg_handle_init(msg);
 
339
                break;
 
340
        case OPAL_PRD_MSG_TYPE_ATTN_ACK:
 
341
                rc = prd_msg_handle_attn_ack(msg);
 
342
                break;
 
343
        case OPAL_PRD_MSG_TYPE_OCC_RESET_NOTIFY:
 
344
                rc = occ_msg_queue_occ_reset();
 
345
                break;
 
346
        default:
 
347
                rc = OPAL_UNSUPPORTED;
 
348
        }
 
349
 
 
350
        return rc;
 
351
}
 
352
 
 
353
void prd_init(void)
 
354
{
 
355
        struct proc_chip *chip;
 
356
 
 
357
        /* mask everything */
 
358
        lock(&ipoll_lock);
 
359
        for_each_chip(chip) {
 
360
                __ipoll_update_mask(chip->id, true, PRD_IPOLL_MASK);
 
361
        }
 
362
        unlock(&ipoll_lock);
 
363
 
 
364
        if (fsp_present()) {
 
365
                /* todo: FSP implementation */
 
366
                queue_prd_msg = queue_prd_msg_nop;
 
367
        } else {
 
368
                queue_prd_msg = queue_prd_msg_hbrt;
 
369
                opal_register(OPAL_PRD_MSG, opal_prd_msg, 1);
 
370
        }
 
371
 
 
372
        prd_node = dt_new(opal_node, "diagnostics");
 
373
        dt_add_property_strings(prd_node, "compatible", "ibm,opal-prd");
 
374
}
 
375
 
 
376
void prd_register_reserved_memory(void)
 
377
{
 
378
        struct mem_region *region;
 
379
 
 
380
        if (!prd_node)
 
381
                return;
 
382
 
 
383
        lock(&mem_region_lock);
 
384
        for (region = mem_region_next(NULL); region;
 
385
                        region = mem_region_next(region)) {
 
386
 
 
387
                if (region->type != REGION_HW_RESERVED)
 
388
                        continue;
 
389
 
 
390
                if (!region->node)
 
391
                        continue;
 
392
 
 
393
                if (!dt_find_property(region->node, "ibm,prd-label")) {
 
394
                        dt_add_property_string(region->node, "ibm,prd-label",
 
395
                                        region->name);
 
396
                }
 
397
        }
 
398
        unlock(&mem_region_lock);
 
399
}