qemu/hw/ppc/pnv_xscom.c
<<
>>
Prefs
   1/*
   2 * QEMU PowerPC PowerNV XSCOM bus
   3 *
   4 * Copyright (c) 2016, IBM Corporation.
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2.1 of the License, or (at your option) any later version.
  10 *
  11 * This library 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 GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "qemu/log.h"
  22#include "qemu/module.h"
  23#include "sysemu/hw_accel.h"
  24#include "target/ppc/cpu.h"
  25#include "hw/sysbus.h"
  26
  27#include "hw/ppc/fdt.h"
  28#include "hw/ppc/pnv.h"
  29#include "hw/ppc/pnv_xscom.h"
  30
  31#include <libfdt.h>
  32
  33/* PRD registers */
  34#define PRD_P8_IPOLL_REG_MASK           0x01020013
  35#define PRD_P8_IPOLL_REG_STATUS         0x01020014
  36#define PRD_P9_IPOLL_REG_MASK           0x000F0033
  37#define PRD_P9_IPOLL_REG_STATUS         0x000F0034
  38
  39static void xscom_complete(CPUState *cs, uint64_t hmer_bits)
  40{
  41    /*
  42     * TODO: When the read/write comes from the monitor, NULL is
  43     * passed for the cpu, and no CPU completion is generated.
  44     */
  45    if (cs) {
  46        PowerPCCPU *cpu = POWERPC_CPU(cs);
  47        CPUPPCState *env = &cpu->env;
  48
  49        /*
  50         * TODO: Need a CPU helper to set HMER, also handle generation
  51         * of HMIs
  52         */
  53        cpu_synchronize_state(cs);
  54        env->spr[SPR_HMER] |= hmer_bits;
  55    }
  56}
  57
  58static uint32_t pnv_xscom_pcba(PnvChip *chip, uint64_t addr)
  59{
  60    return PNV_CHIP_GET_CLASS(chip)->xscom_pcba(chip, addr);
  61}
  62
  63static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba)
  64{
  65    switch (pcba) {
  66    case 0xf000f:
  67        return PNV_CHIP_GET_CLASS(chip)->chip_cfam_id;
  68    case 0x18002:       /* ECID2 */
  69        return 0;
  70
  71    case 0x1010c00:     /* PIBAM FIR */
  72    case 0x1010c03:     /* PIBAM FIR MASK */
  73
  74        /* PRD registers */
  75    case PRD_P8_IPOLL_REG_MASK:
  76    case PRD_P8_IPOLL_REG_STATUS:
  77    case PRD_P9_IPOLL_REG_MASK:
  78    case PRD_P9_IPOLL_REG_STATUS:
  79
  80        /* P9 xscom reset */
  81    case 0x0090018:     /* Receive status reg */
  82    case 0x0090012:     /* log register */
  83    case 0x0090013:     /* error register */
  84
  85        /* P8 xscom reset */
  86    case 0x2020007:     /* ADU stuff, log register */
  87    case 0x2020009:     /* ADU stuff, error register */
  88    case 0x202000f:     /* ADU stuff, receive status register*/
  89        return 0;
  90    case 0x2013f01:     /* PBA stuff */
  91    case 0x2013f05:     /* PBA stuff */
  92        return 0;
  93    case 0x2013028:     /* CAPP stuff */
  94    case 0x201302a:     /* CAPP stuff */
  95    case 0x2013801:     /* CAPP stuff */
  96    case 0x2013802:     /* CAPP stuff */
  97
  98        /* P9 CAPP regs */
  99    case 0x2010841:
 100    case 0x2010842:
 101    case 0x201082a:
 102    case 0x2010828:
 103    case 0x4010841:
 104    case 0x4010842:
 105    case 0x401082a:
 106    case 0x4010828:
 107        return 0;
 108    default:
 109        return -1;
 110    }
 111}
 112
 113static bool xscom_write_default(PnvChip *chip, uint32_t pcba, uint64_t val)
 114{
 115    /* We ignore writes to these */
 116    switch (pcba) {
 117    case 0xf000f:       /* chip id is RO */
 118    case 0x1010c00:     /* PIBAM FIR */
 119    case 0x1010c01:     /* PIBAM FIR */
 120    case 0x1010c02:     /* PIBAM FIR */
 121    case 0x1010c03:     /* PIBAM FIR MASK */
 122    case 0x1010c04:     /* PIBAM FIR MASK */
 123    case 0x1010c05:     /* PIBAM FIR MASK */
 124        /* P9 xscom reset */
 125    case 0x0090018:     /* Receive status reg */
 126    case 0x0090012:     /* log register */
 127    case 0x0090013:     /* error register */
 128
 129        /* P8 xscom reset */
 130    case 0x2020007:     /* ADU stuff, log register */
 131    case 0x2020009:     /* ADU stuff, error register */
 132    case 0x202000f:     /* ADU stuff, receive status register*/
 133
 134    case 0x2013028:     /* CAPP stuff */
 135    case 0x201302a:     /* CAPP stuff */
 136    case 0x2013801:     /* CAPP stuff */
 137    case 0x2013802:     /* CAPP stuff */
 138
 139        /* P9 CAPP regs */
 140    case 0x2010841:
 141    case 0x2010842:
 142    case 0x201082a:
 143    case 0x2010828:
 144    case 0x4010841:
 145    case 0x4010842:
 146    case 0x401082a:
 147    case 0x4010828:
 148
 149        /* P8 PRD registers */
 150    case PRD_P8_IPOLL_REG_MASK:
 151    case PRD_P8_IPOLL_REG_STATUS:
 152    case PRD_P9_IPOLL_REG_MASK:
 153    case PRD_P9_IPOLL_REG_STATUS:
 154        return true;
 155    default:
 156        return false;
 157    }
 158}
 159
 160static uint64_t xscom_read(void *opaque, hwaddr addr, unsigned width)
 161{
 162    PnvChip *chip = opaque;
 163    uint32_t pcba = pnv_xscom_pcba(chip, addr);
 164    uint64_t val = 0;
 165    MemTxResult result;
 166
 167    /* Handle some SCOMs here before dispatch */
 168    val = xscom_read_default(chip, pcba);
 169    if (val != -1) {
 170        goto complete;
 171    }
 172
 173    val = address_space_ldq(&chip->xscom_as, (uint64_t) pcba << 3,
 174                            MEMTXATTRS_UNSPECIFIED, &result);
 175    if (result != MEMTX_OK) {
 176        qemu_log_mask(LOG_GUEST_ERROR, "XSCOM read failed at @0x%"
 177                      HWADDR_PRIx " pcba=0x%08x\n", addr, pcba);
 178        xscom_complete(current_cpu, HMER_XSCOM_FAIL | HMER_XSCOM_DONE);
 179        return 0;
 180    }
 181
 182complete:
 183    xscom_complete(current_cpu, HMER_XSCOM_DONE);
 184    return val;
 185}
 186
 187static void xscom_write(void *opaque, hwaddr addr, uint64_t val,
 188                        unsigned width)
 189{
 190    PnvChip *chip = opaque;
 191    uint32_t pcba = pnv_xscom_pcba(chip, addr);
 192    MemTxResult result;
 193
 194    /* Handle some SCOMs here before dispatch */
 195    if (xscom_write_default(chip, pcba, val)) {
 196        goto complete;
 197    }
 198
 199    address_space_stq(&chip->xscom_as, (uint64_t) pcba << 3, val,
 200                      MEMTXATTRS_UNSPECIFIED, &result);
 201    if (result != MEMTX_OK) {
 202        qemu_log_mask(LOG_GUEST_ERROR, "XSCOM write failed at @0x%"
 203                      HWADDR_PRIx " pcba=0x%08x data=0x%" PRIx64 "\n",
 204                      addr, pcba, val);
 205        xscom_complete(current_cpu, HMER_XSCOM_FAIL | HMER_XSCOM_DONE);
 206        return;
 207    }
 208
 209complete:
 210    xscom_complete(current_cpu, HMER_XSCOM_DONE);
 211}
 212
 213const MemoryRegionOps pnv_xscom_ops = {
 214    .read = xscom_read,
 215    .write = xscom_write,
 216    .valid.min_access_size = 8,
 217    .valid.max_access_size = 8,
 218    .impl.min_access_size = 8,
 219    .impl.max_access_size = 8,
 220    .endianness = DEVICE_BIG_ENDIAN,
 221};
 222
 223void pnv_xscom_realize(PnvChip *chip, uint64_t size, Error **errp)
 224{
 225    SysBusDevice *sbd = SYS_BUS_DEVICE(chip);
 226    char *name;
 227
 228    name = g_strdup_printf("xscom-%x", chip->chip_id);
 229    memory_region_init_io(&chip->xscom_mmio, OBJECT(chip), &pnv_xscom_ops,
 230                          chip, name, size);
 231    sysbus_init_mmio(sbd, &chip->xscom_mmio);
 232
 233    memory_region_init(&chip->xscom, OBJECT(chip), name, size);
 234    address_space_init(&chip->xscom_as, &chip->xscom, name);
 235    g_free(name);
 236}
 237
 238static const TypeInfo pnv_xscom_interface_info = {
 239    .name = TYPE_PNV_XSCOM_INTERFACE,
 240    .parent = TYPE_INTERFACE,
 241    .class_size = sizeof(PnvXScomInterfaceClass),
 242};
 243
 244static void pnv_xscom_register_types(void)
 245{
 246    type_register_static(&pnv_xscom_interface_info);
 247}
 248
 249type_init(pnv_xscom_register_types)
 250
 251typedef struct ForeachPopulateArgs {
 252    void *fdt;
 253    int xscom_offset;
 254} ForeachPopulateArgs;
 255
 256static int xscom_dt_child(Object *child, void *opaque)
 257{
 258    if (object_dynamic_cast(child, TYPE_PNV_XSCOM_INTERFACE)) {
 259        ForeachPopulateArgs *args = opaque;
 260        PnvXScomInterface *xd = PNV_XSCOM_INTERFACE(child);
 261        PnvXScomInterfaceClass *xc = PNV_XSCOM_INTERFACE_GET_CLASS(xd);
 262
 263        /*
 264         * Only "realized" devices should be configured in the DT
 265         */
 266        if (xc->dt_xscom && DEVICE(child)->realized) {
 267            _FDT((xc->dt_xscom(xd, args->fdt, args->xscom_offset)));
 268        }
 269    }
 270    return 0;
 271}
 272
 273int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset,
 274                 uint64_t xscom_base, uint64_t xscom_size,
 275                 const char *compat, int compat_size)
 276{
 277    uint64_t reg[] = { xscom_base, xscom_size };
 278    int xscom_offset;
 279    ForeachPopulateArgs args;
 280    char *name;
 281
 282    name = g_strdup_printf("xscom@%" PRIx64, be64_to_cpu(reg[0]));
 283    xscom_offset = fdt_add_subnode(fdt, root_offset, name);
 284    _FDT(xscom_offset);
 285    g_free(name);
 286    _FDT((fdt_setprop_cell(fdt, xscom_offset, "ibm,chip-id", chip->chip_id)));
 287    /*
 288     * On P10, the xscom bus id has been deprecated and the chip id is
 289     * calculated from the "Primary topology table index". See skiboot.
 290     */
 291    _FDT((fdt_setprop_cell(fdt, xscom_offset, "ibm,primary-topology-index",
 292                           chip->chip_id)));
 293    _FDT((fdt_setprop_cell(fdt, xscom_offset, "#address-cells", 1)));
 294    _FDT((fdt_setprop_cell(fdt, xscom_offset, "#size-cells", 1)));
 295    _FDT((fdt_setprop(fdt, xscom_offset, "reg", reg, sizeof(reg))));
 296    _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat, compat_size)));
 297    _FDT((fdt_setprop(fdt, xscom_offset, "scom-controller", NULL, 0)));
 298
 299    args.fdt = fdt;
 300    args.xscom_offset = xscom_offset;
 301
 302    /*
 303     * Loop on the whole object hierarchy to catch all
 304     * PnvXScomInterface objects which can lie a bit deeper than the
 305     * first layer.
 306     */
 307    object_child_foreach_recursive(OBJECT(chip), xscom_dt_child, &args);
 308    return 0;
 309}
 310
 311void pnv_xscom_add_subregion(PnvChip *chip, hwaddr offset, MemoryRegion *mr)
 312{
 313    memory_region_add_subregion(&chip->xscom, offset << 3, mr);
 314}
 315
 316void pnv_xscom_region_init(MemoryRegion *mr,
 317                           Object *owner,
 318                           const MemoryRegionOps *ops,
 319                           void *opaque,
 320                           const char *name,
 321                           uint64_t size)
 322{
 323    memory_region_init_io(mr, owner, ops, opaque, name, size << 3);
 324}
 325