qemu/hw/ppc/spapr_pci_vfio.c
<<
>>
Prefs
   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 "cpu.h"
  23#include "hw/ppc/spapr.h"
  24#include "hw/pci-host/spapr.h"
  25#include "hw/pci/msix.h"
  26#include "hw/vfio/vfio.h"
  27#include "qemu/error-report.h"
  28
  29bool spapr_phb_eeh_available(SpaprPhbState *sphb)
  30{
  31    return vfio_eeh_as_ok(&sphb->iommu_as);
  32}
  33
  34static void spapr_phb_vfio_eeh_reenable(SpaprPhbState *sphb)
  35{
  36    vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_ENABLE);
  37}
  38
  39void spapr_phb_vfio_reset(DeviceState *qdev)
  40{
  41    /*
  42     * The PE might be in frozen state. To reenable the EEH
  43     * functionality on it will clean the frozen state, which
  44     * ensures that the contained PCI devices will work properly
  45     * after reboot.
  46     */
  47    spapr_phb_vfio_eeh_reenable(SPAPR_PCI_HOST_BRIDGE(qdev));
  48}
  49
  50int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb,
  51                                  unsigned int addr, int option)
  52{
  53    uint32_t op;
  54    int ret;
  55
  56    switch (option) {
  57    case RTAS_EEH_DISABLE:
  58        op = VFIO_EEH_PE_DISABLE;
  59        break;
  60    case RTAS_EEH_ENABLE: {
  61        PCIHostState *phb;
  62        PCIDevice *pdev;
  63
  64        /*
  65         * The EEH functionality is enabled on basis of PCI device,
  66         * instead of PE. We need check the validity of the PCI
  67         * device address.
  68         */
  69        phb = PCI_HOST_BRIDGE(sphb);
  70        pdev = pci_find_device(phb->bus,
  71                               (addr >> 16) & 0xFF, (addr >> 8) & 0xFF);
  72        if (!pdev || !object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
  73            return RTAS_OUT_PARAM_ERROR;
  74        }
  75
  76        op = VFIO_EEH_PE_ENABLE;
  77        break;
  78    }
  79    case RTAS_EEH_THAW_IO:
  80        op = VFIO_EEH_PE_UNFREEZE_IO;
  81        break;
  82    case RTAS_EEH_THAW_DMA:
  83        op = VFIO_EEH_PE_UNFREEZE_DMA;
  84        break;
  85    default:
  86        return RTAS_OUT_PARAM_ERROR;
  87    }
  88
  89    ret = vfio_eeh_as_op(&sphb->iommu_as, op);
  90    if (ret < 0) {
  91        return RTAS_OUT_HW_ERROR;
  92    }
  93
  94    return RTAS_OUT_SUCCESS;
  95}
  96
  97int spapr_phb_vfio_eeh_get_state(SpaprPhbState *sphb, int *state)
  98{
  99    int ret;
 100
 101    ret = vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_GET_STATE);
 102    if (ret < 0) {
 103        return RTAS_OUT_PARAM_ERROR;
 104    }
 105
 106    *state = ret;
 107    return RTAS_OUT_SUCCESS;
 108}
 109
 110static void spapr_phb_vfio_eeh_clear_dev_msix(PCIBus *bus,
 111                                              PCIDevice *pdev,
 112                                              void *opaque)
 113{
 114    /* Check if the device is VFIO PCI device */
 115    if (!object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
 116        return;
 117    }
 118
 119    /*
 120     * The MSIx table will be cleaned out by reset. We need
 121     * disable it so that it can be reenabled properly. Also,
 122     * the cached MSIx table should be cleared as it's not
 123     * reflecting the contents in hardware.
 124     */
 125    if (msix_enabled(pdev)) {
 126        uint16_t flags;
 127
 128        flags = pci_host_config_read_common(pdev,
 129                                            pdev->msix_cap + PCI_MSIX_FLAGS,
 130                                            pci_config_size(pdev), 2);
 131        flags &= ~PCI_MSIX_FLAGS_ENABLE;
 132        pci_host_config_write_common(pdev,
 133                                     pdev->msix_cap + PCI_MSIX_FLAGS,
 134                                     pci_config_size(pdev), flags, 2);
 135    }
 136
 137    msix_reset(pdev);
 138}
 139
 140static void spapr_phb_vfio_eeh_clear_bus_msix(PCIBus *bus, void *opaque)
 141{
 142       pci_for_each_device(bus, pci_bus_num(bus),
 143                           spapr_phb_vfio_eeh_clear_dev_msix, NULL);
 144}
 145
 146static void spapr_phb_vfio_eeh_pre_reset(SpaprPhbState *sphb)
 147{
 148       PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
 149
 150       pci_for_each_bus(phb->bus, spapr_phb_vfio_eeh_clear_bus_msix, NULL);
 151}
 152
 153int spapr_phb_vfio_eeh_reset(SpaprPhbState *sphb, int option)
 154{
 155    uint32_t op;
 156    int ret;
 157
 158    switch (option) {
 159    case RTAS_SLOT_RESET_DEACTIVATE:
 160        op = VFIO_EEH_PE_RESET_DEACTIVATE;
 161        break;
 162    case RTAS_SLOT_RESET_HOT:
 163        spapr_phb_vfio_eeh_pre_reset(sphb);
 164        op = VFIO_EEH_PE_RESET_HOT;
 165        break;
 166    case RTAS_SLOT_RESET_FUNDAMENTAL:
 167        spapr_phb_vfio_eeh_pre_reset(sphb);
 168        op = VFIO_EEH_PE_RESET_FUNDAMENTAL;
 169        break;
 170    default:
 171        return RTAS_OUT_PARAM_ERROR;
 172    }
 173
 174    ret = vfio_eeh_as_op(&sphb->iommu_as, op);
 175    if (ret < 0) {
 176        return RTAS_OUT_HW_ERROR;
 177    }
 178
 179    return RTAS_OUT_SUCCESS;
 180}
 181
 182int spapr_phb_vfio_eeh_configure(SpaprPhbState *sphb)
 183{
 184    int ret;
 185
 186    ret = vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_CONFIGURE);
 187    if (ret < 0) {
 188        return RTAS_OUT_PARAM_ERROR;
 189    }
 190
 191    return RTAS_OUT_SUCCESS;
 192}
 193