qemu/hw/pci-host/pnv_phb3_msi.c
<<
>>
Prefs
   1/*
   2 * QEMU PowerPC PowerNV (POWER8) PHB3 model
   3 *
   4 * Copyright (c) 2014-2020, IBM Corporation.
   5 *
   6 * This code is licensed under the GPL version 2 or later. See the
   7 * COPYING file in the top-level directory.
   8 */
   9#include "qemu/osdep.h"
  10#include "qemu/log.h"
  11#include "qapi/error.h"
  12#include "qemu-common.h"
  13#include "hw/pci-host/pnv_phb3_regs.h"
  14#include "hw/pci-host/pnv_phb3.h"
  15#include "hw/ppc/pnv.h"
  16#include "hw/pci/msi.h"
  17#include "monitor/monitor.h"
  18#include "hw/irq.h"
  19#include "hw/qdev-properties.h"
  20#include "sysemu/reset.h"
  21
  22static uint64_t phb3_msi_ive_addr(PnvPHB3 *phb, int srcno)
  23{
  24    uint64_t ivtbar = phb->regs[PHB_IVT_BAR >> 3];
  25    uint64_t phbctl = phb->regs[PHB_CONTROL >> 3];
  26
  27    if (!(ivtbar & PHB_IVT_BAR_ENABLE)) {
  28        qemu_log_mask(LOG_GUEST_ERROR, "Failed access to disable IVT BAR !");
  29        return 0;
  30    }
  31
  32    if (srcno >= (ivtbar & PHB_IVT_LENGTH_MASK)) {
  33        qemu_log_mask(LOG_GUEST_ERROR, "MSI out of bounds (%d vs  0x%"PRIx64")",
  34                      srcno, (uint64_t) (ivtbar & PHB_IVT_LENGTH_MASK));
  35        return 0;
  36    }
  37
  38    ivtbar &= PHB_IVT_BASE_ADDRESS_MASK;
  39
  40    if (phbctl & PHB_CTRL_IVE_128_BYTES) {
  41        return ivtbar + 128 * srcno;
  42    } else {
  43        return ivtbar + 16 * srcno;
  44    }
  45}
  46
  47static bool phb3_msi_read_ive(PnvPHB3 *phb, int srcno, uint64_t *out_ive)
  48{
  49    uint64_t ive_addr, ive;
  50
  51    ive_addr = phb3_msi_ive_addr(phb, srcno);
  52    if (!ive_addr) {
  53        return false;
  54    }
  55
  56    if (dma_memory_read(&address_space_memory, ive_addr, &ive, sizeof(ive))) {
  57        qemu_log_mask(LOG_GUEST_ERROR, "Failed to read IVE at 0x%" PRIx64,
  58                      ive_addr);
  59        return false;
  60    }
  61    *out_ive = be64_to_cpu(ive);
  62
  63    return true;
  64}
  65
  66static void phb3_msi_set_p(Phb3MsiState *msi, int srcno, uint8_t gen)
  67{
  68    uint64_t ive_addr;
  69    uint8_t p = 0x01 | (gen << 1);
  70
  71    ive_addr = phb3_msi_ive_addr(msi->phb, srcno);
  72    if (!ive_addr) {
  73        return;
  74    }
  75
  76    if (dma_memory_write(&address_space_memory, ive_addr + 4, &p, 1)) {
  77        qemu_log_mask(LOG_GUEST_ERROR,
  78                      "Failed to write IVE (set P) at 0x%" PRIx64, ive_addr);
  79    }
  80}
  81
  82static void phb3_msi_set_q(Phb3MsiState *msi, int srcno)
  83{
  84    uint64_t ive_addr;
  85    uint8_t q = 0x01;
  86
  87    ive_addr = phb3_msi_ive_addr(msi->phb, srcno);
  88    if (!ive_addr) {
  89        return;
  90    }
  91
  92    if (dma_memory_write(&address_space_memory, ive_addr + 5, &q, 1)) {
  93        qemu_log_mask(LOG_GUEST_ERROR,
  94                      "Failed to write IVE (set Q) at 0x%" PRIx64, ive_addr);
  95    }
  96}
  97
  98static void phb3_msi_try_send(Phb3MsiState *msi, int srcno, bool force)
  99{
 100    ICSState *ics = ICS(msi);
 101    uint64_t ive;
 102    uint64_t server, prio, pq, gen;
 103
 104    if (!phb3_msi_read_ive(msi->phb, srcno, &ive)) {
 105        return;
 106    }
 107
 108    server = GETFIELD(IODA2_IVT_SERVER, ive);
 109    prio = GETFIELD(IODA2_IVT_PRIORITY, ive);
 110    if (!force) {
 111        pq = GETFIELD(IODA2_IVT_Q, ive) | (GETFIELD(IODA2_IVT_P, ive) << 1);
 112    } else {
 113        pq = 0;
 114    }
 115    gen = GETFIELD(IODA2_IVT_GEN, ive);
 116
 117    /*
 118     * The low order 2 bits are the link pointer (Type II interrupts).
 119     * Shift back to get a valid IRQ server.
 120     */
 121    server >>= 2;
 122
 123    switch (pq) {
 124    case 0: /* 00 */
 125        if (prio == 0xff) {
 126            /* Masked, set Q */
 127            phb3_msi_set_q(msi, srcno);
 128        } else {
 129            /* Enabled, set P and send */
 130            phb3_msi_set_p(msi, srcno, gen);
 131            icp_irq(ics, server, srcno + ics->offset, prio);
 132        }
 133        break;
 134    case 2: /* 10 */
 135        /* Already pending, set Q */
 136        phb3_msi_set_q(msi, srcno);
 137        break;
 138    case 1: /* 01 */
 139    case 3: /* 11 */
 140    default:
 141        /* Just drop stuff if Q already set */
 142        break;
 143    }
 144}
 145
 146static void phb3_msi_set_irq(void *opaque, int srcno, int val)
 147{
 148    Phb3MsiState *msi = PHB3_MSI(opaque);
 149
 150    if (val) {
 151        phb3_msi_try_send(msi, srcno, false);
 152    }
 153}
 154
 155
 156void pnv_phb3_msi_send(Phb3MsiState *msi, uint64_t addr, uint16_t data,
 157                       int32_t dev_pe)
 158{
 159    ICSState *ics = ICS(msi);
 160    uint64_t ive;
 161    uint16_t pe;
 162    uint32_t src = ((addr >> 4) & 0xffff) | (data & 0x1f);
 163
 164    if (src >= ics->nr_irqs) {
 165        qemu_log_mask(LOG_GUEST_ERROR, "MSI %d out of bounds", src);
 166        return;
 167    }
 168    if (dev_pe >= 0) {
 169        if (!phb3_msi_read_ive(msi->phb, src, &ive)) {
 170            return;
 171        }
 172        pe = GETFIELD(IODA2_IVT_PE, ive);
 173        if (pe != dev_pe) {
 174            qemu_log_mask(LOG_GUEST_ERROR,
 175                          "MSI %d send by PE#%d but assigned to PE#%d",
 176                          src, dev_pe, pe);
 177            return;
 178        }
 179    }
 180    qemu_irq_pulse(msi->qirqs[src]);
 181}
 182
 183void pnv_phb3_msi_ffi(Phb3MsiState *msi, uint64_t val)
 184{
 185    /* Emit interrupt */
 186    pnv_phb3_msi_send(msi, val, 0, -1);
 187
 188    /* Clear FFI lock */
 189    msi->phb->regs[PHB_FFI_LOCK >> 3] = 0;
 190}
 191
 192static void phb3_msi_reject(ICSState *ics, uint32_t nr)
 193{
 194    Phb3MsiState *msi = PHB3_MSI(ics);
 195    unsigned int srcno = nr - ics->offset;
 196    unsigned int idx = srcno >> 6;
 197    unsigned int bit = 1ull << (srcno & 0x3f);
 198
 199    assert(srcno < PHB3_MAX_MSI);
 200
 201    msi->rba[idx] |= bit;
 202    msi->rba_sum |= (1u << idx);
 203}
 204
 205static void phb3_msi_resend(ICSState *ics)
 206{
 207    Phb3MsiState *msi = PHB3_MSI(ics);
 208    unsigned int i, j;
 209
 210    if (msi->rba_sum == 0) {
 211        return;
 212    }
 213
 214    for (i = 0; i < 32; i++) {
 215        if ((msi->rba_sum & (1u << i)) == 0) {
 216            continue;
 217        }
 218        msi->rba_sum &= ~(1u << i);
 219        for (j = 0; j < 64; j++) {
 220            if ((msi->rba[i] & (1ull << j)) == 0) {
 221                continue;
 222            }
 223            msi->rba[i] &= ~(1ull << j);
 224            phb3_msi_try_send(msi, i * 64 + j, true);
 225        }
 226    }
 227}
 228
 229static void phb3_msi_reset(DeviceState *dev)
 230{
 231    Phb3MsiState *msi = PHB3_MSI(dev);
 232    ICSStateClass *icsc = ICS_GET_CLASS(dev);
 233
 234    icsc->parent_reset(dev);
 235
 236    memset(msi->rba, 0, sizeof(msi->rba));
 237    msi->rba_sum = 0;
 238}
 239
 240static void phb3_msi_reset_handler(void *dev)
 241{
 242    phb3_msi_reset(dev);
 243}
 244
 245void pnv_phb3_msi_update_config(Phb3MsiState *msi, uint32_t base,
 246                                uint32_t count)
 247{
 248    ICSState *ics = ICS(msi);
 249
 250    if (count > PHB3_MAX_MSI) {
 251        count = PHB3_MAX_MSI;
 252    }
 253    ics->nr_irqs = count;
 254    ics->offset = base;
 255}
 256
 257static void phb3_msi_realize(DeviceState *dev, Error **errp)
 258{
 259    Phb3MsiState *msi = PHB3_MSI(dev);
 260    ICSState *ics = ICS(msi);
 261    ICSStateClass *icsc = ICS_GET_CLASS(ics);
 262    Error *local_err = NULL;
 263
 264    assert(msi->phb);
 265
 266    icsc->parent_realize(dev, &local_err);
 267    if (local_err) {
 268        error_propagate(errp, local_err);
 269        return;
 270    }
 271
 272    msi->qirqs = qemu_allocate_irqs(phb3_msi_set_irq, msi, ics->nr_irqs);
 273
 274    qemu_register_reset(phb3_msi_reset_handler, dev);
 275}
 276
 277static void phb3_msi_instance_init(Object *obj)
 278{
 279    Phb3MsiState *msi = PHB3_MSI(obj);
 280    ICSState *ics = ICS(obj);
 281
 282    object_property_add_link(obj, "phb", TYPE_PNV_PHB3,
 283                             (Object **)&msi->phb,
 284                             object_property_allow_set_link,
 285                             OBJ_PROP_LINK_STRONG);
 286
 287    /* Will be overriden later */
 288    ics->offset = 0;
 289}
 290
 291static void phb3_msi_class_init(ObjectClass *klass, void *data)
 292{
 293    DeviceClass *dc = DEVICE_CLASS(klass);
 294    ICSStateClass *isc = ICS_CLASS(klass);
 295
 296    device_class_set_parent_realize(dc, phb3_msi_realize,
 297                                    &isc->parent_realize);
 298    device_class_set_parent_reset(dc, phb3_msi_reset,
 299                                  &isc->parent_reset);
 300
 301    isc->reject = phb3_msi_reject;
 302    isc->resend = phb3_msi_resend;
 303}
 304
 305static const TypeInfo phb3_msi_info = {
 306    .name = TYPE_PHB3_MSI,
 307    .parent = TYPE_ICS,
 308    .instance_size = sizeof(Phb3MsiState),
 309    .class_init = phb3_msi_class_init,
 310    .class_size = sizeof(ICSStateClass),
 311    .instance_init = phb3_msi_instance_init,
 312};
 313
 314static void pnv_phb3_msi_register_types(void)
 315{
 316    type_register_static(&phb3_msi_info);
 317}
 318
 319type_init(pnv_phb3_msi_register_types);
 320
 321void pnv_phb3_msi_pic_print_info(Phb3MsiState *msi, Monitor *mon)
 322{
 323    ICSState *ics = ICS(msi);
 324    int i;
 325
 326    monitor_printf(mon, "ICS %4x..%4x %p\n",
 327                   ics->offset, ics->offset + ics->nr_irqs - 1, ics);
 328
 329    for (i = 0; i < ics->nr_irqs; i++) {
 330        uint64_t ive;
 331
 332        if (!phb3_msi_read_ive(msi->phb, i, &ive)) {
 333            return;
 334        }
 335
 336        if (GETFIELD(IODA2_IVT_PRIORITY, ive) == 0xff) {
 337            continue;
 338        }
 339
 340        monitor_printf(mon, "  %4x %c%c server=%04x prio=%02x gen=%d\n",
 341                       ics->offset + i,
 342                       GETFIELD(IODA2_IVT_P, ive) ? 'P' : '-',
 343                       GETFIELD(IODA2_IVT_Q, ive) ? 'Q' : '-',
 344                       (uint32_t) GETFIELD(IODA2_IVT_SERVER, ive) >> 2,
 345                       (uint32_t) GETFIELD(IODA2_IVT_PRIORITY, ive),
 346                       (uint32_t) GETFIELD(IODA2_IVT_GEN, ive));
 347    }
 348}
 349