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