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