qemu/hw/ppc/pnv_occ.c
<<
>>
Prefs
   1/*
   2 * QEMU PowerPC PowerNV Emulation of a few OCC related registers
   3 *
   4 * Copyright (c) 2015-2017, 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, version 2, as
   8 * published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
  17 */
  18
  19#include "qemu/osdep.h"
  20#include "target/ppc/cpu.h"
  21#include "qapi/error.h"
  22#include "qemu/log.h"
  23#include "qemu/module.h"
  24#include "hw/qdev-properties.h"
  25#include "hw/ppc/pnv.h"
  26#include "hw/ppc/pnv_xscom.h"
  27#include "hw/ppc/pnv_occ.h"
  28
  29#define OCB_OCI_OCCMISC         0x4020
  30#define OCB_OCI_OCCMISC_AND     0x4021
  31#define OCB_OCI_OCCMISC_OR      0x4022
  32
  33/* OCC sensors */
  34#define OCC_SENSOR_DATA_BLOCK_OFFSET          0x580000
  35#define OCC_SENSOR_DATA_VALID                 0x580001
  36#define OCC_SENSOR_DATA_VERSION               0x580002
  37#define OCC_SENSOR_DATA_READING_VERSION       0x580004
  38#define OCC_SENSOR_DATA_NR_SENSORS            0x580008
  39#define OCC_SENSOR_DATA_NAMES_OFFSET          0x580010
  40#define OCC_SENSOR_DATA_READING_PING_OFFSET   0x580014
  41#define OCC_SENSOR_DATA_READING_PONG_OFFSET   0x58000c
  42#define OCC_SENSOR_DATA_NAME_LENGTH           0x58000d
  43#define OCC_SENSOR_NAME_STRUCTURE_TYPE        0x580023
  44#define OCC_SENSOR_LOC_CORE                   0x580022
  45#define OCC_SENSOR_LOC_GPU                    0x580020
  46#define OCC_SENSOR_TYPE_POWER                 0x580003
  47#define OCC_SENSOR_NAME                       0x580005
  48#define HWMON_SENSORS_MASK                    0x58001e
  49#define SLW_IMAGE_BASE                        0x0
  50
  51static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
  52{
  53    bool irq_state;
  54    PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
  55
  56    val &= 0xffff000000000000ull;
  57
  58    occ->occmisc = val;
  59    irq_state = !!(val >> 63);
  60    pnv_psi_irq_set(occ->psi, poc->psi_irq, irq_state);
  61}
  62
  63static uint64_t pnv_occ_power8_xscom_read(void *opaque, hwaddr addr,
  64                                          unsigned size)
  65{
  66    PnvOCC *occ = PNV_OCC(opaque);
  67    uint32_t offset = addr >> 3;
  68    uint64_t val = 0;
  69
  70    switch (offset) {
  71    case OCB_OCI_OCCMISC:
  72        val = occ->occmisc;
  73        break;
  74    default:
  75        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
  76                      HWADDR_PRIx "\n", addr >> 3);
  77    }
  78    return val;
  79}
  80
  81static void pnv_occ_power8_xscom_write(void *opaque, hwaddr addr,
  82                                       uint64_t val, unsigned size)
  83{
  84    PnvOCC *occ = PNV_OCC(opaque);
  85    uint32_t offset = addr >> 3;
  86
  87    switch (offset) {
  88    case OCB_OCI_OCCMISC_AND:
  89        pnv_occ_set_misc(occ, occ->occmisc & val);
  90        break;
  91    case OCB_OCI_OCCMISC_OR:
  92        pnv_occ_set_misc(occ, occ->occmisc | val);
  93        break;
  94    case OCB_OCI_OCCMISC:
  95        pnv_occ_set_misc(occ, val);
  96        break;
  97    default:
  98        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
  99                      HWADDR_PRIx "\n", addr >> 3);
 100    }
 101}
 102
 103static uint64_t pnv_occ_common_area_read(void *opaque, hwaddr addr,
 104                                         unsigned width)
 105{
 106    switch (addr) {
 107    /*
 108     * occ-sensor sanity check that asserts the sensor
 109     * header block
 110     */
 111    case OCC_SENSOR_DATA_BLOCK_OFFSET:
 112    case OCC_SENSOR_DATA_VALID:
 113    case OCC_SENSOR_DATA_VERSION:
 114    case OCC_SENSOR_DATA_READING_VERSION:
 115    case OCC_SENSOR_DATA_NR_SENSORS:
 116    case OCC_SENSOR_DATA_NAMES_OFFSET:
 117    case OCC_SENSOR_DATA_READING_PING_OFFSET:
 118    case OCC_SENSOR_DATA_READING_PONG_OFFSET:
 119    case OCC_SENSOR_NAME_STRUCTURE_TYPE:
 120        return 1;
 121    case OCC_SENSOR_DATA_NAME_LENGTH:
 122        return 0x30;
 123    case OCC_SENSOR_LOC_CORE:
 124        return 0x0040;
 125    case OCC_SENSOR_TYPE_POWER:
 126        return 0x0080;
 127    case OCC_SENSOR_NAME:
 128        return 0x1000;
 129    case HWMON_SENSORS_MASK:
 130    case OCC_SENSOR_LOC_GPU:
 131        return 0x8e00;
 132    case SLW_IMAGE_BASE:
 133        return 0x1000000000000000;
 134    }
 135    return 0;
 136}
 137
 138static void pnv_occ_common_area_write(void *opaque, hwaddr addr,
 139                                             uint64_t val, unsigned width)
 140{
 141    /* callback function defined to occ common area write */
 142    return;
 143}
 144
 145static const MemoryRegionOps pnv_occ_power8_xscom_ops = {
 146    .read = pnv_occ_power8_xscom_read,
 147    .write = pnv_occ_power8_xscom_write,
 148    .valid.min_access_size = 8,
 149    .valid.max_access_size = 8,
 150    .impl.min_access_size = 8,
 151    .impl.max_access_size = 8,
 152    .endianness = DEVICE_BIG_ENDIAN,
 153};
 154
 155const MemoryRegionOps pnv_occ_sram_ops = {
 156    .read = pnv_occ_common_area_read,
 157    .write = pnv_occ_common_area_write,
 158    .valid.min_access_size = 1,
 159    .valid.max_access_size = 8,
 160    .impl.min_access_size = 1,
 161    .impl.max_access_size = 8,
 162    .endianness = DEVICE_BIG_ENDIAN,
 163};
 164
 165static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
 166{
 167    PnvOCCClass *poc = PNV_OCC_CLASS(klass);
 168
 169    poc->xscom_size = PNV_XSCOM_OCC_SIZE;
 170    poc->xscom_ops = &pnv_occ_power8_xscom_ops;
 171    poc->psi_irq = PSIHB_IRQ_OCC;
 172}
 173
 174static const TypeInfo pnv_occ_power8_type_info = {
 175    .name          = TYPE_PNV8_OCC,
 176    .parent        = TYPE_PNV_OCC,
 177    .instance_size = sizeof(PnvOCC),
 178    .class_init    = pnv_occ_power8_class_init,
 179};
 180
 181#define P9_OCB_OCI_OCCMISC              0x6080
 182#define P9_OCB_OCI_OCCMISC_CLEAR        0x6081
 183#define P9_OCB_OCI_OCCMISC_OR           0x6082
 184
 185
 186static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
 187                                          unsigned size)
 188{
 189    PnvOCC *occ = PNV_OCC(opaque);
 190    uint32_t offset = addr >> 3;
 191    uint64_t val = 0;
 192
 193    switch (offset) {
 194    case P9_OCB_OCI_OCCMISC:
 195        val = occ->occmisc;
 196        break;
 197    default:
 198        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
 199                      HWADDR_PRIx "\n", addr >> 3);
 200    }
 201    return val;
 202}
 203
 204static void pnv_occ_power9_xscom_write(void *opaque, hwaddr addr,
 205                                       uint64_t val, unsigned size)
 206{
 207    PnvOCC *occ = PNV_OCC(opaque);
 208    uint32_t offset = addr >> 3;
 209
 210    switch (offset) {
 211    case P9_OCB_OCI_OCCMISC_CLEAR:
 212        pnv_occ_set_misc(occ, 0);
 213        break;
 214    case P9_OCB_OCI_OCCMISC_OR:
 215        pnv_occ_set_misc(occ, occ->occmisc | val);
 216        break;
 217    case P9_OCB_OCI_OCCMISC:
 218        pnv_occ_set_misc(occ, val);
 219       break;
 220    default:
 221        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
 222                      HWADDR_PRIx "\n", addr >> 3);
 223    }
 224}
 225
 226static const MemoryRegionOps pnv_occ_power9_xscom_ops = {
 227    .read = pnv_occ_power9_xscom_read,
 228    .write = pnv_occ_power9_xscom_write,
 229    .valid.min_access_size = 8,
 230    .valid.max_access_size = 8,
 231    .impl.min_access_size = 8,
 232    .impl.max_access_size = 8,
 233    .endianness = DEVICE_BIG_ENDIAN,
 234};
 235
 236static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
 237{
 238    PnvOCCClass *poc = PNV_OCC_CLASS(klass);
 239
 240    poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
 241    poc->xscom_ops = &pnv_occ_power9_xscom_ops;
 242    poc->psi_irq = PSIHB9_IRQ_OCC;
 243}
 244
 245static const TypeInfo pnv_occ_power9_type_info = {
 246    .name          = TYPE_PNV9_OCC,
 247    .parent        = TYPE_PNV_OCC,
 248    .instance_size = sizeof(PnvOCC),
 249    .class_init    = pnv_occ_power9_class_init,
 250};
 251
 252static void pnv_occ_realize(DeviceState *dev, Error **errp)
 253{
 254    PnvOCC *occ = PNV_OCC(dev);
 255    PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
 256
 257    assert(occ->psi);
 258
 259    occ->occmisc = 0;
 260
 261    /* XScom region for OCC registers */
 262    pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops,
 263                          occ, "xscom-occ", poc->xscom_size);
 264
 265    /* OCC common area mmio region for OCC SRAM registers */
 266    memory_region_init_io(&occ->sram_regs, OBJECT(dev), &pnv_occ_sram_ops,
 267                          occ, "occ-common-area",
 268                          PNV_OCC_SENSOR_DATA_BLOCK_SIZE);
 269}
 270
 271static Property pnv_occ_properties[] = {
 272    DEFINE_PROP_LINK("psi", PnvOCC, psi, TYPE_PNV_PSI, PnvPsi *),
 273    DEFINE_PROP_END_OF_LIST(),
 274};
 275
 276static void pnv_occ_class_init(ObjectClass *klass, void *data)
 277{
 278    DeviceClass *dc = DEVICE_CLASS(klass);
 279
 280    dc->realize = pnv_occ_realize;
 281    dc->desc = "PowerNV OCC Controller";
 282    device_class_set_props(dc, pnv_occ_properties);
 283    dc->user_creatable = false;
 284}
 285
 286static const TypeInfo pnv_occ_type_info = {
 287    .name          = TYPE_PNV_OCC,
 288    .parent        = TYPE_DEVICE,
 289    .instance_size = sizeof(PnvOCC),
 290    .class_init    = pnv_occ_class_init,
 291    .class_size    = sizeof(PnvOCCClass),
 292    .abstract      = true,
 293};
 294
 295static void pnv_occ_register_types(void)
 296{
 297    type_register_static(&pnv_occ_type_info);
 298    type_register_static(&pnv_occ_power8_type_info);
 299    type_register_static(&pnv_occ_power9_type_info);
 300}
 301
 302type_init(pnv_occ_register_types);
 303