xref: /openbmc/qemu/hw/ppc/spapr_pci_vfio.c (revision 63785678)
1 /*
2  * QEMU sPAPR PCI host for VFIO
3  *
4  * Copyright (c) 2011-2014 Alexey Kardashevskiy, IBM Corporation.
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License,
9  *  or (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "qemu/osdep.h"
21 #include "qapi/error.h"
22 #include "qemu-common.h"
23 #include "cpu.h"
24 #include "hw/ppc/spapr.h"
25 #include "hw/pci-host/spapr.h"
26 #include "hw/pci/msix.h"
27 #include "linux/vfio.h"
28 #include "hw/vfio/vfio.h"
29 #include "qemu/error-report.h"
30 
31 #define TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE "spapr-pci-vfio-host-bridge"
32 
33 #define SPAPR_PCI_VFIO_HOST_BRIDGE(obj) \
34     OBJECT_CHECK(sPAPRPHBVFIOState, (obj), TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE)
35 
36 typedef struct sPAPRPHBVFIOState sPAPRPHBVFIOState;
37 
38 struct sPAPRPHBVFIOState {
39     sPAPRPHBState phb;
40 
41     int32_t iommugroupid;
42 };
43 
44 static Property spapr_phb_vfio_properties[] = {
45     DEFINE_PROP_INT32("iommu", sPAPRPHBVFIOState, iommugroupid, -1),
46     DEFINE_PROP_END_OF_LIST(),
47 };
48 
49 static void spapr_phb_vfio_instance_init(Object *obj)
50 {
51     error_report("spapr-pci-vfio-host-bridge is deprecated");
52 }
53 
54 bool spapr_phb_eeh_available(sPAPRPHBState *sphb)
55 {
56     return vfio_eeh_as_ok(&sphb->iommu_as);
57 }
58 
59 static void spapr_phb_vfio_eeh_reenable(sPAPRPHBState *sphb)
60 {
61     vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_ENABLE);
62 }
63 
64 void spapr_phb_vfio_reset(DeviceState *qdev)
65 {
66     /*
67      * The PE might be in frozen state. To reenable the EEH
68      * functionality on it will clean the frozen state, which
69      * ensures that the contained PCI devices will work properly
70      * after reboot.
71      */
72     spapr_phb_vfio_eeh_reenable(SPAPR_PCI_HOST_BRIDGE(qdev));
73 }
74 
75 int spapr_phb_vfio_eeh_set_option(sPAPRPHBState *sphb,
76                                   unsigned int addr, int option)
77 {
78     uint32_t op;
79     int ret;
80 
81     switch (option) {
82     case RTAS_EEH_DISABLE:
83         op = VFIO_EEH_PE_DISABLE;
84         break;
85     case RTAS_EEH_ENABLE: {
86         PCIHostState *phb;
87         PCIDevice *pdev;
88 
89         /*
90          * The EEH functionality is enabled on basis of PCI device,
91          * instead of PE. We need check the validity of the PCI
92          * device address.
93          */
94         phb = PCI_HOST_BRIDGE(sphb);
95         pdev = pci_find_device(phb->bus,
96                                (addr >> 16) & 0xFF, (addr >> 8) & 0xFF);
97         if (!pdev || !object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
98             return RTAS_OUT_PARAM_ERROR;
99         }
100 
101         op = VFIO_EEH_PE_ENABLE;
102         break;
103     }
104     case RTAS_EEH_THAW_IO:
105         op = VFIO_EEH_PE_UNFREEZE_IO;
106         break;
107     case RTAS_EEH_THAW_DMA:
108         op = VFIO_EEH_PE_UNFREEZE_DMA;
109         break;
110     default:
111         return RTAS_OUT_PARAM_ERROR;
112     }
113 
114     ret = vfio_eeh_as_op(&sphb->iommu_as, op);
115     if (ret < 0) {
116         return RTAS_OUT_HW_ERROR;
117     }
118 
119     return RTAS_OUT_SUCCESS;
120 }
121 
122 int spapr_phb_vfio_eeh_get_state(sPAPRPHBState *sphb, int *state)
123 {
124     int ret;
125 
126     ret = vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_GET_STATE);
127     if (ret < 0) {
128         return RTAS_OUT_PARAM_ERROR;
129     }
130 
131     *state = ret;
132     return RTAS_OUT_SUCCESS;
133 }
134 
135 static void spapr_phb_vfio_eeh_clear_dev_msix(PCIBus *bus,
136                                               PCIDevice *pdev,
137                                               void *opaque)
138 {
139     /* Check if the device is VFIO PCI device */
140     if (!object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
141         return;
142     }
143 
144     /*
145      * The MSIx table will be cleaned out by reset. We need
146      * disable it so that it can be reenabled properly. Also,
147      * the cached MSIx table should be cleared as it's not
148      * reflecting the contents in hardware.
149      */
150     if (msix_enabled(pdev)) {
151         uint16_t flags;
152 
153         flags = pci_host_config_read_common(pdev,
154                                             pdev->msix_cap + PCI_MSIX_FLAGS,
155                                             pci_config_size(pdev), 2);
156         flags &= ~PCI_MSIX_FLAGS_ENABLE;
157         pci_host_config_write_common(pdev,
158                                      pdev->msix_cap + PCI_MSIX_FLAGS,
159                                      pci_config_size(pdev), flags, 2);
160     }
161 
162     msix_reset(pdev);
163 }
164 
165 static void spapr_phb_vfio_eeh_clear_bus_msix(PCIBus *bus, void *opaque)
166 {
167        pci_for_each_device(bus, pci_bus_num(bus),
168                            spapr_phb_vfio_eeh_clear_dev_msix, NULL);
169 }
170 
171 static void spapr_phb_vfio_eeh_pre_reset(sPAPRPHBState *sphb)
172 {
173        PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
174 
175        pci_for_each_bus(phb->bus, spapr_phb_vfio_eeh_clear_bus_msix, NULL);
176 }
177 
178 int spapr_phb_vfio_eeh_reset(sPAPRPHBState *sphb, int option)
179 {
180     uint32_t op;
181     int ret;
182 
183     switch (option) {
184     case RTAS_SLOT_RESET_DEACTIVATE:
185         op = VFIO_EEH_PE_RESET_DEACTIVATE;
186         break;
187     case RTAS_SLOT_RESET_HOT:
188         spapr_phb_vfio_eeh_pre_reset(sphb);
189         op = VFIO_EEH_PE_RESET_HOT;
190         break;
191     case RTAS_SLOT_RESET_FUNDAMENTAL:
192         spapr_phb_vfio_eeh_pre_reset(sphb);
193         op = VFIO_EEH_PE_RESET_FUNDAMENTAL;
194         break;
195     default:
196         return RTAS_OUT_PARAM_ERROR;
197     }
198 
199     ret = vfio_eeh_as_op(&sphb->iommu_as, op);
200     if (ret < 0) {
201         return RTAS_OUT_HW_ERROR;
202     }
203 
204     return RTAS_OUT_SUCCESS;
205 }
206 
207 int spapr_phb_vfio_eeh_configure(sPAPRPHBState *sphb)
208 {
209     int ret;
210 
211     ret = vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_CONFIGURE);
212     if (ret < 0) {
213         return RTAS_OUT_PARAM_ERROR;
214     }
215 
216     return RTAS_OUT_SUCCESS;
217 }
218 
219 static void spapr_phb_vfio_class_init(ObjectClass *klass, void *data)
220 {
221     DeviceClass *dc = DEVICE_CLASS(klass);
222 
223     dc->props = spapr_phb_vfio_properties;
224 }
225 
226 static const TypeInfo spapr_phb_vfio_info = {
227     .name          = TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE,
228     .parent        = TYPE_SPAPR_PCI_HOST_BRIDGE,
229     .instance_size = sizeof(sPAPRPHBVFIOState),
230     .instance_init = spapr_phb_vfio_instance_init,
231     .class_init    = spapr_phb_vfio_class_init,
232 };
233 
234 static void spapr_pci_vfio_register_types(void)
235 {
236     type_register_static(&spapr_phb_vfio_info);
237 }
238 
239 type_init(spapr_pci_vfio_register_types)
240