aboutsummaryrefslogtreecommitdiff
path: root/include/hw/pci/pcie.h
blob: b08451d2c56908fd9c245732f54d09811a20fe9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
 * pcie.h
 *
 * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
 *                    VA Linux Systems Japan K.K.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#ifndef QEMU_PCIE_H
#define QEMU_PCIE_H

#include "hw/hw.h"
#include "hw/pci/pci_regs.h"
#include "hw/pci/pcie_regs.h"
#include "hw/pci/pcie_aer.h"
#include "hw/hotplug.h"

typedef enum {
    /* for attention and power indicator */
    PCI_EXP_HP_IND_RESERVED     = PCI_EXP_SLTCTL_IND_RESERVED,
    PCI_EXP_HP_IND_ON           = PCI_EXP_SLTCTL_IND_ON,
    PCI_EXP_HP_IND_BLINK        = PCI_EXP_SLTCTL_IND_BLINK,
    PCI_EXP_HP_IND_OFF          = PCI_EXP_SLTCTL_IND_OFF,
} PCIExpressIndicator;

typedef enum {
    /* these bits must match the bits in Slot Control/Status registers.
     * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx
     *
     * Not all the bits of slot control register match with the ones of
     * slot status. Not some bits of slot status register is used to
     * show status, not to report event occurrence.
     * So such bits must be masked out when checking the software
     * notification condition.
     */
    PCI_EXP_HP_EV_ABP           = PCI_EXP_SLTCTL_ABPE,
                                        /* attention button pressed */
    PCI_EXP_HP_EV_PDC           = PCI_EXP_SLTCTL_PDCE,
                                        /* presence detect changed */
    PCI_EXP_HP_EV_CCI           = PCI_EXP_SLTCTL_CCIE,
                                        /* command completed */

    PCI_EXP_HP_EV_SUPPORTED     = PCI_EXP_HP_EV_ABP |
                                  PCI_EXP_HP_EV_PDC |
                                  PCI_EXP_HP_EV_CCI,
                                                /* supported event mask  */

    /* events not listed aren't supported */
} PCIExpressHotPlugEvent;

struct PCIExpressDevice {
    /* Offset of express capability in config space */
    uint8_t exp_cap;

    /* SLOT */
    bool hpev_notified; /* Logical AND of conditions for hot plug event.
                         Following 6.7.3.4:
                         Software Notification of Hot-Plug Events, an interrupt
                         is sent whenever the logical and of these conditions
                         transitions from false to true. */

    /* AER */
    uint16_t aer_cap;
    PCIEAERLog aer_log;

    /* Offset of ATS capability in config space */
    uint16_t ats_cap;
};

#define COMPAT_PROP_PCP "power_controller_present"

/* PCI express capability helper functions */
int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port);
int pcie_cap_v1_init(PCIDevice *dev, uint8_t offset,
                     uint8_t type, uint8_t port);
int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset);
void pcie_cap_exit(PCIDevice *dev);
int pcie_endpoint_cap_v1_init(PCIDevice *dev, uint8_t offset);
void pcie_cap_v1_exit(PCIDevice *dev);
uint8_t pcie_cap_get_type(const PCIDevice *dev);
void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector);
uint8_t pcie_cap_flags_get_vector(PCIDevice *dev);

void pcie_cap_deverr_init(PCIDevice *dev);
void pcie_cap_deverr_reset(PCIDevice *dev);

void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot);
void pcie_cap_slot_reset(PCIDevice *dev);
void pcie_cap_slot_write_config(PCIDevice *dev,
                                uint32_t addr, uint32_t val, int len);
int pcie_cap_slot_post_load(void *opaque, int version_id);
void pcie_cap_slot_push_attention_button(PCIDevice *dev);

void pcie_cap_root_init(PCIDevice *dev);
void pcie_cap_root_reset(PCIDevice *dev);

void pcie_cap_flr_init(PCIDevice *dev);
void pcie_cap_flr_write_config(PCIDevice *dev,
                           uint32_t addr, uint32_t val, int len);

/* ARI forwarding capability and control */
void pcie_cap_arifwd_init(PCIDevice *dev);
void pcie_cap_arifwd_reset(PCIDevice *dev);
bool pcie_cap_is_arifwd_enabled(const PCIDevice *dev);

/* PCI express extended capability helper functions */
uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id);
void pcie_add_capability(PCIDevice *dev,
                         uint16_t cap_id, uint8_t cap_ver,
                         uint16_t offset, uint16_t size);

void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num);
void pcie_ats_init(PCIDevice *dev, uint16_t offset);

extern const VMStateDescription vmstate_pcie_device;

#define VMSTATE_PCIE_DEVICE(_field, _state) {                        \
    .name       = (stringify(_field)),                               \
    .size       = sizeof(PCIDevice),                                 \
    .vmsd       = &vmstate_pcie_device,                              \
    .flags      = VMS_STRUCT,                                        \
    .offset     = vmstate_offset_value(_state, _field, PCIDevice),   \
}

void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
                              Error **errp);
void pcie_cap_slot_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
                                         DeviceState *dev, Error **errp);
#endif /* QEMU_PCIE_H */