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