qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

xics_pnv.c (5304B)


      1 /*
      2  * QEMU PowerPC PowerNV Interrupt Control Presenter (ICP) model
      3  *
      4  * Copyright (c) 2017, 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 License
      8  * as published by the Free Software Foundation; either version 2.1 of
      9  * the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful, but
     12  * 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 "qapi/error.h"
     22 #include "qemu/log.h"
     23 #include "qemu/module.h"
     24 #include "hw/ppc/xics.h"
     25 
     26 #define ICP_XIRR_POLL    0 /* 1 byte (CPRR) or 4 bytes */
     27 #define ICP_XIRR         4 /* 1 byte (CPRR) or 4 bytes */
     28 #define ICP_MFRR        12 /* 1 byte access only */
     29 
     30 #define ICP_LINKA       16 /* unused */
     31 #define ICP_LINKB       20 /* unused */
     32 #define ICP_LINKC       24 /* unused */
     33 
     34 static uint64_t pnv_icp_read(void *opaque, hwaddr addr, unsigned width)
     35 {
     36     ICPState *icp = ICP(opaque);
     37     PnvICPState *picp = PNV_ICP(opaque);
     38     bool byte0 = (width == 1 && (addr & 0x3) == 0);
     39     uint64_t val = 0xffffffff;
     40 
     41     switch (addr & 0xffc) {
     42     case ICP_XIRR_POLL:
     43         val = icp_ipoll(icp, NULL);
     44         if (byte0) {
     45             val >>= 24;
     46         } else if (width != 4) {
     47             goto bad_access;
     48         }
     49         break;
     50     case ICP_XIRR:
     51         if (byte0) {
     52             val = icp_ipoll(icp, NULL) >> 24;
     53         } else if (width == 4) {
     54             val = icp_accept(icp);
     55         } else {
     56             goto bad_access;
     57         }
     58         break;
     59     case ICP_MFRR:
     60         if (byte0) {
     61             val = icp->mfrr;
     62         } else {
     63             goto bad_access;
     64         }
     65         break;
     66     case ICP_LINKA:
     67         if (width == 4) {
     68             val = picp->links[0];
     69         } else {
     70             goto bad_access;
     71         }
     72         break;
     73     case ICP_LINKB:
     74         if (width == 4) {
     75             val = picp->links[1];
     76         } else {
     77             goto bad_access;
     78         }
     79         break;
     80     case ICP_LINKC:
     81         if (width == 4) {
     82             val = picp->links[2];
     83         } else {
     84             goto bad_access;
     85         }
     86         break;
     87     default:
     88 bad_access:
     89         qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%"
     90                       HWADDR_PRIx"/%d\n", addr, width);
     91     }
     92 
     93     return val;
     94 }
     95 
     96 static void pnv_icp_write(void *opaque, hwaddr addr, uint64_t val,
     97                               unsigned width)
     98 {
     99     ICPState *icp = ICP(opaque);
    100     PnvICPState *picp = PNV_ICP(opaque);
    101     bool byte0 = (width == 1 && (addr & 0x3) == 0);
    102 
    103     switch (addr & 0xffc) {
    104     case ICP_XIRR:
    105         if (byte0) {
    106             icp_set_cppr(icp, val);
    107         } else if (width == 4) {
    108             icp_eoi(icp, val);
    109         } else {
    110             goto bad_access;
    111         }
    112         break;
    113     case ICP_MFRR:
    114         if (byte0) {
    115             icp_set_mfrr(icp, val);
    116         } else {
    117             goto bad_access;
    118         }
    119         break;
    120     case ICP_LINKA:
    121         if (width == 4) {
    122             picp->links[0] = val;
    123         } else {
    124             goto bad_access;
    125         }
    126         break;
    127     case ICP_LINKB:
    128         if (width == 4) {
    129             picp->links[1] = val;
    130         } else {
    131             goto bad_access;
    132         }
    133         break;
    134     case ICP_LINKC:
    135         if (width == 4) {
    136             picp->links[2] = val;
    137         } else {
    138             goto bad_access;
    139         }
    140         break;
    141     default:
    142 bad_access:
    143         qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%"
    144                       HWADDR_PRIx"/%d\n", addr, width);
    145     }
    146 }
    147 
    148 static const MemoryRegionOps pnv_icp_ops = {
    149     .read = pnv_icp_read,
    150     .write = pnv_icp_write,
    151     .endianness = DEVICE_BIG_ENDIAN,
    152     .valid = {
    153         .min_access_size = 1,
    154         .max_access_size = 4,
    155     },
    156     .impl = {
    157         .min_access_size = 1,
    158         .max_access_size = 4,
    159     },
    160 };
    161 
    162 static void pnv_icp_realize(DeviceState *dev, Error **errp)
    163 {
    164     ICPState *icp = ICP(dev);
    165     PnvICPState *pnv_icp = PNV_ICP(icp);
    166     ICPStateClass *icpc = ICP_GET_CLASS(icp);
    167     Error *local_err = NULL;
    168 
    169     icpc->parent_realize(dev, &local_err);
    170     if (local_err) {
    171         error_propagate(errp, local_err);
    172         return;
    173     }
    174 
    175     memory_region_init_io(&pnv_icp->mmio, OBJECT(icp), &pnv_icp_ops,
    176                           icp, "icp-thread", 0x1000);
    177 }
    178 
    179 static void pnv_icp_class_init(ObjectClass *klass, void *data)
    180 {
    181     DeviceClass *dc = DEVICE_CLASS(klass);
    182     ICPStateClass *icpc = ICP_CLASS(klass);
    183 
    184     device_class_set_parent_realize(dc, pnv_icp_realize,
    185                                     &icpc->parent_realize);
    186     dc->desc = "PowerNV ICP";
    187 }
    188 
    189 static const TypeInfo pnv_icp_info = {
    190     .name          = TYPE_PNV_ICP,
    191     .parent        = TYPE_ICP,
    192     .instance_size = sizeof(PnvICPState),
    193     .class_init    = pnv_icp_class_init,
    194     .class_size    = sizeof(ICPStateClass),
    195 };
    196 
    197 static void pnv_icp_register_types(void)
    198 {
    199     type_register_static(&pnv_icp_info);
    200 }
    201 
    202 type_init(pnv_icp_register_types)