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

« back to all changes in this revision

Viewing changes to roms/skiboot/hw/fsp/fsp-console.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
/*
 
18
 * Service Processor serial console handling code
 
19
 */
 
20
#include <skiboot.h>
 
21
#include <processor.h>
 
22
#include <io.h>
 
23
#include <fsp.h>
 
24
#include <console.h>
 
25
#include <opal.h>
 
26
#include <timebase.h>
 
27
#include <device.h>
 
28
#include <fsp-sysparam.h>
 
29
 
 
30
struct fsp_serbuf_hdr {
 
31
        u16     partition_id;
 
32
        u8      session_id;
 
33
        u8      hmc_id;
 
34
        u16     data_offset;
 
35
        u16     last_valid;
 
36
        u16     ovf_count;
 
37
        u16     next_in;
 
38
        u8      flags;
 
39
        u8      reserved;
 
40
        u16     next_out;
 
41
        u8      data[];
 
42
};
 
43
#define SER_BUF_DATA_SIZE       (0x10000 - sizeof(struct fsp_serbuf_hdr))
 
44
 
 
45
struct fsp_serial {
 
46
        bool                    available;
 
47
        bool                    open;
 
48
        bool                    has_part0;
 
49
        bool                    has_part1;
 
50
        bool                    log_port;
 
51
        bool                    out_poke;
 
52
        char                    loc_code[LOC_CODE_SIZE];
 
53
        u16                     rsrc_id;
 
54
        struct fsp_serbuf_hdr   *in_buf;
 
55
        struct fsp_serbuf_hdr   *out_buf;
 
56
        struct fsp_msg          *poke_msg;
 
57
        u8                      waiting;
 
58
};
 
59
 
 
60
#define SER_BUFFER_SIZE 0x00040000UL
 
61
#define MAX_SERIAL      4
 
62
 
 
63
static struct fsp_serial fsp_serials[MAX_SERIAL];
 
64
static bool got_intf_query;
 
65
static struct lock fsp_con_lock = LOCK_UNLOCKED;
 
66
static void* ser_buffer = NULL;
 
67
 
 
68
static void fsp_console_reinit(void)
 
69
{
 
70
        int i;
 
71
        void *base;
 
72
        struct fsp_msg *msg;
 
73
 
 
74
        /* Initialize out data structure pointers & TCE maps */
 
75
        base = ser_buffer;
 
76
        for (i = 0; i < MAX_SERIAL; i++) {
 
77
                struct fsp_serial *ser = &fsp_serials[i];
 
78
 
 
79
                ser->in_buf = base;
 
80
                ser->out_buf = base + SER_BUFFER_SIZE/2;
 
81
                base += SER_BUFFER_SIZE;
 
82
        }
 
83
        fsp_tce_map(PSI_DMA_SER0_BASE, ser_buffer,
 
84
                        4 * PSI_DMA_SER0_SIZE);
 
85
 
 
86
        for (i = 0; i < MAX_SERIAL; i++) {
 
87
                struct fsp_serial *fs = &fsp_serials[i];
 
88
 
 
89
                if (fs->rsrc_id == 0xffff)
 
90
                        continue;
 
91
                prlog(PR_DEBUG, "FSP: Reassociating HVSI console %d\n", i);
 
92
                msg = fsp_mkmsg(FSP_CMD_ASSOC_SERIAL, 2,
 
93
                                (fs->rsrc_id << 16) | 1, i);
 
94
                if (!msg) {
 
95
                        prerror("FSPCON: Failed to allocate associate msg\n");
 
96
                        return;
 
97
                }
 
98
                if (fsp_queue_msg(msg, fsp_freemsg)) {
 
99
                        fsp_freemsg(msg);
 
100
                        prerror("FSPCON: Failed to queue associate msg\n");
 
101
                        return;
 
102
                }
 
103
        }
 
104
}
 
105
 
 
106
static void fsp_close_consoles(void)
 
107
{
 
108
        unsigned int i;
 
109
 
 
110
        for (i = 0; i < MAX_SERIAL; i++) {
 
111
                struct fsp_serial *fs = &fsp_serials[i];
 
112
 
 
113
                if (!fs->available)
 
114
                        continue;
 
115
 
 
116
                if (fs->rsrc_id == 0xffff)      /* Get clarity from benh */
 
117
                        continue;
 
118
 
 
119
                lock(&fsp_con_lock);
 
120
                if (fs->open) {
 
121
                        fs->open = false;
 
122
                        fs->out_poke = false;
 
123
                        if (fs->poke_msg->state != fsp_msg_unused)
 
124
                                fsp_cancelmsg(fs->poke_msg);
 
125
                        fsp_freemsg(fs->poke_msg);
 
126
                        fs->poke_msg = NULL;
 
127
                }
 
128
                unlock(&fsp_con_lock);
 
129
        }
 
130
        prlog(PR_DEBUG, "FSPCON: Closed consoles due to FSP reset/reload\n");
 
131
}
 
132
 
 
133
static void fsp_pokemsg_reclaim(struct fsp_msg *msg)
 
134
{
 
135
        struct fsp_serial *fs = msg->user_data;
 
136
 
 
137
        /*
 
138
         * The poke_msg might have been "detached" from the console
 
139
         * in vserial_close, so we need to check whether it's current
 
140
         * before touching the state, otherwise, just free it
 
141
         */
 
142
        lock(&fsp_con_lock);
 
143
        if (fs->open && fs->poke_msg == msg) {
 
144
                if (fs->out_poke) {
 
145
                        if (fsp_queue_msg(fs->poke_msg, fsp_pokemsg_reclaim)) {
 
146
                                prerror("FSPCON: failed to queue poke msg\n");
 
147
                                fsp_freemsg(msg);
 
148
                        } else {
 
149
                                fs->out_poke = false;
 
150
                        }
 
151
                } else
 
152
                        fs->poke_msg->state = fsp_msg_unused;
 
153
        } else
 
154
                fsp_freemsg(msg);
 
155
        unlock(&fsp_con_lock);
 
156
}
 
157
 
 
158
/* Called with the fsp_con_lock held */
 
159
static size_t fsp_write_vserial(struct fsp_serial *fs, const char *buf,
 
160
                                size_t len)
 
161
{
 
162
        struct fsp_serbuf_hdr *sb = fs->out_buf;
 
163
        u16 old_nin = sb->next_in;
 
164
        u16 space, chunk;
 
165
 
 
166
        if (!fs->open)
 
167
                return 0;
 
168
 
 
169
        space = (sb->next_out + SER_BUF_DATA_SIZE - old_nin - 1)
 
170
                % SER_BUF_DATA_SIZE;
 
171
        if (space < len)
 
172
                len = space;
 
173
        if (!len)
 
174
                return 0;
 
175
 
 
176
        chunk = SER_BUF_DATA_SIZE - old_nin;
 
177
        if (chunk > len)
 
178
                chunk = len;
 
179
        memcpy(&sb->data[old_nin], buf, chunk);
 
180
        if (chunk < len)
 
181
                memcpy(&sb->data[0], buf + chunk, len - chunk);
 
182
        lwsync();
 
183
        sb->next_in = (old_nin + len) % SER_BUF_DATA_SIZE;
 
184
        sync();
 
185
 
 
186
        if (sb->next_out == old_nin && fs->poke_msg) {
 
187
                if (fs->poke_msg->state == fsp_msg_unused) {
 
188
                        if (fsp_queue_msg(fs->poke_msg, fsp_pokemsg_reclaim))
 
189
                                prerror("FSPCON: poke msg queuing failed\n");
 
190
                } else
 
191
                        fs->out_poke = true;
 
192
        }
 
193
#ifndef DISABLE_CON_PENDING_EVT
 
194
        opal_update_pending_evt(OPAL_EVENT_CONSOLE_OUTPUT,
 
195
                                OPAL_EVENT_CONSOLE_OUTPUT);
 
196
#endif
 
197
        return len;
 
198
}
 
199
 
 
200
#ifdef DVS_CONSOLE
 
201
static int fsp_con_port = -1;
 
202
static bool fsp_con_full;
 
203
 
 
204
/*
 
205
 * This is called by the code in console.c without the con_lock
 
206
 * held. However it can be called as the result of any printf
 
207
 * thus any other lock might be held including possibly the
 
208
 * FSP lock
 
209
 */
 
210
static size_t fsp_con_write(const char *buf, size_t len)
 
211
{
 
212
        size_t written;
 
213
 
 
214
        if (fsp_con_port < 0)
 
215
                return 0;
 
216
 
 
217
        lock(&fsp_con_lock);
 
218
        written = fsp_write_vserial(&fsp_serials[fsp_con_port], buf, len);
 
219
        fsp_con_full = (written < len);
 
220
        unlock(&fsp_con_lock);
 
221
 
 
222
        return written;
 
223
}
 
224
 
 
225
static struct con_ops fsp_con_ops = {
 
226
        .write = fsp_con_write,
 
227
};
 
228
#endif /* DVS_CONSOLE */
 
229
 
 
230
static void fsp_open_vserial(struct fsp_msg *msg)
 
231
{
 
232
        struct fsp_msg *resp;
 
233
 
 
234
        u16 part_id = msg->data.words[0] & 0xffff;
 
235
        u16 sess_id = msg->data.words[1] & 0xffff;
 
236
        u8 hmc_sess = msg->data.bytes[0];       
 
237
        u8 hmc_indx = msg->data.bytes[1];
 
238
        u8 authority = msg->data.bytes[4];
 
239
        u32 tce_in, tce_out;
 
240
        struct fsp_serial *fs;
 
241
 
 
242
        prlog(PR_INFO, "FSPCON: Got VSerial Open\n");
 
243
        prlog(PR_DEBUG, "  part_id   = 0x%04x\n", part_id);
 
244
        prlog(PR_DEBUG, "  sess_id   = 0x%04x\n", sess_id);
 
245
        prlog(PR_DEBUG, "  hmc_sess  = 0x%02x\n", hmc_sess);
 
246
        prlog(PR_DEBUG, "  hmc_indx  = 0x%02x\n", hmc_indx);
 
247
        prlog(PR_DEBUG, "  authority = 0x%02x\n", authority);
 
248
 
 
249
        if (sess_id >= MAX_SERIAL || !fsp_serials[sess_id].available) {
 
250
                prlog(PR_WARNING, "FSPCON: 0x%04x  NOT AVAILABLE!\n", sess_id);
 
251
                resp = fsp_mkmsg(FSP_RSP_OPEN_VSERIAL | 0x2f, 0);
 
252
                if (!resp) {
 
253
                        prerror("FSPCON: Response allocation failed\n");
 
254
                        return;
 
255
                }
 
256
                if (fsp_queue_msg(resp, fsp_freemsg)) {
 
257
                        fsp_freemsg(resp);
 
258
                        prerror("FSPCON: Failed to queue response msg\n");
 
259
                }
 
260
                return;
 
261
        }
 
262
 
 
263
        fs = &fsp_serials[sess_id];
 
264
 
 
265
        /* Hack ! On blades, the console opened via the mm has partition 1
 
266
         * while the debug DVS generally has partition 0 (though you can
 
267
         * use what you want really).
 
268
         * We don't want a DVS open/close to crap on the blademm console
 
269
         * thus if it's a raw console, gets an open with partID 1, we
 
270
         * set a flag that ignores the close of partid 0
 
271
         */
 
272
        if (fs->rsrc_id == 0xffff) {
 
273
                if (part_id == 0)
 
274
                        fs->has_part0 = true;
 
275
                if (part_id == 1)
 
276
                        fs->has_part1 = true;
 
277
        }
 
278
 
 
279
        tce_in = PSI_DMA_SER0_BASE + PSI_DMA_SER0_SIZE * sess_id;
 
280
        tce_out = tce_in + SER_BUFFER_SIZE/2;
 
281
 
 
282
        lock(&fsp_con_lock);
 
283
        if (fs->open) {
 
284
                prlog(PR_DEBUG, "  already open, skipping init !\n");
 
285
                unlock(&fsp_con_lock);
 
286
                goto already_open;
 
287
        }
 
288
 
 
289
        fs->open = true;
 
290
 
 
291
        fs->poke_msg = fsp_mkmsg(FSP_CMD_VSERIAL_OUT, 2,
 
292
                                 msg->data.words[0],
 
293
                                 msg->data.words[1] & 0xffff);
 
294
        fs->poke_msg->user_data = fs;
 
295
 
 
296
        fs->in_buf->partition_id = fs->out_buf->partition_id = part_id;
 
297
        fs->in_buf->session_id   = fs->out_buf->session_id   = sess_id;
 
298
        fs->in_buf->hmc_id       = fs->out_buf->hmc_id       = hmc_indx;
 
299
        fs->in_buf->data_offset  = fs->out_buf->data_offset  =
 
300
                sizeof(struct fsp_serbuf_hdr);
 
301
        fs->in_buf->last_valid   = fs->out_buf->last_valid   =
 
302
                SER_BUF_DATA_SIZE - 1;
 
303
        fs->in_buf->ovf_count    = fs->out_buf->ovf_count    = 0;
 
304
        fs->in_buf->next_in      = fs->out_buf->next_in      = 0;
 
305
        fs->in_buf->flags        = fs->out_buf->flags        = 0;
 
306
        fs->in_buf->reserved     = fs->out_buf->reserved     = 0;
 
307
        fs->in_buf->next_out     = fs->out_buf->next_out     = 0;
 
308
        unlock(&fsp_con_lock);
 
309
 
 
310
 already_open:
 
311
        resp = fsp_mkmsg(FSP_RSP_OPEN_VSERIAL, 6, msg->data.words[0],
 
312
                        msg->data.words[1] & 0xffff, 0, tce_in, 0, tce_out);
 
313
        if (!resp) {
 
314
                prerror("FSPCON: Failed to allocate open msg response\n");
 
315
                return;
 
316
        }
 
317
        if (fsp_queue_msg(resp, fsp_freemsg)) {
 
318
                fsp_freemsg(resp);
 
319
                prerror("FSPCON: Failed to queue open msg response\n");
 
320
                return;
 
321
        }
 
322
 
 
323
#ifdef DVS_CONSOLE
 
324
        prlog(PR_DEBUG, "  log_port  = %d\n", fs->log_port);
 
325
        if (fs->log_port) {
 
326
                fsp_con_port = sess_id;
 
327
                sync();
 
328
                /*
 
329
                 * We mark the FSP lock as being in the console
 
330
                 * path. We do that only once, we never unmark it
 
331
                 * (there is really no much point)
 
332
                 */
 
333
                fsp_used_by_console();
 
334
                fsp_con_lock.in_con_path = true;
 
335
                /* See comment in fsp_used_by_console */
 
336
                lock(&fsp_con_lock);
 
337
                unlock(&fsp_con_lock);
 
338
                set_console(&fsp_con_ops);
 
339
        }
 
340
#endif
 
341
}
 
342
 
 
343
static void fsp_close_vserial(struct fsp_msg *msg)
 
344
{
 
345
        u16 part_id = msg->data.words[0] & 0xffff;
 
346
        u16 sess_id = msg->data.words[1] & 0xffff;
 
347
        u8 hmc_sess = msg->data.bytes[0];       
 
348
        u8 hmc_indx = msg->data.bytes[1];
 
349
        u8 authority = msg->data.bytes[4];
 
350
        struct fsp_serial *fs;
 
351
        struct fsp_msg *resp;
 
352
 
 
353
        prlog(PR_INFO, "FSPCON: Got VSerial Close\n");
 
354
        prlog(PR_DEBUG, "  part_id   = 0x%04x\n", part_id);
 
355
        prlog(PR_DEBUG, "  sess_id   = 0x%04x\n", sess_id);
 
356
        prlog(PR_DEBUG, "  hmc_sess  = 0x%02x\n", hmc_sess);
 
357
        prlog(PR_DEBUG, "  hmc_indx  = 0x%02x\n", hmc_indx);
 
358
        prlog(PR_DEBUG, "  authority = 0x%02x\n", authority);
 
359
 
 
360
        if (sess_id >= MAX_SERIAL || !fsp_serials[sess_id].available) {
 
361
                prlog(PR_WARNING, "FSPCON: 0x%04x  NOT AVAILABLE!\n", sess_id);
 
362
                goto skip_close;
 
363
        }
 
364
 
 
365
        fs = &fsp_serials[sess_id];
 
366
 
 
367
        /* See "HACK" comment in open */
 
368
        if (fs->rsrc_id == 0xffff) {
 
369
                if (part_id == 0)
 
370
                        fs->has_part0 = false;
 
371
                if (part_id == 1)
 
372
                        fs->has_part1 = false;
 
373
                if (fs->has_part0 || fs->has_part1) {
 
374
                        prlog(PR_DEBUG, "  skipping close !\n");
 
375
                        goto skip_close;
 
376
                }
 
377
        }
 
378
 
 
379
#ifdef DVS_CONSOLE
 
380
        if (fs->log_port) {
 
381
                fsp_con_port = -1;
 
382
                set_console(NULL);
 
383
        }
 
384
#endif
 
385
        
 
386
        lock(&fsp_con_lock);
 
387
        if (fs->open) {
 
388
                fs->open = false;
 
389
                fs->out_poke = false;
 
390
                if (fs->poke_msg && fs->poke_msg->state == fsp_msg_unused) {
 
391
                        fsp_freemsg(fs->poke_msg);
 
392
                        fs->poke_msg = NULL;
 
393
                }
 
394
        }
 
395
        unlock(&fsp_con_lock);
 
396
 skip_close:
 
397
        resp = fsp_mkmsg(FSP_RSP_CLOSE_VSERIAL, 2, msg->data.words[0],
 
398
                        msg->data.words[1] & 0xffff);
 
399
        if (!resp) {
 
400
                prerror("FSPCON: Failed to allocate close msg response\n");
 
401
                return;
 
402
        }
 
403
        if (fsp_queue_msg(resp, fsp_freemsg)) {
 
404
                fsp_freemsg(resp);
 
405
                prerror("FSPCON: Failed to queue close msg response\n");
 
406
        }
 
407
}
 
408
 
 
409
static bool fsp_con_msg_hmc(u32 cmd_sub_mod, struct fsp_msg *msg)
 
410
{
 
411
        struct fsp_msg *resp;
 
412
 
 
413
        /* Associate response */
 
414
        if ((cmd_sub_mod >> 8) == 0xe08a) {
 
415
                prlog(PR_TRACE, "FSPCON: Got associate response, status"
 
416
                      " 0x%02x\n", cmd_sub_mod & 0xff);
 
417
                return true;
 
418
        }
 
419
        if ((cmd_sub_mod >> 8) == 0xe08b) {
 
420
                prlog(PR_TRACE, "Got unassociate response, status 0x%02x\n",
 
421
                      cmd_sub_mod & 0xff);
 
422
                return true;
 
423
        }
 
424
        switch(cmd_sub_mod) {
 
425
        case FSP_CMD_OPEN_VSERIAL:
 
426
                fsp_open_vserial(msg);
 
427
                return true;
 
428
        case FSP_CMD_CLOSE_VSERIAL:
 
429
                fsp_close_vserial(msg);
 
430
                return true;
 
431
        case FSP_CMD_HMC_INTF_QUERY:
 
432
                prlog(PR_DEBUG, "FSPCON: Got HMC interface query\n");
 
433
                got_intf_query = true;
 
434
                resp = fsp_mkmsg(FSP_RSP_HMC_INTF_QUERY, 1,
 
435
                                msg->data.words[0] & 0x00ffffff);
 
436
                if (!resp) {
 
437
                        prerror("FSPCON: Failed to allocate hmc intf response\n");
 
438
                        return true;
 
439
                }
 
440
                if (fsp_queue_msg(resp, fsp_freemsg)) {
 
441
                        fsp_freemsg(resp);
 
442
                        prerror("FSPCON: Failed to queue hmc intf response\n");
 
443
                }
 
444
                return true;
 
445
        }
 
446
        return false;
 
447
}
 
448
 
 
449
static bool fsp_con_msg_vt(u32 cmd_sub_mod, struct fsp_msg *msg)
 
450
{
 
451
        u16 sess_id = msg->data.words[1] & 0xffff;
 
452
 
 
453
        if (cmd_sub_mod == FSP_CMD_VSERIAL_IN && sess_id < MAX_SERIAL) {
 
454
                struct fsp_serial *fs = &fsp_serials[sess_id];
 
455
 
 
456
                if (!fs->open)
 
457
                        return true;
 
458
 
 
459
                /* FSP is signaling some incoming data. We take the console
 
460
                 * lock to avoid racing with a simultaneous read, though we
 
461
                 * might want to consider to simplify all that locking into
 
462
                 * one single lock that covers the console and the pending
 
463
                 * events.
 
464
                 */
 
465
                lock(&fsp_con_lock);
 
466
                opal_update_pending_evt(OPAL_EVENT_CONSOLE_INPUT,
 
467
                                        OPAL_EVENT_CONSOLE_INPUT);
 
468
                unlock(&fsp_con_lock);
 
469
        }
 
470
        return true;
 
471
}
 
472
 
 
473
static bool fsp_con_msg_rr(u32 cmd_sub_mod, struct fsp_msg *msg)
 
474
{
 
475
        assert(msg == NULL);
 
476
 
 
477
        switch (cmd_sub_mod) {
 
478
        case FSP_RESET_START:
 
479
                fsp_close_consoles();
 
480
                return true;
 
481
        case FSP_RELOAD_COMPLETE:
 
482
                fsp_console_reinit();
 
483
                return true;
 
484
        }
 
485
        return false;
 
486
}
 
487
 
 
488
static struct fsp_client fsp_con_client_hmc = {
 
489
        .message = fsp_con_msg_hmc,
 
490
};
 
491
 
 
492
static struct fsp_client fsp_con_client_vt = {
 
493
        .message = fsp_con_msg_vt,
 
494
};
 
495
 
 
496
static struct fsp_client fsp_con_client_rr = {
 
497
        .message = fsp_con_msg_rr,
 
498
};
 
499
 
 
500
static void fsp_serial_add(int index, u16 rsrc_id, const char *loc_code,
 
501
                           bool log_port)
 
502
{
 
503
        struct fsp_serial *ser;
 
504
        struct fsp_msg *msg;
 
505
 
 
506
        lock(&fsp_con_lock);
 
507
        ser = &fsp_serials[index];
 
508
 
 
509
        if (ser->available) {
 
510
                unlock(&fsp_con_lock);
 
511
                return;
 
512
        }
 
513
 
 
514
        ser->rsrc_id = rsrc_id;
 
515
        memset(ser->loc_code, 0x00, LOC_CODE_SIZE);
 
516
        strncpy(ser->loc_code, loc_code, LOC_CODE_SIZE - 1);
 
517
        ser->available = true;
 
518
        ser->log_port = log_port;
 
519
        unlock(&fsp_con_lock);
 
520
 
 
521
        /* DVS doesn't have that */
 
522
        if (rsrc_id != 0xffff) {
 
523
                msg = fsp_mkmsg(FSP_CMD_ASSOC_SERIAL, 2,
 
524
                                (rsrc_id << 16) | 1, index);
 
525
                if (!msg) {
 
526
                        prerror("FSPCON: Assoc serial alloc failed\n");
 
527
                        return;
 
528
                }
 
529
                if (fsp_queue_msg(msg, fsp_freemsg)) {
 
530
                        fsp_freemsg(msg);
 
531
                        prerror("FSPCON: Assoc serial queue failed\n");
 
532
                        return;
 
533
                }
 
534
        }
 
535
}
 
536
 
 
537
void fsp_console_preinit(void)
 
538
{
 
539
        int i;
 
540
        void *base;
 
541
 
 
542
        if (!fsp_present())
 
543
                return;
 
544
 
 
545
        ser_buffer = memalign(TCE_PSIZE, SER_BUFFER_SIZE * MAX_SERIAL);
 
546
 
 
547
        /* Initialize out data structure pointers & TCE maps */
 
548
        base = ser_buffer;
 
549
        for (i = 0; i < MAX_SERIAL; i++) {
 
550
                struct fsp_serial *ser = &fsp_serials[i];
 
551
 
 
552
                ser->in_buf = base;
 
553
                ser->out_buf = base + SER_BUFFER_SIZE/2;
 
554
                base += SER_BUFFER_SIZE;
 
555
        }
 
556
        fsp_tce_map(PSI_DMA_SER0_BASE, ser_buffer,
 
557
                    4 * PSI_DMA_SER0_SIZE);
 
558
 
 
559
        /* Register for class E0 and E1 */
 
560
        fsp_register_client(&fsp_con_client_hmc, FSP_MCLASS_HMC_INTFMSG);
 
561
        fsp_register_client(&fsp_con_client_vt, FSP_MCLASS_HMC_VT);
 
562
        fsp_register_client(&fsp_con_client_rr, FSP_MCLASS_RR_EVENT);
 
563
 
 
564
        /* Add DVS ports. We currently have session 0 and 3, 0 is for
 
565
         * OS use. 3 is our debug port. We need to add those before
 
566
         * we complete the OPL or we'll potentially miss the
 
567
         * console setup on Firebird blades.
 
568
         */
 
569
        fsp_serial_add(0, 0xffff, "DVS_OS", false);
 
570
        op_display(OP_LOG, OP_MOD_FSPCON, 0x0001);
 
571
        fsp_serial_add(3, 0xffff, "DVS_FW", true);
 
572
        op_display(OP_LOG, OP_MOD_FSPCON, 0x0002);
 
573
 
 
574
}
 
575
 
 
576
static int64_t fsp_console_write(int64_t term_number, int64_t *length,
 
577
                                 const uint8_t *buffer)
 
578
{
 
579
        struct fsp_serial *fs;
 
580
        size_t written, requested;
 
581
 
 
582
        if (term_number < 0 || term_number >= MAX_SERIAL)
 
583
                return OPAL_PARAMETER;
 
584
        fs = &fsp_serials[term_number];
 
585
        if (!fs->available || fs->log_port)
 
586
                return OPAL_PARAMETER;
 
587
        lock(&fsp_con_lock);
 
588
        if (!fs->open) {
 
589
                unlock(&fsp_con_lock);
 
590
                return OPAL_CLOSED;
 
591
        }
 
592
        /* Clamp to a reasonable size */
 
593
        requested = *length;
 
594
        if (requested > 0x1000)
 
595
                requested = 0x1000;
 
596
        written = fsp_write_vserial(fs, buffer, requested);
 
597
 
 
598
#ifdef OPAL_DEBUG_CONSOLE_IO
 
599
        prlog(PR_TRACE, "OPAL: console write req=%ld written=%ld"
 
600
              " ni=%d no=%d\n",
 
601
              requested, written, fs->out_buf->next_in, fs->out_buf->next_out);
 
602
        prlog(PR_TRACE, "      %02x %02x %02x %02x "
 
603
              "%02x \'%c\' %02x \'%c\' %02x \'%c\'.%02x \'%c\'..\n",
 
604
              buffer[0], buffer[1], buffer[2], buffer[3],
 
605
              buffer[4], buffer[4], buffer[5], buffer[5],
 
606
              buffer[6], buffer[6], buffer[7], buffer[7]);
 
607
#endif /* OPAL_DEBUG_CONSOLE_IO */
 
608
 
 
609
        *length = written;
 
610
        unlock(&fsp_con_lock);
 
611
 
 
612
        return written ? OPAL_SUCCESS : OPAL_BUSY_EVENT;
 
613
}
 
614
 
 
615
static int64_t fsp_console_write_buffer_space(int64_t term_number,
 
616
                                              int64_t *length)
 
617
{
 
618
        struct fsp_serial *fs;
 
619
        struct fsp_serbuf_hdr *sb;
 
620
 
 
621
        if (term_number < 0 || term_number >= MAX_SERIAL)
 
622
                return OPAL_PARAMETER;
 
623
        fs = &fsp_serials[term_number];
 
624
        if (!fs->available || fs->log_port)
 
625
                return OPAL_PARAMETER;
 
626
        lock(&fsp_con_lock);
 
627
        if (!fs->open) {
 
628
                unlock(&fsp_con_lock);
 
629
                return OPAL_CLOSED;
 
630
        }
 
631
        sb = fs->out_buf;
 
632
        *length = (sb->next_out + SER_BUF_DATA_SIZE - sb->next_in - 1)
 
633
                % SER_BUF_DATA_SIZE;
 
634
        unlock(&fsp_con_lock);
 
635
 
 
636
        return OPAL_SUCCESS;
 
637
}
 
638
 
 
639
static int64_t fsp_console_read(int64_t term_number, int64_t *length,
 
640
                                uint8_t *buffer __unused)
 
641
{
 
642
        struct fsp_serial *fs;
 
643
        struct fsp_serbuf_hdr *sb;
 
644
        bool pending = false;
 
645
        uint32_t old_nin, n, i, chunk, req = *length;
 
646
 
 
647
        if (term_number < 0 || term_number >= MAX_SERIAL)
 
648
                return OPAL_PARAMETER;
 
649
        fs = &fsp_serials[term_number];
 
650
        if (!fs->available || fs->log_port)
 
651
                return OPAL_PARAMETER;
 
652
        lock(&fsp_con_lock);
 
653
        if (!fs->open) {
 
654
                unlock(&fsp_con_lock);
 
655
                return OPAL_CLOSED;
 
656
        }
 
657
        if (fs->waiting)
 
658
                fs->waiting = 0;
 
659
        sb = fs->in_buf;
 
660
        old_nin = sb->next_in;
 
661
        lwsync();
 
662
        n = (old_nin + SER_BUF_DATA_SIZE - sb->next_out)
 
663
                % SER_BUF_DATA_SIZE;
 
664
        if (n > req) {
 
665
                pending = true;
 
666
                n = req;
 
667
        }
 
668
        *length = n;
 
669
 
 
670
        chunk = SER_BUF_DATA_SIZE - sb->next_out;
 
671
        if (chunk > n)
 
672
                chunk = n;
 
673
        memcpy(buffer, &sb->data[sb->next_out], chunk);
 
674
        if (chunk < n)
 
675
                memcpy(buffer + chunk, &sb->data[0], n - chunk);
 
676
        sb->next_out = (sb->next_out + n) % SER_BUF_DATA_SIZE;
 
677
 
 
678
#ifdef OPAL_DEBUG_CONSOLE_IO
 
679
        prlog(PR_TRACE, "OPAL: console read req=%d read=%d ni=%d no=%d\n",
 
680
              req, n, sb->next_in, sb->next_out);
 
681
        prlog(PR_TRACE, "      %02x %02x %02x %02x %02x %02x %02x %02x ...\n",
 
682
               buffer[0], buffer[1], buffer[2], buffer[3],
 
683
               buffer[4], buffer[5], buffer[6], buffer[7]);
 
684
#endif /* OPAL_DEBUG_CONSOLE_IO */
 
685
 
 
686
        /* Might clear the input pending flag */
 
687
        for (i = 0; i < MAX_SERIAL && !pending; i++) {
 
688
                struct fsp_serial *fs = &fsp_serials[i];
 
689
                struct fsp_serbuf_hdr *sb = fs->in_buf;
 
690
 
 
691
                if (fs->log_port || !fs->open)
 
692
                        continue;
 
693
                if (sb->next_out != sb->next_in) {
 
694
                        /*
 
695
                         * HACK: Some kernels (4.1+) may fail to properly
 
696
                         * register hvc1 and will never read it. This can lead
 
697
                         * to RCU stalls, so if we notice this console is not
 
698
                         * being read, do not set OPAL_EVENT_CONSOLE_INPUT even
 
699
                         * if it has data
 
700
                         */
 
701
                        if (fs->waiting < 5) {
 
702
                                pending = true;
 
703
                                fs->waiting++;
 
704
                        }
 
705
                }
 
706
        }
 
707
        if (!pending)
 
708
                opal_update_pending_evt(OPAL_EVENT_CONSOLE_INPUT, 0);
 
709
 
 
710
        unlock(&fsp_con_lock);
 
711
 
 
712
        return OPAL_SUCCESS;
 
713
}
 
714
 
 
715
void fsp_console_poll(void *data __unused)
 
716
{
 
717
#ifdef OPAL_DEBUG_CONSOLE_POLL
 
718
        static int debug;
 
719
#endif
 
720
 
 
721
        /*
 
722
         * We don't get messages for out buffer being consumed, so we
 
723
         * need to poll. We also defer sending of poke messages from
 
724
         * the sapphire console to avoid a locking nightmare with
 
725
         * beging called from printf() deep into an existing lock nest
 
726
         * stack.
 
727
         */
 
728
        if (fsp_con_full ||
 
729
            (opal_pending_events & OPAL_EVENT_CONSOLE_OUTPUT)) {
 
730
                unsigned int i;
 
731
                bool pending = false;
 
732
 
 
733
                /* We take the console lock. This is somewhat inefficient
 
734
                 * but it guarantees we aren't racing with a write, and
 
735
                 * thus clearing an event improperly
 
736
                 */
 
737
                lock(&fsp_con_lock);
 
738
                for (i = 0; i < MAX_SERIAL && !pending; i++) {
 
739
                        struct fsp_serial *fs = &fsp_serials[i];
 
740
                        struct fsp_serbuf_hdr *sb = fs->out_buf;
 
741
 
 
742
                        if (!fs->open)
 
743
                                continue;
 
744
                        if (sb->next_out == sb->next_in)
 
745
                                continue;
 
746
                        if (fs->log_port)
 
747
                                __flush_console(true);
 
748
                        else {
 
749
#ifdef OPAL_DEBUG_CONSOLE_POLL
 
750
                                if (debug < 5) {
 
751
                                        prlog(PR_DEBUG,"OPAL: %d still pending"
 
752
                                              " ni=%d no=%d\n",
 
753
                                              i, sb->next_in, sb->next_out);
 
754
                                        debug++;
 
755
                                }
 
756
#endif /* OPAL_DEBUG_CONSOLE_POLL */
 
757
                                pending = true;
 
758
                        }
 
759
                }
 
760
                if (!pending) {
 
761
                        opal_update_pending_evt(OPAL_EVENT_CONSOLE_OUTPUT, 0);
 
762
#ifdef OPAL_DEBUG_CONSOLE_POLL
 
763
                        debug = 0;
 
764
#endif
 
765
                }
 
766
                unlock(&fsp_con_lock);
 
767
        }
 
768
}
 
769
 
 
770
void fsp_console_init(void)
 
771
{
 
772
        struct dt_node *serials, *ser;
 
773
        int i;
 
774
 
 
775
        if (!fsp_present())
 
776
                return;
 
777
 
 
778
        opal_register(OPAL_CONSOLE_READ, fsp_console_read, 3);
 
779
        opal_register(OPAL_CONSOLE_WRITE_BUFFER_SPACE,
 
780
                      fsp_console_write_buffer_space, 2);
 
781
        opal_register(OPAL_CONSOLE_WRITE, fsp_console_write, 3);
 
782
 
 
783
        /* Wait until we got the intf query before moving on */
 
784
        while (!got_intf_query)
 
785
                opal_run_pollers();
 
786
 
 
787
        op_display(OP_LOG, OP_MOD_FSPCON, 0x0000);
 
788
 
 
789
        /* Register poller */
 
790
        opal_add_poller(fsp_console_poll, NULL);
 
791
 
 
792
        /* Parse serial port data */
 
793
        serials = dt_find_by_path(dt_root, "ipl-params/fsp-serial");
 
794
        if (!serials) {
 
795
                prerror("FSPCON: No FSP serial ports in device-tree\n");
 
796
                return;
 
797
        }
 
798
 
 
799
        i = 1;
 
800
        dt_for_each_child(serials, ser) {
 
801
                u32 rsrc_id = dt_prop_get_u32(ser, "reg");
 
802
                const void *lc = dt_prop_get(ser, "ibm,loc-code");
 
803
 
 
804
                prlog(PR_NOTICE, "FSPCON: Serial %d rsrc: %04x loc: %s\n",
 
805
                      i, rsrc_id, (const char *)lc);
 
806
                fsp_serial_add(i++, rsrc_id, lc, false);
 
807
                op_display(OP_LOG, OP_MOD_FSPCON, 0x0010 + i);
 
808
        }
 
809
 
 
810
        op_display(OP_LOG, OP_MOD_FSPCON, 0x0005);
 
811
}
 
812
 
 
813
static void flush_all_input(void)
 
814
{
 
815
        unsigned int i;
 
816
 
 
817
        lock(&fsp_con_lock);
 
818
        for (i = 0; i < MAX_SERIAL; i++) {
 
819
                struct fsp_serial *fs = &fsp_serials[i];
 
820
                struct fsp_serbuf_hdr *sb = fs->in_buf;
 
821
 
 
822
                if (fs->log_port)
 
823
                        continue;
 
824
 
 
825
                sb->next_out = sb->next_in;
 
826
        }
 
827
        unlock(&fsp_con_lock);
 
828
}
 
829
                
 
830
static bool send_all_hvsi_close(void)
 
831
{
 
832
        unsigned int i;
 
833
        bool has_hvsi = false;
 
834
        static const uint8_t close_packet[] = { 0xfe, 6, 0, 1, 0, 3 };
 
835
 
 
836
        for (i = 0; i < MAX_SERIAL; i++) {
 
837
                struct fsp_serial *fs = &fsp_serials[i];
 
838
                struct fsp_serbuf_hdr *sb = fs->out_buf;
 
839
                unsigned int space, timeout = 10;
 
840
 
 
841
                if (fs->log_port)
 
842
                        continue;
 
843
                if (fs->rsrc_id == 0xffff)
 
844
                        continue;
 
845
                has_hvsi = true;
 
846
 
 
847
                /* Do we have room ? Wait a bit if not */
 
848
                while(timeout--) {
 
849
                        space = (sb->next_out + SER_BUF_DATA_SIZE -
 
850
                                 sb->next_in - 1) % SER_BUF_DATA_SIZE;
 
851
                        if (space >= 6)
 
852
                                break;
 
853
                        time_wait_ms(500);
 
854
                }
 
855
                lock(&fsp_con_lock);
 
856
                fsp_write_vserial(fs, close_packet, 6);
 
857
                unlock(&fsp_con_lock);
 
858
        }
 
859
 
 
860
        return has_hvsi;
 
861
}
 
862
 
 
863
static void reopen_all_hvsi(void)
 
864
{
 
865
        unsigned int i;
 
866
 
 
867
        for (i = 0; i < MAX_SERIAL; i++) {
 
868
                struct fsp_serial *fs = &fsp_serials[i];
 
869
                if (fs->rsrc_id == 0xffff)
 
870
                        continue;
 
871
                prlog(PR_NOTICE, "FSP: Deassociating HVSI console %d\n", i);
 
872
                fsp_sync_msg(fsp_mkmsg(FSP_CMD_UNASSOC_SERIAL, 1,
 
873
                                       (i << 16) | 1), true);
 
874
        }
 
875
        for (i = 0; i < MAX_SERIAL; i++) {
 
876
                struct fsp_serial *fs = &fsp_serials[i];
 
877
                if (fs->rsrc_id == 0xffff)
 
878
                        continue;
 
879
                prlog(PR_NOTICE, "FSP: Reassociating HVSI console %d\n", i);
 
880
                fsp_sync_msg(fsp_mkmsg(FSP_CMD_ASSOC_SERIAL, 2,
 
881
                                       (fs->rsrc_id << 16) | 1, i), true);
 
882
        }
 
883
}
 
884
 
 
885
void fsp_console_reset(void)
 
886
{
 
887
        prlog(PR_NOTICE, "FSP: Console reset !\n");
 
888
 
 
889
        /* This is called on a fast-reset. To work around issues with HVSI
 
890
         * initial negotiation, before we reboot the kernel, we flush all
 
891
         * input and send an HVSI close packet.
 
892
         */
 
893
        flush_all_input();
 
894
 
 
895
        /* Returns false if there is no HVSI console */
 
896
        if (!send_all_hvsi_close())
 
897
                return;
 
898
 
 
899
        time_wait_ms(500);
 
900
        
 
901
        flush_all_input();
 
902
 
 
903
        reopen_all_hvsi();
 
904
 
 
905
}
 
906
 
 
907
void fsp_console_add_nodes(void)
 
908
{
 
909
        unsigned int i;
 
910
        struct dt_node *consoles;
 
911
 
 
912
        consoles = dt_new(opal_node, "consoles");
 
913
        dt_add_property_cells(consoles, "#address-cells", 1);
 
914
        dt_add_property_cells(consoles, "#size-cells", 0);
 
915
        for (i = 0; i < MAX_SERIAL; i++) {
 
916
                struct fsp_serial *fs = &fsp_serials[i];
 
917
                struct dt_node *fs_node;
 
918
                char name[32];
 
919
 
 
920
                if (fs->log_port || !fs->available)
 
921
                        continue;
 
922
 
 
923
                snprintf(name, sizeof(name), "serial@%d", i);
 
924
                fs_node = dt_new(consoles, name);
 
925
                if (fs->rsrc_id == 0xffff)
 
926
                        dt_add_property_string(fs_node, "compatible",
 
927
                                               "ibm,opal-console-raw");
 
928
                else
 
929
                        dt_add_property_string(fs_node, "compatible",
 
930
                                               "ibm,opal-console-hvsi");
 
931
                dt_add_property_cells(fs_node,
 
932
                                     "#write-buffer-size", SER_BUF_DATA_SIZE);
 
933
                dt_add_property_cells(fs_node, "reg", i);
 
934
                dt_add_property_string(fs_node, "device_type", "serial");
 
935
        }
 
936
}
 
937
 
 
938
void fsp_console_select_stdout(void)
 
939
{
 
940
        bool use_serial = false;
 
941
 
 
942
        if (!fsp_present())
 
943
                return;
 
944
 
 
945
        /* On P8, we have a sysparam ! yay ! */
 
946
        if (proc_gen >= proc_gen_p8) {
 
947
                int rc;
 
948
                u8 param;
 
949
 
 
950
                rc = fsp_get_sys_param(SYS_PARAM_CONSOLE_SELECT,
 
951
                                       &param, 1, NULL, NULL);
 
952
                if (rc != 1)
 
953
                        prerror("FSPCON: Failed to get console"
 
954
                                " sysparam rc %d\n", rc);
 
955
                else {
 
956
                        switch(param) {
 
957
                        case 0:
 
958
                                use_serial = false;
 
959
                                break;
 
960
                        case 1:
 
961
                                use_serial = true;
 
962
                                break;
 
963
                        default:
 
964
                                prerror("FSPCON: Unknown console"
 
965
                                        " sysparam %d\n", param);
 
966
                        }
 
967
                }
 
968
        } else {
 
969
                struct dt_node *iplp;
 
970
                u32 ipl_mode = 0;
 
971
 
 
972
                /*
 
973
                 * We hijack the "os-ipl-mode" setting in iplparams to select
 
974
                 * out output console. This is the "i5/OS partition mode boot"
 
975
                 * setting in ASMI converted to an integer: 0=A, 1=B.
 
976
                 */
 
977
                iplp = dt_find_by_path(dt_root, "ipl-params/ipl-params");
 
978
                if (iplp) {
 
979
                        ipl_mode = dt_prop_get_u32_def(iplp, "os-ipl-mode", 0);
 
980
                        use_serial = ipl_mode > 0;
 
981
 
 
982
                        /*
 
983
                         * Now, if ipl_mode is > 0, we use serial port A else
 
984
                         * we use IPMI/SOL/DVS
 
985
                         */
 
986
                }
 
987
        }
 
988
        if (fsp_serials[1].open && use_serial) {
 
989
                dt_add_property_string(dt_chosen, "linux,stdout-path",
 
990
                                       "/ibm,opal/consoles/serial@1");
 
991
                prlog(PR_NOTICE, "FSPCON: default console set to serial A\n");
 
992
        } else {
 
993
                dt_add_property_string(dt_chosen, "linux,stdout-path",
 
994
                                       "/ibm,opal/consoles/serial@0");
 
995
                prlog(PR_NOTICE, "FSPCON: default console set to SOL/DVS\n");
 
996
        }
 
997
}
 
998