qemu

Форк
0
/
pcie_aer.c 
957 строк · 29.4 Кб
1
/*
2
 * pcie_aer.c
3
 *
4
 * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
5
 *                    VA Linux Systems Japan K.K.
6
 *
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License along
18
 * with this program; if not, see <http://www.gnu.org/licenses/>.
19
 */
20

21
#include "qemu/osdep.h"
22
#include "migration/vmstate.h"
23
#include "hw/pci/pci_bridge.h"
24
#include "hw/pci/pcie.h"
25
#include "hw/pci/msix.h"
26
#include "hw/pci/msi.h"
27
#include "hw/pci/pci_bus.h"
28
#include "hw/pci/pcie_regs.h"
29
#include "pci-internal.h"
30

31
//#define DEBUG_PCIE
32
#ifdef DEBUG_PCIE
33
# define PCIE_DPRINTF(fmt, ...)                                         \
34
    fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
35
#else
36
# define PCIE_DPRINTF(fmt, ...) do {} while (0)
37
#endif
38
#define PCIE_DEV_PRINTF(dev, fmt, ...)                                  \
39
    PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
40

41
#define PCI_ERR_SRC_COR_OFFS    0
42
#define PCI_ERR_SRC_UNCOR_OFFS  2
43

44
/* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */
45
static uint32_t pcie_aer_uncor_default_severity(uint32_t status)
46
{
47
    switch (status) {
48
    case PCI_ERR_UNC_INTN:
49
    case PCI_ERR_UNC_DLP:
50
    case PCI_ERR_UNC_SDN:
51
    case PCI_ERR_UNC_RX_OVER:
52
    case PCI_ERR_UNC_FCP:
53
    case PCI_ERR_UNC_MALF_TLP:
54
        return PCI_ERR_ROOT_CMD_FATAL_EN;
55
    case PCI_ERR_UNC_POISON_TLP:
56
    case PCI_ERR_UNC_ECRC:
57
    case PCI_ERR_UNC_UNSUP:
58
    case PCI_ERR_UNC_COMP_TIME:
59
    case PCI_ERR_UNC_COMP_ABORT:
60
    case PCI_ERR_UNC_UNX_COMP:
61
    case PCI_ERR_UNC_ACSV:
62
    case PCI_ERR_UNC_MCBTLP:
63
    case PCI_ERR_UNC_ATOP_EBLOCKED:
64
    case PCI_ERR_UNC_TLP_PRF_BLOCKED:
65
        return PCI_ERR_ROOT_CMD_NONFATAL_EN;
66
    default:
67
        abort();
68
        break;
69
    }
70
    return PCI_ERR_ROOT_CMD_FATAL_EN;
71
}
72

73
static int aer_log_add_err(PCIEAERLog *aer_log, const PCIEAERErr *err)
74
{
75
    if (aer_log->log_num == aer_log->log_max) {
76
        return -1;
77
    }
78
    memcpy(&aer_log->log[aer_log->log_num], err, sizeof *err);
79
    aer_log->log_num++;
80
    return 0;
81
}
82

83
static void aer_log_del_err(PCIEAERLog *aer_log, PCIEAERErr *err)
84
{
85
    assert(aer_log->log_num);
86
    *err = aer_log->log[0];
87
    aer_log->log_num--;
88
    memmove(&aer_log->log[0], &aer_log->log[1],
89
            aer_log->log_num * sizeof *err);
90
}
91

92
static void aer_log_clear_all_err(PCIEAERLog *aer_log)
93
{
94
    aer_log->log_num = 0;
95
}
96

97
int pcie_aer_init(PCIDevice *dev, uint8_t cap_ver, uint16_t offset,
98
                  uint16_t size, Error **errp)
99
{
100
    pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, cap_ver,
101
                        offset, size);
102
    dev->exp.aer_cap = offset;
103

104
    /* clip down the value to avoid unreasonable memory usage */
105
    if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) {
106
        error_setg(errp, "Invalid aer_log_max %d. The max number of aer log "
107
                "is %d", dev->exp.aer_log.log_max, PCIE_AER_LOG_MAX_LIMIT);
108
        return -EINVAL;
109
    }
110
    dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] *
111
                                        dev->exp.aer_log.log_max);
112

113
    pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
114
                 PCI_ERR_UNC_SUPPORTED);
115

116
    if (dev->cap_present & QEMU_PCIE_ERR_UNC_MASK) {
117
        pci_set_long(dev->config + offset + PCI_ERR_UNCOR_MASK,
118
                     PCI_ERR_UNC_MASK_DEFAULT);
119
        pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_MASK,
120
                     PCI_ERR_UNC_SUPPORTED);
121
    }
122

123
    pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER,
124
                 PCI_ERR_UNC_SEVERITY_DEFAULT);
125
    pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER,
126
                 PCI_ERR_UNC_SUPPORTED);
127

128
    pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS,
129
                               PCI_ERR_COR_SUPPORTED);
130

131
    pci_set_long(dev->config + offset + PCI_ERR_COR_MASK,
132
                 PCI_ERR_COR_MASK_DEFAULT);
133
    pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK,
134
                 PCI_ERR_COR_SUPPORTED);
135

136
    /* capabilities and control. multiple header logging is supported */
137
    if (dev->exp.aer_log.log_max > 0) {
138
        pci_set_long(dev->config + offset + PCI_ERR_CAP,
139
                     PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC |
140
                     PCI_ERR_CAP_MHRC);
141
        pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
142
                     PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE |
143
                     PCI_ERR_CAP_MHRE);
144
    } else {
145
        pci_set_long(dev->config + offset + PCI_ERR_CAP,
146
                     PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC);
147
        pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
148
                     PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
149
    }
150

151
    switch (pcie_cap_get_type(dev)) {
152
    case PCI_EXP_TYPE_ROOT_PORT:
153
        /* this case will be set by pcie_aer_root_init() */
154
        /* fallthrough */
155
    case PCI_EXP_TYPE_DOWNSTREAM:
156
    case PCI_EXP_TYPE_UPSTREAM:
157
        pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL,
158
                                   PCI_BRIDGE_CTL_SERR);
159
        pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS,
160
                                   PCI_SEC_STATUS_RCV_SYSTEM_ERROR);
161
        break;
162
    default:
163
        /* nothing */
164
        break;
165
    }
166
    return 0;
167
}
168

169
void pcie_aer_exit(PCIDevice *dev)
170
{
171
    g_free(dev->exp.aer_log.log);
172
}
173

174
static void pcie_aer_update_uncor_status(PCIDevice *dev)
175
{
176
    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
177
    PCIEAERLog *aer_log = &dev->exp.aer_log;
178

179
    uint16_t i;
180
    for (i = 0; i < aer_log->log_num; i++) {
181
        pci_long_test_and_set_mask(aer_cap + PCI_ERR_UNCOR_STATUS,
182
                                   dev->exp.aer_log.log[i].status);
183
    }
184
}
185

186
/*
187
 * return value:
188
 * true: error message needs to be sent up
189
 * false: error message is masked
190
 *
191
 * 6.2.6 Error Message Control
192
 * Figure 6-3
193
 * all pci express devices part
194
 */
195
static bool
196
pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg)
197
{
198
    uint16_t devctl = pci_get_word(dev->config + dev->exp.exp_cap +
199
                                   PCI_EXP_DEVCTL);
200
    if (!(pcie_aer_msg_is_uncor(msg) &&
201
          (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR)) &&
202
        !((msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN) &&
203
          (devctl & PCI_EXP_DEVCTL_NFERE)) &&
204
        !((msg->severity == PCI_ERR_ROOT_CMD_COR_EN) &&
205
          (devctl & PCI_EXP_DEVCTL_CERE)) &&
206
        !((msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN) &&
207
          (devctl & PCI_EXP_DEVCTL_FERE))) {
208
        return false;
209
    }
210

211
    /* Signaled System Error
212
     *
213
     * 7.5.1.1 Command register
214
     * Bit 8 SERR# Enable
215
     *
216
     * When Set, this bit enables reporting of Non-fatal and Fatal
217
     * errors detected by the Function to the Root Complex. Note that
218
     * errors are reported if enabled either through this bit or through
219
     * the PCI Express specific bits in the Device Control register (see
220
     * Section 7.8.4).
221
     */
222
    pci_word_test_and_set_mask(dev->config + PCI_STATUS,
223
                               PCI_STATUS_SIG_SYSTEM_ERROR);
224

225
    if (!(msg->severity &
226
          pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL))) {
227
        return false;
228
    }
229

230
    /* send up error message */
231
    return true;
232
}
233

234
/*
235
 * return value:
236
 * true: error message is sent up
237
 * false: error message is masked
238
 *
239
 * 6.2.6 Error Message Control
240
 * Figure 6-3
241
 * virtual pci bridge part
242
 */
243
static bool pcie_aer_msg_vbridge(PCIDevice *dev, const PCIEAERMsg *msg)
244
{
245
    uint16_t bridge_control = pci_get_word(dev->config + PCI_BRIDGE_CONTROL);
246

247
    if (pcie_aer_msg_is_uncor(msg)) {
248
        /* Received System Error */
249
        pci_word_test_and_set_mask(dev->config + PCI_SEC_STATUS,
250
                                   PCI_SEC_STATUS_RCV_SYSTEM_ERROR);
251
    }
252

253
    if (!(bridge_control & PCI_BRIDGE_CTL_SERR)) {
254
        return false;
255
    }
256
    return true;
257
}
258

259
void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector)
260
{
261
    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
262
    assert(vector < PCI_ERR_ROOT_IRQ_MAX);
263
    pci_long_test_and_clear_mask(aer_cap + PCI_ERR_ROOT_STATUS,
264
                                 PCI_ERR_ROOT_IRQ);
265
    pci_long_test_and_set_mask(aer_cap + PCI_ERR_ROOT_STATUS,
266
                               vector << PCI_ERR_ROOT_IRQ_SHIFT);
267
}
268

269
static unsigned int pcie_aer_root_get_vector(PCIDevice *dev)
270
{
271
    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
272
    uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
273
    return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT;
274
}
275

276
/* Given a status register, get corresponding bits in the command register */
277
static uint32_t pcie_aer_status_to_cmd(uint32_t status)
278
{
279
    uint32_t cmd = 0;
280
    if (status & PCI_ERR_ROOT_COR_RCV) {
281
        cmd |= PCI_ERR_ROOT_CMD_COR_EN;
282
    }
283
    if (status & PCI_ERR_ROOT_NONFATAL_RCV) {
284
        cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN;
285
    }
286
    if (status & PCI_ERR_ROOT_FATAL_RCV) {
287
        cmd |= PCI_ERR_ROOT_CMD_FATAL_EN;
288
    }
289
    return cmd;
290
}
291

292
static void pcie_aer_root_notify(PCIDevice *dev)
293
{
294
    if (msix_enabled(dev)) {
295
        msix_notify(dev, pcie_aer_root_get_vector(dev));
296
    } else if (msi_enabled(dev)) {
297
        msi_notify(dev, pcie_aer_root_get_vector(dev));
298
    } else if (pci_intx(dev) != -1) {
299
        pci_irq_assert(dev);
300
    }
301
}
302

303
/*
304
 * 6.2.6 Error Message Control
305
 * Figure 6-3
306
 * root port part
307
 */
308
static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
309
{
310
    uint16_t cmd;
311
    uint8_t *aer_cap;
312
    uint32_t root_cmd;
313
    uint32_t root_status, prev_status;
314

315
    cmd = pci_get_word(dev->config + PCI_COMMAND);
316
    aer_cap = dev->config + dev->exp.aer_cap;
317
    root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
318
    prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
319

320
    if (cmd & PCI_COMMAND_SERR) {
321
        /* System Error.
322
         *
323
         * The way to report System Error is platform specific and
324
         * it isn't implemented in qemu right now.
325
         * So just discard the error for now.
326
         * OS which cares of aer would receive errors via
327
         * native aer mechanisms, so this wouldn't matter.
328
         */
329
    }
330

331
    /* Error Message Received: Root Error Status register */
332
    switch (msg->severity) {
333
    case PCI_ERR_ROOT_CMD_COR_EN:
334
        if (root_status & PCI_ERR_ROOT_COR_RCV) {
335
            root_status |= PCI_ERR_ROOT_MULTI_COR_RCV;
336
        } else {
337
            pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + PCI_ERR_SRC_COR_OFFS,
338
                         msg->source_id);
339
        }
340
        root_status |= PCI_ERR_ROOT_COR_RCV;
341
        break;
342
    case PCI_ERR_ROOT_CMD_NONFATAL_EN:
343
        root_status |= PCI_ERR_ROOT_NONFATAL_RCV;
344
        break;
345
    case PCI_ERR_ROOT_CMD_FATAL_EN:
346
        if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) {
347
            root_status |= PCI_ERR_ROOT_FIRST_FATAL;
348
        }
349
        root_status |= PCI_ERR_ROOT_FATAL_RCV;
350
        break;
351
    default:
352
        abort();
353
        break;
354
    }
355
    if (pcie_aer_msg_is_uncor(msg)) {
356
        if (root_status & PCI_ERR_ROOT_UNCOR_RCV) {
357
            root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV;
358
        } else {
359
            pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC +
360
                         PCI_ERR_SRC_UNCOR_OFFS, msg->source_id);
361
        }
362
        root_status |= PCI_ERR_ROOT_UNCOR_RCV;
363
    }
364
    pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status);
365

366
    /* 6.2.4.1.2 Interrupt Generation */
367
    /* All the above did was set some bits in the status register.
368
     * Specifically these that match message severity.
369
     * The below code relies on this fact. */
370
    if (!(root_cmd & msg->severity) ||
371
        (pcie_aer_status_to_cmd(prev_status) & root_cmd)) {
372
        /* Condition is not being set or was already true so nothing to do. */
373
        return;
374
    }
375

376
    pcie_aer_root_notify(dev);
377
}
378

379
/*
380
 * 6.2.6 Error Message Control Figure 6-3
381
 *
382
 * Walk up the bus tree from the device, propagate the error message.
383
 */
384
static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg)
385
{
386
    uint8_t type;
387

388
    while (dev) {
389
        if (!pci_is_express(dev)) {
390
            /* just ignore it */
391
            /* TODO: Shouldn't we set PCI_STATUS_SIG_SYSTEM_ERROR?
392
             * Consider e.g. a PCI bridge above a PCI Express device. */
393
            return;
394
        }
395

396
        type = pcie_cap_get_type(dev);
397
        if ((type == PCI_EXP_TYPE_ROOT_PORT ||
398
            type == PCI_EXP_TYPE_UPSTREAM ||
399
            type == PCI_EXP_TYPE_DOWNSTREAM) &&
400
            !pcie_aer_msg_vbridge(dev, msg)) {
401
                return;
402
        }
403
        if (!pcie_aer_msg_alldev(dev, msg)) {
404
            return;
405
        }
406
        if (type == PCI_EXP_TYPE_ROOT_PORT) {
407
            pcie_aer_msg_root_port(dev, msg);
408
            /* Root port can notify system itself,
409
               or send the error message to root complex event collector. */
410
            /*
411
             * if root port is associated with an event collector,
412
             * return the root complex event collector here.
413
             * For now root complex event collector isn't supported.
414
             */
415
            return;
416
        }
417
        dev = pci_bridge_get_device(pci_get_bus(dev));
418
    }
419
}
420

421
static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err)
422
{
423
    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
424
    uint8_t first_bit = ctz32(err->status);
425
    uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
426
    int i;
427

428
    assert(err->status);
429
    assert(!(err->status & (err->status - 1)));
430

431
    errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP);
432
    errcap |= PCI_ERR_CAP_FEP(first_bit);
433

434
    if (err->flags & PCIE_AER_ERR_HEADER_VALID) {
435
        for (i = 0; i < ARRAY_SIZE(err->header); ++i) {
436
            /* 7.10.8 Header Log Register */
437
            uint8_t *header_log =
438
                aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->header[0];
439
            stl_be_p(header_log, err->header[i]);
440
        }
441
    } else {
442
        assert(!(err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT));
443
        memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE);
444
    }
445

446
    if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) &&
447
        (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP2) &
448
         PCI_EXP_DEVCAP2_EETLPP)) {
449
        for (i = 0; i < ARRAY_SIZE(err->prefix); ++i) {
450
            /* 7.10.12 tlp prefix log register */
451
            uint8_t *prefix_log =
452
                aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->prefix[0];
453
            stl_be_p(prefix_log, err->prefix[i]);
454
        }
455
        errcap |= PCI_ERR_CAP_TLP;
456
    } else {
457
        memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0,
458
               PCI_ERR_TLP_PREFIX_LOG_SIZE);
459
    }
460
    pci_set_long(aer_cap + PCI_ERR_CAP, errcap);
461
}
462

463
static void pcie_aer_clear_log(PCIDevice *dev)
464
{
465
    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
466

467
    pci_long_test_and_clear_mask(aer_cap + PCI_ERR_CAP,
468
                                 PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP);
469

470
    memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE);
471
    memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, PCI_ERR_TLP_PREFIX_LOG_SIZE);
472
}
473

474
static void pcie_aer_clear_error(PCIDevice *dev)
475
{
476
    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
477
    uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
478
    PCIEAERLog *aer_log = &dev->exp.aer_log;
479
    PCIEAERErr err;
480

481
    if (!(errcap & PCI_ERR_CAP_MHRE) || !aer_log->log_num) {
482
        pcie_aer_clear_log(dev);
483
        return;
484
    }
485

486
    /*
487
     * If more errors are queued, set corresponding bits in uncorrectable
488
     * error status.
489
     * We emulate uncorrectable error status register as W1CS.
490
     * So set bit in uncorrectable error status here again for multiple
491
     * error recording support.
492
     *
493
     * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capability)
494
     */
495
    pcie_aer_update_uncor_status(dev);
496

497
    aer_log_del_err(aer_log, &err);
498
    pcie_aer_update_log(dev, &err);
499
}
500

501
static int pcie_aer_record_error(PCIDevice *dev,
502
                                 const PCIEAERErr *err)
503
{
504
    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
505
    uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
506
    int fep = PCI_ERR_CAP_FEP(errcap);
507

508
    assert(err->status);
509
    assert(!(err->status & (err->status - 1)));
510

511
    if (errcap & PCI_ERR_CAP_MHRE &&
512
        (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) {
513
        /*  Not first error. queue error */
514
        if (aer_log_add_err(&dev->exp.aer_log, err) < 0) {
515
            /* overflow */
516
            return -1;
517
        }
518
        return 0;
519
    }
520

521
    pcie_aer_update_log(dev, err);
522
    return 0;
523
}
524

525
typedef struct PCIEAERInject {
526
    PCIDevice *dev;
527
    uint8_t *aer_cap;
528
    const PCIEAERErr *err;
529
    uint16_t devctl;
530
    uint16_t devsta;
531
    uint32_t error_status;
532
    bool unsupported_request;
533
    bool log_overflow;
534
    PCIEAERMsg msg;
535
} PCIEAERInject;
536

537
static bool pcie_aer_inject_cor_error(PCIEAERInject *inj,
538
                                      uint32_t uncor_status,
539
                                      bool is_advisory_nonfatal)
540
{
541
    PCIDevice *dev = inj->dev;
542

543
    inj->devsta |= PCI_EXP_DEVSTA_CED;
544
    if (inj->unsupported_request) {
545
        inj->devsta |= PCI_EXP_DEVSTA_URD;
546
    }
547
    pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta);
548

549
    if (inj->aer_cap) {
550
        uint32_t mask;
551
        pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_COR_STATUS,
552
                                   inj->error_status);
553
        mask = pci_get_long(inj->aer_cap + PCI_ERR_COR_MASK);
554
        if (mask & inj->error_status) {
555
            return false;
556
        }
557
        if (is_advisory_nonfatal) {
558
            uint32_t uncor_mask =
559
                pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK);
560
            if (!(uncor_mask & uncor_status)) {
561
                inj->log_overflow = !!pcie_aer_record_error(dev, inj->err);
562
            }
563
            pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
564
                                       uncor_status);
565
        }
566
    }
567

568
    if (inj->unsupported_request && !(inj->devctl & PCI_EXP_DEVCTL_URRE)) {
569
        return false;
570
    }
571
    if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) {
572
        return false;
573
    }
574

575
    inj->msg.severity = PCI_ERR_ROOT_CMD_COR_EN;
576
    return true;
577
}
578

579
static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal)
580
{
581
    PCIDevice *dev = inj->dev;
582
    uint16_t cmd;
583

584
    if (is_fatal) {
585
        inj->devsta |= PCI_EXP_DEVSTA_FED;
586
    } else {
587
        inj->devsta |= PCI_EXP_DEVSTA_NFED;
588
    }
589
    if (inj->unsupported_request) {
590
        inj->devsta |= PCI_EXP_DEVSTA_URD;
591
    }
592
    pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta);
593

594
    if (inj->aer_cap) {
595
        uint32_t mask = pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK);
596
        if (mask & inj->error_status) {
597
            pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
598
                                       inj->error_status);
599
            return false;
600
        }
601

602
        inj->log_overflow = !!pcie_aer_record_error(dev, inj->err);
603
        pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
604
                                   inj->error_status);
605
    }
606

607
    cmd = pci_get_word(dev->config + PCI_COMMAND);
608
    if (inj->unsupported_request &&
609
        !(inj->devctl & PCI_EXP_DEVCTL_URRE) && !(cmd & PCI_COMMAND_SERR)) {
610
        return false;
611
    }
612
    if (is_fatal) {
613
        if (!((cmd & PCI_COMMAND_SERR) ||
614
              (inj->devctl & PCI_EXP_DEVCTL_FERE))) {
615
            return false;
616
        }
617
        inj->msg.severity = PCI_ERR_ROOT_CMD_FATAL_EN;
618
    } else {
619
        if (!((cmd & PCI_COMMAND_SERR) ||
620
              (inj->devctl & PCI_EXP_DEVCTL_NFERE))) {
621
            return false;
622
        }
623
        inj->msg.severity = PCI_ERR_ROOT_CMD_NONFATAL_EN;
624
    }
625
    return true;
626
}
627

628
/*
629
 * non-Function specific error must be recorded in all functions.
630
 * It is the responsibility of the caller of this function.
631
 * It is also caller's responsibility to determine which function should
632
 * report the error.
633
 *
634
 * 6.2.4 Error Logging
635
 * 6.2.5 Sequence of Device Error Signaling and Logging Operations
636
 * Figure 6-2: Flowchart Showing Sequence of Device Error Signaling and Logging
637
 *             Operations
638
 */
639
int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err)
640
{
641
    uint8_t *aer_cap = NULL;
642
    uint16_t devctl = 0;
643
    uint16_t devsta = 0;
644
    uint32_t error_status = err->status;
645
    PCIEAERInject inj;
646

647
    if (!pci_is_express(dev)) {
648
        return -ENOSYS;
649
    }
650

651
    if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) {
652
        error_status &= PCI_ERR_COR_SUPPORTED;
653
    } else {
654
        error_status &= PCI_ERR_UNC_SUPPORTED;
655
    }
656

657
    /* invalid status bit. one and only one bit must be set */
658
    if (!error_status || (error_status & (error_status - 1))) {
659
        return -EINVAL;
660
    }
661

662
    if (dev->exp.aer_cap) {
663
        uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
664
        aer_cap = dev->config + dev->exp.aer_cap;
665
        devctl = pci_get_long(exp_cap + PCI_EXP_DEVCTL);
666
        devsta = pci_get_long(exp_cap + PCI_EXP_DEVSTA);
667
    }
668

669
    inj.dev = dev;
670
    inj.aer_cap = aer_cap;
671
    inj.err = err;
672
    inj.devctl = devctl;
673
    inj.devsta = devsta;
674
    inj.error_status = error_status;
675
    inj.unsupported_request = !(err->flags & PCIE_AER_ERR_IS_CORRECTABLE) &&
676
        err->status == PCI_ERR_UNC_UNSUP;
677
    inj.log_overflow = false;
678

679
    if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) {
680
        if (!pcie_aer_inject_cor_error(&inj, 0, false)) {
681
            return 0;
682
        }
683
    } else {
684
        bool is_fatal =
685
            pcie_aer_uncor_default_severity(error_status) ==
686
            PCI_ERR_ROOT_CMD_FATAL_EN;
687
        if (aer_cap) {
688
            is_fatal =
689
                error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_SEVER);
690
        }
691
        if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY)) {
692
            inj.error_status = PCI_ERR_COR_ADV_NONFATAL;
693
            if (!pcie_aer_inject_cor_error(&inj, error_status, true)) {
694
                return 0;
695
            }
696
        } else {
697
            if (!pcie_aer_inject_uncor_error(&inj, is_fatal)) {
698
                return 0;
699
            }
700
        }
701
    }
702

703
    /* send up error message */
704
    inj.msg.source_id = err->source_id;
705
    pcie_aer_msg(dev, &inj.msg);
706

707
    if (inj.log_overflow) {
708
        PCIEAERErr header_log_overflow = {
709
            .status = PCI_ERR_COR_HL_OVERFLOW,
710
            .flags = PCIE_AER_ERR_IS_CORRECTABLE,
711
        };
712
        int ret = pcie_aer_inject_error(dev, &header_log_overflow);
713
        assert(!ret);
714
    }
715
    return 0;
716
}
717

718
void pcie_aer_write_config(PCIDevice *dev,
719
                           uint32_t addr, uint32_t val, int len)
720
{
721
    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
722
    uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
723
    uint32_t first_error = 1U << PCI_ERR_CAP_FEP(errcap);
724
    uint32_t uncorsta = pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS);
725

726
    /* uncorrectable error */
727
    if (!(uncorsta & first_error)) {
728
        /* the bit that corresponds to the first error is cleared */
729
        pcie_aer_clear_error(dev);
730
    } else if (errcap & PCI_ERR_CAP_MHRE) {
731
        /* When PCI_ERR_CAP_MHRE is enabled and the first error isn't cleared
732
         * nothing should happen. So we have to revert the modification to
733
         * the register.
734
         */
735
        pcie_aer_update_uncor_status(dev);
736
    } else {
737
        /* capability & control
738
         * PCI_ERR_CAP_MHRE might be cleared, so clear of header log.
739
         */
740
        aer_log_clear_all_err(&dev->exp.aer_log);
741
    }
742
}
743

744
void pcie_aer_root_init(PCIDevice *dev)
745
{
746
    uint16_t pos = dev->exp.aer_cap;
747

748
    pci_set_long(dev->wmask + pos + PCI_ERR_ROOT_COMMAND,
749
                 PCI_ERR_ROOT_CMD_EN_MASK);
750
    pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS,
751
                 PCI_ERR_ROOT_STATUS_REPORT_MASK);
752
    /* PCI_ERR_ROOT_IRQ is RO but devices change it using a
753
     * device-specific method.
754
     */
755
    pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS,
756
                 ~PCI_ERR_ROOT_IRQ);
757
}
758

759
void pcie_aer_root_reset(PCIDevice *dev)
760
{
761
    uint8_t* aer_cap = dev->config + dev->exp.aer_cap;
762

763
    pci_set_long(aer_cap + PCI_ERR_ROOT_COMMAND, 0);
764

765
    /*
766
     * Advanced Error Interrupt Message Number in Root Error Status Register
767
     * must be updated by chip dependent code because it's chip dependent
768
     * which number is used.
769
     */
770
}
771

772
void pcie_aer_root_write_config(PCIDevice *dev,
773
                                uint32_t addr, uint32_t val, int len,
774
                                uint32_t root_cmd_prev)
775
{
776
    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
777
    uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
778
    uint32_t enabled_cmd = pcie_aer_status_to_cmd(root_status);
779
    uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
780
    /* 6.2.4.1.2 Interrupt Generation */
781
    if (!msix_enabled(dev) && !msi_enabled(dev)) {
782
        if (pci_intx(dev) != -1) {
783
            pci_set_irq(dev, !!(root_cmd & enabled_cmd));
784
        }
785
        return;
786
    }
787

788
    if ((root_cmd_prev & enabled_cmd) || !(root_cmd & enabled_cmd)) {
789
        /* Send MSI on transition from false to true. */
790
        return;
791
    }
792

793
    pcie_aer_root_notify(dev);
794
}
795

796
static const VMStateDescription vmstate_pcie_aer_err = {
797
    .name = "PCIE_AER_ERROR",
798
    .version_id = 1,
799
    .minimum_version_id = 1,
800
    .fields = (const VMStateField[]) {
801
        VMSTATE_UINT32(status, PCIEAERErr),
802
        VMSTATE_UINT16(source_id, PCIEAERErr),
803
        VMSTATE_UINT16(flags, PCIEAERErr),
804
        VMSTATE_UINT32_ARRAY(header, PCIEAERErr, 4),
805
        VMSTATE_UINT32_ARRAY(prefix, PCIEAERErr, 4),
806
        VMSTATE_END_OF_LIST()
807
    }
808
};
809

810
static bool pcie_aer_state_log_num_valid(void *opaque, int version_id)
811
{
812
    PCIEAERLog *s = opaque;
813

814
    return s->log_num <= s->log_max;
815
}
816

817
const VMStateDescription vmstate_pcie_aer_log = {
818
    .name = "PCIE_AER_ERROR_LOG",
819
    .version_id = 1,
820
    .minimum_version_id = 1,
821
    .fields = (const VMStateField[]) {
822
        VMSTATE_UINT16(log_num, PCIEAERLog),
823
        VMSTATE_UINT16_EQUAL(log_max, PCIEAERLog, NULL),
824
        VMSTATE_VALIDATE("log_num <= log_max", pcie_aer_state_log_num_valid),
825
        VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num,
826
                              vmstate_pcie_aer_err, PCIEAERErr),
827
        VMSTATE_END_OF_LIST()
828
    }
829
};
830

831
typedef struct PCIEAERErrorName {
832
    const char *name;
833
    uint32_t val;
834
    bool correctable;
835
} PCIEAERErrorName;
836

837
/*
838
 * AER error name -> value conversion table
839
 * This naming scheme is same to linux aer-injection tool.
840
 */
841
static const struct PCIEAERErrorName pcie_aer_error_list[] = {
842
    {
843
        .name = "DLP",
844
        .val = PCI_ERR_UNC_DLP,
845
        .correctable = false,
846
    }, {
847
        .name = "SDN",
848
        .val = PCI_ERR_UNC_SDN,
849
        .correctable = false,
850
    }, {
851
        .name = "POISON_TLP",
852
        .val = PCI_ERR_UNC_POISON_TLP,
853
        .correctable = false,
854
    }, {
855
        .name = "FCP",
856
        .val = PCI_ERR_UNC_FCP,
857
        .correctable = false,
858
    }, {
859
        .name = "COMP_TIME",
860
        .val = PCI_ERR_UNC_COMP_TIME,
861
        .correctable = false,
862
    }, {
863
        .name = "COMP_ABORT",
864
        .val = PCI_ERR_UNC_COMP_ABORT,
865
        .correctable = false,
866
    }, {
867
        .name = "UNX_COMP",
868
        .val = PCI_ERR_UNC_UNX_COMP,
869
        .correctable = false,
870
    }, {
871
        .name = "RX_OVER",
872
        .val = PCI_ERR_UNC_RX_OVER,
873
        .correctable = false,
874
    }, {
875
        .name = "MALF_TLP",
876
        .val = PCI_ERR_UNC_MALF_TLP,
877
        .correctable = false,
878
    }, {
879
        .name = "ECRC",
880
        .val = PCI_ERR_UNC_ECRC,
881
        .correctable = false,
882
    }, {
883
        .name = "UNSUP",
884
        .val = PCI_ERR_UNC_UNSUP,
885
        .correctable = false,
886
    }, {
887
        .name = "ACSV",
888
        .val = PCI_ERR_UNC_ACSV,
889
        .correctable = false,
890
    }, {
891
        .name = "INTN",
892
        .val = PCI_ERR_UNC_INTN,
893
        .correctable = false,
894
    }, {
895
        .name = "MCBTLP",
896
        .val = PCI_ERR_UNC_MCBTLP,
897
        .correctable = false,
898
    }, {
899
        .name = "ATOP_EBLOCKED",
900
        .val = PCI_ERR_UNC_ATOP_EBLOCKED,
901
        .correctable = false,
902
    }, {
903
        .name = "TLP_PRF_BLOCKED",
904
        .val = PCI_ERR_UNC_TLP_PRF_BLOCKED,
905
        .correctable = false,
906
    }, {
907
        .name = "RCVR",
908
        .val = PCI_ERR_COR_RCVR,
909
        .correctable = true,
910
    }, {
911
        .name = "BAD_TLP",
912
        .val = PCI_ERR_COR_BAD_TLP,
913
        .correctable = true,
914
    }, {
915
        .name = "BAD_DLLP",
916
        .val = PCI_ERR_COR_BAD_DLLP,
917
        .correctable = true,
918
    }, {
919
        .name = "REP_ROLL",
920
        .val = PCI_ERR_COR_REP_ROLL,
921
        .correctable = true,
922
    }, {
923
        .name = "REP_TIMER",
924
        .val = PCI_ERR_COR_REP_TIMER,
925
        .correctable = true,
926
    }, {
927
        .name = "ADV_NONFATAL",
928
        .val = PCI_ERR_COR_ADV_NONFATAL,
929
        .correctable = true,
930
    }, {
931
        .name = "INTERNAL",
932
        .val = PCI_ERR_COR_INTERNAL,
933
        .correctable = true,
934
    }, {
935
        .name = "HL_OVERFLOW",
936
        .val = PCI_ERR_COR_HL_OVERFLOW,
937
        .correctable = true,
938
    },
939
};
940

941
int pcie_aer_parse_error_string(const char *error_name,
942
                                uint32_t *status, bool *correctable)
943
{
944
    int i;
945

946
    for (i = 0; i < ARRAY_SIZE(pcie_aer_error_list); i++) {
947
        const  PCIEAERErrorName *e = &pcie_aer_error_list[i];
948
        if (strcmp(error_name, e->name)) {
949
            continue;
950
        }
951

952
        *status = e->val;
953
        *correctable = e->correctable;
954
        return 0;
955
    }
956
    return -EINVAL;
957
}
958

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.